/*
 * crypto - Tcl bindings for parts of the `nettle' crypto library
 * Copyright 2006-2012 Ian Jackson
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this library; if not, see <http://www.gnu.org/licenses/>.
 */


#include "chiark_tcl_crypto.h"

#include <nettle/md5.h>
#include <nettle/sha.h>
#include <nettle/sha3.h>
#include <nettle/serpent.h>
#include <nettle/twofish.h>
#include <nettle/aes.h>
#include <nettle/blowfish.h>

#define NETTLE_BLOCKCIPHERS			\
  DO(serpent,  SERPENT)				\
  DO(twofish,  TWOFISH)				\
/* DO(aes,      AES) */				\
  DO(blowfish, BLOWFISH)			\
  /*  ALIAS(rijndael, aes, AES)*/

#define ALIAS(alias,name,NAME)
#define DO(name,NAME)							      \
  static void alg_##name##_makekey(void *sch, const void *key, int keylen) {  \
    name##_set_key(sch, keylen, key);					      \
  }									      \
  static void alg_##name##_encr(const void *sch, const void *in, void *out) { \
    name##_encrypt((void*)sch, NAME##_BLOCK_SIZE, out, in);		      \
  }									      \
  static void alg_##name##_decr(const void *sch, const void *in, void *out) { \
    name##_decrypt((void*)sch, NAME##_BLOCK_SIZE, out, in);		      \
  }
  NETTLE_BLOCKCIPHERS
#undef DO
#undef ALIAS

const BlockCipherAlgInfo cht_blockcipheralginfo_entries[]= {
#define ALIAS(alias,name,NAME)					\
  { #alias, NAME##_BLOCK_SIZE, sizeof(struct name##_ctx),	\
       NAME##_MIN_KEY_SIZE, NAME##_MAX_KEY_SIZE,		\
    { alg_##name##_makekey, alg_##name##_encr },		\
    { alg_##name##_makekey, alg_##name##_decr }			\
  },
#define DO(name,NAME) ALIAS(name,name,NAME)
  NETTLE_BLOCKCIPHERS
#undef DO
#undef ALIAS
  { 0 }
};

const BlockCipherPropInfo cht_blockcipherpropinfo_entries[]= {
  { "blocklen",  offsetof(BlockCipherAlgInfo, blocksize) },
  { "minkeylen", offsetof(BlockCipherAlgInfo, key_min)   },
  { "maxkeylen", offsetof(BlockCipherAlgInfo, key_max)   },
  { 0 }
};

#define NETTLE_DIGESTS				\
  DO("sha3-224", sha3_224, SHA3_224)		\
  DO("sha3-256", sha3_256, SHA3_256)		\
  DO("sha3-384", sha3_384, SHA3_384)		\
  DO("sha3-512", sha3_512, SHA3_512)		\
  DO2(sha1,   SHA1)				\
  DO2(sha256, SHA256)				\
  DO2(md5,    MD5)

#define DO2(name,NAME) DO(#name,name,NAME)

#define DO(hyname,name,NAME)						      \
  static void alg_##name##_init(void *state) {				      \
    name##_init(state);							      \
  }									      \
  static void alg_##name##_update(void *state, const void *data, int len) {   \
    name##_update(state, len, data);					      \
  }									      \
  static void alg_##name##_final(void *state, void *digest) {		      \
    name##_digest(state,NAME##_DIGEST_SIZE,digest);			      \
  }									      \
  static void alg_##name##_oneshot(void *digest, const void *data, int len) { \
    struct name##_ctx ctx;						      \
    name##_init(&ctx);							      \
    name##_update(&ctx, len, data);					      \
    name##_digest(&ctx,NAME##_DIGEST_SIZE,digest);			      \
  }
  NETTLE_DIGESTS
#undef DO

const HashAlgPropInfo cht_hashalgpropinfo_entries[]= {
  { "hashlen",  offsetof(HashAlgInfo, hashsize)  },
  { "blocklen", offsetof(HashAlgInfo, blocksize) },
  { 0 }
};

const HashAlgInfo cht_hashalginfo_entries[]= {
#define DO(hyname,name,NAME)						    \
  { hyname, NAME##_DIGEST_SIZE, NAME##_DATA_SIZE, sizeof(struct name##_ctx), \
    alg_##name##_init, alg_##name##_update, alg_##name##_final,		    \
    alg_##name##_oneshot },
  NETTLE_DIGESTS
#undef DO
  { 0 }
};
