From a6a5fc648b43b8d4e2685fab4c50753faee365fc Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Mon, 3 Mar 2003 00:59:24 +0000 Subject: [PATCH] added libtomcrypt-0.75 --- aes.c | 409 +++++ aes_tab.c | 851 ++++++++++ ampi.c | 55 + authors | 48 + base64.c | 111 ++ bits.c | 193 +++ blowfish.c | 691 ++++++++ cast5.c | 622 +++++++ cbc.c | 101 ++ cfb.c | 86 + changes | 622 +++++++ crypt.c | 507 ++++++ crypt.pdf | Bin 0 -> 340546 bytes crypt.tex | 2412 ++++++++++++++++++++++++++ ctr.c | 77 + demos/encrypt.c | 202 +++ demos/hashsum.c | 77 + demos/small.c | 11 + demos/test.c | 1586 ++++++++++++++++++ demos/timer.c | 7 + demos/timer.h | 51 + des.c | 728 ++++++++ dh.c | 489 ++++++ dh_sys.c | 774 +++++++++ ecb.c | 49 + ecc.c | 827 +++++++++ ecc_sys.c | 862 ++++++++++ gf.c | 295 ++++ hash.c | 93 + hmac.c | 478 ++++++ keyring.c | 840 ++++++++++ makefile | 262 +++ makefile.ps2 | 293 ++++ makefile.vc | 254 +++ md2.c | 203 +++ md4.c | 290 ++++ md5.c | 268 +++ mem.c | 19 + mpi-config.h | 87 + mpi-types.h | 16 + mpi.c | 4009 ++++++++++++++++++++++++++++++++++++++++++++ mpi.h | 225 +++ mycrypt.h | 75 + mycrypt_argchk.h | 41 + mycrypt_cfg.h | 122 ++ mycrypt_cipher.h | 349 ++++ mycrypt_gf.h | 32 + mycrypt_hash.h | 184 ++ mycrypt_kr.h | 77 + mycrypt_macros.h | 200 +++ mycrypt_misc.h | 16 + mycrypt_pk.h | 219 +++ mycrypt_prng.h | 62 + notes/tech0001.txt | 73 + ofb.c | 60 + packet.c | 43 + prime.c | 1008 +++++++++++ rc2.c | 321 ++++ rc4.c | 97 ++ rc5.c | 234 +++ rc6.c | 253 +++ rsa.c | 436 +++++ rsa_sys.c | 584 +++++++ safer+.c | 506 ++++++ safer.c | 421 +++++ safer_tab.c | 48 + serpent.c | 719 ++++++++ sha1.c | 232 +++ sha256.c | 229 +++ sha384.c | 107 ++ sha512.c | 272 +++ sprng.c | 42 + strings.c | 47 + tiger.c | 775 +++++++++ twofish.c | 727 ++++++++ xtea.c | 121 ++ yarrow.c | 144 ++ 77 files changed, 28956 insertions(+) create mode 100644 aes.c create mode 100644 aes_tab.c create mode 100644 ampi.c create mode 100644 authors create mode 100644 base64.c create mode 100644 bits.c create mode 100644 blowfish.c create mode 100644 cast5.c create mode 100644 cbc.c create mode 100644 cfb.c create mode 100644 changes create mode 100644 crypt.c create mode 100644 crypt.pdf create mode 100644 crypt.tex create mode 100644 ctr.c create mode 100644 demos/encrypt.c create mode 100644 demos/hashsum.c create mode 100644 demos/small.c create mode 100644 demos/test.c create mode 100644 demos/timer.c create mode 100644 demos/timer.h create mode 100644 des.c create mode 100644 dh.c create mode 100644 dh_sys.c create mode 100644 ecb.c create mode 100644 ecc.c create mode 100644 ecc_sys.c create mode 100644 gf.c create mode 100644 hash.c create mode 100644 hmac.c create mode 100644 keyring.c create mode 100644 makefile create mode 100644 makefile.ps2 create mode 100644 makefile.vc create mode 100644 md2.c create mode 100644 md4.c create mode 100644 md5.c create mode 100644 mem.c create mode 100644 mpi-config.h create mode 100644 mpi-types.h create mode 100644 mpi.c create mode 100644 mpi.h create mode 100644 mycrypt.h create mode 100644 mycrypt_argchk.h create mode 100644 mycrypt_cfg.h create mode 100644 mycrypt_cipher.h create mode 100644 mycrypt_gf.h create mode 100644 mycrypt_hash.h create mode 100644 mycrypt_kr.h create mode 100644 mycrypt_macros.h create mode 100644 mycrypt_misc.h create mode 100644 mycrypt_pk.h create mode 100644 mycrypt_prng.h create mode 100644 notes/tech0001.txt create mode 100644 ofb.c create mode 100644 packet.c create mode 100644 prime.c create mode 100644 rc2.c create mode 100644 rc4.c create mode 100644 rc5.c create mode 100644 rc6.c create mode 100644 rsa.c create mode 100644 rsa_sys.c create mode 100644 safer+.c create mode 100644 safer.c create mode 100644 safer_tab.c create mode 100644 serpent.c create mode 100644 sha1.c create mode 100644 sha256.c create mode 100644 sha384.c create mode 100644 sha512.c create mode 100644 sprng.c create mode 100644 strings.c create mode 100644 tiger.c create mode 100644 twofish.c create mode 100644 xtea.c create mode 100644 yarrow.c diff --git a/aes.c b/aes.c new file mode 100644 index 0000000..6f265a8 --- /dev/null +++ b/aes.c @@ -0,0 +1,409 @@ +/* This is an independent implementation of the encryption algorithm: */ +/* */ +/* RIJNDAEL by Joan Daemen and Vincent Rijmen */ +/* */ +/* which is a candidate algorithm in the Advanced Encryption Standard */ +/* programme of the US National Institute of Standards and Technology. */ +/* */ +/* Copyright in this implementation is held by Dr B R Gladman but I */ +/* hereby give permission for its free direct or derivative use subject */ +/* to acknowledgment of its origin and compliance with any conditions */ +/* that the originators of the algorithm place on its exploitation. */ +/* */ +/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */ + + +/* This code has been modified by Tom St Denis for libtomcrypt.a */ + +#include "mycrypt.h" + +#ifdef RIJNDAEL + +const struct _cipher_descriptor rijndael_desc = +{ + "rijndael", + 6, + 16, 32, 16, 10, + &rijndael_setup, + &rijndael_ecb_encrypt, + &rijndael_ecb_decrypt, + &rijndael_test, + &rijndael_keysize +}; + +#include "aes_tab.c" + +#define byte(x, y) (((x)>>(8*(y)))&255) + +#define f_rn(bo, bi, n, k) \ + bo[n] = ft_tab[0][byte(bi[n],0)] ^ \ + ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + +#define i_rn(bo, bi, n, k) \ + bo[n] = it_tab[0][byte(bi[n],0)] ^ \ + it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + +#define ls_box(x) \ + ( fl_tab[0][byte(x, 0)] ^ \ + fl_tab[1][byte(x, 1)] ^ \ + fl_tab[2][byte(x, 2)] ^ \ + fl_tab[3][byte(x, 3)] ) + +#define f_rl(bo, bi, n, k) \ + bo[n] = fl_tab[0][byte(bi[n],0)] ^ \ + fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \ + fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n) + +#define i_rl(bo, bi, n, k) \ + bo[n] = il_tab[0][byte(bi[n],0)] ^ \ + il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \ + il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \ + il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n) + +#define star_x(x) (((x) & 0x7f7f7f7fUL) << 1) ^ ((((x) & 0x80808080UL) >> 7) * 0x1bUL) + +#define imix_col(y,x) \ + u = star_x(x); \ + v = star_x(u); \ + w = star_x(v); \ + t = w ^ (x); \ + (y) = u ^ v ^ w; \ + (y) ^= ROR(u ^ t, 8) ^ \ + ROR(v ^ t, 16) ^ \ + ROR(t,24) + +#ifdef CLEAN_STACK +static int _rijndael_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey) +#else +int rijndael_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey) +#endif +{ + unsigned long t, u, v, w, in_key[8]; + int i, k_len; + + /* check arguments */ + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + if (numrounds == 0) + numrounds = 10 + (2 * ((keylen/8)-2)); + + if (keylen != 16 && keylen != 24 && keylen != 32) { + return CRYPT_INVALID_KEYSIZE; + } + + if (numrounds != (10 + (2 * ((keylen/8)-2)))) { + return CRYPT_INVALID_ROUNDS; + } + + k_len = keylen / 4; + for (i = 0; i < k_len; i++) { + LOAD32L(in_key[i], key+(4*i)); + } + + skey->rijndael.k_len = k_len; + skey->rijndael.eK[0] = in_key[0]; skey->rijndael.eK[1] = in_key[1]; + skey->rijndael.eK[2] = in_key[2]; skey->rijndael.eK[3] = in_key[3]; + + switch(k_len) { + case 4: t = skey->rijndael.eK[3]; + for(i = 0; i < 10; ++i) { + t = ls_box(ROR(t, 8)) ^ rco_tab[i]; + t ^= skey->rijndael.eK[4 * i]; skey->rijndael.eK[4 * i + 4] = t; + t ^= skey->rijndael.eK[4 * i + 1]; skey->rijndael.eK[4 * i + 5] = t; + t ^= skey->rijndael.eK[4 * i + 2]; skey->rijndael.eK[4 * i + 6] = t; + t ^= skey->rijndael.eK[4 * i + 3]; skey->rijndael.eK[4 * i + 7] = t; + } + break; + case 6: skey->rijndael.eK[4] = in_key[4]; + t = skey->rijndael.eK[5] = in_key[5]; + for(i = 0; i < 8; ++i) { + t = ls_box(ROR(t, 8)) ^ rco_tab[i]; + t ^= skey->rijndael.eK[6 * i]; skey->rijndael.eK[6 * i + 6] = t; + t ^= skey->rijndael.eK[6 * i + 1]; skey->rijndael.eK[6 * i + 7] = t; + t ^= skey->rijndael.eK[6 * i + 2]; skey->rijndael.eK[6 * i + 8] = t; + t ^= skey->rijndael.eK[6 * i + 3]; skey->rijndael.eK[6 * i + 9] = t; + t ^= skey->rijndael.eK[6 * i + 4]; skey->rijndael.eK[6 * i + 10] = t; + t ^= skey->rijndael.eK[6 * i + 5]; skey->rijndael.eK[6 * i + 11] = t; + } + break; + case 8: skey->rijndael.eK[4] = in_key[4]; + skey->rijndael.eK[5] = in_key[5]; + skey->rijndael.eK[6] = in_key[6]; + t = skey->rijndael.eK[7] = in_key[7]; + for(i = 0; i < 7; ++i) { + t = ls_box(ROR(t, 8)) ^ rco_tab[i]; + t ^= skey->rijndael.eK[8 * i]; skey->rijndael.eK[8 * i + 8] = t; + t ^= skey->rijndael.eK[8 * i + 1]; skey->rijndael.eK[8 * i + 9] = t; + t ^= skey->rijndael.eK[8 * i + 2]; skey->rijndael.eK[8 * i + 10] = t; + t ^= skey->rijndael.eK[8 * i + 3]; skey->rijndael.eK[8 * i + 11] = t; + + t = skey->rijndael.eK[8 * i + 4] ^ ls_box(t); skey->rijndael.eK[8 * i + 12] = t; + t ^= skey->rijndael.eK[8 * i + 5]; skey->rijndael.eK[8 * i + 13] = t; + t ^= skey->rijndael.eK[8 * i + 6]; skey->rijndael.eK[8 * i + 14] = t; + t ^= skey->rijndael.eK[8 * i + 7]; skey->rijndael.eK[8 * i + 15] = t; + } + break; + } + + skey->rijndael.dK[0] = skey->rijndael.eK[0]; + skey->rijndael.dK[1] = skey->rijndael.eK[1]; + skey->rijndael.dK[2] = skey->rijndael.eK[2]; + skey->rijndael.dK[3] = skey->rijndael.eK[3]; + for(i = 4; i < 4 * k_len + 24; ++i) { + imix_col(skey->rijndael.dK[i], skey->rijndael.eK[i]); + } + return CRYPT_OK; +}; + +#ifdef CLEAN_STACK +int rijndael_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey) +{ + int x; + x = _rijndael_setup(key, keylen, numrounds, skey); + burn_stack(sizeof(unsigned long) * 12 + sizeof(int) * 2); + return x; +} +#endif + +/* encrypt a block of text */ + +#define f_nround(bo, bi, k) \ + f_rn(bo, bi, 0, k); \ + f_rn(bo, bi, 1, k); \ + f_rn(bo, bi, 2, k); \ + f_rn(bo, bi, 3, k); \ + k += 4 + +#define f_lround(bo, bi, k) \ + f_rl(bo, bi, 0, k); \ + f_rl(bo, bi, 1, k); \ + f_rl(bo, bi, 2, k); \ + f_rl(bo, bi, 3, k) + +#ifdef RIJNDAEL_SMALL + +static void _fnround(unsigned long *bo, unsigned long *bi, unsigned long *k) +{ + f_nround(bo, bi, k); +} + +static void _flround(unsigned long *bo, unsigned long *bi, unsigned long *k) +{ + f_lround(bo, bi, k); +} + +#undef f_nround +#define f_nround(bo, bi, k) { _fnround(bo, bi, k); k += 4; } + +#undef f_lround +#define f_lround(bo, bi, k) _flround(bo, bi, k) + +#endif + +void rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) +{ + unsigned long b0[4], b1[4], *kp; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(skey != NULL); + + LOAD32L(b0[0], &pt[0]); LOAD32L(b0[1], &pt[4]); + LOAD32L(b0[2], &pt[8]); LOAD32L(b0[3], &pt[12]); + b0[0] ^= skey->rijndael.eK[0]; b0[1] ^= skey->rijndael.eK[1]; + b0[2] ^= skey->rijndael.eK[2]; b0[3] ^= skey->rijndael.eK[3]; + kp = skey->rijndael.eK + 4; + + if(skey->rijndael.k_len > 6) { + f_nround(b1, b0, kp); f_nround(b0, b1, kp); + } + + if(skey->rijndael.k_len > 4) { + f_nround(b1, b0, kp); f_nround(b0, b1, kp); + } + + f_nround(b1, b0, kp); f_nround(b0, b1, kp); + f_nround(b1, b0, kp); f_nround(b0, b1, kp); + f_nround(b1, b0, kp); f_nround(b0, b1, kp); + f_nround(b1, b0, kp); f_nround(b0, b1, kp); + f_nround(b1, b0, kp); f_lround(b0, b1, kp); + + STORE32L(b0[0], &ct[0]); STORE32L(b0[1], &ct[4]); + STORE32L(b0[2], &ct[8]); STORE32L(b0[3], &ct[12]); +#ifdef CLEAN_STACK + zeromem(b0, sizeof(b0)); + zeromem(b1, sizeof(b1)); +#endif +}; + +/* decrypt a block of text */ +#define i_nround(bo, bi, k) \ + i_rn(bo, bi, 0, k); \ + i_rn(bo, bi, 1, k); \ + i_rn(bo, bi, 2, k); \ + i_rn(bo, bi, 3, k); \ + k -= 4 + +#define i_lround(bo, bi, k) \ + i_rl(bo, bi, 0, k); \ + i_rl(bo, bi, 1, k); \ + i_rl(bo, bi, 2, k); \ + i_rl(bo, bi, 3, k) + +#ifdef RIJNDAEL_SMALL + +static void _inround(unsigned long *bo, unsigned long *bi, unsigned long *k) +{ + i_nround(bo, bi, k); +} + +static void _ilround(unsigned long *bo, unsigned long *bi, unsigned long *k) +{ + i_lround(bo, bi, k); +} + +#undef i_nround +#define i_nround(bo, bi, k) { _inround(bo, bi, k); k -= 4; } + +#undef i_lround +#define i_lround(bo, bi, k) _ilround(bo, bi, k) + +#endif + +void rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) +{ + unsigned long b0[4], b1[4], *kp; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(skey != NULL); + + LOAD32L(b0[0], &ct[0]); LOAD32L(b0[1], &ct[4]); + LOAD32L(b0[2], &ct[8]); LOAD32L(b0[3], &ct[12]); + b0[0] ^= skey->rijndael.eK[4 * skey->rijndael.k_len + 24]; + b0[1] ^= skey->rijndael.eK[4 * skey->rijndael.k_len + 25]; + b0[2] ^= skey->rijndael.eK[4 * skey->rijndael.k_len + 26]; + b0[3] ^= skey->rijndael.eK[4 * skey->rijndael.k_len + 27]; + kp = skey->rijndael.dK + 4 * (skey->rijndael.k_len + 5); + + if(skey->rijndael.k_len > 6) { + i_nround(b1, b0, kp); i_nround(b0, b1, kp); + } + + if(skey->rijndael.k_len > 4) { + i_nround(b1, b0, kp); i_nround(b0, b1, kp); + } + + i_nround(b1, b0, kp); i_nround(b0, b1, kp); + i_nround(b1, b0, kp); i_nround(b0, b1, kp); + i_nround(b1, b0, kp); i_nround(b0, b1, kp); + i_nround(b1, b0, kp); i_nround(b0, b1, kp); + i_nround(b1, b0, kp); i_lround(b0, b1, kp); + + STORE32L(b0[0], &pt[0]); STORE32L(b0[1], &pt[4]); + STORE32L(b0[2], &pt[8]); STORE32L(b0[3], &pt[12]); +#ifdef CLEAN_STACK + zeromem(b0, sizeof(b0)); + zeromem(b1, sizeof(b1)); +#endif +}; + +int rijndael_test(void) +{ + int errno; + + static const unsigned char pt128[16] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; + static const unsigned char key128[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + static const unsigned char ct128[16] = { + 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, + 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a }; + + static const unsigned char key192[24] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }; + static const unsigned char ct192[16] = { + 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, + 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91 }; + + static const unsigned char key256[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }; + static const unsigned char ct256[16] = { + 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, + 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 }; + symmetric_key key; + unsigned char tmp[2][16]; + + if ((errno = rijndael_setup(key128, 16, 0, &key)) != CRYPT_OK) { + return errno; + } + + rijndael_ecb_encrypt(pt128, tmp[0], &key); + rijndael_ecb_decrypt(tmp[0], tmp[1], &key); + if (memcmp(tmp[0], ct128, 16)) { + return CRYPT_FAIL_TESTVECTOR; + } + if (memcmp(tmp[1], pt128, 16)) { + return CRYPT_FAIL_TESTVECTOR; + } + + if ((errno = rijndael_setup(key192, 24, 0, &key)) != CRYPT_OK) { + return errno; + } + + rijndael_ecb_encrypt(pt128, tmp[0], &key); + rijndael_ecb_decrypt(tmp[0], tmp[1], &key); + if (memcmp(tmp[0], ct192, 16)) { + return CRYPT_FAIL_TESTVECTOR; + } + if (memcmp(tmp[1], pt128, 16)) { + return CRYPT_FAIL_TESTVECTOR; + } + + if ((errno = rijndael_setup(key256, 32, 0, &key)) != CRYPT_OK) { + return errno; + } + rijndael_ecb_encrypt(pt128, tmp[0], &key); + rijndael_ecb_decrypt(tmp[0], tmp[1], &key); + if (memcmp(tmp[0], ct256, 16)) { + return CRYPT_FAIL_TESTVECTOR; + } + if (memcmp(tmp[1], pt128, 16)) { + return CRYPT_FAIL_TESTVECTOR; + } + return CRYPT_OK; +} + +int rijndael_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize != NULL); + + if (*desired_keysize < 16) + return CRYPT_INVALID_KEYSIZE; + if (*desired_keysize < 24) { + *desired_keysize = 16; + return CRYPT_OK; + } else if (*desired_keysize < 32) { + *desired_keysize = 24; + return CRYPT_OK; + } else { + *desired_keysize = 32; + return CRYPT_OK; + } +} + +#endif + diff --git a/aes_tab.c b/aes_tab.c new file mode 100644 index 0000000..6088576 --- /dev/null +++ b/aes_tab.c @@ -0,0 +1,851 @@ +/* The precompute tables for AES */ + +static const unsigned long ft_tab[4][256] = { +{0xa56363c6UL, 0x847c7cf8UL, 0x997777eeUL, 0x8d7b7bf6UL, 0x0df2f2ffUL, + 0xbd6b6bd6UL, 0xb16f6fdeUL, 0x54c5c591UL, 0x50303060UL, 0x03010102UL, + 0xa96767ceUL, 0x7d2b2b56UL, 0x19fefee7UL, 0x62d7d7b5UL, 0xe6abab4dUL, + 0x9a7676ecUL, 0x45caca8fUL, 0x9d82821fUL, 0x40c9c989UL, 0x877d7dfaUL, + 0x15fafaefUL, 0xeb5959b2UL, 0xc947478eUL, 0x0bf0f0fbUL, 0xecadad41UL, + 0x67d4d4b3UL, 0xfda2a25fUL, 0xeaafaf45UL, 0xbf9c9c23UL, 0xf7a4a453UL, + 0x967272e4UL, 0x5bc0c09bUL, 0xc2b7b775UL, 0x1cfdfde1UL, 0xae93933dUL, + 0x6a26264cUL, 0x5a36366cUL, 0x413f3f7eUL, 0x02f7f7f5UL, 0x4fcccc83UL, + 0x5c343468UL, 0xf4a5a551UL, 0x34e5e5d1UL, 0x08f1f1f9UL, 0x937171e2UL, + 0x73d8d8abUL, 0x53313162UL, 0x3f15152aUL, 0x0c040408UL, 0x52c7c795UL, + 0x65232346UL, 0x5ec3c39dUL, 0x28181830UL, 0xa1969637UL, 0x0f05050aUL, + 0xb59a9a2fUL, 0x0907070eUL, 0x36121224UL, 0x9b80801bUL, 0x3de2e2dfUL, + 0x26ebebcdUL, 0x6927274eUL, 0xcdb2b27fUL, 0x9f7575eaUL, 0x1b090912UL, + 0x9e83831dUL, 0x742c2c58UL, 0x2e1a1a34UL, 0x2d1b1b36UL, 0xb26e6edcUL, + 0xee5a5ab4UL, 0xfba0a05bUL, 0xf65252a4UL, 0x4d3b3b76UL, 0x61d6d6b7UL, + 0xceb3b37dUL, 0x7b292952UL, 0x3ee3e3ddUL, 0x712f2f5eUL, 0x97848413UL, + 0xf55353a6UL, 0x68d1d1b9UL, 0x00000000UL, 0x2cededc1UL, 0x60202040UL, + 0x1ffcfce3UL, 0xc8b1b179UL, 0xed5b5bb6UL, 0xbe6a6ad4UL, 0x46cbcb8dUL, + 0xd9bebe67UL, 0x4b393972UL, 0xde4a4a94UL, 0xd44c4c98UL, 0xe85858b0UL, + 0x4acfcf85UL, 0x6bd0d0bbUL, 0x2aefefc5UL, 0xe5aaaa4fUL, 0x16fbfbedUL, + 0xc5434386UL, 0xd74d4d9aUL, 0x55333366UL, 0x94858511UL, 0xcf45458aUL, + 0x10f9f9e9UL, 0x06020204UL, 0x817f7ffeUL, 0xf05050a0UL, 0x443c3c78UL, + 0xba9f9f25UL, 0xe3a8a84bUL, 0xf35151a2UL, 0xfea3a35dUL, 0xc0404080UL, + 0x8a8f8f05UL, 0xad92923fUL, 0xbc9d9d21UL, 0x48383870UL, 0x04f5f5f1UL, + 0xdfbcbc63UL, 0xc1b6b677UL, 0x75dadaafUL, 0x63212142UL, 0x30101020UL, + 0x1affffe5UL, 0x0ef3f3fdUL, 0x6dd2d2bfUL, 0x4ccdcd81UL, 0x140c0c18UL, + 0x35131326UL, 0x2fececc3UL, 0xe15f5fbeUL, 0xa2979735UL, 0xcc444488UL, + 0x3917172eUL, 0x57c4c493UL, 0xf2a7a755UL, 0x827e7efcUL, 0x473d3d7aUL, + 0xac6464c8UL, 0xe75d5dbaUL, 0x2b191932UL, 0x957373e6UL, 0xa06060c0UL, + 0x98818119UL, 0xd14f4f9eUL, 0x7fdcdca3UL, 0x66222244UL, 0x7e2a2a54UL, + 0xab90903bUL, 0x8388880bUL, 0xca46468cUL, 0x29eeeec7UL, 0xd3b8b86bUL, + 0x3c141428UL, 0x79dedea7UL, 0xe25e5ebcUL, 0x1d0b0b16UL, 0x76dbdbadUL, + 0x3be0e0dbUL, 0x56323264UL, 0x4e3a3a74UL, 0x1e0a0a14UL, 0xdb494992UL, + 0x0a06060cUL, 0x6c242448UL, 0xe45c5cb8UL, 0x5dc2c29fUL, 0x6ed3d3bdUL, + 0xefacac43UL, 0xa66262c4UL, 0xa8919139UL, 0xa4959531UL, 0x37e4e4d3UL, + 0x8b7979f2UL, 0x32e7e7d5UL, 0x43c8c88bUL, 0x5937376eUL, 0xb76d6ddaUL, + 0x8c8d8d01UL, 0x64d5d5b1UL, 0xd24e4e9cUL, 0xe0a9a949UL, 0xb46c6cd8UL, + 0xfa5656acUL, 0x07f4f4f3UL, 0x25eaeacfUL, 0xaf6565caUL, 0x8e7a7af4UL, + 0xe9aeae47UL, 0x18080810UL, 0xd5baba6fUL, 0x887878f0UL, 0x6f25254aUL, + 0x722e2e5cUL, 0x241c1c38UL, 0xf1a6a657UL, 0xc7b4b473UL, 0x51c6c697UL, + 0x23e8e8cbUL, 0x7cdddda1UL, 0x9c7474e8UL, 0x211f1f3eUL, 0xdd4b4b96UL, + 0xdcbdbd61UL, 0x868b8b0dUL, 0x858a8a0fUL, 0x907070e0UL, 0x423e3e7cUL, + 0xc4b5b571UL, 0xaa6666ccUL, 0xd8484890UL, 0x05030306UL, 0x01f6f6f7UL, + 0x120e0e1cUL, 0xa36161c2UL, 0x5f35356aUL, 0xf95757aeUL, 0xd0b9b969UL, + 0x91868617UL, 0x58c1c199UL, 0x271d1d3aUL, 0xb99e9e27UL, 0x38e1e1d9UL, + 0x13f8f8ebUL, 0xb398982bUL, 0x33111122UL, 0xbb6969d2UL, 0x70d9d9a9UL, + 0x898e8e07UL, 0xa7949433UL, 0xb69b9b2dUL, 0x221e1e3cUL, 0x92878715UL, + 0x20e9e9c9UL, 0x49cece87UL, 0xff5555aaUL, 0x78282850UL, 0x7adfdfa5UL, + 0x8f8c8c03UL, 0xf8a1a159UL, 0x80898909UL, 0x170d0d1aUL, 0xdabfbf65UL, + 0x31e6e6d7UL, 0xc6424284UL, 0xb86868d0UL, 0xc3414182UL, 0xb0999929UL, + 0x772d2d5aUL, 0x110f0f1eUL, 0xcbb0b07bUL, 0xfc5454a8UL, 0xd6bbbb6dUL, + 0x3a16162cUL}, +{0x6363c6a5UL, 0x7c7cf884UL, 0x7777ee99UL, 0x7b7bf68dUL, 0xf2f2ff0dUL, + 0x6b6bd6bdUL, 0x6f6fdeb1UL, 0xc5c59154UL, 0x30306050UL, 0x01010203UL, + 0x6767cea9UL, 0x2b2b567dUL, 0xfefee719UL, 0xd7d7b562UL, 0xabab4de6UL, + 0x7676ec9aUL, 0xcaca8f45UL, 0x82821f9dUL, 0xc9c98940UL, 0x7d7dfa87UL, + 0xfafaef15UL, 0x5959b2ebUL, 0x47478ec9UL, 0xf0f0fb0bUL, 0xadad41ecUL, + 0xd4d4b367UL, 0xa2a25ffdUL, 0xafaf45eaUL, 0x9c9c23bfUL, 0xa4a453f7UL, + 0x7272e496UL, 0xc0c09b5bUL, 0xb7b775c2UL, 0xfdfde11cUL, 0x93933daeUL, + 0x26264c6aUL, 0x36366c5aUL, 0x3f3f7e41UL, 0xf7f7f502UL, 0xcccc834fUL, + 0x3434685cUL, 0xa5a551f4UL, 0xe5e5d134UL, 0xf1f1f908UL, 0x7171e293UL, + 0xd8d8ab73UL, 0x31316253UL, 0x15152a3fUL, 0x0404080cUL, 0xc7c79552UL, + 0x23234665UL, 0xc3c39d5eUL, 0x18183028UL, 0x969637a1UL, 0x05050a0fUL, + 0x9a9a2fb5UL, 0x07070e09UL, 0x12122436UL, 0x80801b9bUL, 0xe2e2df3dUL, + 0xebebcd26UL, 0x27274e69UL, 0xb2b27fcdUL, 0x7575ea9fUL, 0x0909121bUL, + 0x83831d9eUL, 0x2c2c5874UL, 0x1a1a342eUL, 0x1b1b362dUL, 0x6e6edcb2UL, + 0x5a5ab4eeUL, 0xa0a05bfbUL, 0x5252a4f6UL, 0x3b3b764dUL, 0xd6d6b761UL, + 0xb3b37dceUL, 0x2929527bUL, 0xe3e3dd3eUL, 0x2f2f5e71UL, 0x84841397UL, + 0x5353a6f5UL, 0xd1d1b968UL, 0x00000000UL, 0xededc12cUL, 0x20204060UL, + 0xfcfce31fUL, 0xb1b179c8UL, 0x5b5bb6edUL, 0x6a6ad4beUL, 0xcbcb8d46UL, + 0xbebe67d9UL, 0x3939724bUL, 0x4a4a94deUL, 0x4c4c98d4UL, 0x5858b0e8UL, + 0xcfcf854aUL, 0xd0d0bb6bUL, 0xefefc52aUL, 0xaaaa4fe5UL, 0xfbfbed16UL, + 0x434386c5UL, 0x4d4d9ad7UL, 0x33336655UL, 0x85851194UL, 0x45458acfUL, + 0xf9f9e910UL, 0x02020406UL, 0x7f7ffe81UL, 0x5050a0f0UL, 0x3c3c7844UL, + 0x9f9f25baUL, 0xa8a84be3UL, 0x5151a2f3UL, 0xa3a35dfeUL, 0x404080c0UL, + 0x8f8f058aUL, 0x92923fadUL, 0x9d9d21bcUL, 0x38387048UL, 0xf5f5f104UL, + 0xbcbc63dfUL, 0xb6b677c1UL, 0xdadaaf75UL, 0x21214263UL, 0x10102030UL, + 0xffffe51aUL, 0xf3f3fd0eUL, 0xd2d2bf6dUL, 0xcdcd814cUL, 0x0c0c1814UL, + 0x13132635UL, 0xececc32fUL, 0x5f5fbee1UL, 0x979735a2UL, 0x444488ccUL, + 0x17172e39UL, 0xc4c49357UL, 0xa7a755f2UL, 0x7e7efc82UL, 0x3d3d7a47UL, + 0x6464c8acUL, 0x5d5dbae7UL, 0x1919322bUL, 0x7373e695UL, 0x6060c0a0UL, + 0x81811998UL, 0x4f4f9ed1UL, 0xdcdca37fUL, 0x22224466UL, 0x2a2a547eUL, + 0x90903babUL, 0x88880b83UL, 0x46468ccaUL, 0xeeeec729UL, 0xb8b86bd3UL, + 0x1414283cUL, 0xdedea779UL, 0x5e5ebce2UL, 0x0b0b161dUL, 0xdbdbad76UL, + 0xe0e0db3bUL, 0x32326456UL, 0x3a3a744eUL, 0x0a0a141eUL, 0x494992dbUL, + 0x06060c0aUL, 0x2424486cUL, 0x5c5cb8e4UL, 0xc2c29f5dUL, 0xd3d3bd6eUL, + 0xacac43efUL, 0x6262c4a6UL, 0x919139a8UL, 0x959531a4UL, 0xe4e4d337UL, + 0x7979f28bUL, 0xe7e7d532UL, 0xc8c88b43UL, 0x37376e59UL, 0x6d6ddab7UL, + 0x8d8d018cUL, 0xd5d5b164UL, 0x4e4e9cd2UL, 0xa9a949e0UL, 0x6c6cd8b4UL, + 0x5656acfaUL, 0xf4f4f307UL, 0xeaeacf25UL, 0x6565caafUL, 0x7a7af48eUL, + 0xaeae47e9UL, 0x08081018UL, 0xbaba6fd5UL, 0x7878f088UL, 0x25254a6fUL, + 0x2e2e5c72UL, 0x1c1c3824UL, 0xa6a657f1UL, 0xb4b473c7UL, 0xc6c69751UL, + 0xe8e8cb23UL, 0xdddda17cUL, 0x7474e89cUL, 0x1f1f3e21UL, 0x4b4b96ddUL, + 0xbdbd61dcUL, 0x8b8b0d86UL, 0x8a8a0f85UL, 0x7070e090UL, 0x3e3e7c42UL, + 0xb5b571c4UL, 0x6666ccaaUL, 0x484890d8UL, 0x03030605UL, 0xf6f6f701UL, + 0x0e0e1c12UL, 0x6161c2a3UL, 0x35356a5fUL, 0x5757aef9UL, 0xb9b969d0UL, + 0x86861791UL, 0xc1c19958UL, 0x1d1d3a27UL, 0x9e9e27b9UL, 0xe1e1d938UL, + 0xf8f8eb13UL, 0x98982bb3UL, 0x11112233UL, 0x6969d2bbUL, 0xd9d9a970UL, + 0x8e8e0789UL, 0x949433a7UL, 0x9b9b2db6UL, 0x1e1e3c22UL, 0x87871592UL, + 0xe9e9c920UL, 0xcece8749UL, 0x5555aaffUL, 0x28285078UL, 0xdfdfa57aUL, + 0x8c8c038fUL, 0xa1a159f8UL, 0x89890980UL, 0x0d0d1a17UL, 0xbfbf65daUL, + 0xe6e6d731UL, 0x424284c6UL, 0x6868d0b8UL, 0x414182c3UL, 0x999929b0UL, + 0x2d2d5a77UL, 0x0f0f1e11UL, 0xb0b07bcbUL, 0x5454a8fcUL, 0xbbbb6dd6UL, + 0x16162c3aUL}, +{0x63c6a563UL, 0x7cf8847cUL, 0x77ee9977UL, 0x7bf68d7bUL, 0xf2ff0df2UL, + 0x6bd6bd6bUL, 0x6fdeb16fUL, 0xc59154c5UL, 0x30605030UL, 0x01020301UL, + 0x67cea967UL, 0x2b567d2bUL, 0xfee719feUL, 0xd7b562d7UL, 0xab4de6abUL, + 0x76ec9a76UL, 0xca8f45caUL, 0x821f9d82UL, 0xc98940c9UL, 0x7dfa877dUL, + 0xfaef15faUL, 0x59b2eb59UL, 0x478ec947UL, 0xf0fb0bf0UL, 0xad41ecadUL, + 0xd4b367d4UL, 0xa25ffda2UL, 0xaf45eaafUL, 0x9c23bf9cUL, 0xa453f7a4UL, + 0x72e49672UL, 0xc09b5bc0UL, 0xb775c2b7UL, 0xfde11cfdUL, 0x933dae93UL, + 0x264c6a26UL, 0x366c5a36UL, 0x3f7e413fUL, 0xf7f502f7UL, 0xcc834fccUL, + 0x34685c34UL, 0xa551f4a5UL, 0xe5d134e5UL, 0xf1f908f1UL, 0x71e29371UL, + 0xd8ab73d8UL, 0x31625331UL, 0x152a3f15UL, 0x04080c04UL, 0xc79552c7UL, + 0x23466523UL, 0xc39d5ec3UL, 0x18302818UL, 0x9637a196UL, 0x050a0f05UL, + 0x9a2fb59aUL, 0x070e0907UL, 0x12243612UL, 0x801b9b80UL, 0xe2df3de2UL, + 0xebcd26ebUL, 0x274e6927UL, 0xb27fcdb2UL, 0x75ea9f75UL, 0x09121b09UL, + 0x831d9e83UL, 0x2c58742cUL, 0x1a342e1aUL, 0x1b362d1bUL, 0x6edcb26eUL, + 0x5ab4ee5aUL, 0xa05bfba0UL, 0x52a4f652UL, 0x3b764d3bUL, 0xd6b761d6UL, + 0xb37dceb3UL, 0x29527b29UL, 0xe3dd3ee3UL, 0x2f5e712fUL, 0x84139784UL, + 0x53a6f553UL, 0xd1b968d1UL, 0x00000000UL, 0xedc12cedUL, 0x20406020UL, + 0xfce31ffcUL, 0xb179c8b1UL, 0x5bb6ed5bUL, 0x6ad4be6aUL, 0xcb8d46cbUL, + 0xbe67d9beUL, 0x39724b39UL, 0x4a94de4aUL, 0x4c98d44cUL, 0x58b0e858UL, + 0xcf854acfUL, 0xd0bb6bd0UL, 0xefc52aefUL, 0xaa4fe5aaUL, 0xfbed16fbUL, + 0x4386c543UL, 0x4d9ad74dUL, 0x33665533UL, 0x85119485UL, 0x458acf45UL, + 0xf9e910f9UL, 0x02040602UL, 0x7ffe817fUL, 0x50a0f050UL, 0x3c78443cUL, + 0x9f25ba9fUL, 0xa84be3a8UL, 0x51a2f351UL, 0xa35dfea3UL, 0x4080c040UL, + 0x8f058a8fUL, 0x923fad92UL, 0x9d21bc9dUL, 0x38704838UL, 0xf5f104f5UL, + 0xbc63dfbcUL, 0xb677c1b6UL, 0xdaaf75daUL, 0x21426321UL, 0x10203010UL, + 0xffe51affUL, 0xf3fd0ef3UL, 0xd2bf6dd2UL, 0xcd814ccdUL, 0x0c18140cUL, + 0x13263513UL, 0xecc32fecUL, 0x5fbee15fUL, 0x9735a297UL, 0x4488cc44UL, + 0x172e3917UL, 0xc49357c4UL, 0xa755f2a7UL, 0x7efc827eUL, 0x3d7a473dUL, + 0x64c8ac64UL, 0x5dbae75dUL, 0x19322b19UL, 0x73e69573UL, 0x60c0a060UL, + 0x81199881UL, 0x4f9ed14fUL, 0xdca37fdcUL, 0x22446622UL, 0x2a547e2aUL, + 0x903bab90UL, 0x880b8388UL, 0x468cca46UL, 0xeec729eeUL, 0xb86bd3b8UL, + 0x14283c14UL, 0xdea779deUL, 0x5ebce25eUL, 0x0b161d0bUL, 0xdbad76dbUL, + 0xe0db3be0UL, 0x32645632UL, 0x3a744e3aUL, 0x0a141e0aUL, 0x4992db49UL, + 0x060c0a06UL, 0x24486c24UL, 0x5cb8e45cUL, 0xc29f5dc2UL, 0xd3bd6ed3UL, + 0xac43efacUL, 0x62c4a662UL, 0x9139a891UL, 0x9531a495UL, 0xe4d337e4UL, + 0x79f28b79UL, 0xe7d532e7UL, 0xc88b43c8UL, 0x376e5937UL, 0x6ddab76dUL, + 0x8d018c8dUL, 0xd5b164d5UL, 0x4e9cd24eUL, 0xa949e0a9UL, 0x6cd8b46cUL, + 0x56acfa56UL, 0xf4f307f4UL, 0xeacf25eaUL, 0x65caaf65UL, 0x7af48e7aUL, + 0xae47e9aeUL, 0x08101808UL, 0xba6fd5baUL, 0x78f08878UL, 0x254a6f25UL, + 0x2e5c722eUL, 0x1c38241cUL, 0xa657f1a6UL, 0xb473c7b4UL, 0xc69751c6UL, + 0xe8cb23e8UL, 0xdda17cddUL, 0x74e89c74UL, 0x1f3e211fUL, 0x4b96dd4bUL, + 0xbd61dcbdUL, 0x8b0d868bUL, 0x8a0f858aUL, 0x70e09070UL, 0x3e7c423eUL, + 0xb571c4b5UL, 0x66ccaa66UL, 0x4890d848UL, 0x03060503UL, 0xf6f701f6UL, + 0x0e1c120eUL, 0x61c2a361UL, 0x356a5f35UL, 0x57aef957UL, 0xb969d0b9UL, + 0x86179186UL, 0xc19958c1UL, 0x1d3a271dUL, 0x9e27b99eUL, 0xe1d938e1UL, + 0xf8eb13f8UL, 0x982bb398UL, 0x11223311UL, 0x69d2bb69UL, 0xd9a970d9UL, + 0x8e07898eUL, 0x9433a794UL, 0x9b2db69bUL, 0x1e3c221eUL, 0x87159287UL, + 0xe9c920e9UL, 0xce8749ceUL, 0x55aaff55UL, 0x28507828UL, 0xdfa57adfUL, + 0x8c038f8cUL, 0xa159f8a1UL, 0x89098089UL, 0x0d1a170dUL, 0xbf65dabfUL, + 0xe6d731e6UL, 0x4284c642UL, 0x68d0b868UL, 0x4182c341UL, 0x9929b099UL, + 0x2d5a772dUL, 0x0f1e110fUL, 0xb07bcbb0UL, 0x54a8fc54UL, 0xbb6dd6bbUL, + 0x162c3a16UL}, +{0xc6a56363UL, 0xf8847c7cUL, 0xee997777UL, 0xf68d7b7bUL, 0xff0df2f2UL, + 0xd6bd6b6bUL, 0xdeb16f6fUL, 0x9154c5c5UL, 0x60503030UL, 0x02030101UL, + 0xcea96767UL, 0x567d2b2bUL, 0xe719fefeUL, 0xb562d7d7UL, 0x4de6ababUL, + 0xec9a7676UL, 0x8f45cacaUL, 0x1f9d8282UL, 0x8940c9c9UL, 0xfa877d7dUL, + 0xef15fafaUL, 0xb2eb5959UL, 0x8ec94747UL, 0xfb0bf0f0UL, 0x41ecadadUL, + 0xb367d4d4UL, 0x5ffda2a2UL, 0x45eaafafUL, 0x23bf9c9cUL, 0x53f7a4a4UL, + 0xe4967272UL, 0x9b5bc0c0UL, 0x75c2b7b7UL, 0xe11cfdfdUL, 0x3dae9393UL, + 0x4c6a2626UL, 0x6c5a3636UL, 0x7e413f3fUL, 0xf502f7f7UL, 0x834fccccUL, + 0x685c3434UL, 0x51f4a5a5UL, 0xd134e5e5UL, 0xf908f1f1UL, 0xe2937171UL, + 0xab73d8d8UL, 0x62533131UL, 0x2a3f1515UL, 0x080c0404UL, 0x9552c7c7UL, + 0x46652323UL, 0x9d5ec3c3UL, 0x30281818UL, 0x37a19696UL, 0x0a0f0505UL, + 0x2fb59a9aUL, 0x0e090707UL, 0x24361212UL, 0x1b9b8080UL, 0xdf3de2e2UL, + 0xcd26ebebUL, 0x4e692727UL, 0x7fcdb2b2UL, 0xea9f7575UL, 0x121b0909UL, + 0x1d9e8383UL, 0x58742c2cUL, 0x342e1a1aUL, 0x362d1b1bUL, 0xdcb26e6eUL, + 0xb4ee5a5aUL, 0x5bfba0a0UL, 0xa4f65252UL, 0x764d3b3bUL, 0xb761d6d6UL, + 0x7dceb3b3UL, 0x527b2929UL, 0xdd3ee3e3UL, 0x5e712f2fUL, 0x13978484UL, + 0xa6f55353UL, 0xb968d1d1UL, 0x00000000UL, 0xc12cededUL, 0x40602020UL, + 0xe31ffcfcUL, 0x79c8b1b1UL, 0xb6ed5b5bUL, 0xd4be6a6aUL, 0x8d46cbcbUL, + 0x67d9bebeUL, 0x724b3939UL, 0x94de4a4aUL, 0x98d44c4cUL, 0xb0e85858UL, + 0x854acfcfUL, 0xbb6bd0d0UL, 0xc52aefefUL, 0x4fe5aaaaUL, 0xed16fbfbUL, + 0x86c54343UL, 0x9ad74d4dUL, 0x66553333UL, 0x11948585UL, 0x8acf4545UL, + 0xe910f9f9UL, 0x04060202UL, 0xfe817f7fUL, 0xa0f05050UL, 0x78443c3cUL, + 0x25ba9f9fUL, 0x4be3a8a8UL, 0xa2f35151UL, 0x5dfea3a3UL, 0x80c04040UL, + 0x058a8f8fUL, 0x3fad9292UL, 0x21bc9d9dUL, 0x70483838UL, 0xf104f5f5UL, + 0x63dfbcbcUL, 0x77c1b6b6UL, 0xaf75dadaUL, 0x42632121UL, 0x20301010UL, + 0xe51affffUL, 0xfd0ef3f3UL, 0xbf6dd2d2UL, 0x814ccdcdUL, 0x18140c0cUL, + 0x26351313UL, 0xc32fececUL, 0xbee15f5fUL, 0x35a29797UL, 0x88cc4444UL, + 0x2e391717UL, 0x9357c4c4UL, 0x55f2a7a7UL, 0xfc827e7eUL, 0x7a473d3dUL, + 0xc8ac6464UL, 0xbae75d5dUL, 0x322b1919UL, 0xe6957373UL, 0xc0a06060UL, + 0x19988181UL, 0x9ed14f4fUL, 0xa37fdcdcUL, 0x44662222UL, 0x547e2a2aUL, + 0x3bab9090UL, 0x0b838888UL, 0x8cca4646UL, 0xc729eeeeUL, 0x6bd3b8b8UL, + 0x283c1414UL, 0xa779dedeUL, 0xbce25e5eUL, 0x161d0b0bUL, 0xad76dbdbUL, + 0xdb3be0e0UL, 0x64563232UL, 0x744e3a3aUL, 0x141e0a0aUL, 0x92db4949UL, + 0x0c0a0606UL, 0x486c2424UL, 0xb8e45c5cUL, 0x9f5dc2c2UL, 0xbd6ed3d3UL, + 0x43efacacUL, 0xc4a66262UL, 0x39a89191UL, 0x31a49595UL, 0xd337e4e4UL, + 0xf28b7979UL, 0xd532e7e7UL, 0x8b43c8c8UL, 0x6e593737UL, 0xdab76d6dUL, + 0x018c8d8dUL, 0xb164d5d5UL, 0x9cd24e4eUL, 0x49e0a9a9UL, 0xd8b46c6cUL, + 0xacfa5656UL, 0xf307f4f4UL, 0xcf25eaeaUL, 0xcaaf6565UL, 0xf48e7a7aUL, + 0x47e9aeaeUL, 0x10180808UL, 0x6fd5babaUL, 0xf0887878UL, 0x4a6f2525UL, + 0x5c722e2eUL, 0x38241c1cUL, 0x57f1a6a6UL, 0x73c7b4b4UL, 0x9751c6c6UL, + 0xcb23e8e8UL, 0xa17cddddUL, 0xe89c7474UL, 0x3e211f1fUL, 0x96dd4b4bUL, + 0x61dcbdbdUL, 0x0d868b8bUL, 0x0f858a8aUL, 0xe0907070UL, 0x7c423e3eUL, + 0x71c4b5b5UL, 0xccaa6666UL, 0x90d84848UL, 0x06050303UL, 0xf701f6f6UL, + 0x1c120e0eUL, 0xc2a36161UL, 0x6a5f3535UL, 0xaef95757UL, 0x69d0b9b9UL, + 0x17918686UL, 0x9958c1c1UL, 0x3a271d1dUL, 0x27b99e9eUL, 0xd938e1e1UL, + 0xeb13f8f8UL, 0x2bb39898UL, 0x22331111UL, 0xd2bb6969UL, 0xa970d9d9UL, + 0x07898e8eUL, 0x33a79494UL, 0x2db69b9bUL, 0x3c221e1eUL, 0x15928787UL, + 0xc920e9e9UL, 0x8749ceceUL, 0xaaff5555UL, 0x50782828UL, 0xa57adfdfUL, + 0x038f8c8cUL, 0x59f8a1a1UL, 0x09808989UL, 0x1a170d0dUL, 0x65dabfbfUL, + 0xd731e6e6UL, 0x84c64242UL, 0xd0b86868UL, 0x82c34141UL, 0x29b09999UL, + 0x5a772d2dUL, 0x1e110f0fUL, 0x7bcbb0b0UL, 0xa8fc5454UL, 0x6dd6bbbbUL, + 0x2c3a1616UL} + }; + +static const unsigned long it_tab[4][256] = { +{0x50a7f451UL, 0x5365417eUL, 0xc3a4171aUL, 0x965e273aUL, 0xcb6bab3bUL, + 0xf1459d1fUL, 0xab58faacUL, 0x9303e34bUL, 0x55fa3020UL, 0xf66d76adUL, + 0x9176cc88UL, 0x254c02f5UL, 0xfcd7e54fUL, 0xd7cb2ac5UL, 0x80443526UL, + 0x8fa362b5UL, 0x495ab1deUL, 0x671bba25UL, 0x980eea45UL, 0xe1c0fe5dUL, + 0x02752fc3UL, 0x12f04c81UL, 0xa397468dUL, 0xc6f9d36bUL, 0xe75f8f03UL, + 0x959c9215UL, 0xeb7a6dbfUL, 0xda595295UL, 0x2d83bed4UL, 0xd3217458UL, + 0x2969e049UL, 0x44c8c98eUL, 0x6a89c275UL, 0x78798ef4UL, 0x6b3e5899UL, + 0xdd71b927UL, 0xb64fe1beUL, 0x17ad88f0UL, 0x66ac20c9UL, 0xb43ace7dUL, + 0x184adf63UL, 0x82311ae5UL, 0x60335197UL, 0x457f5362UL, 0xe07764b1UL, + 0x84ae6bbbUL, 0x1ca081feUL, 0x942b08f9UL, 0x58684870UL, 0x19fd458fUL, + 0x876cde94UL, 0xb7f87b52UL, 0x23d373abUL, 0xe2024b72UL, 0x578f1fe3UL, + 0x2aab5566UL, 0x0728ebb2UL, 0x03c2b52fUL, 0x9a7bc586UL, 0xa50837d3UL, + 0xf2872830UL, 0xb2a5bf23UL, 0xba6a0302UL, 0x5c8216edUL, 0x2b1ccf8aUL, + 0x92b479a7UL, 0xf0f207f3UL, 0xa1e2694eUL, 0xcdf4da65UL, 0xd5be0506UL, + 0x1f6234d1UL, 0x8afea6c4UL, 0x9d532e34UL, 0xa055f3a2UL, 0x32e18a05UL, + 0x75ebf6a4UL, 0x39ec830bUL, 0xaaef6040UL, 0x069f715eUL, 0x51106ebdUL, + 0xf98a213eUL, 0x3d06dd96UL, 0xae053eddUL, 0x46bde64dUL, 0xb58d5491UL, + 0x055dc471UL, 0x6fd40604UL, 0xff155060UL, 0x24fb9819UL, 0x97e9bdd6UL, + 0xcc434089UL, 0x779ed967UL, 0xbd42e8b0UL, 0x888b8907UL, 0x385b19e7UL, + 0xdbeec879UL, 0x470a7ca1UL, 0xe90f427cUL, 0xc91e84f8UL, 0x00000000UL, + 0x83868009UL, 0x48ed2b32UL, 0xac70111eUL, 0x4e725a6cUL, 0xfbff0efdUL, + 0x5638850fUL, 0x1ed5ae3dUL, 0x27392d36UL, 0x64d90f0aUL, 0x21a65c68UL, + 0xd1545b9bUL, 0x3a2e3624UL, 0xb1670a0cUL, 0x0fe75793UL, 0xd296eeb4UL, + 0x9e919b1bUL, 0x4fc5c080UL, 0xa220dc61UL, 0x694b775aUL, 0x161a121cUL, + 0x0aba93e2UL, 0xe52aa0c0UL, 0x43e0223cUL, 0x1d171b12UL, 0x0b0d090eUL, + 0xadc78bf2UL, 0xb9a8b62dUL, 0xc8a91e14UL, 0x8519f157UL, 0x4c0775afUL, + 0xbbdd99eeUL, 0xfd607fa3UL, 0x9f2601f7UL, 0xbcf5725cUL, 0xc53b6644UL, + 0x347efb5bUL, 0x7629438bUL, 0xdcc623cbUL, 0x68fcedb6UL, 0x63f1e4b8UL, + 0xcadc31d7UL, 0x10856342UL, 0x40229713UL, 0x2011c684UL, 0x7d244a85UL, + 0xf83dbbd2UL, 0x1132f9aeUL, 0x6da129c7UL, 0x4b2f9e1dUL, 0xf330b2dcUL, + 0xec52860dUL, 0xd0e3c177UL, 0x6c16b32bUL, 0x99b970a9UL, 0xfa489411UL, + 0x2264e947UL, 0xc48cfca8UL, 0x1a3ff0a0UL, 0xd82c7d56UL, 0xef903322UL, + 0xc74e4987UL, 0xc1d138d9UL, 0xfea2ca8cUL, 0x360bd498UL, 0xcf81f5a6UL, + 0x28de7aa5UL, 0x268eb7daUL, 0xa4bfad3fUL, 0xe49d3a2cUL, 0x0d927850UL, + 0x9bcc5f6aUL, 0x62467e54UL, 0xc2138df6UL, 0xe8b8d890UL, 0x5ef7392eUL, + 0xf5afc382UL, 0xbe805d9fUL, 0x7c93d069UL, 0xa92dd56fUL, 0xb31225cfUL, + 0x3b99acc8UL, 0xa77d1810UL, 0x6e639ce8UL, 0x7bbb3bdbUL, 0x097826cdUL, + 0xf418596eUL, 0x01b79aecUL, 0xa89a4f83UL, 0x656e95e6UL, 0x7ee6ffaaUL, + 0x08cfbc21UL, 0xe6e815efUL, 0xd99be7baUL, 0xce366f4aUL, 0xd4099feaUL, + 0xd67cb029UL, 0xafb2a431UL, 0x31233f2aUL, 0x3094a5c6UL, 0xc066a235UL, + 0x37bc4e74UL, 0xa6ca82fcUL, 0xb0d090e0UL, 0x15d8a733UL, 0x4a9804f1UL, + 0xf7daec41UL, 0x0e50cd7fUL, 0x2ff69117UL, 0x8dd64d76UL, 0x4db0ef43UL, + 0x544daaccUL, 0xdf0496e4UL, 0xe3b5d19eUL, 0x1b886a4cUL, 0xb81f2cc1UL, + 0x7f516546UL, 0x04ea5e9dUL, 0x5d358c01UL, 0x737487faUL, 0x2e410bfbUL, + 0x5a1d67b3UL, 0x52d2db92UL, 0x335610e9UL, 0x1347d66dUL, 0x8c61d79aUL, + 0x7a0ca137UL, 0x8e14f859UL, 0x893c13ebUL, 0xee27a9ceUL, 0x35c961b7UL, + 0xede51ce1UL, 0x3cb1477aUL, 0x59dfd29cUL, 0x3f73f255UL, 0x79ce1418UL, + 0xbf37c773UL, 0xeacdf753UL, 0x5baafd5fUL, 0x146f3ddfUL, 0x86db4478UL, + 0x81f3afcaUL, 0x3ec468b9UL, 0x2c342438UL, 0x5f40a3c2UL, 0x72c31d16UL, + 0x0c25e2bcUL, 0x8b493c28UL, 0x41950dffUL, 0x7101a839UL, 0xdeb30c08UL, + 0x9ce4b4d8UL, 0x90c15664UL, 0x6184cb7bUL, 0x70b632d5UL, 0x745c6c48UL, + 0x4257b8d0UL}, +{0xa7f45150UL, 0x65417e53UL, 0xa4171ac3UL, 0x5e273a96UL, 0x6bab3bcbUL, + 0x459d1ff1UL, 0x58faacabUL, 0x03e34b93UL, 0xfa302055UL, 0x6d76adf6UL, + 0x76cc8891UL, 0x4c02f525UL, 0xd7e54ffcUL, 0xcb2ac5d7UL, 0x44352680UL, + 0xa362b58fUL, 0x5ab1de49UL, 0x1bba2567UL, 0x0eea4598UL, 0xc0fe5de1UL, + 0x752fc302UL, 0xf04c8112UL, 0x97468da3UL, 0xf9d36bc6UL, 0x5f8f03e7UL, + 0x9c921595UL, 0x7a6dbfebUL, 0x595295daUL, 0x83bed42dUL, 0x217458d3UL, + 0x69e04929UL, 0xc8c98e44UL, 0x89c2756aUL, 0x798ef478UL, 0x3e58996bUL, + 0x71b927ddUL, 0x4fe1beb6UL, 0xad88f017UL, 0xac20c966UL, 0x3ace7db4UL, + 0x4adf6318UL, 0x311ae582UL, 0x33519760UL, 0x7f536245UL, 0x7764b1e0UL, + 0xae6bbb84UL, 0xa081fe1cUL, 0x2b08f994UL, 0x68487058UL, 0xfd458f19UL, + 0x6cde9487UL, 0xf87b52b7UL, 0xd373ab23UL, 0x024b72e2UL, 0x8f1fe357UL, + 0xab55662aUL, 0x28ebb207UL, 0xc2b52f03UL, 0x7bc5869aUL, 0x0837d3a5UL, + 0x872830f2UL, 0xa5bf23b2UL, 0x6a0302baUL, 0x8216ed5cUL, 0x1ccf8a2bUL, + 0xb479a792UL, 0xf207f3f0UL, 0xe2694ea1UL, 0xf4da65cdUL, 0xbe0506d5UL, + 0x6234d11fUL, 0xfea6c48aUL, 0x532e349dUL, 0x55f3a2a0UL, 0xe18a0532UL, + 0xebf6a475UL, 0xec830b39UL, 0xef6040aaUL, 0x9f715e06UL, 0x106ebd51UL, + 0x8a213ef9UL, 0x06dd963dUL, 0x053eddaeUL, 0xbde64d46UL, 0x8d5491b5UL, + 0x5dc47105UL, 0xd406046fUL, 0x155060ffUL, 0xfb981924UL, 0xe9bdd697UL, + 0x434089ccUL, 0x9ed96777UL, 0x42e8b0bdUL, 0x8b890788UL, 0x5b19e738UL, + 0xeec879dbUL, 0x0a7ca147UL, 0x0f427ce9UL, 0x1e84f8c9UL, 0x00000000UL, + 0x86800983UL, 0xed2b3248UL, 0x70111eacUL, 0x725a6c4eUL, 0xff0efdfbUL, + 0x38850f56UL, 0xd5ae3d1eUL, 0x392d3627UL, 0xd90f0a64UL, 0xa65c6821UL, + 0x545b9bd1UL, 0x2e36243aUL, 0x670a0cb1UL, 0xe757930fUL, 0x96eeb4d2UL, + 0x919b1b9eUL, 0xc5c0804fUL, 0x20dc61a2UL, 0x4b775a69UL, 0x1a121c16UL, + 0xba93e20aUL, 0x2aa0c0e5UL, 0xe0223c43UL, 0x171b121dUL, 0x0d090e0bUL, + 0xc78bf2adUL, 0xa8b62db9UL, 0xa91e14c8UL, 0x19f15785UL, 0x0775af4cUL, + 0xdd99eebbUL, 0x607fa3fdUL, 0x2601f79fUL, 0xf5725cbcUL, 0x3b6644c5UL, + 0x7efb5b34UL, 0x29438b76UL, 0xc623cbdcUL, 0xfcedb668UL, 0xf1e4b863UL, + 0xdc31d7caUL, 0x85634210UL, 0x22971340UL, 0x11c68420UL, 0x244a857dUL, + 0x3dbbd2f8UL, 0x32f9ae11UL, 0xa129c76dUL, 0x2f9e1d4bUL, 0x30b2dcf3UL, + 0x52860decUL, 0xe3c177d0UL, 0x16b32b6cUL, 0xb970a999UL, 0x489411faUL, + 0x64e94722UL, 0x8cfca8c4UL, 0x3ff0a01aUL, 0x2c7d56d8UL, 0x903322efUL, + 0x4e4987c7UL, 0xd138d9c1UL, 0xa2ca8cfeUL, 0x0bd49836UL, 0x81f5a6cfUL, + 0xde7aa528UL, 0x8eb7da26UL, 0xbfad3fa4UL, 0x9d3a2ce4UL, 0x9278500dUL, + 0xcc5f6a9bUL, 0x467e5462UL, 0x138df6c2UL, 0xb8d890e8UL, 0xf7392e5eUL, + 0xafc382f5UL, 0x805d9fbeUL, 0x93d0697cUL, 0x2dd56fa9UL, 0x1225cfb3UL, + 0x99acc83bUL, 0x7d1810a7UL, 0x639ce86eUL, 0xbb3bdb7bUL, 0x7826cd09UL, + 0x18596ef4UL, 0xb79aec01UL, 0x9a4f83a8UL, 0x6e95e665UL, 0xe6ffaa7eUL, + 0xcfbc2108UL, 0xe815efe6UL, 0x9be7bad9UL, 0x366f4aceUL, 0x099fead4UL, + 0x7cb029d6UL, 0xb2a431afUL, 0x233f2a31UL, 0x94a5c630UL, 0x66a235c0UL, + 0xbc4e7437UL, 0xca82fca6UL, 0xd090e0b0UL, 0xd8a73315UL, 0x9804f14aUL, + 0xdaec41f7UL, 0x50cd7f0eUL, 0xf691172fUL, 0xd64d768dUL, 0xb0ef434dUL, + 0x4daacc54UL, 0x0496e4dfUL, 0xb5d19ee3UL, 0x886a4c1bUL, 0x1f2cc1b8UL, + 0x5165467fUL, 0xea5e9d04UL, 0x358c015dUL, 0x7487fa73UL, 0x410bfb2eUL, + 0x1d67b35aUL, 0xd2db9252UL, 0x5610e933UL, 0x47d66d13UL, 0x61d79a8cUL, + 0x0ca1377aUL, 0x14f8598eUL, 0x3c13eb89UL, 0x27a9ceeeUL, 0xc961b735UL, + 0xe51ce1edUL, 0xb1477a3cUL, 0xdfd29c59UL, 0x73f2553fUL, 0xce141879UL, + 0x37c773bfUL, 0xcdf753eaUL, 0xaafd5f5bUL, 0x6f3ddf14UL, 0xdb447886UL, + 0xf3afca81UL, 0xc468b93eUL, 0x3424382cUL, 0x40a3c25fUL, 0xc31d1672UL, + 0x25e2bc0cUL, 0x493c288bUL, 0x950dff41UL, 0x01a83971UL, 0xb30c08deUL, + 0xe4b4d89cUL, 0xc1566490UL, 0x84cb7b61UL, 0xb632d570UL, 0x5c6c4874UL, + 0x57b8d042UL}, +{0xf45150a7UL, 0x417e5365UL, 0x171ac3a4UL, 0x273a965eUL, 0xab3bcb6bUL, + 0x9d1ff145UL, 0xfaacab58UL, 0xe34b9303UL, 0x302055faUL, 0x76adf66dUL, + 0xcc889176UL, 0x02f5254cUL, 0xe54ffcd7UL, 0x2ac5d7cbUL, 0x35268044UL, + 0x62b58fa3UL, 0xb1de495aUL, 0xba25671bUL, 0xea45980eUL, 0xfe5de1c0UL, + 0x2fc30275UL, 0x4c8112f0UL, 0x468da397UL, 0xd36bc6f9UL, 0x8f03e75fUL, + 0x9215959cUL, 0x6dbfeb7aUL, 0x5295da59UL, 0xbed42d83UL, 0x7458d321UL, + 0xe0492969UL, 0xc98e44c8UL, 0xc2756a89UL, 0x8ef47879UL, 0x58996b3eUL, + 0xb927dd71UL, 0xe1beb64fUL, 0x88f017adUL, 0x20c966acUL, 0xce7db43aUL, + 0xdf63184aUL, 0x1ae58231UL, 0x51976033UL, 0x5362457fUL, 0x64b1e077UL, + 0x6bbb84aeUL, 0x81fe1ca0UL, 0x08f9942bUL, 0x48705868UL, 0x458f19fdUL, + 0xde94876cUL, 0x7b52b7f8UL, 0x73ab23d3UL, 0x4b72e202UL, 0x1fe3578fUL, + 0x55662aabUL, 0xebb20728UL, 0xb52f03c2UL, 0xc5869a7bUL, 0x37d3a508UL, + 0x2830f287UL, 0xbf23b2a5UL, 0x0302ba6aUL, 0x16ed5c82UL, 0xcf8a2b1cUL, + 0x79a792b4UL, 0x07f3f0f2UL, 0x694ea1e2UL, 0xda65cdf4UL, 0x0506d5beUL, + 0x34d11f62UL, 0xa6c48afeUL, 0x2e349d53UL, 0xf3a2a055UL, 0x8a0532e1UL, + 0xf6a475ebUL, 0x830b39ecUL, 0x6040aaefUL, 0x715e069fUL, 0x6ebd5110UL, + 0x213ef98aUL, 0xdd963d06UL, 0x3eddae05UL, 0xe64d46bdUL, 0x5491b58dUL, + 0xc471055dUL, 0x06046fd4UL, 0x5060ff15UL, 0x981924fbUL, 0xbdd697e9UL, + 0x4089cc43UL, 0xd967779eUL, 0xe8b0bd42UL, 0x8907888bUL, 0x19e7385bUL, + 0xc879dbeeUL, 0x7ca1470aUL, 0x427ce90fUL, 0x84f8c91eUL, 0x00000000UL, + 0x80098386UL, 0x2b3248edUL, 0x111eac70UL, 0x5a6c4e72UL, 0x0efdfbffUL, + 0x850f5638UL, 0xae3d1ed5UL, 0x2d362739UL, 0x0f0a64d9UL, 0x5c6821a6UL, + 0x5b9bd154UL, 0x36243a2eUL, 0x0a0cb167UL, 0x57930fe7UL, 0xeeb4d296UL, + 0x9b1b9e91UL, 0xc0804fc5UL, 0xdc61a220UL, 0x775a694bUL, 0x121c161aUL, + 0x93e20abaUL, 0xa0c0e52aUL, 0x223c43e0UL, 0x1b121d17UL, 0x090e0b0dUL, + 0x8bf2adc7UL, 0xb62db9a8UL, 0x1e14c8a9UL, 0xf1578519UL, 0x75af4c07UL, + 0x99eebbddUL, 0x7fa3fd60UL, 0x01f79f26UL, 0x725cbcf5UL, 0x6644c53bUL, + 0xfb5b347eUL, 0x438b7629UL, 0x23cbdcc6UL, 0xedb668fcUL, 0xe4b863f1UL, + 0x31d7cadcUL, 0x63421085UL, 0x97134022UL, 0xc6842011UL, 0x4a857d24UL, + 0xbbd2f83dUL, 0xf9ae1132UL, 0x29c76da1UL, 0x9e1d4b2fUL, 0xb2dcf330UL, + 0x860dec52UL, 0xc177d0e3UL, 0xb32b6c16UL, 0x70a999b9UL, 0x9411fa48UL, + 0xe9472264UL, 0xfca8c48cUL, 0xf0a01a3fUL, 0x7d56d82cUL, 0x3322ef90UL, + 0x4987c74eUL, 0x38d9c1d1UL, 0xca8cfea2UL, 0xd498360bUL, 0xf5a6cf81UL, + 0x7aa528deUL, 0xb7da268eUL, 0xad3fa4bfUL, 0x3a2ce49dUL, 0x78500d92UL, + 0x5f6a9bccUL, 0x7e546246UL, 0x8df6c213UL, 0xd890e8b8UL, 0x392e5ef7UL, + 0xc382f5afUL, 0x5d9fbe80UL, 0xd0697c93UL, 0xd56fa92dUL, 0x25cfb312UL, + 0xacc83b99UL, 0x1810a77dUL, 0x9ce86e63UL, 0x3bdb7bbbUL, 0x26cd0978UL, + 0x596ef418UL, 0x9aec01b7UL, 0x4f83a89aUL, 0x95e6656eUL, 0xffaa7ee6UL, + 0xbc2108cfUL, 0x15efe6e8UL, 0xe7bad99bUL, 0x6f4ace36UL, 0x9fead409UL, + 0xb029d67cUL, 0xa431afb2UL, 0x3f2a3123UL, 0xa5c63094UL, 0xa235c066UL, + 0x4e7437bcUL, 0x82fca6caUL, 0x90e0b0d0UL, 0xa73315d8UL, 0x04f14a98UL, + 0xec41f7daUL, 0xcd7f0e50UL, 0x91172ff6UL, 0x4d768dd6UL, 0xef434db0UL, + 0xaacc544dUL, 0x96e4df04UL, 0xd19ee3b5UL, 0x6a4c1b88UL, 0x2cc1b81fUL, + 0x65467f51UL, 0x5e9d04eaUL, 0x8c015d35UL, 0x87fa7374UL, 0x0bfb2e41UL, + 0x67b35a1dUL, 0xdb9252d2UL, 0x10e93356UL, 0xd66d1347UL, 0xd79a8c61UL, + 0xa1377a0cUL, 0xf8598e14UL, 0x13eb893cUL, 0xa9ceee27UL, 0x61b735c9UL, + 0x1ce1ede5UL, 0x477a3cb1UL, 0xd29c59dfUL, 0xf2553f73UL, 0x141879ceUL, + 0xc773bf37UL, 0xf753eacdUL, 0xfd5f5baaUL, 0x3ddf146fUL, 0x447886dbUL, + 0xafca81f3UL, 0x68b93ec4UL, 0x24382c34UL, 0xa3c25f40UL, 0x1d1672c3UL, + 0xe2bc0c25UL, 0x3c288b49UL, 0x0dff4195UL, 0xa8397101UL, 0x0c08deb3UL, + 0xb4d89ce4UL, 0x566490c1UL, 0xcb7b6184UL, 0x32d570b6UL, 0x6c48745cUL, + 0xb8d04257UL}, +{0x5150a7f4UL, 0x7e536541UL, 0x1ac3a417UL, 0x3a965e27UL, 0x3bcb6babUL, + 0x1ff1459dUL, 0xacab58faUL, 0x4b9303e3UL, 0x2055fa30UL, 0xadf66d76UL, + 0x889176ccUL, 0xf5254c02UL, 0x4ffcd7e5UL, 0xc5d7cb2aUL, 0x26804435UL, + 0xb58fa362UL, 0xde495ab1UL, 0x25671bbaUL, 0x45980eeaUL, 0x5de1c0feUL, + 0xc302752fUL, 0x8112f04cUL, 0x8da39746UL, 0x6bc6f9d3UL, 0x03e75f8fUL, + 0x15959c92UL, 0xbfeb7a6dUL, 0x95da5952UL, 0xd42d83beUL, 0x58d32174UL, + 0x492969e0UL, 0x8e44c8c9UL, 0x756a89c2UL, 0xf478798eUL, 0x996b3e58UL, + 0x27dd71b9UL, 0xbeb64fe1UL, 0xf017ad88UL, 0xc966ac20UL, 0x7db43aceUL, + 0x63184adfUL, 0xe582311aUL, 0x97603351UL, 0x62457f53UL, 0xb1e07764UL, + 0xbb84ae6bUL, 0xfe1ca081UL, 0xf9942b08UL, 0x70586848UL, 0x8f19fd45UL, + 0x94876cdeUL, 0x52b7f87bUL, 0xab23d373UL, 0x72e2024bUL, 0xe3578f1fUL, + 0x662aab55UL, 0xb20728ebUL, 0x2f03c2b5UL, 0x869a7bc5UL, 0xd3a50837UL, + 0x30f28728UL, 0x23b2a5bfUL, 0x02ba6a03UL, 0xed5c8216UL, 0x8a2b1ccfUL, + 0xa792b479UL, 0xf3f0f207UL, 0x4ea1e269UL, 0x65cdf4daUL, 0x06d5be05UL, + 0xd11f6234UL, 0xc48afea6UL, 0x349d532eUL, 0xa2a055f3UL, 0x0532e18aUL, + 0xa475ebf6UL, 0x0b39ec83UL, 0x40aaef60UL, 0x5e069f71UL, 0xbd51106eUL, + 0x3ef98a21UL, 0x963d06ddUL, 0xddae053eUL, 0x4d46bde6UL, 0x91b58d54UL, + 0x71055dc4UL, 0x046fd406UL, 0x60ff1550UL, 0x1924fb98UL, 0xd697e9bdUL, + 0x89cc4340UL, 0x67779ed9UL, 0xb0bd42e8UL, 0x07888b89UL, 0xe7385b19UL, + 0x79dbeec8UL, 0xa1470a7cUL, 0x7ce90f42UL, 0xf8c91e84UL, 0x00000000UL, + 0x09838680UL, 0x3248ed2bUL, 0x1eac7011UL, 0x6c4e725aUL, 0xfdfbff0eUL, + 0x0f563885UL, 0x3d1ed5aeUL, 0x3627392dUL, 0x0a64d90fUL, 0x6821a65cUL, + 0x9bd1545bUL, 0x243a2e36UL, 0x0cb1670aUL, 0x930fe757UL, 0xb4d296eeUL, + 0x1b9e919bUL, 0x804fc5c0UL, 0x61a220dcUL, 0x5a694b77UL, 0x1c161a12UL, + 0xe20aba93UL, 0xc0e52aa0UL, 0x3c43e022UL, 0x121d171bUL, 0x0e0b0d09UL, + 0xf2adc78bUL, 0x2db9a8b6UL, 0x14c8a91eUL, 0x578519f1UL, 0xaf4c0775UL, + 0xeebbdd99UL, 0xa3fd607fUL, 0xf79f2601UL, 0x5cbcf572UL, 0x44c53b66UL, + 0x5b347efbUL, 0x8b762943UL, 0xcbdcc623UL, 0xb668fcedUL, 0xb863f1e4UL, + 0xd7cadc31UL, 0x42108563UL, 0x13402297UL, 0x842011c6UL, 0x857d244aUL, + 0xd2f83dbbUL, 0xae1132f9UL, 0xc76da129UL, 0x1d4b2f9eUL, 0xdcf330b2UL, + 0x0dec5286UL, 0x77d0e3c1UL, 0x2b6c16b3UL, 0xa999b970UL, 0x11fa4894UL, + 0x472264e9UL, 0xa8c48cfcUL, 0xa01a3ff0UL, 0x56d82c7dUL, 0x22ef9033UL, + 0x87c74e49UL, 0xd9c1d138UL, 0x8cfea2caUL, 0x98360bd4UL, 0xa6cf81f5UL, + 0xa528de7aUL, 0xda268eb7UL, 0x3fa4bfadUL, 0x2ce49d3aUL, 0x500d9278UL, + 0x6a9bcc5fUL, 0x5462467eUL, 0xf6c2138dUL, 0x90e8b8d8UL, 0x2e5ef739UL, + 0x82f5afc3UL, 0x9fbe805dUL, 0x697c93d0UL, 0x6fa92dd5UL, 0xcfb31225UL, + 0xc83b99acUL, 0x10a77d18UL, 0xe86e639cUL, 0xdb7bbb3bUL, 0xcd097826UL, + 0x6ef41859UL, 0xec01b79aUL, 0x83a89a4fUL, 0xe6656e95UL, 0xaa7ee6ffUL, + 0x2108cfbcUL, 0xefe6e815UL, 0xbad99be7UL, 0x4ace366fUL, 0xead4099fUL, + 0x29d67cb0UL, 0x31afb2a4UL, 0x2a31233fUL, 0xc63094a5UL, 0x35c066a2UL, + 0x7437bc4eUL, 0xfca6ca82UL, 0xe0b0d090UL, 0x3315d8a7UL, 0xf14a9804UL, + 0x41f7daecUL, 0x7f0e50cdUL, 0x172ff691UL, 0x768dd64dUL, 0x434db0efUL, + 0xcc544daaUL, 0xe4df0496UL, 0x9ee3b5d1UL, 0x4c1b886aUL, 0xc1b81f2cUL, + 0x467f5165UL, 0x9d04ea5eUL, 0x015d358cUL, 0xfa737487UL, 0xfb2e410bUL, + 0xb35a1d67UL, 0x9252d2dbUL, 0xe9335610UL, 0x6d1347d6UL, 0x9a8c61d7UL, + 0x377a0ca1UL, 0x598e14f8UL, 0xeb893c13UL, 0xceee27a9UL, 0xb735c961UL, + 0xe1ede51cUL, 0x7a3cb147UL, 0x9c59dfd2UL, 0x553f73f2UL, 0x1879ce14UL, + 0x73bf37c7UL, 0x53eacdf7UL, 0x5f5baafdUL, 0xdf146f3dUL, 0x7886db44UL, + 0xca81f3afUL, 0xb93ec468UL, 0x382c3424UL, 0xc25f40a3UL, 0x1672c31dUL, + 0xbc0c25e2UL, 0x288b493cUL, 0xff41950dUL, 0x397101a8UL, 0x08deb30cUL, + 0xd89ce4b4UL, 0x6490c156UL, 0x7b6184cbUL, 0xd570b632UL, 0x48745c6cUL, + 0xd04257b8UL} + }; + +static const unsigned long fl_tab[4][256] = { +{0x00000063UL, 0x0000007cUL, 0x00000077UL, 0x0000007bUL, 0x000000f2UL, + 0x0000006bUL, 0x0000006fUL, 0x000000c5UL, 0x00000030UL, 0x00000001UL, + 0x00000067UL, 0x0000002bUL, 0x000000feUL, 0x000000d7UL, 0x000000abUL, + 0x00000076UL, 0x000000caUL, 0x00000082UL, 0x000000c9UL, 0x0000007dUL, + 0x000000faUL, 0x00000059UL, 0x00000047UL, 0x000000f0UL, 0x000000adUL, + 0x000000d4UL, 0x000000a2UL, 0x000000afUL, 0x0000009cUL, 0x000000a4UL, + 0x00000072UL, 0x000000c0UL, 0x000000b7UL, 0x000000fdUL, 0x00000093UL, + 0x00000026UL, 0x00000036UL, 0x0000003fUL, 0x000000f7UL, 0x000000ccUL, + 0x00000034UL, 0x000000a5UL, 0x000000e5UL, 0x000000f1UL, 0x00000071UL, + 0x000000d8UL, 0x00000031UL, 0x00000015UL, 0x00000004UL, 0x000000c7UL, + 0x00000023UL, 0x000000c3UL, 0x00000018UL, 0x00000096UL, 0x00000005UL, + 0x0000009aUL, 0x00000007UL, 0x00000012UL, 0x00000080UL, 0x000000e2UL, + 0x000000ebUL, 0x00000027UL, 0x000000b2UL, 0x00000075UL, 0x00000009UL, + 0x00000083UL, 0x0000002cUL, 0x0000001aUL, 0x0000001bUL, 0x0000006eUL, + 0x0000005aUL, 0x000000a0UL, 0x00000052UL, 0x0000003bUL, 0x000000d6UL, + 0x000000b3UL, 0x00000029UL, 0x000000e3UL, 0x0000002fUL, 0x00000084UL, + 0x00000053UL, 0x000000d1UL, 0x00000000UL, 0x000000edUL, 0x00000020UL, + 0x000000fcUL, 0x000000b1UL, 0x0000005bUL, 0x0000006aUL, 0x000000cbUL, + 0x000000beUL, 0x00000039UL, 0x0000004aUL, 0x0000004cUL, 0x00000058UL, + 0x000000cfUL, 0x000000d0UL, 0x000000efUL, 0x000000aaUL, 0x000000fbUL, + 0x00000043UL, 0x0000004dUL, 0x00000033UL, 0x00000085UL, 0x00000045UL, + 0x000000f9UL, 0x00000002UL, 0x0000007fUL, 0x00000050UL, 0x0000003cUL, + 0x0000009fUL, 0x000000a8UL, 0x00000051UL, 0x000000a3UL, 0x00000040UL, + 0x0000008fUL, 0x00000092UL, 0x0000009dUL, 0x00000038UL, 0x000000f5UL, + 0x000000bcUL, 0x000000b6UL, 0x000000daUL, 0x00000021UL, 0x00000010UL, + 0x000000ffUL, 0x000000f3UL, 0x000000d2UL, 0x000000cdUL, 0x0000000cUL, + 0x00000013UL, 0x000000ecUL, 0x0000005fUL, 0x00000097UL, 0x00000044UL, + 0x00000017UL, 0x000000c4UL, 0x000000a7UL, 0x0000007eUL, 0x0000003dUL, + 0x00000064UL, 0x0000005dUL, 0x00000019UL, 0x00000073UL, 0x00000060UL, + 0x00000081UL, 0x0000004fUL, 0x000000dcUL, 0x00000022UL, 0x0000002aUL, + 0x00000090UL, 0x00000088UL, 0x00000046UL, 0x000000eeUL, 0x000000b8UL, + 0x00000014UL, 0x000000deUL, 0x0000005eUL, 0x0000000bUL, 0x000000dbUL, + 0x000000e0UL, 0x00000032UL, 0x0000003aUL, 0x0000000aUL, 0x00000049UL, + 0x00000006UL, 0x00000024UL, 0x0000005cUL, 0x000000c2UL, 0x000000d3UL, + 0x000000acUL, 0x00000062UL, 0x00000091UL, 0x00000095UL, 0x000000e4UL, + 0x00000079UL, 0x000000e7UL, 0x000000c8UL, 0x00000037UL, 0x0000006dUL, + 0x0000008dUL, 0x000000d5UL, 0x0000004eUL, 0x000000a9UL, 0x0000006cUL, + 0x00000056UL, 0x000000f4UL, 0x000000eaUL, 0x00000065UL, 0x0000007aUL, + 0x000000aeUL, 0x00000008UL, 0x000000baUL, 0x00000078UL, 0x00000025UL, + 0x0000002eUL, 0x0000001cUL, 0x000000a6UL, 0x000000b4UL, 0x000000c6UL, + 0x000000e8UL, 0x000000ddUL, 0x00000074UL, 0x0000001fUL, 0x0000004bUL, + 0x000000bdUL, 0x0000008bUL, 0x0000008aUL, 0x00000070UL, 0x0000003eUL, + 0x000000b5UL, 0x00000066UL, 0x00000048UL, 0x00000003UL, 0x000000f6UL, + 0x0000000eUL, 0x00000061UL, 0x00000035UL, 0x00000057UL, 0x000000b9UL, + 0x00000086UL, 0x000000c1UL, 0x0000001dUL, 0x0000009eUL, 0x000000e1UL, + 0x000000f8UL, 0x00000098UL, 0x00000011UL, 0x00000069UL, 0x000000d9UL, + 0x0000008eUL, 0x00000094UL, 0x0000009bUL, 0x0000001eUL, 0x00000087UL, + 0x000000e9UL, 0x000000ceUL, 0x00000055UL, 0x00000028UL, 0x000000dfUL, + 0x0000008cUL, 0x000000a1UL, 0x00000089UL, 0x0000000dUL, 0x000000bfUL, + 0x000000e6UL, 0x00000042UL, 0x00000068UL, 0x00000041UL, 0x00000099UL, + 0x0000002dUL, 0x0000000fUL, 0x000000b0UL, 0x00000054UL, 0x000000bbUL, + 0x00000016UL}, +{0x00006300UL, 0x00007c00UL, 0x00007700UL, 0x00007b00UL, 0x0000f200UL, + 0x00006b00UL, 0x00006f00UL, 0x0000c500UL, 0x00003000UL, 0x00000100UL, + 0x00006700UL, 0x00002b00UL, 0x0000fe00UL, 0x0000d700UL, 0x0000ab00UL, + 0x00007600UL, 0x0000ca00UL, 0x00008200UL, 0x0000c900UL, 0x00007d00UL, + 0x0000fa00UL, 0x00005900UL, 0x00004700UL, 0x0000f000UL, 0x0000ad00UL, + 0x0000d400UL, 0x0000a200UL, 0x0000af00UL, 0x00009c00UL, 0x0000a400UL, + 0x00007200UL, 0x0000c000UL, 0x0000b700UL, 0x0000fd00UL, 0x00009300UL, + 0x00002600UL, 0x00003600UL, 0x00003f00UL, 0x0000f700UL, 0x0000cc00UL, + 0x00003400UL, 0x0000a500UL, 0x0000e500UL, 0x0000f100UL, 0x00007100UL, + 0x0000d800UL, 0x00003100UL, 0x00001500UL, 0x00000400UL, 0x0000c700UL, + 0x00002300UL, 0x0000c300UL, 0x00001800UL, 0x00009600UL, 0x00000500UL, + 0x00009a00UL, 0x00000700UL, 0x00001200UL, 0x00008000UL, 0x0000e200UL, + 0x0000eb00UL, 0x00002700UL, 0x0000b200UL, 0x00007500UL, 0x00000900UL, + 0x00008300UL, 0x00002c00UL, 0x00001a00UL, 0x00001b00UL, 0x00006e00UL, + 0x00005a00UL, 0x0000a000UL, 0x00005200UL, 0x00003b00UL, 0x0000d600UL, + 0x0000b300UL, 0x00002900UL, 0x0000e300UL, 0x00002f00UL, 0x00008400UL, + 0x00005300UL, 0x0000d100UL, 0x00000000UL, 0x0000ed00UL, 0x00002000UL, + 0x0000fc00UL, 0x0000b100UL, 0x00005b00UL, 0x00006a00UL, 0x0000cb00UL, + 0x0000be00UL, 0x00003900UL, 0x00004a00UL, 0x00004c00UL, 0x00005800UL, + 0x0000cf00UL, 0x0000d000UL, 0x0000ef00UL, 0x0000aa00UL, 0x0000fb00UL, + 0x00004300UL, 0x00004d00UL, 0x00003300UL, 0x00008500UL, 0x00004500UL, + 0x0000f900UL, 0x00000200UL, 0x00007f00UL, 0x00005000UL, 0x00003c00UL, + 0x00009f00UL, 0x0000a800UL, 0x00005100UL, 0x0000a300UL, 0x00004000UL, + 0x00008f00UL, 0x00009200UL, 0x00009d00UL, 0x00003800UL, 0x0000f500UL, + 0x0000bc00UL, 0x0000b600UL, 0x0000da00UL, 0x00002100UL, 0x00001000UL, + 0x0000ff00UL, 0x0000f300UL, 0x0000d200UL, 0x0000cd00UL, 0x00000c00UL, + 0x00001300UL, 0x0000ec00UL, 0x00005f00UL, 0x00009700UL, 0x00004400UL, + 0x00001700UL, 0x0000c400UL, 0x0000a700UL, 0x00007e00UL, 0x00003d00UL, + 0x00006400UL, 0x00005d00UL, 0x00001900UL, 0x00007300UL, 0x00006000UL, + 0x00008100UL, 0x00004f00UL, 0x0000dc00UL, 0x00002200UL, 0x00002a00UL, + 0x00009000UL, 0x00008800UL, 0x00004600UL, 0x0000ee00UL, 0x0000b800UL, + 0x00001400UL, 0x0000de00UL, 0x00005e00UL, 0x00000b00UL, 0x0000db00UL, + 0x0000e000UL, 0x00003200UL, 0x00003a00UL, 0x00000a00UL, 0x00004900UL, + 0x00000600UL, 0x00002400UL, 0x00005c00UL, 0x0000c200UL, 0x0000d300UL, + 0x0000ac00UL, 0x00006200UL, 0x00009100UL, 0x00009500UL, 0x0000e400UL, + 0x00007900UL, 0x0000e700UL, 0x0000c800UL, 0x00003700UL, 0x00006d00UL, + 0x00008d00UL, 0x0000d500UL, 0x00004e00UL, 0x0000a900UL, 0x00006c00UL, + 0x00005600UL, 0x0000f400UL, 0x0000ea00UL, 0x00006500UL, 0x00007a00UL, + 0x0000ae00UL, 0x00000800UL, 0x0000ba00UL, 0x00007800UL, 0x00002500UL, + 0x00002e00UL, 0x00001c00UL, 0x0000a600UL, 0x0000b400UL, 0x0000c600UL, + 0x0000e800UL, 0x0000dd00UL, 0x00007400UL, 0x00001f00UL, 0x00004b00UL, + 0x0000bd00UL, 0x00008b00UL, 0x00008a00UL, 0x00007000UL, 0x00003e00UL, + 0x0000b500UL, 0x00006600UL, 0x00004800UL, 0x00000300UL, 0x0000f600UL, + 0x00000e00UL, 0x00006100UL, 0x00003500UL, 0x00005700UL, 0x0000b900UL, + 0x00008600UL, 0x0000c100UL, 0x00001d00UL, 0x00009e00UL, 0x0000e100UL, + 0x0000f800UL, 0x00009800UL, 0x00001100UL, 0x00006900UL, 0x0000d900UL, + 0x00008e00UL, 0x00009400UL, 0x00009b00UL, 0x00001e00UL, 0x00008700UL, + 0x0000e900UL, 0x0000ce00UL, 0x00005500UL, 0x00002800UL, 0x0000df00UL, + 0x00008c00UL, 0x0000a100UL, 0x00008900UL, 0x00000d00UL, 0x0000bf00UL, + 0x0000e600UL, 0x00004200UL, 0x00006800UL, 0x00004100UL, 0x00009900UL, + 0x00002d00UL, 0x00000f00UL, 0x0000b000UL, 0x00005400UL, 0x0000bb00UL, + 0x00001600UL}, +{0x00630000UL, 0x007c0000UL, 0x00770000UL, 0x007b0000UL, 0x00f20000UL, + 0x006b0000UL, 0x006f0000UL, 0x00c50000UL, 0x00300000UL, 0x00010000UL, + 0x00670000UL, 0x002b0000UL, 0x00fe0000UL, 0x00d70000UL, 0x00ab0000UL, + 0x00760000UL, 0x00ca0000UL, 0x00820000UL, 0x00c90000UL, 0x007d0000UL, + 0x00fa0000UL, 0x00590000UL, 0x00470000UL, 0x00f00000UL, 0x00ad0000UL, + 0x00d40000UL, 0x00a20000UL, 0x00af0000UL, 0x009c0000UL, 0x00a40000UL, + 0x00720000UL, 0x00c00000UL, 0x00b70000UL, 0x00fd0000UL, 0x00930000UL, + 0x00260000UL, 0x00360000UL, 0x003f0000UL, 0x00f70000UL, 0x00cc0000UL, + 0x00340000UL, 0x00a50000UL, 0x00e50000UL, 0x00f10000UL, 0x00710000UL, + 0x00d80000UL, 0x00310000UL, 0x00150000UL, 0x00040000UL, 0x00c70000UL, + 0x00230000UL, 0x00c30000UL, 0x00180000UL, 0x00960000UL, 0x00050000UL, + 0x009a0000UL, 0x00070000UL, 0x00120000UL, 0x00800000UL, 0x00e20000UL, + 0x00eb0000UL, 0x00270000UL, 0x00b20000UL, 0x00750000UL, 0x00090000UL, + 0x00830000UL, 0x002c0000UL, 0x001a0000UL, 0x001b0000UL, 0x006e0000UL, + 0x005a0000UL, 0x00a00000UL, 0x00520000UL, 0x003b0000UL, 0x00d60000UL, + 0x00b30000UL, 0x00290000UL, 0x00e30000UL, 0x002f0000UL, 0x00840000UL, + 0x00530000UL, 0x00d10000UL, 0x00000000UL, 0x00ed0000UL, 0x00200000UL, + 0x00fc0000UL, 0x00b10000UL, 0x005b0000UL, 0x006a0000UL, 0x00cb0000UL, + 0x00be0000UL, 0x00390000UL, 0x004a0000UL, 0x004c0000UL, 0x00580000UL, + 0x00cf0000UL, 0x00d00000UL, 0x00ef0000UL, 0x00aa0000UL, 0x00fb0000UL, + 0x00430000UL, 0x004d0000UL, 0x00330000UL, 0x00850000UL, 0x00450000UL, + 0x00f90000UL, 0x00020000UL, 0x007f0000UL, 0x00500000UL, 0x003c0000UL, + 0x009f0000UL, 0x00a80000UL, 0x00510000UL, 0x00a30000UL, 0x00400000UL, + 0x008f0000UL, 0x00920000UL, 0x009d0000UL, 0x00380000UL, 0x00f50000UL, + 0x00bc0000UL, 0x00b60000UL, 0x00da0000UL, 0x00210000UL, 0x00100000UL, + 0x00ff0000UL, 0x00f30000UL, 0x00d20000UL, 0x00cd0000UL, 0x000c0000UL, + 0x00130000UL, 0x00ec0000UL, 0x005f0000UL, 0x00970000UL, 0x00440000UL, + 0x00170000UL, 0x00c40000UL, 0x00a70000UL, 0x007e0000UL, 0x003d0000UL, + 0x00640000UL, 0x005d0000UL, 0x00190000UL, 0x00730000UL, 0x00600000UL, + 0x00810000UL, 0x004f0000UL, 0x00dc0000UL, 0x00220000UL, 0x002a0000UL, + 0x00900000UL, 0x00880000UL, 0x00460000UL, 0x00ee0000UL, 0x00b80000UL, + 0x00140000UL, 0x00de0000UL, 0x005e0000UL, 0x000b0000UL, 0x00db0000UL, + 0x00e00000UL, 0x00320000UL, 0x003a0000UL, 0x000a0000UL, 0x00490000UL, + 0x00060000UL, 0x00240000UL, 0x005c0000UL, 0x00c20000UL, 0x00d30000UL, + 0x00ac0000UL, 0x00620000UL, 0x00910000UL, 0x00950000UL, 0x00e40000UL, + 0x00790000UL, 0x00e70000UL, 0x00c80000UL, 0x00370000UL, 0x006d0000UL, + 0x008d0000UL, 0x00d50000UL, 0x004e0000UL, 0x00a90000UL, 0x006c0000UL, + 0x00560000UL, 0x00f40000UL, 0x00ea0000UL, 0x00650000UL, 0x007a0000UL, + 0x00ae0000UL, 0x00080000UL, 0x00ba0000UL, 0x00780000UL, 0x00250000UL, + 0x002e0000UL, 0x001c0000UL, 0x00a60000UL, 0x00b40000UL, 0x00c60000UL, + 0x00e80000UL, 0x00dd0000UL, 0x00740000UL, 0x001f0000UL, 0x004b0000UL, + 0x00bd0000UL, 0x008b0000UL, 0x008a0000UL, 0x00700000UL, 0x003e0000UL, + 0x00b50000UL, 0x00660000UL, 0x00480000UL, 0x00030000UL, 0x00f60000UL, + 0x000e0000UL, 0x00610000UL, 0x00350000UL, 0x00570000UL, 0x00b90000UL, + 0x00860000UL, 0x00c10000UL, 0x001d0000UL, 0x009e0000UL, 0x00e10000UL, + 0x00f80000UL, 0x00980000UL, 0x00110000UL, 0x00690000UL, 0x00d90000UL, + 0x008e0000UL, 0x00940000UL, 0x009b0000UL, 0x001e0000UL, 0x00870000UL, + 0x00e90000UL, 0x00ce0000UL, 0x00550000UL, 0x00280000UL, 0x00df0000UL, + 0x008c0000UL, 0x00a10000UL, 0x00890000UL, 0x000d0000UL, 0x00bf0000UL, + 0x00e60000UL, 0x00420000UL, 0x00680000UL, 0x00410000UL, 0x00990000UL, + 0x002d0000UL, 0x000f0000UL, 0x00b00000UL, 0x00540000UL, 0x00bb0000UL, + 0x00160000UL}, +{0x63000000UL, 0x7c000000UL, 0x77000000UL, 0x7b000000UL, 0xf2000000UL, + 0x6b000000UL, 0x6f000000UL, 0xc5000000UL, 0x30000000UL, 0x01000000UL, + 0x67000000UL, 0x2b000000UL, 0xfe000000UL, 0xd7000000UL, 0xab000000UL, + 0x76000000UL, 0xca000000UL, 0x82000000UL, 0xc9000000UL, 0x7d000000UL, + 0xfa000000UL, 0x59000000UL, 0x47000000UL, 0xf0000000UL, 0xad000000UL, + 0xd4000000UL, 0xa2000000UL, 0xaf000000UL, 0x9c000000UL, 0xa4000000UL, + 0x72000000UL, 0xc0000000UL, 0xb7000000UL, 0xfd000000UL, 0x93000000UL, + 0x26000000UL, 0x36000000UL, 0x3f000000UL, 0xf7000000UL, 0xcc000000UL, + 0x34000000UL, 0xa5000000UL, 0xe5000000UL, 0xf1000000UL, 0x71000000UL, + 0xd8000000UL, 0x31000000UL, 0x15000000UL, 0x04000000UL, 0xc7000000UL, + 0x23000000UL, 0xc3000000UL, 0x18000000UL, 0x96000000UL, 0x05000000UL, + 0x9a000000UL, 0x07000000UL, 0x12000000UL, 0x80000000UL, 0xe2000000UL, + 0xeb000000UL, 0x27000000UL, 0xb2000000UL, 0x75000000UL, 0x09000000UL, + 0x83000000UL, 0x2c000000UL, 0x1a000000UL, 0x1b000000UL, 0x6e000000UL, + 0x5a000000UL, 0xa0000000UL, 0x52000000UL, 0x3b000000UL, 0xd6000000UL, + 0xb3000000UL, 0x29000000UL, 0xe3000000UL, 0x2f000000UL, 0x84000000UL, + 0x53000000UL, 0xd1000000UL, 0x00000000UL, 0xed000000UL, 0x20000000UL, + 0xfc000000UL, 0xb1000000UL, 0x5b000000UL, 0x6a000000UL, 0xcb000000UL, + 0xbe000000UL, 0x39000000UL, 0x4a000000UL, 0x4c000000UL, 0x58000000UL, + 0xcf000000UL, 0xd0000000UL, 0xef000000UL, 0xaa000000UL, 0xfb000000UL, + 0x43000000UL, 0x4d000000UL, 0x33000000UL, 0x85000000UL, 0x45000000UL, + 0xf9000000UL, 0x02000000UL, 0x7f000000UL, 0x50000000UL, 0x3c000000UL, + 0x9f000000UL, 0xa8000000UL, 0x51000000UL, 0xa3000000UL, 0x40000000UL, + 0x8f000000UL, 0x92000000UL, 0x9d000000UL, 0x38000000UL, 0xf5000000UL, + 0xbc000000UL, 0xb6000000UL, 0xda000000UL, 0x21000000UL, 0x10000000UL, + 0xff000000UL, 0xf3000000UL, 0xd2000000UL, 0xcd000000UL, 0x0c000000UL, + 0x13000000UL, 0xec000000UL, 0x5f000000UL, 0x97000000UL, 0x44000000UL, + 0x17000000UL, 0xc4000000UL, 0xa7000000UL, 0x7e000000UL, 0x3d000000UL, + 0x64000000UL, 0x5d000000UL, 0x19000000UL, 0x73000000UL, 0x60000000UL, + 0x81000000UL, 0x4f000000UL, 0xdc000000UL, 0x22000000UL, 0x2a000000UL, + 0x90000000UL, 0x88000000UL, 0x46000000UL, 0xee000000UL, 0xb8000000UL, + 0x14000000UL, 0xde000000UL, 0x5e000000UL, 0x0b000000UL, 0xdb000000UL, + 0xe0000000UL, 0x32000000UL, 0x3a000000UL, 0x0a000000UL, 0x49000000UL, + 0x06000000UL, 0x24000000UL, 0x5c000000UL, 0xc2000000UL, 0xd3000000UL, + 0xac000000UL, 0x62000000UL, 0x91000000UL, 0x95000000UL, 0xe4000000UL, + 0x79000000UL, 0xe7000000UL, 0xc8000000UL, 0x37000000UL, 0x6d000000UL, + 0x8d000000UL, 0xd5000000UL, 0x4e000000UL, 0xa9000000UL, 0x6c000000UL, + 0x56000000UL, 0xf4000000UL, 0xea000000UL, 0x65000000UL, 0x7a000000UL, + 0xae000000UL, 0x08000000UL, 0xba000000UL, 0x78000000UL, 0x25000000UL, + 0x2e000000UL, 0x1c000000UL, 0xa6000000UL, 0xb4000000UL, 0xc6000000UL, + 0xe8000000UL, 0xdd000000UL, 0x74000000UL, 0x1f000000UL, 0x4b000000UL, + 0xbd000000UL, 0x8b000000UL, 0x8a000000UL, 0x70000000UL, 0x3e000000UL, + 0xb5000000UL, 0x66000000UL, 0x48000000UL, 0x03000000UL, 0xf6000000UL, + 0x0e000000UL, 0x61000000UL, 0x35000000UL, 0x57000000UL, 0xb9000000UL, + 0x86000000UL, 0xc1000000UL, 0x1d000000UL, 0x9e000000UL, 0xe1000000UL, + 0xf8000000UL, 0x98000000UL, 0x11000000UL, 0x69000000UL, 0xd9000000UL, + 0x8e000000UL, 0x94000000UL, 0x9b000000UL, 0x1e000000UL, 0x87000000UL, + 0xe9000000UL, 0xce000000UL, 0x55000000UL, 0x28000000UL, 0xdf000000UL, + 0x8c000000UL, 0xa1000000UL, 0x89000000UL, 0x0d000000UL, 0xbf000000UL, + 0xe6000000UL, 0x42000000UL, 0x68000000UL, 0x41000000UL, 0x99000000UL, + 0x2d000000UL, 0x0f000000UL, 0xb0000000UL, 0x54000000UL, 0xbb000000UL, + 0x16000000UL} + }; + +static const unsigned long il_tab[4][256] = { +{0x00000052UL, 0x00000009UL, 0x0000006aUL, 0x000000d5UL, 0x00000030UL, + 0x00000036UL, 0x000000a5UL, 0x00000038UL, 0x000000bfUL, 0x00000040UL, + 0x000000a3UL, 0x0000009eUL, 0x00000081UL, 0x000000f3UL, 0x000000d7UL, + 0x000000fbUL, 0x0000007cUL, 0x000000e3UL, 0x00000039UL, 0x00000082UL, + 0x0000009bUL, 0x0000002fUL, 0x000000ffUL, 0x00000087UL, 0x00000034UL, + 0x0000008eUL, 0x00000043UL, 0x00000044UL, 0x000000c4UL, 0x000000deUL, + 0x000000e9UL, 0x000000cbUL, 0x00000054UL, 0x0000007bUL, 0x00000094UL, + 0x00000032UL, 0x000000a6UL, 0x000000c2UL, 0x00000023UL, 0x0000003dUL, + 0x000000eeUL, 0x0000004cUL, 0x00000095UL, 0x0000000bUL, 0x00000042UL, + 0x000000faUL, 0x000000c3UL, 0x0000004eUL, 0x00000008UL, 0x0000002eUL, + 0x000000a1UL, 0x00000066UL, 0x00000028UL, 0x000000d9UL, 0x00000024UL, + 0x000000b2UL, 0x00000076UL, 0x0000005bUL, 0x000000a2UL, 0x00000049UL, + 0x0000006dUL, 0x0000008bUL, 0x000000d1UL, 0x00000025UL, 0x00000072UL, + 0x000000f8UL, 0x000000f6UL, 0x00000064UL, 0x00000086UL, 0x00000068UL, + 0x00000098UL, 0x00000016UL, 0x000000d4UL, 0x000000a4UL, 0x0000005cUL, + 0x000000ccUL, 0x0000005dUL, 0x00000065UL, 0x000000b6UL, 0x00000092UL, + 0x0000006cUL, 0x00000070UL, 0x00000048UL, 0x00000050UL, 0x000000fdUL, + 0x000000edUL, 0x000000b9UL, 0x000000daUL, 0x0000005eUL, 0x00000015UL, + 0x00000046UL, 0x00000057UL, 0x000000a7UL, 0x0000008dUL, 0x0000009dUL, + 0x00000084UL, 0x00000090UL, 0x000000d8UL, 0x000000abUL, 0x00000000UL, + 0x0000008cUL, 0x000000bcUL, 0x000000d3UL, 0x0000000aUL, 0x000000f7UL, + 0x000000e4UL, 0x00000058UL, 0x00000005UL, 0x000000b8UL, 0x000000b3UL, + 0x00000045UL, 0x00000006UL, 0x000000d0UL, 0x0000002cUL, 0x0000001eUL, + 0x0000008fUL, 0x000000caUL, 0x0000003fUL, 0x0000000fUL, 0x00000002UL, + 0x000000c1UL, 0x000000afUL, 0x000000bdUL, 0x00000003UL, 0x00000001UL, + 0x00000013UL, 0x0000008aUL, 0x0000006bUL, 0x0000003aUL, 0x00000091UL, + 0x00000011UL, 0x00000041UL, 0x0000004fUL, 0x00000067UL, 0x000000dcUL, + 0x000000eaUL, 0x00000097UL, 0x000000f2UL, 0x000000cfUL, 0x000000ceUL, + 0x000000f0UL, 0x000000b4UL, 0x000000e6UL, 0x00000073UL, 0x00000096UL, + 0x000000acUL, 0x00000074UL, 0x00000022UL, 0x000000e7UL, 0x000000adUL, + 0x00000035UL, 0x00000085UL, 0x000000e2UL, 0x000000f9UL, 0x00000037UL, + 0x000000e8UL, 0x0000001cUL, 0x00000075UL, 0x000000dfUL, 0x0000006eUL, + 0x00000047UL, 0x000000f1UL, 0x0000001aUL, 0x00000071UL, 0x0000001dUL, + 0x00000029UL, 0x000000c5UL, 0x00000089UL, 0x0000006fUL, 0x000000b7UL, + 0x00000062UL, 0x0000000eUL, 0x000000aaUL, 0x00000018UL, 0x000000beUL, + 0x0000001bUL, 0x000000fcUL, 0x00000056UL, 0x0000003eUL, 0x0000004bUL, + 0x000000c6UL, 0x000000d2UL, 0x00000079UL, 0x00000020UL, 0x0000009aUL, + 0x000000dbUL, 0x000000c0UL, 0x000000feUL, 0x00000078UL, 0x000000cdUL, + 0x0000005aUL, 0x000000f4UL, 0x0000001fUL, 0x000000ddUL, 0x000000a8UL, + 0x00000033UL, 0x00000088UL, 0x00000007UL, 0x000000c7UL, 0x00000031UL, + 0x000000b1UL, 0x00000012UL, 0x00000010UL, 0x00000059UL, 0x00000027UL, + 0x00000080UL, 0x000000ecUL, 0x0000005fUL, 0x00000060UL, 0x00000051UL, + 0x0000007fUL, 0x000000a9UL, 0x00000019UL, 0x000000b5UL, 0x0000004aUL, + 0x0000000dUL, 0x0000002dUL, 0x000000e5UL, 0x0000007aUL, 0x0000009fUL, + 0x00000093UL, 0x000000c9UL, 0x0000009cUL, 0x000000efUL, 0x000000a0UL, + 0x000000e0UL, 0x0000003bUL, 0x0000004dUL, 0x000000aeUL, 0x0000002aUL, + 0x000000f5UL, 0x000000b0UL, 0x000000c8UL, 0x000000ebUL, 0x000000bbUL, + 0x0000003cUL, 0x00000083UL, 0x00000053UL, 0x00000099UL, 0x00000061UL, + 0x00000017UL, 0x0000002bUL, 0x00000004UL, 0x0000007eUL, 0x000000baUL, + 0x00000077UL, 0x000000d6UL, 0x00000026UL, 0x000000e1UL, 0x00000069UL, + 0x00000014UL, 0x00000063UL, 0x00000055UL, 0x00000021UL, 0x0000000cUL, + 0x0000007dUL}, +{0x00005200UL, 0x00000900UL, 0x00006a00UL, 0x0000d500UL, 0x00003000UL, + 0x00003600UL, 0x0000a500UL, 0x00003800UL, 0x0000bf00UL, 0x00004000UL, + 0x0000a300UL, 0x00009e00UL, 0x00008100UL, 0x0000f300UL, 0x0000d700UL, + 0x0000fb00UL, 0x00007c00UL, 0x0000e300UL, 0x00003900UL, 0x00008200UL, + 0x00009b00UL, 0x00002f00UL, 0x0000ff00UL, 0x00008700UL, 0x00003400UL, + 0x00008e00UL, 0x00004300UL, 0x00004400UL, 0x0000c400UL, 0x0000de00UL, + 0x0000e900UL, 0x0000cb00UL, 0x00005400UL, 0x00007b00UL, 0x00009400UL, + 0x00003200UL, 0x0000a600UL, 0x0000c200UL, 0x00002300UL, 0x00003d00UL, + 0x0000ee00UL, 0x00004c00UL, 0x00009500UL, 0x00000b00UL, 0x00004200UL, + 0x0000fa00UL, 0x0000c300UL, 0x00004e00UL, 0x00000800UL, 0x00002e00UL, + 0x0000a100UL, 0x00006600UL, 0x00002800UL, 0x0000d900UL, 0x00002400UL, + 0x0000b200UL, 0x00007600UL, 0x00005b00UL, 0x0000a200UL, 0x00004900UL, + 0x00006d00UL, 0x00008b00UL, 0x0000d100UL, 0x00002500UL, 0x00007200UL, + 0x0000f800UL, 0x0000f600UL, 0x00006400UL, 0x00008600UL, 0x00006800UL, + 0x00009800UL, 0x00001600UL, 0x0000d400UL, 0x0000a400UL, 0x00005c00UL, + 0x0000cc00UL, 0x00005d00UL, 0x00006500UL, 0x0000b600UL, 0x00009200UL, + 0x00006c00UL, 0x00007000UL, 0x00004800UL, 0x00005000UL, 0x0000fd00UL, + 0x0000ed00UL, 0x0000b900UL, 0x0000da00UL, 0x00005e00UL, 0x00001500UL, + 0x00004600UL, 0x00005700UL, 0x0000a700UL, 0x00008d00UL, 0x00009d00UL, + 0x00008400UL, 0x00009000UL, 0x0000d800UL, 0x0000ab00UL, 0x00000000UL, + 0x00008c00UL, 0x0000bc00UL, 0x0000d300UL, 0x00000a00UL, 0x0000f700UL, + 0x0000e400UL, 0x00005800UL, 0x00000500UL, 0x0000b800UL, 0x0000b300UL, + 0x00004500UL, 0x00000600UL, 0x0000d000UL, 0x00002c00UL, 0x00001e00UL, + 0x00008f00UL, 0x0000ca00UL, 0x00003f00UL, 0x00000f00UL, 0x00000200UL, + 0x0000c100UL, 0x0000af00UL, 0x0000bd00UL, 0x00000300UL, 0x00000100UL, + 0x00001300UL, 0x00008a00UL, 0x00006b00UL, 0x00003a00UL, 0x00009100UL, + 0x00001100UL, 0x00004100UL, 0x00004f00UL, 0x00006700UL, 0x0000dc00UL, + 0x0000ea00UL, 0x00009700UL, 0x0000f200UL, 0x0000cf00UL, 0x0000ce00UL, + 0x0000f000UL, 0x0000b400UL, 0x0000e600UL, 0x00007300UL, 0x00009600UL, + 0x0000ac00UL, 0x00007400UL, 0x00002200UL, 0x0000e700UL, 0x0000ad00UL, + 0x00003500UL, 0x00008500UL, 0x0000e200UL, 0x0000f900UL, 0x00003700UL, + 0x0000e800UL, 0x00001c00UL, 0x00007500UL, 0x0000df00UL, 0x00006e00UL, + 0x00004700UL, 0x0000f100UL, 0x00001a00UL, 0x00007100UL, 0x00001d00UL, + 0x00002900UL, 0x0000c500UL, 0x00008900UL, 0x00006f00UL, 0x0000b700UL, + 0x00006200UL, 0x00000e00UL, 0x0000aa00UL, 0x00001800UL, 0x0000be00UL, + 0x00001b00UL, 0x0000fc00UL, 0x00005600UL, 0x00003e00UL, 0x00004b00UL, + 0x0000c600UL, 0x0000d200UL, 0x00007900UL, 0x00002000UL, 0x00009a00UL, + 0x0000db00UL, 0x0000c000UL, 0x0000fe00UL, 0x00007800UL, 0x0000cd00UL, + 0x00005a00UL, 0x0000f400UL, 0x00001f00UL, 0x0000dd00UL, 0x0000a800UL, + 0x00003300UL, 0x00008800UL, 0x00000700UL, 0x0000c700UL, 0x00003100UL, + 0x0000b100UL, 0x00001200UL, 0x00001000UL, 0x00005900UL, 0x00002700UL, + 0x00008000UL, 0x0000ec00UL, 0x00005f00UL, 0x00006000UL, 0x00005100UL, + 0x00007f00UL, 0x0000a900UL, 0x00001900UL, 0x0000b500UL, 0x00004a00UL, + 0x00000d00UL, 0x00002d00UL, 0x0000e500UL, 0x00007a00UL, 0x00009f00UL, + 0x00009300UL, 0x0000c900UL, 0x00009c00UL, 0x0000ef00UL, 0x0000a000UL, + 0x0000e000UL, 0x00003b00UL, 0x00004d00UL, 0x0000ae00UL, 0x00002a00UL, + 0x0000f500UL, 0x0000b000UL, 0x0000c800UL, 0x0000eb00UL, 0x0000bb00UL, + 0x00003c00UL, 0x00008300UL, 0x00005300UL, 0x00009900UL, 0x00006100UL, + 0x00001700UL, 0x00002b00UL, 0x00000400UL, 0x00007e00UL, 0x0000ba00UL, + 0x00007700UL, 0x0000d600UL, 0x00002600UL, 0x0000e100UL, 0x00006900UL, + 0x00001400UL, 0x00006300UL, 0x00005500UL, 0x00002100UL, 0x00000c00UL, + 0x00007d00UL}, +{0x00520000UL, 0x00090000UL, 0x006a0000UL, 0x00d50000UL, 0x00300000UL, + 0x00360000UL, 0x00a50000UL, 0x00380000UL, 0x00bf0000UL, 0x00400000UL, + 0x00a30000UL, 0x009e0000UL, 0x00810000UL, 0x00f30000UL, 0x00d70000UL, + 0x00fb0000UL, 0x007c0000UL, 0x00e30000UL, 0x00390000UL, 0x00820000UL, + 0x009b0000UL, 0x002f0000UL, 0x00ff0000UL, 0x00870000UL, 0x00340000UL, + 0x008e0000UL, 0x00430000UL, 0x00440000UL, 0x00c40000UL, 0x00de0000UL, + 0x00e90000UL, 0x00cb0000UL, 0x00540000UL, 0x007b0000UL, 0x00940000UL, + 0x00320000UL, 0x00a60000UL, 0x00c20000UL, 0x00230000UL, 0x003d0000UL, + 0x00ee0000UL, 0x004c0000UL, 0x00950000UL, 0x000b0000UL, 0x00420000UL, + 0x00fa0000UL, 0x00c30000UL, 0x004e0000UL, 0x00080000UL, 0x002e0000UL, + 0x00a10000UL, 0x00660000UL, 0x00280000UL, 0x00d90000UL, 0x00240000UL, + 0x00b20000UL, 0x00760000UL, 0x005b0000UL, 0x00a20000UL, 0x00490000UL, + 0x006d0000UL, 0x008b0000UL, 0x00d10000UL, 0x00250000UL, 0x00720000UL, + 0x00f80000UL, 0x00f60000UL, 0x00640000UL, 0x00860000UL, 0x00680000UL, + 0x00980000UL, 0x00160000UL, 0x00d40000UL, 0x00a40000UL, 0x005c0000UL, + 0x00cc0000UL, 0x005d0000UL, 0x00650000UL, 0x00b60000UL, 0x00920000UL, + 0x006c0000UL, 0x00700000UL, 0x00480000UL, 0x00500000UL, 0x00fd0000UL, + 0x00ed0000UL, 0x00b90000UL, 0x00da0000UL, 0x005e0000UL, 0x00150000UL, + 0x00460000UL, 0x00570000UL, 0x00a70000UL, 0x008d0000UL, 0x009d0000UL, + 0x00840000UL, 0x00900000UL, 0x00d80000UL, 0x00ab0000UL, 0x00000000UL, + 0x008c0000UL, 0x00bc0000UL, 0x00d30000UL, 0x000a0000UL, 0x00f70000UL, + 0x00e40000UL, 0x00580000UL, 0x00050000UL, 0x00b80000UL, 0x00b30000UL, + 0x00450000UL, 0x00060000UL, 0x00d00000UL, 0x002c0000UL, 0x001e0000UL, + 0x008f0000UL, 0x00ca0000UL, 0x003f0000UL, 0x000f0000UL, 0x00020000UL, + 0x00c10000UL, 0x00af0000UL, 0x00bd0000UL, 0x00030000UL, 0x00010000UL, + 0x00130000UL, 0x008a0000UL, 0x006b0000UL, 0x003a0000UL, 0x00910000UL, + 0x00110000UL, 0x00410000UL, 0x004f0000UL, 0x00670000UL, 0x00dc0000UL, + 0x00ea0000UL, 0x00970000UL, 0x00f20000UL, 0x00cf0000UL, 0x00ce0000UL, + 0x00f00000UL, 0x00b40000UL, 0x00e60000UL, 0x00730000UL, 0x00960000UL, + 0x00ac0000UL, 0x00740000UL, 0x00220000UL, 0x00e70000UL, 0x00ad0000UL, + 0x00350000UL, 0x00850000UL, 0x00e20000UL, 0x00f90000UL, 0x00370000UL, + 0x00e80000UL, 0x001c0000UL, 0x00750000UL, 0x00df0000UL, 0x006e0000UL, + 0x00470000UL, 0x00f10000UL, 0x001a0000UL, 0x00710000UL, 0x001d0000UL, + 0x00290000UL, 0x00c50000UL, 0x00890000UL, 0x006f0000UL, 0x00b70000UL, + 0x00620000UL, 0x000e0000UL, 0x00aa0000UL, 0x00180000UL, 0x00be0000UL, + 0x001b0000UL, 0x00fc0000UL, 0x00560000UL, 0x003e0000UL, 0x004b0000UL, + 0x00c60000UL, 0x00d20000UL, 0x00790000UL, 0x00200000UL, 0x009a0000UL, + 0x00db0000UL, 0x00c00000UL, 0x00fe0000UL, 0x00780000UL, 0x00cd0000UL, + 0x005a0000UL, 0x00f40000UL, 0x001f0000UL, 0x00dd0000UL, 0x00a80000UL, + 0x00330000UL, 0x00880000UL, 0x00070000UL, 0x00c70000UL, 0x00310000UL, + 0x00b10000UL, 0x00120000UL, 0x00100000UL, 0x00590000UL, 0x00270000UL, + 0x00800000UL, 0x00ec0000UL, 0x005f0000UL, 0x00600000UL, 0x00510000UL, + 0x007f0000UL, 0x00a90000UL, 0x00190000UL, 0x00b50000UL, 0x004a0000UL, + 0x000d0000UL, 0x002d0000UL, 0x00e50000UL, 0x007a0000UL, 0x009f0000UL, + 0x00930000UL, 0x00c90000UL, 0x009c0000UL, 0x00ef0000UL, 0x00a00000UL, + 0x00e00000UL, 0x003b0000UL, 0x004d0000UL, 0x00ae0000UL, 0x002a0000UL, + 0x00f50000UL, 0x00b00000UL, 0x00c80000UL, 0x00eb0000UL, 0x00bb0000UL, + 0x003c0000UL, 0x00830000UL, 0x00530000UL, 0x00990000UL, 0x00610000UL, + 0x00170000UL, 0x002b0000UL, 0x00040000UL, 0x007e0000UL, 0x00ba0000UL, + 0x00770000UL, 0x00d60000UL, 0x00260000UL, 0x00e10000UL, 0x00690000UL, + 0x00140000UL, 0x00630000UL, 0x00550000UL, 0x00210000UL, 0x000c0000UL, + 0x007d0000UL}, +{0x52000000UL, 0x09000000UL, 0x6a000000UL, 0xd5000000UL, 0x30000000UL, + 0x36000000UL, 0xa5000000UL, 0x38000000UL, 0xbf000000UL, 0x40000000UL, + 0xa3000000UL, 0x9e000000UL, 0x81000000UL, 0xf3000000UL, 0xd7000000UL, + 0xfb000000UL, 0x7c000000UL, 0xe3000000UL, 0x39000000UL, 0x82000000UL, + 0x9b000000UL, 0x2f000000UL, 0xff000000UL, 0x87000000UL, 0x34000000UL, + 0x8e000000UL, 0x43000000UL, 0x44000000UL, 0xc4000000UL, 0xde000000UL, + 0xe9000000UL, 0xcb000000UL, 0x54000000UL, 0x7b000000UL, 0x94000000UL, + 0x32000000UL, 0xa6000000UL, 0xc2000000UL, 0x23000000UL, 0x3d000000UL, + 0xee000000UL, 0x4c000000UL, 0x95000000UL, 0x0b000000UL, 0x42000000UL, + 0xfa000000UL, 0xc3000000UL, 0x4e000000UL, 0x08000000UL, 0x2e000000UL, + 0xa1000000UL, 0x66000000UL, 0x28000000UL, 0xd9000000UL, 0x24000000UL, + 0xb2000000UL, 0x76000000UL, 0x5b000000UL, 0xa2000000UL, 0x49000000UL, + 0x6d000000UL, 0x8b000000UL, 0xd1000000UL, 0x25000000UL, 0x72000000UL, + 0xf8000000UL, 0xf6000000UL, 0x64000000UL, 0x86000000UL, 0x68000000UL, + 0x98000000UL, 0x16000000UL, 0xd4000000UL, 0xa4000000UL, 0x5c000000UL, + 0xcc000000UL, 0x5d000000UL, 0x65000000UL, 0xb6000000UL, 0x92000000UL, + 0x6c000000UL, 0x70000000UL, 0x48000000UL, 0x50000000UL, 0xfd000000UL, + 0xed000000UL, 0xb9000000UL, 0xda000000UL, 0x5e000000UL, 0x15000000UL, + 0x46000000UL, 0x57000000UL, 0xa7000000UL, 0x8d000000UL, 0x9d000000UL, + 0x84000000UL, 0x90000000UL, 0xd8000000UL, 0xab000000UL, 0x00000000UL, + 0x8c000000UL, 0xbc000000UL, 0xd3000000UL, 0x0a000000UL, 0xf7000000UL, + 0xe4000000UL, 0x58000000UL, 0x05000000UL, 0xb8000000UL, 0xb3000000UL, + 0x45000000UL, 0x06000000UL, 0xd0000000UL, 0x2c000000UL, 0x1e000000UL, + 0x8f000000UL, 0xca000000UL, 0x3f000000UL, 0x0f000000UL, 0x02000000UL, + 0xc1000000UL, 0xaf000000UL, 0xbd000000UL, 0x03000000UL, 0x01000000UL, + 0x13000000UL, 0x8a000000UL, 0x6b000000UL, 0x3a000000UL, 0x91000000UL, + 0x11000000UL, 0x41000000UL, 0x4f000000UL, 0x67000000UL, 0xdc000000UL, + 0xea000000UL, 0x97000000UL, 0xf2000000UL, 0xcf000000UL, 0xce000000UL, + 0xf0000000UL, 0xb4000000UL, 0xe6000000UL, 0x73000000UL, 0x96000000UL, + 0xac000000UL, 0x74000000UL, 0x22000000UL, 0xe7000000UL, 0xad000000UL, + 0x35000000UL, 0x85000000UL, 0xe2000000UL, 0xf9000000UL, 0x37000000UL, + 0xe8000000UL, 0x1c000000UL, 0x75000000UL, 0xdf000000UL, 0x6e000000UL, + 0x47000000UL, 0xf1000000UL, 0x1a000000UL, 0x71000000UL, 0x1d000000UL, + 0x29000000UL, 0xc5000000UL, 0x89000000UL, 0x6f000000UL, 0xb7000000UL, + 0x62000000UL, 0x0e000000UL, 0xaa000000UL, 0x18000000UL, 0xbe000000UL, + 0x1b000000UL, 0xfc000000UL, 0x56000000UL, 0x3e000000UL, 0x4b000000UL, + 0xc6000000UL, 0xd2000000UL, 0x79000000UL, 0x20000000UL, 0x9a000000UL, + 0xdb000000UL, 0xc0000000UL, 0xfe000000UL, 0x78000000UL, 0xcd000000UL, + 0x5a000000UL, 0xf4000000UL, 0x1f000000UL, 0xdd000000UL, 0xa8000000UL, + 0x33000000UL, 0x88000000UL, 0x07000000UL, 0xc7000000UL, 0x31000000UL, + 0xb1000000UL, 0x12000000UL, 0x10000000UL, 0x59000000UL, 0x27000000UL, + 0x80000000UL, 0xec000000UL, 0x5f000000UL, 0x60000000UL, 0x51000000UL, + 0x7f000000UL, 0xa9000000UL, 0x19000000UL, 0xb5000000UL, 0x4a000000UL, + 0x0d000000UL, 0x2d000000UL, 0xe5000000UL, 0x7a000000UL, 0x9f000000UL, + 0x93000000UL, 0xc9000000UL, 0x9c000000UL, 0xef000000UL, 0xa0000000UL, + 0xe0000000UL, 0x3b000000UL, 0x4d000000UL, 0xae000000UL, 0x2a000000UL, + 0xf5000000UL, 0xb0000000UL, 0xc8000000UL, 0xeb000000UL, 0xbb000000UL, + 0x3c000000UL, 0x83000000UL, 0x53000000UL, 0x99000000UL, 0x61000000UL, + 0x17000000UL, 0x2b000000UL, 0x04000000UL, 0x7e000000UL, 0xba000000UL, + 0x77000000UL, 0xd6000000UL, 0x26000000UL, 0xe1000000UL, 0x69000000UL, + 0x14000000UL, 0x63000000UL, 0x55000000UL, 0x21000000UL, 0x0c000000UL, + 0x7d000000UL} + }; + +static const unsigned long rco_tab[10] = { + 0x00000001UL, 0x00000002UL, 0x00000004UL, 0x00000008UL, 0x00000010UL, + 0x00000020UL, 0x00000040UL, 0x00000080UL, 0x0000001bUL, 0x00000036UL + }; + diff --git a/ampi.c b/ampi.c new file mode 100644 index 0000000..2d015ca --- /dev/null +++ b/ampi.c @@ -0,0 +1,55 @@ +/* Code submitted by Svante Seleborg, cleaned up by Tom St Denis */ + +#include "mycrypt.h" +#include + +#ifdef MPI + +mp_err mp_init_multi(mp_int *mp, ...) +{ + mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ + int n = 0; /* Number of ok inits */ + mp_int* cur_arg = mp; + va_list args; + + va_start(args, mp); /* init args to next argument from caller */ + while (cur_arg != NULL) { + if (mp_init(cur_arg) != MP_OKAY) { + /* Oops - error! Back-track and mp_clear what we already + succeeded in init-ing, then return error. + */ + va_list clean_args; + cur_arg = mp; + va_start(clean_args, mp); + while (n--) { + mp_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_int*); + } + va_end(clean_args); + res = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_int*); + } + va_end(args); + return res; /* Assumed ok, if error flagged above. */ +} + +/* + Clear all arguments given, ended by a NULL marker. +*/ +void mp_clear_multi(mp_int *mp, ...) +{ + mp_int* next_mp = mp; + va_list args; + va_start(args, mp); + while (next_mp != NULL) { + mp_clear(next_mp); + next_mp = va_arg(args, mp_int*); + } + va_end(args); +} + +#endif + diff --git a/authors b/authors new file mode 100644 index 0000000..7938176 --- /dev/null +++ b/authors @@ -0,0 +1,48 @@ +This is a list of people who have contributed [directly or indirectly] to the project +[in no partcular order]. If you have helped and your name is not here email me at +tomstdenis@yahoo.com. + + +1) Richard.van.de.Laarschot@ict.nl + + Gave help porting the lib to MSVC particularly pointed out various warnings and errors. + +2) Richard Heathfield + + Gave a lot of help concerning valid C portable code. + +3) Ajay K. Agrawal + + Helped port the library to MSVC and spotted a few bugs and errors. + +4) Brian Gladman + + Wrote the AES and Serpent code used. Found a bug in the hash code for certain types of inputs. + +5) Svante Seleborg + + Submitted the "ampi.c" code as well as many suggestions on improving the readability of the source code. + +6) Clay Culver + + Submitted a fix for "rsa.c" which cleaned up some code. + +7) Jason Klapste + + Submitted fixes to the yarrow, hash, make process and test code as well as other subtle bug fixes. The +yarrow code can now default to any cipher/hash that is left after you remove them from a build. + +8) Dobes Vandermeer + + Submitted HMAC code that worked flawlessly out of the box... good job! Also submitted a MD4 routine. + Submitted some modified DES code that was merged into the code base [using the libtomcrypt API] + +9) Wayne Scott (wscott@bitmover.com) + + Submitted base64 that complies with the RFC standards. + +10) Sky Schulz (sky@ogn.com) + + Has submitted a set of ideas to improve the library and make it more attractive for professional users. + + \ No newline at end of file diff --git a/base64.c b/base64.c new file mode 100644 index 0000000..3ab94d0 --- /dev/null +++ b/base64.c @@ -0,0 +1,111 @@ +/* compliant base64 code donated by Wayne Scott (wscott@bitmover.com) */ +#include "mycrypt.h" + +#ifdef BASE64 + +static const char *codes = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const unsigned char map[256] = { +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, +255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, +255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255 }; + +int base64_encode(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen) +{ + unsigned long i, len2, leven; + unsigned char *p; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* valid output size ? */ + len2 = 4 * ((len + 2) / 3); + if (*outlen < len2 + 1) { + return CRYPT_BUFFER_OVERFLOW; + } + p = out; + leven = 3*(len / 3); + for (i = 0; i < leven; i += 3) { + *p++ = codes[in[0] >> 2]; + *p++ = codes[((in[0] & 3) << 4) + (in[1] >> 4)]; + *p++ = codes[((in[1] & 0xf) << 2) + (in[2] >> 6)]; + *p++ = codes[in[2] & 0x3f]; + in += 3; + } + /* Pad it if necessary... */ + if (i < len) { + unsigned a = in[0]; + unsigned b = (i+1 < len) ? in[1] : 0; + unsigned c = 0; + + *p++ = codes[a >> 2]; + *p++ = codes[((a & 3) << 4) + (b >> 4)]; + *p++ = (i+1 < len) ? codes[((b & 0xf) << 2) + (c >> 6)] : '='; + *p++ = '='; + } + + /* append a NULL byte */ + *p = '\0'; + + /* return ok */ + *outlen = p - out; + return CRYPT_OK; +} + +int base64_decode(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen) +{ + unsigned long t, x, y, z; + unsigned char c; + int g = 3; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + for (x = y = z = t = 0; x < len; x++) { + c = map[in[x]]; + if (c == 255) continue; + if (c == 254) { c = 0; g--; } + t = (t<<6)|c; + if (++y == 4) { + if (z + g > *outlen) goto error; + out[z++] = (unsigned char)((t>>16)&255); + if (g > 1) out[z++] = (unsigned char)((t>>8)&255); + if (g > 2) out[z++] = (unsigned char)(t&255); + y = t = 0; + } + } + if (y != 0) { + return CRYPT_INVALID_PACKET; + } + *outlen = z; + return CRYPT_OK; +error: + return CRYPT_BUFFER_OVERFLOW; +} + +#endif + diff --git a/bits.c b/bits.c new file mode 100644 index 0000000..0643888 --- /dev/null +++ b/bits.c @@ -0,0 +1,193 @@ +/* portable way to get secure random bits to feed a PRNG */ +#include "mycrypt.h" + +#ifdef DEVRANDOM +/* on *NIX read /dev/random */ +static unsigned long rng_nix(unsigned char *buf, unsigned long len, + void (*callback)(void)) +{ +#ifdef NO_FILE + return 0; +#else + FILE *f; + int x; +#ifdef TRY_URANDOM_FIRST + f = fopen("/dev/urandom", "rb"); + if (f == NULL) +#endif /* TRY_URANDOM_FIRST */ + f = fopen("/dev/random", "rb"); + + if (f == NULL) { + return 0; + } + + x = fread(buf, 1, len, f); + fclose(f); + return x; +#endif /* NO_FILE */ +} + +#endif /* DEVRANDOM */ + +#ifdef SONY_PS2 +#include +#include +#define min(a,b) ((a) < (b) ? (a) : (b)) +// Very simple/stupid MD5-based RNG that samples "entropy" from various PS2 control registers +static unsigned long rng_ps2(unsigned char *buf, unsigned long len, + void (*callback)(void)) +{ + static unsigned long lastx[2] = { 0xaab7cb4b2fd3b2b9, 0xcec58aff72afe49f }; // md5sum of bits.c + unsigned long j; + unsigned int samples[10]; // number of sample data sources + int l; + hash_state md; + + for (j = 0; j < len; j += sizeof(lastx)) { + md5_init(&md); + samples[0] = *T2_COUNT; + samples[1] = *T3_COUNT; + samples[2] = *IPU_TOP; + samples[3] = *GIF_TAG0; + samples[4] = *GIF_TAG1; + samples[5] = *GIF_TAG2; + samples[6] = *VIF1_CODE; + samples[7] = *VIF0_CODE; + samples[8] = *D0_MADR; + samples[9] = *D1_MADR; + md5_process(&md, (unsigned char *)(&samples[0]), sizeof(samples)); + // include previous round + md5_process(&md, (unsigned char *)(&lastx[0]), sizeof(lastx)); + md5_done(&md, (unsigned char *)(&lastx[0])); + l = min(sizeof(lastx), len-j); + memcpy(buf+j, &lastx[0], l); //min(sizeof(lastx), len-j)); + } + return len; +} +#endif /* SONY_PS2 */ + +/* on ANSI C platforms with 100 < CLOCKS_PER_SEC < 10000 */ +#if !defined(SONY_PS2) && defined(CLOCKS_PER_SEC) + +#define ANSI_RNG + +static unsigned long rng_ansic(unsigned char *buf, unsigned long len, + void (*callback)(void)) +{ + clock_t t1; + int l, acc, bits, a, b; + + if (XCLOCKS_PER_SEC < 100 || XCLOCKS_PER_SEC > 10000) { + return 0; + } + + l = len; + bits = 8; + acc = a = b = 0; + while (len--) { + if (callback != NULL) callback(); + while (bits--) { + do { + t1 = XCLOCK(); while (t1 == XCLOCK()) a ^= 1; + t1 = XCLOCK(); while (t1 == XCLOCK()) b ^= 1; + } while (a == b); + acc = (acc << 1) | a; + } + *buf++ = acc; + acc = 0; + bits = 8; + } + acc = bits = a = b = 0; + return l; +} + +#endif + +/* Try the Microsoft CSP */ +#ifdef WIN32 +#define _WIN32_WINNT 0x0400 +#include +#include + +static unsigned long rng_win32(unsigned char *buf, unsigned long len, + void (*callback)(void)) +{ + HCRYPTPROV hProv = 0; + if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, + (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) && + !CryptAcquireContext (&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) + return 0; + + if (CryptGenRandom(hProv, len, buf) == TRUE) { + CryptReleaseContext(hProv, 0); + return len; + } else { + CryptReleaseContext(hProv, 0); + return 0; + } +} + +#endif /* WIN32 */ + +unsigned long rng_get_bytes(unsigned char *buf, unsigned long len, + void (*callback)(void)) +{ + int x; + + _ARGCHK(buf != NULL); + +#ifdef SONY_PS2 + x = rng_ps2(buf, len, callback); if (x) { return x; } +#elif defined(DEVRANDOM) + x = rng_nix(buf, len, callback); if (x) { return x; } +#endif +#ifdef WIN32 + x = rng_win32(buf, len, callback); if (x) { return x; } +#endif +#ifdef ANSI_RNG + x = rng_ansic(buf, len, callback); if (x) { return x; } +#endif + return 0; +} + +int rng_make_prng(int bits, int wprng, prng_state *prng, + void (*callback)(void)) +{ + unsigned char buf[256]; + int errno; + + _ARGCHK(prng != NULL); + + /* check parameter */ + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + if (bits < 64 || bits > 1024) { + return CRYPT_INVALID_PRNGSIZE; + } + + if ((errno = prng_descriptor[wprng].start(prng)) != CRYPT_OK) { + return errno; + } + + bits = ((bits/8)+(bits&7?1:0)) * 2; + if (rng_get_bytes(buf, bits, callback) != (unsigned long)bits) { + return CRYPT_ERROR_READPRNG; + } + + if ((errno = prng_descriptor[wprng].add_entropy(buf, bits, prng)) != CRYPT_OK) { + return errno; + } + + if ((errno = prng_descriptor[wprng].ready(prng)) != CRYPT_OK) { + return errno; + } + + #ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); + #endif + return CRYPT_OK; +} + diff --git a/blowfish.c b/blowfish.c new file mode 100644 index 0000000..e00cec7 --- /dev/null +++ b/blowfish.c @@ -0,0 +1,691 @@ +#include "mycrypt.h" + +#ifdef BLOWFISH + +const struct _cipher_descriptor blowfish_desc = +{ + "blowfish", + 0, + 8, 56, 8, 16, + &blowfish_setup, + &blowfish_ecb_encrypt, + &blowfish_ecb_decrypt, + &blowfish_test, + &blowfish_keysize +}; + +static const unsigned long ORIG_P[16 + 2] = { + 0x243F6A88UL, 0x85A308D3UL, 0x13198A2EUL, 0x03707344UL, + 0xA4093822UL, 0x299F31D0UL, 0x082EFA98UL, 0xEC4E6C89UL, + 0x452821E6UL, 0x38D01377UL, 0xBE5466CFUL, 0x34E90C6CUL, + 0xC0AC29B7UL, 0xC97C50DDUL, 0x3F84D5B5UL, 0xB5470917UL, + 0x9216D5D9UL, 0x8979FB1BUL +}; + +static const unsigned long ORIG_S[4][256] = { + { 0xD1310BA6UL, 0x98DFB5ACUL, 0x2FFD72DBUL, 0xD01ADFB7UL, + 0xB8E1AFEDUL, 0x6A267E96UL, 0xBA7C9045UL, 0xF12C7F99UL, + 0x24A19947UL, 0xB3916CF7UL, 0x0801F2E2UL, 0x858EFC16UL, + 0x636920D8UL, 0x71574E69UL, 0xA458FEA3UL, 0xF4933D7EUL, + 0x0D95748FUL, 0x728EB658UL, 0x718BCD58UL, 0x82154AEEUL, + 0x7B54A41DUL, 0xC25A59B5UL, 0x9C30D539UL, 0x2AF26013UL, + 0xC5D1B023UL, 0x286085F0UL, 0xCA417918UL, 0xB8DB38EFUL, + 0x8E79DCB0UL, 0x603A180EUL, 0x6C9E0E8BUL, 0xB01E8A3EUL, + 0xD71577C1UL, 0xBD314B27UL, 0x78AF2FDAUL, 0x55605C60UL, + 0xE65525F3UL, 0xAA55AB94UL, 0x57489862UL, 0x63E81440UL, + 0x55CA396AUL, 0x2AAB10B6UL, 0xB4CC5C34UL, 0x1141E8CEUL, + 0xA15486AFUL, 0x7C72E993UL, 0xB3EE1411UL, 0x636FBC2AUL, + 0x2BA9C55DUL, 0x741831F6UL, 0xCE5C3E16UL, 0x9B87931EUL, + 0xAFD6BA33UL, 0x6C24CF5CUL, 0x7A325381UL, 0x28958677UL, + 0x3B8F4898UL, 0x6B4BB9AFUL, 0xC4BFE81BUL, 0x66282193UL, + 0x61D809CCUL, 0xFB21A991UL, 0x487CAC60UL, 0x5DEC8032UL, + 0xEF845D5DUL, 0xE98575B1UL, 0xDC262302UL, 0xEB651B88UL, + 0x23893E81UL, 0xD396ACC5UL, 0x0F6D6FF3UL, 0x83F44239UL, + 0x2E0B4482UL, 0xA4842004UL, 0x69C8F04AUL, 0x9E1F9B5EUL, + 0x21C66842UL, 0xF6E96C9AUL, 0x670C9C61UL, 0xABD388F0UL, + 0x6A51A0D2UL, 0xD8542F68UL, 0x960FA728UL, 0xAB5133A3UL, + 0x6EEF0B6CUL, 0x137A3BE4UL, 0xBA3BF050UL, 0x7EFB2A98UL, + 0xA1F1651DUL, 0x39AF0176UL, 0x66CA593EUL, 0x82430E88UL, + 0x8CEE8619UL, 0x456F9FB4UL, 0x7D84A5C3UL, 0x3B8B5EBEUL, + 0xE06F75D8UL, 0x85C12073UL, 0x401A449FUL, 0x56C16AA6UL, + 0x4ED3AA62UL, 0x363F7706UL, 0x1BFEDF72UL, 0x429B023DUL, + 0x37D0D724UL, 0xD00A1248UL, 0xDB0FEAD3UL, 0x49F1C09BUL, + 0x075372C9UL, 0x80991B7BUL, 0x25D479D8UL, 0xF6E8DEF7UL, + 0xE3FE501AUL, 0xB6794C3BUL, 0x976CE0BDUL, 0x04C006BAUL, + 0xC1A94FB6UL, 0x409F60C4UL, 0x5E5C9EC2UL, 0x196A2463UL, + 0x68FB6FAFUL, 0x3E6C53B5UL, 0x1339B2EBUL, 0x3B52EC6FUL, + 0x6DFC511FUL, 0x9B30952CUL, 0xCC814544UL, 0xAF5EBD09UL, + 0xBEE3D004UL, 0xDE334AFDUL, 0x660F2807UL, 0x192E4BB3UL, + 0xC0CBA857UL, 0x45C8740FUL, 0xD20B5F39UL, 0xB9D3FBDBUL, + 0x5579C0BDUL, 0x1A60320AUL, 0xD6A100C6UL, 0x402C7279UL, + 0x679F25FEUL, 0xFB1FA3CCUL, 0x8EA5E9F8UL, 0xDB3222F8UL, + 0x3C7516DFUL, 0xFD616B15UL, 0x2F501EC8UL, 0xAD0552ABUL, + 0x323DB5FAUL, 0xFD238760UL, 0x53317B48UL, 0x3E00DF82UL, + 0x9E5C57BBUL, 0xCA6F8CA0UL, 0x1A87562EUL, 0xDF1769DBUL, + 0xD542A8F6UL, 0x287EFFC3UL, 0xAC6732C6UL, 0x8C4F5573UL, + 0x695B27B0UL, 0xBBCA58C8UL, 0xE1FFA35DUL, 0xB8F011A0UL, + 0x10FA3D98UL, 0xFD2183B8UL, 0x4AFCB56CUL, 0x2DD1D35BUL, + 0x9A53E479UL, 0xB6F84565UL, 0xD28E49BCUL, 0x4BFB9790UL, + 0xE1DDF2DAUL, 0xA4CB7E33UL, 0x62FB1341UL, 0xCEE4C6E8UL, + 0xEF20CADAUL, 0x36774C01UL, 0xD07E9EFEUL, 0x2BF11FB4UL, + 0x95DBDA4DUL, 0xAE909198UL, 0xEAAD8E71UL, 0x6B93D5A0UL, + 0xD08ED1D0UL, 0xAFC725E0UL, 0x8E3C5B2FUL, 0x8E7594B7UL, + 0x8FF6E2FBUL, 0xF2122B64UL, 0x8888B812UL, 0x900DF01CUL, + 0x4FAD5EA0UL, 0x688FC31CUL, 0xD1CFF191UL, 0xB3A8C1ADUL, + 0x2F2F2218UL, 0xBE0E1777UL, 0xEA752DFEUL, 0x8B021FA1UL, + 0xE5A0CC0FUL, 0xB56F74E8UL, 0x18ACF3D6UL, 0xCE89E299UL, + 0xB4A84FE0UL, 0xFD13E0B7UL, 0x7CC43B81UL, 0xD2ADA8D9UL, + 0x165FA266UL, 0x80957705UL, 0x93CC7314UL, 0x211A1477UL, + 0xE6AD2065UL, 0x77B5FA86UL, 0xC75442F5UL, 0xFB9D35CFUL, + 0xEBCDAF0CUL, 0x7B3E89A0UL, 0xD6411BD3UL, 0xAE1E7E49UL, + 0x00250E2DUL, 0x2071B35EUL, 0x226800BBUL, 0x57B8E0AFUL, + 0x2464369BUL, 0xF009B91EUL, 0x5563911DUL, 0x59DFA6AAUL, + 0x78C14389UL, 0xD95A537FUL, 0x207D5BA2UL, 0x02E5B9C5UL, + 0x83260376UL, 0x6295CFA9UL, 0x11C81968UL, 0x4E734A41UL, + 0xB3472DCAUL, 0x7B14A94AUL, 0x1B510052UL, 0x9A532915UL, + 0xD60F573FUL, 0xBC9BC6E4UL, 0x2B60A476UL, 0x81E67400UL, + 0x08BA6FB5UL, 0x571BE91FUL, 0xF296EC6BUL, 0x2A0DD915UL, + 0xB6636521UL, 0xE7B9F9B6UL, 0xFF34052EUL, 0xC5855664UL, + 0x53B02D5DUL, 0xA99F8FA1UL, 0x08BA4799UL, 0x6E85076AUL }, + { 0x4B7A70E9UL, 0xB5B32944UL, 0xDB75092EUL, 0xC4192623UL, + 0xAD6EA6B0UL, 0x49A7DF7DUL, 0x9CEE60B8UL, 0x8FEDB266UL, + 0xECAA8C71UL, 0x699A17FFUL, 0x5664526CUL, 0xC2B19EE1UL, + 0x193602A5UL, 0x75094C29UL, 0xA0591340UL, 0xE4183A3EUL, + 0x3F54989AUL, 0x5B429D65UL, 0x6B8FE4D6UL, 0x99F73FD6UL, + 0xA1D29C07UL, 0xEFE830F5UL, 0x4D2D38E6UL, 0xF0255DC1UL, + 0x4CDD2086UL, 0x8470EB26UL, 0x6382E9C6UL, 0x021ECC5EUL, + 0x09686B3FUL, 0x3EBAEFC9UL, 0x3C971814UL, 0x6B6A70A1UL, + 0x687F3584UL, 0x52A0E286UL, 0xB79C5305UL, 0xAA500737UL, + 0x3E07841CUL, 0x7FDEAE5CUL, 0x8E7D44ECUL, 0x5716F2B8UL, + 0xB03ADA37UL, 0xF0500C0DUL, 0xF01C1F04UL, 0x0200B3FFUL, + 0xAE0CF51AUL, 0x3CB574B2UL, 0x25837A58UL, 0xDC0921BDUL, + 0xD19113F9UL, 0x7CA92FF6UL, 0x94324773UL, 0x22F54701UL, + 0x3AE5E581UL, 0x37C2DADCUL, 0xC8B57634UL, 0x9AF3DDA7UL, + 0xA9446146UL, 0x0FD0030EUL, 0xECC8C73EUL, 0xA4751E41UL, + 0xE238CD99UL, 0x3BEA0E2FUL, 0x3280BBA1UL, 0x183EB331UL, + 0x4E548B38UL, 0x4F6DB908UL, 0x6F420D03UL, 0xF60A04BFUL, + 0x2CB81290UL, 0x24977C79UL, 0x5679B072UL, 0xBCAF89AFUL, + 0xDE9A771FUL, 0xD9930810UL, 0xB38BAE12UL, 0xDCCF3F2EUL, + 0x5512721FUL, 0x2E6B7124UL, 0x501ADDE6UL, 0x9F84CD87UL, + 0x7A584718UL, 0x7408DA17UL, 0xBC9F9ABCUL, 0xE94B7D8CUL, + 0xEC7AEC3AUL, 0xDB851DFAUL, 0x63094366UL, 0xC464C3D2UL, + 0xEF1C1847UL, 0x3215D908UL, 0xDD433B37UL, 0x24C2BA16UL, + 0x12A14D43UL, 0x2A65C451UL, 0x50940002UL, 0x133AE4DDUL, + 0x71DFF89EUL, 0x10314E55UL, 0x81AC77D6UL, 0x5F11199BUL, + 0x043556F1UL, 0xD7A3C76BUL, 0x3C11183BUL, 0x5924A509UL, + 0xF28FE6EDUL, 0x97F1FBFAUL, 0x9EBABF2CUL, 0x1E153C6EUL, + 0x86E34570UL, 0xEAE96FB1UL, 0x860E5E0AUL, 0x5A3E2AB3UL, + 0x771FE71CUL, 0x4E3D06FAUL, 0x2965DCB9UL, 0x99E71D0FUL, + 0x803E89D6UL, 0x5266C825UL, 0x2E4CC978UL, 0x9C10B36AUL, + 0xC6150EBAUL, 0x94E2EA78UL, 0xA5FC3C53UL, 0x1E0A2DF4UL, + 0xF2F74EA7UL, 0x361D2B3DUL, 0x1939260FUL, 0x19C27960UL, + 0x5223A708UL, 0xF71312B6UL, 0xEBADFE6EUL, 0xEAC31F66UL, + 0xE3BC4595UL, 0xA67BC883UL, 0xB17F37D1UL, 0x018CFF28UL, + 0xC332DDEFUL, 0xBE6C5AA5UL, 0x65582185UL, 0x68AB9802UL, + 0xEECEA50FUL, 0xDB2F953BUL, 0x2AEF7DADUL, 0x5B6E2F84UL, + 0x1521B628UL, 0x29076170UL, 0xECDD4775UL, 0x619F1510UL, + 0x13CCA830UL, 0xEB61BD96UL, 0x0334FE1EUL, 0xAA0363CFUL, + 0xB5735C90UL, 0x4C70A239UL, 0xD59E9E0BUL, 0xCBAADE14UL, + 0xEECC86BCUL, 0x60622CA7UL, 0x9CAB5CABUL, 0xB2F3846EUL, + 0x648B1EAFUL, 0x19BDF0CAUL, 0xA02369B9UL, 0x655ABB50UL, + 0x40685A32UL, 0x3C2AB4B3UL, 0x319EE9D5UL, 0xC021B8F7UL, + 0x9B540B19UL, 0x875FA099UL, 0x95F7997EUL, 0x623D7DA8UL, + 0xF837889AUL, 0x97E32D77UL, 0x11ED935FUL, 0x16681281UL, + 0x0E358829UL, 0xC7E61FD6UL, 0x96DEDFA1UL, 0x7858BA99UL, + 0x57F584A5UL, 0x1B227263UL, 0x9B83C3FFUL, 0x1AC24696UL, + 0xCDB30AEBUL, 0x532E3054UL, 0x8FD948E4UL, 0x6DBC3128UL, + 0x58EBF2EFUL, 0x34C6FFEAUL, 0xFE28ED61UL, 0xEE7C3C73UL, + 0x5D4A14D9UL, 0xE864B7E3UL, 0x42105D14UL, 0x203E13E0UL, + 0x45EEE2B6UL, 0xA3AAABEAUL, 0xDB6C4F15UL, 0xFACB4FD0UL, + 0xC742F442UL, 0xEF6ABBB5UL, 0x654F3B1DUL, 0x41CD2105UL, + 0xD81E799EUL, 0x86854DC7UL, 0xE44B476AUL, 0x3D816250UL, + 0xCF62A1F2UL, 0x5B8D2646UL, 0xFC8883A0UL, 0xC1C7B6A3UL, + 0x7F1524C3UL, 0x69CB7492UL, 0x47848A0BUL, 0x5692B285UL, + 0x095BBF00UL, 0xAD19489DUL, 0x1462B174UL, 0x23820E00UL, + 0x58428D2AUL, 0x0C55F5EAUL, 0x1DADF43EUL, 0x233F7061UL, + 0x3372F092UL, 0x8D937E41UL, 0xD65FECF1UL, 0x6C223BDBUL, + 0x7CDE3759UL, 0xCBEE7460UL, 0x4085F2A7UL, 0xCE77326EUL, + 0xA6078084UL, 0x19F8509EUL, 0xE8EFD855UL, 0x61D99735UL, + 0xA969A7AAUL, 0xC50C06C2UL, 0x5A04ABFCUL, 0x800BCADCUL, + 0x9E447A2EUL, 0xC3453484UL, 0xFDD56705UL, 0x0E1E9EC9UL, + 0xDB73DBD3UL, 0x105588CDUL, 0x675FDA79UL, 0xE3674340UL, + 0xC5C43465UL, 0x713E38D8UL, 0x3D28F89EUL, 0xF16DFF20UL, + 0x153E21E7UL, 0x8FB03D4AUL, 0xE6E39F2BUL, 0xDB83ADF7UL }, + { 0xE93D5A68UL, 0x948140F7UL, 0xF64C261CUL, 0x94692934UL, + 0x411520F7UL, 0x7602D4F7UL, 0xBCF46B2EUL, 0xD4A20068UL, + 0xD4082471UL, 0x3320F46AUL, 0x43B7D4B7UL, 0x500061AFUL, + 0x1E39F62EUL, 0x97244546UL, 0x14214F74UL, 0xBF8B8840UL, + 0x4D95FC1DUL, 0x96B591AFUL, 0x70F4DDD3UL, 0x66A02F45UL, + 0xBFBC09ECUL, 0x03BD9785UL, 0x7FAC6DD0UL, 0x31CB8504UL, + 0x96EB27B3UL, 0x55FD3941UL, 0xDA2547E6UL, 0xABCA0A9AUL, + 0x28507825UL, 0x530429F4UL, 0x0A2C86DAUL, 0xE9B66DFBUL, + 0x68DC1462UL, 0xD7486900UL, 0x680EC0A4UL, 0x27A18DEEUL, + 0x4F3FFEA2UL, 0xE887AD8CUL, 0xB58CE006UL, 0x7AF4D6B6UL, + 0xAACE1E7CUL, 0xD3375FECUL, 0xCE78A399UL, 0x406B2A42UL, + 0x20FE9E35UL, 0xD9F385B9UL, 0xEE39D7ABUL, 0x3B124E8BUL, + 0x1DC9FAF7UL, 0x4B6D1856UL, 0x26A36631UL, 0xEAE397B2UL, + 0x3A6EFA74UL, 0xDD5B4332UL, 0x6841E7F7UL, 0xCA7820FBUL, + 0xFB0AF54EUL, 0xD8FEB397UL, 0x454056ACUL, 0xBA489527UL, + 0x55533A3AUL, 0x20838D87UL, 0xFE6BA9B7UL, 0xD096954BUL, + 0x55A867BCUL, 0xA1159A58UL, 0xCCA92963UL, 0x99E1DB33UL, + 0xA62A4A56UL, 0x3F3125F9UL, 0x5EF47E1CUL, 0x9029317CUL, + 0xFDF8E802UL, 0x04272F70UL, 0x80BB155CUL, 0x05282CE3UL, + 0x95C11548UL, 0xE4C66D22UL, 0x48C1133FUL, 0xC70F86DCUL, + 0x07F9C9EEUL, 0x41041F0FUL, 0x404779A4UL, 0x5D886E17UL, + 0x325F51EBUL, 0xD59BC0D1UL, 0xF2BCC18FUL, 0x41113564UL, + 0x257B7834UL, 0x602A9C60UL, 0xDFF8E8A3UL, 0x1F636C1BUL, + 0x0E12B4C2UL, 0x02E1329EUL, 0xAF664FD1UL, 0xCAD18115UL, + 0x6B2395E0UL, 0x333E92E1UL, 0x3B240B62UL, 0xEEBEB922UL, + 0x85B2A20EUL, 0xE6BA0D99UL, 0xDE720C8CUL, 0x2DA2F728UL, + 0xD0127845UL, 0x95B794FDUL, 0x647D0862UL, 0xE7CCF5F0UL, + 0x5449A36FUL, 0x877D48FAUL, 0xC39DFD27UL, 0xF33E8D1EUL, + 0x0A476341UL, 0x992EFF74UL, 0x3A6F6EABUL, 0xF4F8FD37UL, + 0xA812DC60UL, 0xA1EBDDF8UL, 0x991BE14CUL, 0xDB6E6B0DUL, + 0xC67B5510UL, 0x6D672C37UL, 0x2765D43BUL, 0xDCD0E804UL, + 0xF1290DC7UL, 0xCC00FFA3UL, 0xB5390F92UL, 0x690FED0BUL, + 0x667B9FFBUL, 0xCEDB7D9CUL, 0xA091CF0BUL, 0xD9155EA3UL, + 0xBB132F88UL, 0x515BAD24UL, 0x7B9479BFUL, 0x763BD6EBUL, + 0x37392EB3UL, 0xCC115979UL, 0x8026E297UL, 0xF42E312DUL, + 0x6842ADA7UL, 0xC66A2B3BUL, 0x12754CCCUL, 0x782EF11CUL, + 0x6A124237UL, 0xB79251E7UL, 0x06A1BBE6UL, 0x4BFB6350UL, + 0x1A6B1018UL, 0x11CAEDFAUL, 0x3D25BDD8UL, 0xE2E1C3C9UL, + 0x44421659UL, 0x0A121386UL, 0xD90CEC6EUL, 0xD5ABEA2AUL, + 0x64AF674EUL, 0xDA86A85FUL, 0xBEBFE988UL, 0x64E4C3FEUL, + 0x9DBC8057UL, 0xF0F7C086UL, 0x60787BF8UL, 0x6003604DUL, + 0xD1FD8346UL, 0xF6381FB0UL, 0x7745AE04UL, 0xD736FCCCUL, + 0x83426B33UL, 0xF01EAB71UL, 0xB0804187UL, 0x3C005E5FUL, + 0x77A057BEUL, 0xBDE8AE24UL, 0x55464299UL, 0xBF582E61UL, + 0x4E58F48FUL, 0xF2DDFDA2UL, 0xF474EF38UL, 0x8789BDC2UL, + 0x5366F9C3UL, 0xC8B38E74UL, 0xB475F255UL, 0x46FCD9B9UL, + 0x7AEB2661UL, 0x8B1DDF84UL, 0x846A0E79UL, 0x915F95E2UL, + 0x466E598EUL, 0x20B45770UL, 0x8CD55591UL, 0xC902DE4CUL, + 0xB90BACE1UL, 0xBB8205D0UL, 0x11A86248UL, 0x7574A99EUL, + 0xB77F19B6UL, 0xE0A9DC09UL, 0x662D09A1UL, 0xC4324633UL, + 0xE85A1F02UL, 0x09F0BE8CUL, 0x4A99A025UL, 0x1D6EFE10UL, + 0x1AB93D1DUL, 0x0BA5A4DFUL, 0xA186F20FUL, 0x2868F169UL, + 0xDCB7DA83UL, 0x573906FEUL, 0xA1E2CE9BUL, 0x4FCD7F52UL, + 0x50115E01UL, 0xA70683FAUL, 0xA002B5C4UL, 0x0DE6D027UL, + 0x9AF88C27UL, 0x773F8641UL, 0xC3604C06UL, 0x61A806B5UL, + 0xF0177A28UL, 0xC0F586E0UL, 0x006058AAUL, 0x30DC7D62UL, + 0x11E69ED7UL, 0x2338EA63UL, 0x53C2DD94UL, 0xC2C21634UL, + 0xBBCBEE56UL, 0x90BCB6DEUL, 0xEBFC7DA1UL, 0xCE591D76UL, + 0x6F05E409UL, 0x4B7C0188UL, 0x39720A3DUL, 0x7C927C24UL, + 0x86E3725FUL, 0x724D9DB9UL, 0x1AC15BB4UL, 0xD39EB8FCUL, + 0xED545578UL, 0x08FCA5B5UL, 0xD83D7CD3UL, 0x4DAD0FC4UL, + 0x1E50EF5EUL, 0xB161E6F8UL, 0xA28514D9UL, 0x6C51133CUL, + 0x6FD5C7E7UL, 0x56E14EC4UL, 0x362ABFCEUL, 0xDDC6C837UL, + 0xD79A3234UL, 0x92638212UL, 0x670EFA8EUL, 0x406000E0UL }, + { 0x3A39CE37UL, 0xD3FAF5CFUL, 0xABC27737UL, 0x5AC52D1BUL, + 0x5CB0679EUL, 0x4FA33742UL, 0xD3822740UL, 0x99BC9BBEUL, + 0xD5118E9DUL, 0xBF0F7315UL, 0xD62D1C7EUL, 0xC700C47BUL, + 0xB78C1B6BUL, 0x21A19045UL, 0xB26EB1BEUL, 0x6A366EB4UL, + 0x5748AB2FUL, 0xBC946E79UL, 0xC6A376D2UL, 0x6549C2C8UL, + 0x530FF8EEUL, 0x468DDE7DUL, 0xD5730A1DUL, 0x4CD04DC6UL, + 0x2939BBDBUL, 0xA9BA4650UL, 0xAC9526E8UL, 0xBE5EE304UL, + 0xA1FAD5F0UL, 0x6A2D519AUL, 0x63EF8CE2UL, 0x9A86EE22UL, + 0xC089C2B8UL, 0x43242EF6UL, 0xA51E03AAUL, 0x9CF2D0A4UL, + 0x83C061BAUL, 0x9BE96A4DUL, 0x8FE51550UL, 0xBA645BD6UL, + 0x2826A2F9UL, 0xA73A3AE1UL, 0x4BA99586UL, 0xEF5562E9UL, + 0xC72FEFD3UL, 0xF752F7DAUL, 0x3F046F69UL, 0x77FA0A59UL, + 0x80E4A915UL, 0x87B08601UL, 0x9B09E6ADUL, 0x3B3EE593UL, + 0xE990FD5AUL, 0x9E34D797UL, 0x2CF0B7D9UL, 0x022B8B51UL, + 0x96D5AC3AUL, 0x017DA67DUL, 0xD1CF3ED6UL, 0x7C7D2D28UL, + 0x1F9F25CFUL, 0xADF2B89BUL, 0x5AD6B472UL, 0x5A88F54CUL, + 0xE029AC71UL, 0xE019A5E6UL, 0x47B0ACFDUL, 0xED93FA9BUL, + 0xE8D3C48DUL, 0x283B57CCUL, 0xF8D56629UL, 0x79132E28UL, + 0x785F0191UL, 0xED756055UL, 0xF7960E44UL, 0xE3D35E8CUL, + 0x15056DD4UL, 0x88F46DBAUL, 0x03A16125UL, 0x0564F0BDUL, + 0xC3EB9E15UL, 0x3C9057A2UL, 0x97271AECUL, 0xA93A072AUL, + 0x1B3F6D9BUL, 0x1E6321F5UL, 0xF59C66FBUL, 0x26DCF319UL, + 0x7533D928UL, 0xB155FDF5UL, 0x03563482UL, 0x8ABA3CBBUL, + 0x28517711UL, 0xC20AD9F8UL, 0xABCC5167UL, 0xCCAD925FUL, + 0x4DE81751UL, 0x3830DC8EUL, 0x379D5862UL, 0x9320F991UL, + 0xEA7A90C2UL, 0xFB3E7BCEUL, 0x5121CE64UL, 0x774FBE32UL, + 0xA8B6E37EUL, 0xC3293D46UL, 0x48DE5369UL, 0x6413E680UL, + 0xA2AE0810UL, 0xDD6DB224UL, 0x69852DFDUL, 0x09072166UL, + 0xB39A460AUL, 0x6445C0DDUL, 0x586CDECFUL, 0x1C20C8AEUL, + 0x5BBEF7DDUL, 0x1B588D40UL, 0xCCD2017FUL, 0x6BB4E3BBUL, + 0xDDA26A7EUL, 0x3A59FF45UL, 0x3E350A44UL, 0xBCB4CDD5UL, + 0x72EACEA8UL, 0xFA6484BBUL, 0x8D6612AEUL, 0xBF3C6F47UL, + 0xD29BE463UL, 0x542F5D9EUL, 0xAEC2771BUL, 0xF64E6370UL, + 0x740E0D8DUL, 0xE75B1357UL, 0xF8721671UL, 0xAF537D5DUL, + 0x4040CB08UL, 0x4EB4E2CCUL, 0x34D2466AUL, 0x0115AF84UL, + 0xE1B00428UL, 0x95983A1DUL, 0x06B89FB4UL, 0xCE6EA048UL, + 0x6F3F3B82UL, 0x3520AB82UL, 0x011A1D4BUL, 0x277227F8UL, + 0x611560B1UL, 0xE7933FDCUL, 0xBB3A792BUL, 0x344525BDUL, + 0xA08839E1UL, 0x51CE794BUL, 0x2F32C9B7UL, 0xA01FBAC9UL, + 0xE01CC87EUL, 0xBCC7D1F6UL, 0xCF0111C3UL, 0xA1E8AAC7UL, + 0x1A908749UL, 0xD44FBD9AUL, 0xD0DADECBUL, 0xD50ADA38UL, + 0x0339C32AUL, 0xC6913667UL, 0x8DF9317CUL, 0xE0B12B4FUL, + 0xF79E59B7UL, 0x43F5BB3AUL, 0xF2D519FFUL, 0x27D9459CUL, + 0xBF97222CUL, 0x15E6FC2AUL, 0x0F91FC71UL, 0x9B941525UL, + 0xFAE59361UL, 0xCEB69CEBUL, 0xC2A86459UL, 0x12BAA8D1UL, + 0xB6C1075EUL, 0xE3056A0CUL, 0x10D25065UL, 0xCB03A442UL, + 0xE0EC6E0EUL, 0x1698DB3BUL, 0x4C98A0BEUL, 0x3278E964UL, + 0x9F1F9532UL, 0xE0D392DFUL, 0xD3A0342BUL, 0x8971F21EUL, + 0x1B0A7441UL, 0x4BA3348CUL, 0xC5BE7120UL, 0xC37632D8UL, + 0xDF359F8DUL, 0x9B992F2EUL, 0xE60B6F47UL, 0x0FE3F11DUL, + 0xE54CDA54UL, 0x1EDAD891UL, 0xCE6279CFUL, 0xCD3E7E6FUL, + 0x1618B166UL, 0xFD2C1D05UL, 0x848FD2C5UL, 0xF6FB2299UL, + 0xF523F357UL, 0xA6327623UL, 0x93A83531UL, 0x56CCCD02UL, + 0xACF08162UL, 0x5A75EBB5UL, 0x6E163697UL, 0x88D273CCUL, + 0xDE966292UL, 0x81B949D0UL, 0x4C50901BUL, 0x71C65614UL, + 0xE6C6C7BDUL, 0x327A140AUL, 0x45E1D006UL, 0xC3F27B9AUL, + 0xC9AA53FDUL, 0x62A80F00UL, 0xBB25BFE2UL, 0x35BDD2F6UL, + 0x71126905UL, 0xB2040222UL, 0xB6CBCF7CUL, 0xCD769C2BUL, + 0x53113EC0UL, 0x1640E3D3UL, 0x38ABBD60UL, 0x2547ADF0UL, + 0xBA38209CUL, 0xF746CE76UL, 0x77AFA1C5UL, 0x20756060UL, + 0x85CBFE4EUL, 0x8AE88DD8UL, 0x7AAAF9B0UL, 0x4CF9AA7EUL, + 0x1948C25CUL, 0x02FB8A8CUL, 0x01C36AE4UL, 0xD6EBE1F9UL, + 0x90D4F869UL, 0xA65CDEA0UL, 0x3F09252DUL, 0xC208E69FUL, + 0xB74E6132UL, 0xCE77E25BUL, 0x578FDFE3UL, 0x3AC372E6UL } +}; + +static unsigned long F(unsigned long x, symmetric_key *key) +{ + return (((key->blowfish.S[0][(x>>24)&255] + + key->blowfish.S[1][(x>>16)&255]) ^ + key->blowfish.S[2][(x>>8)&255]) + + key->blowfish.S[3][(x>>0)&255]); +} + +int blowfish_setup(const unsigned char *key, int keylen, int num_rounds, + symmetric_key *skey) +{ + unsigned long x, y, z, A; + unsigned char B[8]; + + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + /* check key length */ + if (keylen < 8 || keylen > 56) { + return CRYPT_INVALID_KEYSIZE; + } + + /* check rounds */ + if (num_rounds != 0 && num_rounds != 16) { + return CRYPT_INVALID_ROUNDS; + } + + /* load in key bytes (Supplied by David Hopwood) */ + for (x = y = 0; x < 18; x++) { + A = 0; + for (z = 0; z < 4; z++) { + A = (A << 8) | (unsigned long) key[y++ % keylen]; + } + skey->blowfish.K[x] = ORIG_P[x] ^ A; + } + + /* copy sboxes */ + for (x = 0; x < 4; x++) { + for (y = 0; y < 256; y++) { + skey->blowfish.S[x][y] = ORIG_S[x][y]; + } + } + + /* encrypt K array */ + zeromem(B, 8); + for (x = 0; x < 18; x += 2) { + /* encrypt it */ + blowfish_ecb_encrypt(B, B, skey); + /* copy it */ + LOAD32H(skey->blowfish.K[x], &B[0]); + LOAD32H(skey->blowfish.K[x+1], &B[4]); + } + + /* encrypt S array */ + for (x = 0; x < 4; x++) { + for (y = 0; y < 256; y += 2) { + /* encrypt it */ + blowfish_ecb_encrypt(B, B, skey); + /* copy it */ + LOAD32H(skey->blowfish.S[x][y], &B[0]); + LOAD32H(skey->blowfish.S[x][y+1], &B[4]); + } + } + +#ifdef CLEAN_STACK + zeromem(B, sizeof(B)); +#endif + + return CRYPT_OK; +} + +#ifdef CLEAN_STACK +static void _blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#else +void blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#endif +{ + unsigned long L, R; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + + /* load it */ + LOAD32H(L, &pt[0]); + LOAD32H(R, &pt[4]); + + /* do 16 rounds */ + L ^= key->blowfish.K[0]; R ^= F(L, key); + R ^= key->blowfish.K[1]; L ^= F(R, key); + L ^= key->blowfish.K[2]; R ^= F(L, key); + R ^= key->blowfish.K[3]; L ^= F(R, key); + L ^= key->blowfish.K[4]; R ^= F(L, key); + R ^= key->blowfish.K[5]; L ^= F(R, key); + L ^= key->blowfish.K[6]; R ^= F(L, key); + R ^= key->blowfish.K[7]; L ^= F(R, key); + L ^= key->blowfish.K[8]; R ^= F(L, key); + R ^= key->blowfish.K[9]; L ^= F(R, key); + L ^= key->blowfish.K[10]; R ^= F(L, key); + R ^= key->blowfish.K[11]; L ^= F(R, key); + L ^= key->blowfish.K[12]; R ^= F(L, key); + R ^= key->blowfish.K[13]; L ^= F(R, key); + L ^= key->blowfish.K[14]; R ^= F(L, key); + R ^= key->blowfish.K[15]; L ^= F(R, key); + + /* last keying */ + R ^= key->blowfish.K[17]; + L ^= key->blowfish.K[16]; + + /* store */ + STORE32H(R, &ct[0]); + STORE32H(L, &ct[4]); +} + +#ifdef CLEAN_STACK +void blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + _blowfish_ecb_encrypt(pt, ct, key); + burn_stack(sizeof(unsigned long) * 2); +} +#endif + +#ifdef CLEAN_STACK +static void _blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#else +void blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#endif +{ + unsigned long L, R; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + + /* load it */ + LOAD32H(R, &ct[0]); + LOAD32H(L, &ct[4]); + + /* undo last keying */ + R ^= key->blowfish.K[17]; + L ^= key->blowfish.K[16]; + + /* do 16 rounds */ + L ^= F(R, key); R ^= key->blowfish.K[15]; + R ^= F(L, key); L ^= key->blowfish.K[14]; + L ^= F(R, key); R ^= key->blowfish.K[13]; + R ^= F(L, key); L ^= key->blowfish.K[12]; + L ^= F(R, key); R ^= key->blowfish.K[11]; + R ^= F(L, key); L ^= key->blowfish.K[10]; + L ^= F(R, key); R ^= key->blowfish.K[9]; + R ^= F(L, key); L ^= key->blowfish.K[8]; + L ^= F(R, key); R ^= key->blowfish.K[7]; + R ^= F(L, key); L ^= key->blowfish.K[6]; + L ^= F(R, key); R ^= key->blowfish.K[5]; + R ^= F(L, key); L ^= key->blowfish.K[4]; + L ^= F(R, key); R ^= key->blowfish.K[3]; + R ^= F(L, key); L ^= key->blowfish.K[2]; + L ^= F(R, key); R ^= key->blowfish.K[1]; + R ^= F(L, key); L ^= key->blowfish.K[0]; + + /* store */ + STORE32H(L, &pt[0]); + STORE32H(R, &pt[4]); +} + +#ifdef CLEAN_STACK +void blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +{ + _blowfish_ecb_decrypt(ct, pt, key); + burn_stack(sizeof(unsigned long) * 2); +} +#endif + + +int blowfish_test(void) +{ + int errno; + symmetric_key key; + static const struct { + unsigned char key[8], pt[8], ct[8]; + } tests[] = { + { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + { 0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78} + }, + { + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + { 0x51, 0x86, 0x6F, 0xD5, 0xB8, 0x5E, 0xCB, 0x8A} + }, + { + { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + { 0x7D, 0x85, 0x6F, 0x9A, 0x61, 0x30, 0x63, 0xF2} + }, + { + { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, + { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, + { 0x24, 0x66, 0xDD, 0x87, 0x8B, 0x96, 0x3C, 0x9D} + }, + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, + { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, + { 0x61, 0xF9, 0xC3, 0x80, 0x22, 0x81, 0xB0, 0x96} + }, + { + { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, + { 0x7D, 0x0C, 0xC6, 0x30, 0xAF, 0xDA, 0x1E, 0xC7} + }, + { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + { 0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78} + }, + { + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, + { 0x0A, 0xCE, 0xAB, 0x0F, 0xC6, 0xA0, 0xA2, 0x8D} + }, + { + { 0x7C, 0xA1, 0x10, 0x45, 0x4A, 0x1A, 0x6E, 0x57}, + { 0x01, 0xA1, 0xD6, 0xD0, 0x39, 0x77, 0x67, 0x42}, + { 0x59, 0xC6, 0x82, 0x45, 0xEB, 0x05, 0x28, 0x2B} + }, + { + { 0x01, 0x31, 0xD9, 0x61, 0x9D, 0xC1, 0x37, 0x6E}, + { 0x5C, 0xD5, 0x4C, 0xA8, 0x3D, 0xEF, 0x57, 0xDA}, + { 0xB1, 0xB8, 0xCC, 0x0B, 0x25, 0x0F, 0x09, 0xA0} + }, + { + { 0x07, 0xA1, 0x13, 0x3E, 0x4A, 0x0B, 0x26, 0x86}, + { 0x02, 0x48, 0xD4, 0x38, 0x06, 0xF6, 0x71, 0x72}, + { 0x17, 0x30, 0xE5, 0x77, 0x8B, 0xEA, 0x1D, 0xA4} + }, + { + { 0x38, 0x49, 0x67, 0x4C, 0x26, 0x02, 0x31, 0x9E}, + { 0x51, 0x45, 0x4B, 0x58, 0x2D, 0xDF, 0x44, 0x0A}, + { 0xA2, 0x5E, 0x78, 0x56, 0xCF, 0x26, 0x51, 0xEB} + }, + { + { 0x04, 0xB9, 0x15, 0xBA, 0x43, 0xFE, 0xB5, 0xB6}, + { 0x42, 0xFD, 0x44, 0x30, 0x59, 0x57, 0x7F, 0xA2}, + { 0x35, 0x38, 0x82, 0xB1, 0x09, 0xCE, 0x8F, 0x1A} + }, + { + { 0x01, 0x13, 0xB9, 0x70, 0xFD, 0x34, 0xF2, 0xCE}, + { 0x05, 0x9B, 0x5E, 0x08, 0x51, 0xCF, 0x14, 0x3A}, + { 0x48, 0xF4, 0xD0, 0x88, 0x4C, 0x37, 0x99, 0x18} + }, + { + { 0x01, 0x70, 0xF1, 0x75, 0x46, 0x8F, 0xB5, 0xE6}, + { 0x07, 0x56, 0xD8, 0xE0, 0x77, 0x47, 0x61, 0xD2}, + { 0x43, 0x21, 0x93, 0xB7, 0x89, 0x51, 0xFC, 0x98} + }, + { + { 0x43, 0x29, 0x7F, 0xAD, 0x38, 0xE3, 0x73, 0xFE}, + { 0x76, 0x25, 0x14, 0xB8, 0x29, 0xBF, 0x48, 0x6A}, + { 0x13, 0xF0, 0x41, 0x54, 0xD6, 0x9D, 0x1A, 0xE5} + }, + { + { 0x07, 0xA7, 0x13, 0x70, 0x45, 0xDA, 0x2A, 0x16}, + { 0x3B, 0xDD, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02}, + { 0x2E, 0xED, 0xDA, 0x93, 0xFF, 0xD3, 0x9C, 0x79} + }, + { + { 0x04, 0x68, 0x91, 0x04, 0xC2, 0xFD, 0x3B, 0x2F}, + { 0x26, 0x95, 0x5F, 0x68, 0x35, 0xAF, 0x60, 0x9A}, + { 0xD8, 0x87, 0xE0, 0x39, 0x3C, 0x2D, 0xA6, 0xE3} + }, + { + { 0x37, 0xD0, 0x6B, 0xB5, 0x16, 0xCB, 0x75, 0x46}, + { 0x16, 0x4D, 0x5E, 0x40, 0x4F, 0x27, 0x52, 0x32}, + { 0x5F, 0x99, 0xD0, 0x4F, 0x5B, 0x16, 0x39, 0x69} + }, + { + { 0x1F, 0x08, 0x26, 0x0D, 0x1A, 0xC2, 0x46, 0x5E}, + { 0x6B, 0x05, 0x6E, 0x18, 0x75, 0x9F, 0x5C, 0xCA}, + { 0x4A, 0x05, 0x7A, 0x3B, 0x24, 0xD3, 0x97, 0x7B} + }, + { + { 0x58, 0x40, 0x23, 0x64, 0x1A, 0xBA, 0x61, 0x76}, + { 0x00, 0x4B, 0xD6, 0xEF, 0x09, 0x17, 0x60, 0x62}, + { 0x45, 0x20, 0x31, 0xC1, 0xE4, 0xFA, 0xDA, 0x8E} + }, + { + { 0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xB0, 0x07}, + { 0x48, 0x0D, 0x39, 0x00, 0x6E, 0xE7, 0x62, 0xF2}, + { 0x75, 0x55, 0xAE, 0x39, 0xF5, 0x9B, 0x87, 0xBD} + }, + { + { 0x49, 0x79, 0x3E, 0xBC, 0x79, 0xB3, 0x25, 0x8F}, + { 0x43, 0x75, 0x40, 0xC8, 0x69, 0x8F, 0x3C, 0xFA}, + { 0x53, 0xC5, 0x5F, 0x9C, 0xB4, 0x9F, 0xC0, 0x19} + }, + { + { 0x4F, 0xB0, 0x5E, 0x15, 0x15, 0xAB, 0x73, 0xA7}, + { 0x07, 0x2D, 0x43, 0xA0, 0x77, 0x07, 0x52, 0x92}, + { 0x7A, 0x8E, 0x7B, 0xFA, 0x93, 0x7E, 0x89, 0xA3} + }, + { + { 0x49, 0xE9, 0x5D, 0x6D, 0x4C, 0xA2, 0x29, 0xBF}, + { 0x02, 0xFE, 0x55, 0x77, 0x81, 0x17, 0xF1, 0x2A}, + { 0xCF, 0x9C, 0x5D, 0x7A, 0x49, 0x86, 0xAD, 0xB5} + }, + { + { 0x01, 0x83, 0x10, 0xDC, 0x40, 0x9B, 0x26, 0xD6}, + { 0x1D, 0x9D, 0x5C, 0x50, 0x18, 0xF7, 0x28, 0xC2}, + { 0xD1, 0xAB, 0xB2, 0x90, 0x65, 0x8B, 0xC7, 0x78} + }, + { + { 0x1C, 0x58, 0x7F, 0x1C, 0x13, 0x92, 0x4F, 0xEF}, + { 0x30, 0x55, 0x32, 0x28, 0x6D, 0x6F, 0x29, 0x5A}, + { 0x55, 0xCB, 0x37, 0x74, 0xD1, 0x3E, 0xF2, 0x01} + }, + { + { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, + { 0xFA, 0x34, 0xEC, 0x48, 0x47, 0xB2, 0x68, 0xB2} + }, + { + { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E}, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, + { 0xA7, 0x90, 0x79, 0x51, 0x08, 0xEA, 0x3C, 0xAE} + }, + { + { 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE}, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, + { 0xC3, 0x9E, 0x07, 0x2D, 0x9F, 0xAC, 0x63, 0x1D} + }, + { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + { 0x01, 0x49, 0x33, 0xE0, 0xCD, 0xAF, 0xF6, 0xE4} + }, + { + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + { 0xF2, 0x1E, 0x9A, 0x77, 0xB7, 0x1C, 0x49, 0xBC} + }, + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + { 0x24, 0x59, 0x46, 0x88, 0x57, 0x54, 0x36, 0x9A} + }, + { + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + { 0x6B, 0x5C, 0x5A, 0x9C, 0x5D, 0x9E, 0x0A, 0x5A} + } + }; + unsigned char buf[2][8]; + int x, failed; + + for (x = failed = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) { + /* setup key */ + if ((errno = blowfish_setup(tests[x].key, 8, 16, &key)) != CRYPT_OK) { + return errno; + } + + /* encrypt and decrypt */ + blowfish_ecb_encrypt(tests[x].pt, buf[0], &key); + blowfish_ecb_decrypt(buf[0], buf[1], &key); + + /* compare */ + if (memcmp(buf[0], tests[x].ct, 8)) { +#if 0 + int y; + printf("\nEncrypt test %d failed\n", x); + for (y = 0; y < 8; y++) printf("%02x ", buf[0][y]); + printf("\n"); +#endif + failed = 1; + } + + if (memcmp(buf[1], tests[x].pt, 8)) { +#if 0 + int y; + printf("\nDecrypt test %d failed\n", x); + for (y = 0; y < 8; y++) printf("%02x ", buf[1][y]); + printf("\n"); +#endif + failed = 1; + } + } + + if (failed == 1) { + return CRYPT_FAIL_TESTVECTOR; + } else { + return CRYPT_OK; + } +} + +int blowfish_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize != NULL); + + if (*desired_keysize < 8) { + return CRYPT_INVALID_KEYSIZE; + } else if (*desired_keysize > 56) { + *desired_keysize = 56; + } + return CRYPT_OK; +} + +#endif + diff --git a/cast5.c b/cast5.c new file mode 100644 index 0000000..62431d7 --- /dev/null +++ b/cast5.c @@ -0,0 +1,622 @@ +/* Implementation of CAST5 (RFC 2144) by Tom St Denis */ +#include "mycrypt.h" + +#ifdef CAST5 + +const struct _cipher_descriptor cast5_desc = { + "cast5", + 15, + 5, 16, 8, 16, + &cast5_setup, + &cast5_ecb_encrypt, + &cast5_ecb_decrypt, + &cast5_test, + &cast5_keysize +}; + +static const unsigned long S1[256] = { +0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, +0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, +0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, 0x28683b6f, 0xc07fd059, +0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, +0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, +0x22568e3a, 0xa2d341d0, 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, +0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, 0xb82cbaef, 0xd751d159, +0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, +0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, +0xb48ee411, 0x4bff345d, 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, +0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, 0x882240f2, 0x0c6e4f38, +0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, +0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, +0xe63d37e0, 0x2a54f6b3, 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, +0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, 0x38901091, 0xc6b505eb, +0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, +0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, +0xa0bebc3c, 0x54623779, 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, +0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, 0x81383f05, 0x6963c5c8, +0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, +0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, +0xaa573b04, 0x4a805d8d, 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, +0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, 0x6b54bfab, 0x2b0b1426, +0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, +0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, +0xe31231b2, 0x2ad5ad6c, 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, +0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, 0x7b5a41f0, 0xd37cfbad, +0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, +0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, +0x5ad328d8, 0xb347cc96, 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, +0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, 0x3f04442f, 0x6188b153, +0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, +0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, +0xdd24cb9e, 0x7e1c54bd, 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, +0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, 0x580304f0, 0xca042cf1, +0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, +0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, +0xd5ea50f1, 0x85a92872, 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, +0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, 0x474d6ad7, 0x7c0c5e5c, +0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, +0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, +0xb141ab08, 0x7cca89b9, 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, +0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf}; + +static const unsigned long S2[256] = { +0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, +0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, +0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, 0xa0b52f7b, 0x59e83605, +0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, +0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, +0x25a1ff41, 0xe180f806, 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, +0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, 0xe113c85b, 0xacc40083, +0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, +0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, +0x361e3084, 0xe4eb573b, 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, +0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, 0x10843094, 0x2537a95e, +0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, +0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, +0x721d9bfd, 0xa58684bb, 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, +0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, 0xc5d655dd, 0xeb667064, +0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, +0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, +0x83ca6b94, 0x2d6ed23b, 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, +0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, 0x81ed6f61, 0x20e74364, +0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, +0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, +0xa4b09f6b, 0x1ca815cf, 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, +0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, 0xee41e729, 0x6e1d2d7c, +0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, +0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, +0x7cbad9a2, 0x2180036f, 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, +0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, 0xcdf0b680, 0x17844d3b, +0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, +0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, +0xef8579cc, 0xd152de58, 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, +0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, 0xb8da230c, 0x80823028, +0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, +0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, +0x273be979, 0xb0ffeaa6, 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, +0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, 0xdc8637a0, 0x16a7d3b1, +0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, +0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, +0x145892f5, 0x91584f7f, 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, +0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, 0xb284600c, 0xd835731d, +0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, +0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, +0x5c038323, 0x3e5d3bb9, 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, +0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1}; + +static const unsigned long S3[256] = { +0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, +0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, +0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, 0x11107d9f, 0x07647db9, +0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, +0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, +0x9255c5ed, 0x1257a240, 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, +0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, 0xa8c01db7, 0x579fc264, +0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, +0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, +0xc5884a28, 0xccc36f71, 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, +0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, 0xa747d2d0, 0x1651192e, +0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, +0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, +0x796fb449, 0x8252dc15, 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, +0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, 0x23efe941, 0xa903f12e, +0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, +0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, +0x96bbb682, 0x93b4b148, 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, +0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, 0x8b907cee, 0xb51fd240, +0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, +0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, +0x127dadaa, 0x438a074e, 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, +0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, 0x68cc7bfb, 0xd90f2788, +0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, +0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, +0x27627545, 0x825cf47a, 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, +0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, 0x285ba1c8, 0x3c62f44f, +0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, +0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, +0x12deca4d, 0x2c3f8cc5, 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, +0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, 0x3a609437, 0xec00c9a9, +0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, +0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, +0xa2e53f55, 0xb9e6d4bc, 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, +0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, 0x947b0001, 0x570075d2, +0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, +0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, +0xf1ac2571, 0xcc8239c2, 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, +0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, 0x5727c148, 0x2be98a1d, +0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, +0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, +0x52bce688, 0x1b03588a, 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, +0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783}; + +static const unsigned long S4[256] = { +0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, +0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, +0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, 0x28147f5f, 0x4fa2b8cd, +0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, +0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, +0x081b08ca, 0x05170121, 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, +0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, 0xce84ffdf, 0xf5718801, +0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, +0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, +0x72500e03, 0xf80eb2bb, 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, +0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, 0x4d351805, 0x7f3d5ce3, +0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, +0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, +0x18f8931e, 0x281658e6, 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, +0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, 0x69dead38, 0x1574ca16, +0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, +0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, +0x0ce5c2ec, 0x4db4bba6, 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, +0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, 0x6e85cb75, 0xbe07c002, +0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, +0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, +0x041afa32, 0x1d16625a, 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, +0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, 0x026a4ceb, 0x52437eff, +0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, +0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, +0x213d42f6, 0x2c1c7c26, 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, +0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, 0x63315c21, 0x5e0a72ec, +0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, +0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, +0xcfcbd12f, 0xc1de8417, 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, +0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, 0x6f7de532, 0x58fd7eb6, +0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, +0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, +0xaf9eb3db, 0x29c9ed2a, 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, +0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, 0x77079103, 0xdea03af6, +0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, +0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, +0xf3e0eb5b, 0xd6cc9876, 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, +0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, 0xb5676e69, 0x9bd3ddda, +0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, +0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, +0xb657c34d, 0x4edfd282, 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, +0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2}; + +static const unsigned long S5[256] = { +0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, +0x44dd9d44, 0x1731167f, 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, +0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, 0xe6a2e77f, 0xf0c720cd, +0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, +0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, +0x8dba1cfe, 0x41a99b02, 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, +0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, 0xf2f3f763, 0x68af8040, +0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, +0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, +0x2261be02, 0xd642a0c9, 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, +0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, 0x5c1ff900, 0xfe38d399, +0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, +0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, +0xdfdd55bc, 0x29de0655, 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, +0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, 0xbcf3f0aa, 0x87ac36e9, +0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, +0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, +0xf24766e3, 0x8eca36c1, 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, +0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, 0x26e46695, 0xb7566419, +0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, +0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, +0x68cb3e47, 0x086c010f, 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, +0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, 0x0ab378d5, 0xd951fb0c, +0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, +0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, +0x646c6bd7, 0x44904db3, 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, +0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, 0x76f0ae02, 0x083be84d, +0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, +0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, +0x9cad9010, 0xaf462ba2, 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, +0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, 0x445f7382, 0x175683f4, +0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, +0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, +0x1ad2fff3, 0x8c25404e, 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, +0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, 0x44094f85, 0x3f481d87, +0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, +0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, +0x1b5ad7a8, 0xf61ed5ad, 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, +0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, 0x5ce96c28, 0xe176eda3, +0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, +0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, +0x34010718, 0xbb30cab8, 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, +0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4}; + +static const unsigned long S6[256] = { +0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, +0xeced5cbc, 0x325553ac, 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, +0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, 0x33f14961, 0xc01937bd, +0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, +0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, +0xa888614a, 0x2900af98, 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, +0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, 0xfd41197e, 0x9305a6b0, +0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, +0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, +0x2c0e636a, 0xba7dd9cd, 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, +0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, 0x284caf89, 0xaa928223, +0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, +0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, +0x9a69a02f, 0x68818a54, 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, +0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, 0x53bddb65, 0xe76ffbe7, +0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, +0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, +0xfd339fed, 0xb87834bf, 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, +0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, 0x4ec75b95, 0x24f2c3c0, +0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, +0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, +0xe9a9d848, 0xf3160289, 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, +0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, 0x36f73523, 0x4cfb6e87, +0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, +0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, +0xdc049441, 0xc8098f9b, 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, +0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, 0xbf32679d, 0xd45b5b75, +0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, +0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, +0x3cc2acfb, 0x3fc06976, 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, +0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, 0x3007cd3e, 0x74719eef, +0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, +0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, +0xbc60b42a, 0x953498da, 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, +0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, 0xe8816f4a, 0x3814f200, +0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, +0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, +0x3a479c3a, 0x5302da25, 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, +0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, 0xb81a928a, 0x60ed5869, +0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, +0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, +0xb0e93524, 0xbebb8fbd, 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, +0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f}; + +static const unsigned long S7[256] = { +0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, +0xde6008a1, 0x2028da1f, 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, +0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, 0xa05fbcf6, 0xcd4181e9, +0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, +0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, +0x1286becf, 0xb6eacb19, 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, +0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, 0x107789be, 0xb3b2e9ce, +0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, +0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, +0xd0d854c0, 0xcb3a6c88, 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, +0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, 0x0a961288, 0xe1a5c06e, +0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, +0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, +0xc6e6fa14, 0xbae8584a, 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, +0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, 0x92544a8b, 0x009b4fc3, +0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, +0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, +0x16746233, 0x3c034c28, 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, +0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, 0x0c4fb99a, 0xbb325778, +0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, +0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, +0xbe8b9d2d, 0x7979fb06, 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, +0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, 0xf28ebfb0, 0xf5b9c310, +0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, +0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, +0x488dcf25, 0x36c9d566, 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, +0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, 0xf22b017d, 0xa4173f70, +0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, +0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, +0x058745b9, 0x3453dc1e, 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, +0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, 0x66626c1c, 0x7154c24c, +0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, +0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, +0xe4f2dfa6, 0x693ed285, 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, +0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, 0xc79f022f, 0x3c997e7e, +0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, +0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, +0xcfd2a87f, 0x60aeb767, 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, +0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, 0x97fd61a9, 0xea7759f4, +0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, +0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, +0xc3c0bdae, 0x4958c24c, 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, +0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3}; + +static const unsigned long S8[256] = { +0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, +0x0e241600, 0x052ce8b5, 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, +0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, 0xde9adeb1, 0x0a0cc32c, +0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, +0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, +0x72df191b, 0x7580330d, 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, +0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, 0x12a8ddec, 0xfdaa335d, +0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, +0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, +0x57e8726e, 0x647a78fc, 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, +0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, 0xbbd35049, 0x2998df04, +0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, +0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, +0x424f7618, 0x35856039, 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, +0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, 0x7170c608, 0x2d5e3354, +0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, +0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, +0x7895cda5, 0x859c15a5, 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, +0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, 0x835ffcb8, 0x6df4c1f2, +0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, +0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, +0x7cd16efc, 0x1436876c, 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, +0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, 0xa842eedf, 0xfdba60b4, +0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, +0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, +0xbae7dfdc, 0x42cbda70, 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, +0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, 0x77853b53, 0x37effcb5, +0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, +0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, +0xc4248289, 0xacf3ebc3, 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, +0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, 0xe87b40e4, 0xe98ea084, +0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, +0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, +0xe0779695, 0xf9c17a8f, 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, +0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, 0x11403092, 0x00da6d77, +0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, +0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, +0xdf09822b, 0xbd691a6c, 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, +0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, 0x5938fa0f, 0x42399ef3, +0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, +0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, +0xa466bb1e, 0xf8da0a82, 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, +0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e}; + +/* returns the i'th byte of a variable */ +#define GB(x, i) (((x[(15-i)>>2])>>(8*((15-i)&3)))&255) + +int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + unsigned long x[4], z[4]; + unsigned char buf[16]; + int y, i; + + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + if (num_rounds != 12 && num_rounds != 16 && num_rounds != 0) { + return CRYPT_INVALID_ROUNDS; + } + + if (num_rounds == 12 && keylen > 10) { + return CRYPT_INVALID_ROUNDS; + } + + if (keylen < 5 || keylen > 16) { + return CRYPT_INVALID_KEYSIZE; + } + + /* extend the key as required */ + zeromem(buf, sizeof(buf)); + memcpy(buf, key, keylen); + + /* load and start the awful looking network */ + for (y = 0; y < 4; y++) { + LOAD32H(x[3-y],buf+4*y); + } + + for (i = y = 0; y < 2; y++) { + z[3] = x[3] ^ S5[GB(x, 0xD)] ^ S6[GB(x, 0xF)] ^ S7[GB(x, 0xC)] ^ S8[GB(x, 0xE)] ^ S7[GB(x, 0x8)]; + z[2] = x[1] ^ S5[GB(z, 0x0)] ^ S6[GB(z, 0x2)] ^ S7[GB(z, 0x1)] ^ S8[GB(z, 0x3)] ^ S8[GB(x, 0xA)]; + z[1] = x[0] ^ S5[GB(z, 0x7)] ^ S6[GB(z, 0x6)] ^ S7[GB(z, 0x5)] ^ S8[GB(z, 0x4)] ^ S5[GB(x, 0x9)]; + z[0] = x[2] ^ S5[GB(z, 0xA)] ^ S6[GB(z, 0x9)] ^ S7[GB(z, 0xb)] ^ S8[GB(z, 0x8)] ^ S6[GB(x, 0xB)]; + skey->cast5.K[i++] = S5[GB(z, 0x8)] ^ S6[GB(z, 0x9)] ^ S7[GB(z, 0x7)] ^ S8[GB(z, 0x6)] ^ S5[GB(z, 0x2)]; + skey->cast5.K[i++] = S5[GB(z, 0xA)] ^ S6[GB(z, 0xB)] ^ S7[GB(z, 0x5)] ^ S8[GB(z, 0x4)] ^ S6[GB(z, 0x6)]; + skey->cast5.K[i++] = S5[GB(z, 0xC)] ^ S6[GB(z, 0xd)] ^ S7[GB(z, 0x3)] ^ S8[GB(z, 0x2)] ^ S7[GB(z, 0x9)]; + skey->cast5.K[i++] = S5[GB(z, 0xE)] ^ S6[GB(z, 0xF)] ^ S7[GB(z, 0x1)] ^ S8[GB(z, 0x0)] ^ S8[GB(z, 0xc)]; + + x[3] = z[1] ^ S5[GB(z, 0x5)] ^ S6[GB(z, 0x7)] ^ S7[GB(z, 0x4)] ^ S8[GB(z, 0x6)] ^ S7[GB(z, 0x0)]; + x[2] = z[3] ^ S5[GB(x, 0x0)] ^ S6[GB(x, 0x2)] ^ S7[GB(x, 0x1)] ^ S8[GB(x, 0x3)] ^ S8[GB(z, 0x2)]; + x[1] = z[2] ^ S5[GB(x, 0x7)] ^ S6[GB(x, 0x6)] ^ S7[GB(x, 0x5)] ^ S8[GB(x, 0x4)] ^ S5[GB(z, 0x1)]; + x[0] = z[0] ^ S5[GB(x, 0xA)] ^ S6[GB(x, 0x9)] ^ S7[GB(x, 0xb)] ^ S8[GB(x, 0x8)] ^ S6[GB(z, 0x3)]; + skey->cast5.K[i++] = S5[GB(x, 0x3)] ^ S6[GB(x, 0x2)] ^ S7[GB(x, 0xc)] ^ S8[GB(x, 0xd)] ^ S5[GB(x, 0x8)]; + skey->cast5.K[i++] = S5[GB(x, 0x1)] ^ S6[GB(x, 0x0)] ^ S7[GB(x, 0xe)] ^ S8[GB(x, 0xf)] ^ S6[GB(x, 0xd)]; + skey->cast5.K[i++] = S5[GB(x, 0x7)] ^ S6[GB(x, 0x6)] ^ S7[GB(x, 0x8)] ^ S8[GB(x, 0x9)] ^ S7[GB(x, 0x3)]; + skey->cast5.K[i++] = S5[GB(x, 0x5)] ^ S6[GB(x, 0x4)] ^ S7[GB(x, 0xa)] ^ S8[GB(x, 0xb)] ^ S8[GB(x, 0x7)]; + + /* second half */ + + z[3] = x[3] ^ S5[GB(x, 0xD)] ^ S6[GB(x, 0xF)] ^ S7[GB(x, 0xC)] ^ S8[GB(x, 0xE)] ^ S7[GB(x, 0x8)]; + z[2] = x[1] ^ S5[GB(z, 0x0)] ^ S6[GB(z, 0x2)] ^ S7[GB(z, 0x1)] ^ S8[GB(z, 0x3)] ^ S8[GB(x, 0xA)]; + z[1] = x[0] ^ S5[GB(z, 0x7)] ^ S6[GB(z, 0x6)] ^ S7[GB(z, 0x5)] ^ S8[GB(z, 0x4)] ^ S5[GB(x, 0x9)]; + z[0] = x[2] ^ S5[GB(z, 0xA)] ^ S6[GB(z, 0x9)] ^ S7[GB(z, 0xb)] ^ S8[GB(z, 0x8)] ^ S6[GB(x, 0xB)]; + skey->cast5.K[i++] = S5[GB(z, 0x3)] ^ S6[GB(z, 0x2)] ^ S7[GB(z, 0xc)] ^ S8[GB(z, 0xd)] ^ S5[GB(z, 0x9)]; + skey->cast5.K[i++] = S5[GB(z, 0x1)] ^ S6[GB(z, 0x0)] ^ S7[GB(z, 0xe)] ^ S8[GB(z, 0xf)] ^ S6[GB(z, 0xc)]; + skey->cast5.K[i++] = S5[GB(z, 0x7)] ^ S6[GB(z, 0x6)] ^ S7[GB(z, 0x8)] ^ S8[GB(z, 0x9)] ^ S7[GB(z, 0x2)]; + skey->cast5.K[i++] = S5[GB(z, 0x5)] ^ S6[GB(z, 0x4)] ^ S7[GB(z, 0xa)] ^ S8[GB(z, 0xb)] ^ S8[GB(z, 0x6)]; + + x[3] = z[1] ^ S5[GB(z, 0x5)] ^ S6[GB(z, 0x7)] ^ S7[GB(z, 0x4)] ^ S8[GB(z, 0x6)] ^ S7[GB(z, 0x0)]; + x[2] = z[3] ^ S5[GB(x, 0x0)] ^ S6[GB(x, 0x2)] ^ S7[GB(x, 0x1)] ^ S8[GB(x, 0x3)] ^ S8[GB(z, 0x2)]; + x[1] = z[2] ^ S5[GB(x, 0x7)] ^ S6[GB(x, 0x6)] ^ S7[GB(x, 0x5)] ^ S8[GB(x, 0x4)] ^ S5[GB(z, 0x1)]; + x[0] = z[0] ^ S5[GB(x, 0xA)] ^ S6[GB(x, 0x9)] ^ S7[GB(x, 0xb)] ^ S8[GB(x, 0x8)] ^ S6[GB(z, 0x3)]; + skey->cast5.K[i++] = S5[GB(x, 0x8)] ^ S6[GB(x, 0x9)] ^ S7[GB(x, 0x7)] ^ S8[GB(x, 0x6)] ^ S5[GB(x, 0x3)]; + skey->cast5.K[i++] = S5[GB(x, 0xa)] ^ S6[GB(x, 0xb)] ^ S7[GB(x, 0x5)] ^ S8[GB(x, 0x4)] ^ S6[GB(x, 0x7)]; + skey->cast5.K[i++] = S5[GB(x, 0xc)] ^ S6[GB(x, 0xd)] ^ S7[GB(x, 0x3)] ^ S8[GB(x, 0x2)] ^ S7[GB(x, 0x8)]; + skey->cast5.K[i++] = S5[GB(x, 0xe)] ^ S6[GB(x, 0xf)] ^ S7[GB(x, 0x1)] ^ S8[GB(x, 0x0)] ^ S8[GB(x, 0xd)]; + } + + skey->cast5.keylen = keylen; + +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); + zeromem(x, sizeof(x)); + zeromem(z, sizeof(z)); +#endif + + return CRYPT_OK; +} + +static unsigned long FI(unsigned long R, unsigned long Km, unsigned long Kr) +{ + unsigned long I; + I = (Km + R); + I = ROL(I, Kr); + return ((S1[(I>>24)&255] ^ S2[(I>>16)&255]) - S3[(I>>8)&255]) + S4[I&255]; +} + +static unsigned long FII(unsigned long R, unsigned long Km, unsigned long Kr) +{ + unsigned long I; + I = (Km ^ R); + I = ROL(I, Kr); + return ((S1[(I>>24)&255] - S2[(I>>16)&255]) + S3[(I>>8)&255]) ^ S4[I&255]; +} + +static unsigned long FIII(unsigned long R, unsigned long Km, unsigned long Kr) +{ + unsigned long I; + I = (Km - R); + I = ROL(I, Kr); + return ((S1[(I>>24)&255] + S2[(I>>16)&255]) ^ S3[(I>>8)&255]) - S4[I&255]; +} + +void cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + unsigned long R, L; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + + LOAD32H(L,&pt[0]); + LOAD32H(R,&pt[4]); + + L ^= FI(R, key->cast5.K[0], key->cast5.K[16]); + R ^= FII(L, key->cast5.K[1], key->cast5.K[17]); + L ^= FIII(R, key->cast5.K[2], key->cast5.K[18]); + R ^= FI(L, key->cast5.K[3], key->cast5.K[19]); + L ^= FII(R, key->cast5.K[4], key->cast5.K[20]); + R ^= FIII(L, key->cast5.K[5], key->cast5.K[21]); + L ^= FI(R, key->cast5.K[6], key->cast5.K[22]); + R ^= FII(L, key->cast5.K[7], key->cast5.K[23]); + L ^= FIII(R, key->cast5.K[8], key->cast5.K[24]); + R ^= FI(L, key->cast5.K[9], key->cast5.K[25]); + L ^= FII(R, key->cast5.K[10], key->cast5.K[26]); + R ^= FIII(L, key->cast5.K[11], key->cast5.K[27]); + if (key->cast5.keylen > 10) { + L ^= FI(R, key->cast5.K[12], key->cast5.K[28]); + R ^= FII(L, key->cast5.K[13], key->cast5.K[29]); + L ^= FIII(R, key->cast5.K[14], key->cast5.K[30]); + R ^= FI(L, key->cast5.K[15], key->cast5.K[31]); + } + STORE32H(R,&ct[0]); + STORE32H(L,&ct[4]); +} + +void cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +{ + unsigned long R, L; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + + LOAD32H(R,&ct[0]); + LOAD32H(L,&ct[4]); + + if (key->cast5.keylen > 10) { + R ^= FI(L, key->cast5.K[15], key->cast5.K[31]); + L ^= FIII(R, key->cast5.K[14], key->cast5.K[30]); + R ^= FII(L, key->cast5.K[13], key->cast5.K[29]); + L ^= FI(R, key->cast5.K[12], key->cast5.K[28]); + } + + R ^= FIII(L, key->cast5.K[11], key->cast5.K[27]); + L ^= FII(R, key->cast5.K[10], key->cast5.K[26]); + R ^= FI(L, key->cast5.K[9], key->cast5.K[25]); + L ^= FIII(R, key->cast5.K[8], key->cast5.K[24]); + R ^= FII(L, key->cast5.K[7], key->cast5.K[23]); + L ^= FI(R, key->cast5.K[6], key->cast5.K[22]); + R ^= FIII(L, key->cast5.K[5], key->cast5.K[21]); + L ^= FII(R, key->cast5.K[4], key->cast5.K[20]); + R ^= FI(L, key->cast5.K[3], key->cast5.K[19]); + L ^= FIII(R, key->cast5.K[2], key->cast5.K[18]); + R ^= FII(L, key->cast5.K[1], key->cast5.K[17]); + L ^= FI(R, key->cast5.K[0], key->cast5.K[16]); + + STORE32H(L,&pt[0]); + STORE32H(R,&pt[4]); +} + +int cast5_test(void) +{ + static const struct { + int keylen; + unsigned char key[16]; + unsigned char pt[8]; + unsigned char ct[8]; + } tests[] = { + { 16, + {0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A}, + {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, + {0x23, 0x8B, 0x4F, 0xE5, 0x84, 0x7E, 0x44, 0xB2} + }, + { 10, + {0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45}, + {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, + {0xEB, 0x6A, 0x71, 0x1A, 0x2C, 0x02, 0x27, 0x1B}, + }, + { 5, + {0x01, 0x23, 0x45, 0x67, 0x12}, + {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, + {0x7A, 0xC8, 0x16, 0xD1, 0x6E, 0x9B, 0x30, 0x2E} + } + }; + int i, errno; + symmetric_key key; + unsigned char buf[8], buf2[8]; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + if ((errno = cast5_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) { + return errno; + } + cast5_ecb_encrypt(tests[i].pt, buf, &key); + if (memcmp(buf, tests[i].ct, 8)) { +#if 0 + int j; + printf("\n\n\nFailed encrypt test: %d\n", i); + for (j = 0; j < 8; j++) printf("%02x ", buf[j]); + printf("\n"); +#endif + return CRYPT_FAIL_TESTVECTOR; + } + cast5_ecb_decrypt(buf, buf2, &key); + if (memcmp(buf2, tests[i].pt, 8)) { +#if 0 + int j; + printf("\n\n\nFailed decrypt test: %d\n", i); + for (j = 0; j < 8; j++) printf("%02x ", buf2[j]); + printf("\n"); +#endif + return CRYPT_FAIL_TESTVECTOR; + } + + } + return CRYPT_OK; +} + +int cast5_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize != NULL); + if (*desired_keysize < 5) { + return CRYPT_INVALID_KEYSIZE; + } else if (*desired_keysize > 16) { + *desired_keysize = 16; + } + return CRYPT_OK; +} + +#endif + diff --git a/cbc.c b/cbc.c new file mode 100644 index 0000000..fd980ca --- /dev/null +++ b/cbc.c @@ -0,0 +1,101 @@ +#include "mycrypt.h" + +#ifdef CBC + +int cbc_start(int cipher, const unsigned char *IV, const unsigned char *key, + int keylen, int num_rounds, symmetric_CBC *cbc) +{ + int x, errno; + + _ARGCHK(IV != NULL); + _ARGCHK(key != NULL); + _ARGCHK(cbc != NULL); + + /* bad param? */ + if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) { + return errno; + } + + /* setup cipher */ + if ((errno = cipher_descriptor[cipher].setup(key, keylen, num_rounds, &cbc->key)) != CRYPT_OK) { + return errno; + } + + /* copy IV */ + cbc->blocklen = cipher_descriptor[cipher].block_length; + cbc->cipher = cipher; + for (x = 0; x < cbc->blocklen; x++) { + cbc->IV[x] = IV[x]; + } + return CRYPT_OK; +} + +int cbc_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_CBC *cbc) +{ + int x, errno; + unsigned char tmp[MAXBLOCKSIZE]; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(cbc != NULL); + + if ((errno = cipher_is_valid(cbc->cipher)) != CRYPT_OK) { + return errno; + } + + /* xor IV against plaintext */ + for (x = 0; x < cbc->blocklen; x++) { + tmp[x] = pt[x] ^ cbc->IV[x]; + } + + /* encrypt */ + cipher_descriptor[cbc->cipher].ecb_encrypt(tmp, ct, &cbc->key); + + /* store IV [ciphertext] for a future block */ + for (x = 0; x < cbc->blocklen; x++) { + cbc->IV[x] = ct[x]; + } + + #ifdef CLEAN_STACK + zeromem(tmp, sizeof(tmp)); + #endif + return CRYPT_OK; +} + +int cbc_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_CBC *cbc) +{ + int x, errno; + unsigned char tmp[MAXBLOCKSIZE], tmp2[MAXBLOCKSIZE]; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(cbc != NULL); + + /* decrypt the block from ct into tmp */ + if ((errno = cipher_is_valid(cbc->cipher)) != CRYPT_OK) { + return errno; + } + cipher_descriptor[cbc->cipher].ecb_decrypt(ct, tmp, &cbc->key); + + /* xor IV against the plaintext of the previous step */ + for (x = 0; x < cbc->blocklen; x++) { + /* copy CT in case ct == pt */ + tmp2[x] = ct[x]; + + /* actually decrypt the byte */ + pt[x] = tmp[x] ^ cbc->IV[x]; + } + + /* replace IV with this current ciphertext */ + for (x = 0; x < cbc->blocklen; x++) { + cbc->IV[x] = tmp2[x]; + } + #ifdef CLEAN_STACK + zeromem(tmp, sizeof(tmp)); + zeromem(tmp2, sizeof(tmp2)); + #endif + return CRYPT_OK; +} + +#endif + diff --git a/cfb.c b/cfb.c new file mode 100644 index 0000000..c193751 --- /dev/null +++ b/cfb.c @@ -0,0 +1,86 @@ +#include "mycrypt.h" + +#ifdef CFB + +int cfb_start(int cipher, const unsigned char *IV, const unsigned char *key, + int keylen, int num_rounds, symmetric_CFB *cfb) +{ + int x, errno; + + _ARGCHK(IV != NULL); + _ARGCHK(key != NULL); + _ARGCHK(cfb != NULL); + + if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) { + return errno; + } + + /* copy data */ + cfb->cipher = cipher; + cfb->blocklen = cipher_descriptor[cipher].block_length; + for (x = 0; x < cfb->blocklen; x++) + cfb->IV[x] = IV[x]; + + /* init the cipher */ + if ((errno = cipher_descriptor[cipher].setup(key, keylen, num_rounds, &cfb->key)) != CRYPT_OK) { + return errno; + } + + /* encrypt the IV */ + cipher_descriptor[cfb->cipher].ecb_encrypt(cfb->IV, cfb->IV, &cfb->key); + cfb->padlen = 0; + + return CRYPT_OK; +} + +int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CFB *cfb) +{ + int errno; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(cfb != NULL); + + if ((errno = cipher_is_valid(cfb->cipher)) != CRYPT_OK) { + return errno; + } + while (len--) { + if (cfb->padlen == cfb->blocklen) { + cipher_descriptor[cfb->cipher].ecb_encrypt(cfb->pad, cfb->IV, &cfb->key); + cfb->padlen = 0; + } + cfb->pad[cfb->padlen] = (*ct = *pt ^ cfb->IV[cfb->padlen]); + ++pt; + ++ct; + ++cfb->padlen; + } + return CRYPT_OK; +} + +int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CFB *cfb) +{ + int errno; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(cfb != NULL); + + if ((errno = cipher_is_valid(cfb->cipher)) != CRYPT_OK) { + return errno; + } + while (len--) { + if (cfb->padlen == cfb->blocklen) { + cipher_descriptor[cfb->cipher].ecb_encrypt(cfb->pad, cfb->IV, &cfb->key); + cfb->padlen = 0; + } + cfb->pad[cfb->padlen] = *ct; + *pt = *ct ^ cfb->IV[cfb->padlen]; + ++pt; + ++ct; + ++cfb->padlen; + } + return CRYPT_OK; +} + +#endif + diff --git a/changes b/changes new file mode 100644 index 0000000..5988099 --- /dev/null +++ b/changes @@ -0,0 +1,622 @@ +Nov 24th, 2002 +v0.75 -- Fixed a flaw in hash_filehandle, it should ARGCHK that the filehandle is not NULL + -- Fixed a bug where in hash_file if the call to hash_filehandle failed the open file would + not be closed. + -- Added more strict rules to build process, starting to weed out "oh this works in GCC" style code + In the next release "-Wconversion" will be enabled which will deal with all implicit casts. + +Nov 22nd, 2002 [later in the day] +v0.74 -- Wrote a small variant of SAFER+ which shaved 50KB off the size of the library on x86 platforms + -- Wrote a build option to remove the PK packet functions [keeps the encrypt_key/sign_hash functions] + -- Wrote a small variant of Rijndael (trimmed 13KB) + -- Trimmed the TIGER/192 hash function a bit + -- Overall the entire lib compiled is 295KB [down from 400KB before] + -- Fixed a few minor oversights in the MSVC makefile + +Nov 22nd, 2002 +v0.73 -- Fixed bug in RC4 code where it could only use 255 byte keys. + -- Fixed bug in yarrow code where it would allow cast5 or md2 to be used with it... + -- Removed the ecc compress/expand points from the global scope. Reduces namespace polution + -- Fixed bug where if you used the SPRNG you couldn't pass NULL as your prng_state which you should be + able todo since the SPRNG has no state... + -- Corrected some oversights in the manual and the examples... + -- By default the GF(2^W) math library is excluded from the build. The source is maintained because I wrote it + and like it :-). This way the built library is a tad smaller + -- the MSVC makefile will now build for a SPACE optimized library rather than TIME optimized. + +Nov 21th, 2002 +v0.72 -- Fixed bug in the prime testing. In the Miller-Rabin test I was raising the base to "N-1" not "r". + The math still worked out fine because in effect it was performing a Fermat test. Tested the new code and it + works properly + -- Fixed some of the code where it was still using the old error syntax + -- Sped up the RSA decrypt/sign routines + -- Optimized the ecc_shared_secret routine to not use so much stack + -- Fixed up the makefile to make releases where the version # is in the file name and directory it will unzip + to + +Nov 19th, 2002 +v0.71 -- HELP TOM. I need tuition for the January semester. Now I don't want to force donations [nor will I ever] + but I really need the help! See my website http://tom.iahu.ca/help_tom.html for more details. Please help + if you can! + -------------------------------------------------------------------------------------------------------------- + -- Officially the library is no longer supported in GCC 3.2 in windows [cygwin]. + In windows you can either use GCC 2.95.3 or try your luck with 3.2 It seems that + "-fomit-frame-pointer" is broken in the windows build [but not the linux x86 build???] + If you simply must use 3.2 then I suggest you limit the optimizations to simply "-O2" + -- Started new error handling API. Similar to the previous except there are more error codes than just + CRYPT_ERROR + -- Added my implementation of the MD2 hash function [despite the errors in the RFC I managed to get it right!] + -- Merged in more changes from Sky Schulz. I have to make mention here that he has been a tremendous help in + getting me motivated to make some much needed updates to the library! + -- Fixed one of the many mistakes in the manual as pointed out by Daniel Richards + -- Fixed a bug in the RC4 code [wasn't setting up the key correctly] + -- Added my implementation of the CAST5 [aka CAST-128] block cipher (conforms...) + -- Fixed numerous bugs in the PK code. Essentially I was "freeing" keys when the import failed. This is neither + required nor a good a idea [double free]. + -- Tom needs a job. + -- Fixed up the test harness as requested by Sky Schulz. Also modifed the timing routines to run for X seconds + and count # of ops performed. This is more suitable than say encrypting 10 million blocks on a slow processor + where it could take minutes! + -- Modified test programs hashsum/encrypt to use the new algorithms and error handling syntax + -- Removed the PKCS code since it was incomplete. In the future I plan on writing a "add-on" library that + provides PKCS support... + -- updated the config system so the #defines are in the makefiles instead of mycrypt_cfg.h + -- Willing to work on an hourly basis for 15$ CDN per hour. + -- updated the test program to not test ciphers not included + -- updated the makefile to make "rsa_sys.c" a dependency of rsa.o [helps develop the code...] + -- fixed numerous failures to detect buffer overflows [minor] in the PK code. + -- fixed the safer [64-bit block version] test routines which didn't check the returns of the setup + function + -- check out my CV at http://tom.iahu.ca/cv.html + -- removed the GBA makefile and code from demos/test.c [not a particularly useful demo...] + -- merged in rudimentary [for testing] PS2 RNG from Sky Schulz + -- merged in PS2 timer code [only shell included due to NDA reasons...] + -- updated HMAC code to return errors where possible + -- Thanks go to Sky Schulz who bought me a RegCode for TextPad [the official editor of libtomcrypt] + +Nov 12th, 2002 +v0.70 -- Updated so you can swap out the default malloc/calloc/free routines at build time with others. (Sky Schulz) + -- Sky Schulz contributed some code towards autodetecting the PS2 in mycrypt_cfg.h + -- Added PS2 makefile contributed by Sky Schulz [see a pattern forming?] + -- Added ability to have no FILE I/O functions at all (see makefile), Sky Schulz.... + -- Added support for substituting out the clock() function (Sky Schulz) + -- Fixed up makefile to include new headers in the HEADERS variable + -- Removed "coin.c" as its not really useful anyways + -- Removed many "debug" printfs that would show up on failures. Basically I wanted to ensure the only output + would be from the developer themselves. + -- Added "rc4.c" a RC4 implementation with a PRNG interface. Since RC4 isn't a block cipher it wouldn't work + too well as a block cipher. + -- Fixed ARGCHK macro usage when ARGTYPE=1 throughout the code + -- updated makefile to make subdirectory properly (Sku Schulz) + -- Started towards new API setup. Instead of checking for "== CRYPT_ERROR" you should check "!= CRYPT_OK" + In future releases functions will return things other than CRYPT_ERROR on error to give more useful + thread safe error reporting. The manual will be updated to reflect this. For this release all + errors are returned as CRYPT_ERROR (except as noted) but in future releases this will change. + -- Removed the zlib branch since its not really required anyways. Makes the package smaller + +Nov 11th, 2002 +v0.69 -- Added ARGCHK (see mycrypt_argchk.h) "arguement checking" to all functions that accept pointers + -- Note I forgot to change the CRYPT version tag in v0.68... fixed now. + +Nov 8th, 2002 +v0.68 -- Fixed flaw in kr_import/kr_export that wasted 4 bytes. Source but not binary compatible with v0.67 + -- Fixed bug in kr_find_name that used memcmp to match strings. Uses strncmp now. + -- kr_clear now sets the pointer to NULL to facilate debugging [e.g. using the keyring after clearing] + -- static functions in _write/_read in keyring.c now check the return of ctr_encrypt/ctr_decrypt. + -- Updated blowfish/rc2/rc5/rc6 keysize() function to not reject keys larger than the biggest key the + respective ciphers can use. + -- Fixed a bug in hashsum demo that would report the hash for files that don't exist! + +Oct 16th, 2002 +v0.67 -- Moved the function prototypes into files mycrypt_*.h. To "install" the lib just copy all the + header files "*.h" from the base of this project into your global include path. + -- Made the OFB/CFB/CTR functions use "unsigned long" for the length instead of "int" + -- Added keyring support for the PK functions + -- ***API CHANGE*** changed the ecc_make_key and dh_make_key to act more like rsa_make_key. Basically + move the first argument to the next to last. + -- Fixed bug in dh_test() that wouldn't test the primality of the order of the sub-group + -- replaced the primes in the DH code with new ones that are larger than the size they are + associated with. That is a 1024-bit DH key will have a 1025-bit prime as the modulus + -- cleaned up all the PK code, changed a bit of the API around [not source compatible with v0.66] + -- major editing of the manual, started Docer program + -- added 160 and 224 bit key settings for ECC. This makes the DH and ECC binary wise incompatible with v0.66 + -- Added an additional check for memory errors in is_prime() and cleaned up prime.c a bit + -- Removed ID_TAG from all files [meh, not a big fan...] + -- Removed unused variable from yarrow state and made AES/SHA256 the default cipher/hash combo + -- Fixed a bug in the Yarrow code that called prng_is_valid instead of cipher_is_valid from yarrow_start() + -- The ECB/CBC/OFB/CFB/CTR wrappers now check that the cipher is valid in the encrypt/decrypt calls + Returns int now instead of void. + +Sept 24th, 2002 +v0.66 -- Updated the /demos/test.c program to time the hashes correctly. Also it uses the yarrow PRNG for all of the + tests meaning its possible to run on RNG less platforms + -- Updated the /demos/hashsum.c program to hash from the standard input + -- Updated the RSA code to make keys a bit quicker [update by Wayne Scott] by not making both primes at the same + time. + -- Dan Kaminsky suggested some cleanups for the code and the MPI config + Code ships in unix LF format by default now too... will still build in MSVC and all... but if you want + to read the stuff you'll have to convert it + -- Changes to the manual to reflect new API [e.g. hash_memory/file have v0.65 prototypes]and some typos fixed + +Sept 20th, 2002 +v0.65 -- Wayne Scott (wscott@bitmover.com) made a few of suggestions to improve the library. Most + importantly he pointed out the math lib is not really required. He's also tested the lib on 18 + different platforms. According to him with only a few troubles [lack of /dev/random, etc] the + library worked as it was supposed to. You can find the list at + http://www.bitkeeper.com/Products.BitKeeper.Platforms.html + -- Updated the hash_file and hash_memory functions to keep track of the size of the output + -- Wayne Scott updated the demos/test.c file to use the SPRNG less and Yarrow more + -- Modified the mycrypt_cfg.h to autodetect x86-32 machines + +Sept 19th, 2002 +v0.64 -- wrote makefile for the GBA device [and hacked the demos/test.c file to support it conditionally] + -- Fixed error in PK (e.g. ECC, RSA, DH) import functions where I was clobbering the packet error messages + -- fixed more typos in the manual + -- removed all unused variables from the core library (ignore the ID_TAG stuff) + -- added "const char *crypt_build_settings" string which is a build time constant that gives a listing + of all the build time options. Useful for debugging since you can send that to me and I will know what + exactly you had set for the mycrypt_cfg.h file. + -- Added control over endianess. Out of the box it defaults to endianess neutral but you can trivially + configure the library for your platform. Using this I boosted RC5 from 660Mbit/sec to 785Mbit/sec on my + Athlon box. See "mycrypt_cfg.h" for more information. + +Sept 11th, 2002 +v0.63 -- Made hashsum demo output like the original md5sum program + -- Made additions to the examples in the manual (fixed them up a bunch) + -- Merged in the base64 code from Wayne Scott (wscott@bitmover.com) + +Aug 29th, 2002 +v0.62 -- Added the CLEAN_STACK functionality to several of the hashes I forgot to update. + +Aug 9th, 2002 +v0.61 -- Fixed a bug in the DES code [oops I read something wrong]. + +Aug 8th, 2002 +v0.60 -- Merged in DES code [and wrote 3DES-EDE code based on it] from Dobes V. + +Aug 7th, 2002 +v0.59 -- Fixed a "unsigned long long" bug that caused v0.58 not to build in MSVC. + -- Cleaned up a little in the makefile + -- added code that times the hash functions too in the test program + +Aug 3rd, 2002 +v0.58 -- Added more stack cleaning conditionals throughout the code. + -- corrected some CLEAR_STACK conditionals... should have been CLEAN_STACK + -- Simplified the RSA, DH and ECC encrypt() routines where they use CTR to encode the message + now they only make one call to ctr_encrypt()/ctr_decrypt(). + +Aug 2nd, 2002 +v0.57 -- Fixed a few errors messages in the SAFER code to actually report the correct cipher name. + -- rsa_encrypt() uses the "keysize()" method of the cipher being used to more accurately pick a + key size. By default rsa_encrypt() will choose to use a 256-bit key but the cipher can turn that + down if required. + -- The rsa_exptmod() function will now more reliably detect invalid inputs (e.g. greater than the modulus). + -- The padding method for RSA is more clearly documented. Namely if you want to encrypt/sign something of length + N then your modulus must be of length 1+3N. So to sign a message with say SHA-384 [48 bytes] you need a + 145 byte (1160 bits) modulus. This is all in the manual now. + -- Added build option CLEAN_STACK which will allow you to choose whether you want to clean the stack or not after every + cipher/hash call + -- Sped up the hash "process()" functions by not copying one byte at a time. + ++ (added just after I uploaded...) + MD4 process() now handles input buffers > 64 bytes + +Aug 1st, 2002 +v0.56 -- Cleaned up the comments in the Blowfish code. + -- Oh yeah, in v0.55 I made all of the descriptor elements constant. I just forgot to mention it. + -- fixed a couple of places where descriptor indexes were tested wrong. Not a huge bug but now its harder + to mess up. + -- Added the SAFER [64-bit block] ciphers K64, SK64, K128 and SK128 to the library. + -- Added the RC2 block cipher to the library. + -- Changed the SAFER define for the SAFER+ cipher to SAFERP so that the new SAFER [64-bit] ciphers + can use them with less confusion. + +July 29th, 2002 +v0.55 -- My god stupid Blowfish has yet again been fixed. I swear I hate that cipher. Next bug in it and boom its out of the + library. Use AES or something else cuz I really hate Blowfish at this stage.... + -- Partial PKCS support [hint DONT USE IT YET CUZ ITS UNTESTED!] + +July 19th, 2002 +v0.54 -- Blowfish now conforms to known test vectors. Silly bad coding tom! + -- RC5/RC6/Serpent all have more test vectors now [and they seemed to have been working before] + +July 18th, 2002 +v0.53 -- Added more test vectors to the blowfish code just for kicks [and they are const now too :-)] + -- added prng/hash/cipher is_valid functions and used them in all of the PK code so you can't enter the code + with an invalid index ever now. + -- Simplified the Yarrow code once again :-) + +July 12th, 2002 +v0.52 -- Fixed a bug in MD4 where the hash descriptor ID was the same as SHA-512. Now MD4 will work with + all the routines... + -- Fixed the comments in SHA-512 to be a bit more meaningful + -- In md4 I made the PADDING array const [again to store it in ROM] + -- in hash_file I switched the constant "512" to "sizeof(buf)" to be a bit safer + -- in SHA-1's test routine I fixed the string literal to say SHA-1 not sha1 + -- Fixed a logical error in the CTR code which would make it skip the first IV value. This means + the CTR code from v0.52 will be incompatible [binary wise] with previous releases but it makes more + sense this way. + -- Added {} braces for as many if/for/blocks of code I could find. My rule is that every for/if/while/do block + must have {} braces around it. + -- made the rounds table in saferp_setup const [again for the ROM think about the ROM!] + -- fixed RC5 since it no longer requires rc5 to be registered in the lib. It used to since the descriptors used to + be part of the table... + -- the packet.c code now makes crypt_error literal string errors when an error occurs + -- cleaned up the SAFER+ key schedule to be a bit easier to read. + -- fixed a huge bug in Twofish with the TWOFISH_SMALL define. Because I clean the stack now I had + changed the "g_func()" to be called indirectly. I forgot to actually return the return of the Twofish + g_func() function which caused it not to work... [does now :-)] + +July 11th, 2002 +v0.51 -- Fixed a bug in SHA512/384 code for multi-block messages. + -- Added more test vectors to the SHA384/512 and TIGER hash functions + -- cleaned up the hash done routines to make more sense + +July 10th, 2002 +v0.50 -- Fixed yarrow.c so that the cipher/hash used would be registered. Also fixed + a bug where the SAFER+ name was "safer" but should have been "safer+". + -- Added an element to the hash descriptors that gives the size of a block [sent into the compressor] + -- Cleaned up the support for HMAC's + -- Cleaned up the test vector routines to make the test vector data const. This means on some platforms it will be + placed in ROM not RAM now. + -- Added MD4 code submited by Dobes Vandermeer (dobes@smartt.com) + -- Added "burn_stack" function [idea taken from another source of crypto code]. The idea is if a function has + alot of variables it will clean up better. Functions like the ecb serpent and twofish code will now have their + stacks cleaned and the rest of the code is getting much more straightforward. + -- Added a hashing demo by Daniel Richards (kyhwana@world-net.co.nz) + -- I (Tom) modified some of the test vector routines to use more vectors ala Dobes style. + For example, the MD5/SHA1 code now uses all of the test vectors from the RFC/FIPS spec. + -- Fixed the register/unregister functions to properly report errors in crypt_error + -- Correctly updated yarrow code to remove a few unused variables. + -- Updated manual to fix a few erroneous examples. + -- Added section on Hash based Message Authentication Codes (HMAC) to the manual + +June 19th, 2002 +v0.46 -- Added in HMAC code from Dobes Vandermeer (dobes@smartt.com) + +June 8th, 2002 +v0.45 -- Fixed bug in rc5.c where if you called rc5_setup() before registering RC5 it would cause + undefined behaviour. + -- Fixed mycrypt_cfg.h to eliminate the 224 bit ECC key. + -- made the "default" makefile target have depends on mycrypt.h and mycrypt_cfg.h + +Apr 4th, 2002 +v0.44 -- Fixed bug in ecc.c::new_point() where if the initial malloc fails it would not catch it. + +Mar 22nd, 2002 +v0.43 -- Changed the ZLIB code over to the 1.1.4 code base to avoid the "double free" bug. + -- Updated the GCC makefile not to use -O3 or -funroll-loops + -- Version tag in mycrypt.h has been updated :-) + +Mar 10th, 2002 +v0.42 -- The RNG code can now use /dev/urandom before trying /dev/random (J. Klapste) + +Mar 3rd, 2002 +v0.41 -- Added support to link and use ciphers at compile time. This can greatly reduce the code size! + -- Added a demo to show off how small an application can get... 46kb! + -- Disastry pointed out that Blowfish is supposed to be high endian. + -- Made registry code for the PRNGs as well [now the smallest useable link is 43kb] + +Feb 11th, 2002 +v0.40 -- RSA signatures use [and check for] fixed padding scheme. + -- I'm developing in Linux now :-) + -- No more warnings from GCC 2.96 + +Feb 5th, 2002 +v0.39 -- Updated the XTEA code to work in accordance with the XTEA design + +January 24th, 2002 +v0.38 -- CFB and OFB modes can now handle blocks of variable size like the CTR code + -- Wrote a wrapper around the memory compress functions in Zlib that act like the functions + in the rest of my crypto lib + +January 23rd, 2002 +v0.37 -- Added support code so that if a hash size and key size for a cipher don't match up they will + use the next lower key supported. (mainly for the PK code). So you can now use SHA-1 with + Twofish, etc... + -- Added more options for Twofish. You can now tell it to use precomputed sboxes and MDS multiplications + This will speed up the TWOFISH_SMALL implementation by increasing the code size by 1024 bytes. + -- Fixed a bug in prime.c that would not use the correct table if you undefined SMALL_PRIME_TAB + -- Fixed all of the PK packet code to use the same header format [see packet.c]. This makes the PK code + binary wise incompatible with previous releases while the API has not changed at all. + +January 22nd, 2002 +v0.36 -- Corrections to the manual + -- Made a modification to Twofish which lets you build a "small ram" variant. It requires + about 190 bytes of ram for the key storage compared to the 4,200 bytes the normal + variant requires. + -- Reduced the stack space used in all of the PK routines. + +January 19th, 2002 +v0.35 -- If you removed the first hash or cipher from the library it wouldn't return an error if + you used an ID=0 [i.e blowfish or sha256] in any routine. Now it checks for that and will + return an error like it should + -- Merged in new routines from Clay Culver. These routines are for the PK code so you can easily + encode a symmetric key for multiple recipients. + -- Made the ecc and DH make_key() routines make secret keys of the same size as the keysize listed. + Originally I wanted to ensure that the keys were smaller than the order of the field used + However, the bias is so insignifcant using full sizes. For example, with a ECC-192 key the order + is about 2^191.99, so instead I rounded down and used a 184-bit secret key. Now I simply use a full 192-bit + key the code will work just the same except that some 192-bit keys will be duplicates which is not a big + deal since 1/2^192 is a very small bias! + -- Made the configuration a bit simpler and more exacting. You can for example now select which DH or ECC + key settings you wish to support without including the data for all other key settings. I put the #defines + in a new file called "mycrypt_cfg.h" + -- Configured "mpi-config.h" so its a bit more conservative with the memory required and code space used + -- Jason Klapste submitted bug fixes to the yarrow, hash and various other issues. The yarrow code will now + use what ever remaining hash/cipher combo is left [after you #undef them] at build time. He also suggested + a fix to remove unused structures from the symmetric_key and hash_state unions. + -- Made the CTR code handle variable length blocks better. It will buffer the encryption pad so you can + encrypt messages any size block at a time. + -- Simplified the yarrow code to take advantage of the new CTR code. + -- Added a 4096-bit DH key setting. That took me about 36 hours to find! + -- Changed the base64 routines to use a real base64 encoding scheme. + -- Added in DH and ECC "encrypt_key()" functions. They are still rather "beta"ish. + -- Added **Twofish** to the list of ciphers! + +January 18th, 2002 +v0.34 -- Added "sha512" to the list of hashes. Produces a 512-bit message digest. Note that with the current + padding with the rsa_sign() function you cannot use sha512 with a key less than 1536 bits for signatures. + -- Cleaned up the other hash functions to use the LOAD and STORE macros... + +January 17th, 2002 +v0.33 -- Made the lower limit on keysizes for RSA 1024 bits again because I realized that 768 bit keys wouldn't + work with the padding scheme and large symmetric keys. + -- Added information concerning the Zlib license to the manual + -- Added a 3072-bit key setting for the DH code. + -- Made the "find_xyz()" routines take "const char *" as per Clay Culver's suggestion. + -- Fixed an embarassing typo in the manual concerning the hashes. Thank's Clay for finding it! + -- Fixed rand_prime() so that it makes primes bigger than the setting you give. For example, + if you want a 1024-bit prime it would make a 1023-bit one. Now it ensures that the prime + it makes is always greater than 2^(8n) (n == bytes in prime). This doesn't have a huge + impact on security but I corrected it just the same. + -- Fixed the CTR routine to work on platforms where char != 8-bits + -- Fixed sha1/sha256/md5/blowfish to not assume "unsigned long == 32-bits", Basically any operation with carries + I "AND" with 0xFFFFFFFF. That forces only the lower 32-bits to have information in it. On x86 platforms + most compilers optimize out the AND operation since its a nop. + +January 16th, 2002 +v0.32 -- Made Rijndael's setup function fully static so it is thread safe + -- Svante Seleborg suggested a cosmetic style fixup for aes.c, + basically to remove some of the #defines to clean it up + -- Made the PK routines not export the ASCII version of the names of ciphers/hashes which makes + the PK message formats *incompatible* with previous releases. + -- Merge in Zlib :-) + + +January 15th, 2002 +v0.31 -- The RSA routines can now use CRT to speed up decryption/signatures. The routines are backwards + compatible with previous releases. + -- Fixed another bug that Svante Seleborg found. Basically you could buffer-overrun the + rsa_exptmod() function itself if you're not careful. That's fixed now. Fixed another bug in + rsa_exptmod() where if it knows the buffer you passed is too small it wouldn't free all used + memory. + -- improved the readability of the PK import/export functions + -- Added a fix to RSA.C by Clay Culver + -- Changed the CONST64 macro for MSVC to use the "unsigned __int64" type, e.g. "ui64" instead of "i64". + +January 14th, 2002 +v0.30 -- Major change to the Yarrow PRNG code, fixed a bug that Eugene Starokoltsev found. + Basically if you added entropy to the pool in small increments it could in fact + cancel out. Now I hash the pool with the new data which is way smarter. + +January 12th, 2002 +v0.29 -- Added MPI code written by Svante Seleborg to the library. This will make the PK code much + easier to follow and debug. Actually I've already fixed a memory leak in dh_shared_secret(). + -- Memory leaks found and correct in all three PK routines. The leaks would occur when a bignum + operation fails so it wouldn't normally turn up in the course of a program + -- Fixed bugs in dh_key_size and ecc_key_size which would return garbage for invalid key idx'es + +January 11th, 2002 +v0.28 -- Cleaned up some code so that it doesn't assume "char == 8bits". Mainly SAFER+ has been + changed. + -- ***HUGE*** changes in the PK code. I check all return values in the bignum code so if there + are errors [insufficient memory, etc..] it will be reported. This makes the code fairly more + robust and likely to catch any errors. + -- Updated the is_prime() function to use a new prototype [it can return errors now] and it also + does trial divisions against more primes before the Rabin Miller steps + -- Added OFB, CFB and ECB generic wrappers for the symmetric ciphers to round out the implementations. + -- Added Xtea to the list of ciphers, to the best of my ability I have verified this implementation. + I should note that there is not alot of concrete information about the cipher. "Ansi C" versions + I found did not address endianess and were not even portable!. This code is portable and to the + best of my knowledge implements the Xtea algorithm as per the [short] X-Tea paper. + -- Reformated the manual to include the **FULL** source code optimized to be pritable. + +January 9th, 2002 +v0.27 -- Changed the char constants to numerical values. It is backwards compatible and should work on + platforms where 'd' != 100 [for example]. + -- Made a change to rand_prime() which takes the input length as a signed type so you can pass + a negative len to get a "3 mod 4" style prime... oops + -- changed the MSVC makefile to build with a warning level of three, no warnings! + +January 8th, 2002 +v0.26 -- updated SHA-256 to use ROR() for a rotate so 64-bit machines won't corrupt + the output + -- Changed #include <> to #include "" for local .h files as per Richard Heathfields' suggestions. + -- Fixed bug in MPI [well bug in MSVC] that compiled code incorrectly in mp_set_int() + I added a work around that catches the error and continues normally. + +January 8th, 2002 +v0.25 -- Added a stupid define so MSVC 6.00 can build the library. + -- Big thanks to sci.crypt and "Ajay K. Agrawal" for helping me port this to MSVC + +January 7th, 2002 +v0.24 -- Sped up Blowfish by unrolling and removing the swaps. + -- Made the code comply with more traditional ANSI C standards + Should compile with MSVC with less errors + -- moved the demos and documentation into their own directories + so you can easily build the library with other tool chains + by compiling the files in the root + -- converted functions with length of outputs to use + "unsigned long" so 16-bit platforms will like this library more. + +January 5th, 2002 +v0.23 -- Fixed a small error in the MPI config it should build fine anywhere. + +January 4th, 2002 +v0.22 -- faster gf_mul() code + -- gf_shl() and gf_shr() are safe on 64-bit platforms now + -- Fixed an error in the hashes that Brian Gladman found. + Basically if the message has exactly 56 bytes left to be + compressed I handled them incorrectly. + +January 4th, 2002 +v0.21 -- sped up the ECC code by removing redundant divisions in the + point add and double routines. I also extract the bits more + efficiently in "ecc_mulmod()" now. + -- sped up [and documented] the rand_prime() function. Now it just + makes a random integer and increments by two until a prime is found + This is faster since it doesn't require alot of calls to the PRNG and + it doesn't require loading huge integers over and over. rand_prime() + can also make primes congruent to 3 mod 4 [i.e for a blum integer] + -- added a gf_sqrt() function that finds square roots in a GF(2^w) field + -- fixed a bug in gf_div() that would return the wrong results if the divisor had a greator + divisor than the dividend. + +January 4th, 2002 +v0.20 -- Added the fixed MPI back in so RSA and DH are much faster again + +v0.19 -- Updated the manual to reflect the fact that Brian Gladman wrote the AES and Serpent code. + -- DH, ECC and RSA signature/decryption functions check if the key is private + -- new DH signature/verification code works just like the RSA/ECC versions + +January 3rd, 2002 +v0.18 -- Added way more comments to each .C file + -- fixed a bug in cbc_decrypt(pt, ct, key) where pt == ct [i.e same buffer] + -- fixed RC5 so it reads the default rounds out of the cipher_descriptor table + -- cleaned up ecc_export() + -- Cleaned up dh_import() and ecc_import() which also perform more + error checking now + -- Fixed a serious flaw in rsa_import() with private keys. + +January 2nd, 2002 +v0.17 -- Fixed a bug in the random prime generator that fixes the wrong bits to one + -- ECC and DH code verify that the moduli and orders are in fact prime. That + slows down the test routines alot but what are you gonna do? + -- Fixed a huge bug in the mp_exptmod() function which incorrectly calculates g^x mod p for some + values of p. I replaced it with a slow function. Once the author of MPI fixes his faster routine + I will switch back. + +January 1st, 2002 [whoa new year!] +v0.16 -- Improved GF division code that is faster. + -- documented the GF code + +December 31st, 2001 +v0.15 -- A 1792-bit and 2048-bit DH setting was added. Took me all night to + find a 1792 and 2048-bit strong prime but what the heck + -- Library now has polynomial-basis GF(2^w) routines I wrote myself. Can be used to perform + ECC over GF(2^w) later on.... + -- Fixed a bug with the defines that allows it to build in windows + +December 30th, 2001 +v0.14 -- Fixed the xxx_encrypt() packet routines to make an IV of appropriate size + for the cipher used. It was defaulting to making a 256-bit IV... + -- base64_encode() now appends a NULL byte, um "duh" stupid mistake now fixed... + -- spell checked the manual again... :-) + +December 30th, 2001 +v0.13 -- Switching back to older copy of MPI since it works! arrg.. + -- Added sign/verify functions for ECC + -- all signature verification routines default to invalid signatures. + -- Changed all calls to memset to zeromem. Fixed up some buffer problems + in other routines. All calls to zeromem let the compiler determine the size + of the data to wipe. + +December 29th, 2001 +v0.12 -- Imported a new version of MPI [the bignum library] that should + be a bit more stable [if you want to write your own bignum + routines with the library that is...] + -- Manual has way more info + -- hash_file() clears stack now [like it should] + -- The artificial cap on the hash input size of 2^32 bits has been + removed. Basically I was too lazy todo 64-bit math before + [don't ask why... I can't remember]. Anyways the hashes + support the size of 2^64 bits [if you ever use that many bits in a message + that's just wierd...] + -- The hashes now wipe the "hash_state" after the digest is computed. This helps + prevent the internal state of the hash being leaked accidently [i.e stack problems] + +December 29th, 2001 +v0.11 -- Made #define's so you can trim the library down by removing + ciphers, hashs, modes of operation, prngs, and even PK algorithms + For example, the library with rijndael+ctr+sha1+ECC is 91KB compared + to the 246kb the full library takes. + -- Added ECC packet routines for encrypt/decrypt/sign/verify much akin to + the RSA packet routines. + -- ECC now compresses the public key, a ECC-192 public key takes 33 bytes + for example.... + +December 28th, 2001 +v0.10 -- going to restart the manual from scratch to make it more + clear and professional + -- Added ECC over Z/pZ. Basically provides as much as DH + except its faster since the numbers are smaller. For example, + A comparable 256-bit ECC key provides as much security as expected + from a DH key over 1024-bits. + -- Cleaned up the DH code to not export the symbol "sets[]" + -- Fixed a bug in the DH code that would not make the correct size + random string if you made the key short. For instance if you wanted + a 512-bit DH key it would make a 768-bit one but only make up 512-bits + for the exponent... now it makes the full 768 bits [or whatever the case + is] + -- Fixed another ***SERIOUS*** bug in the DH code that would default to 768-bit + keys by mistake. + +December 25th, 2001 +v0.09 -- Includes a demo program called file_crypt which shows off + how to use the library to make a command line tool which + allows the user to encode/decode a file with any + hash (on the passphrase) and cipher in CTR mode. + -- Switched everything to use typedef's now to clear up the code. + -- Added AES (128/192 and 256 bit key modes) + +December 24th, 2001 +v0.08 -- fixed a typo in the manual. MPI stores its bignums in + BIG endian not little. + -- Started adding a RNG to the library. Right now it tries + to open /dev/random and if that fails it uses either the + MS CSP or the clock drift RNG. It also allows callbacks + since the drift RNG is slow (about 3.5 bytes/sec) + -- the RNG can also automatically setup a PRNG as well now + +v0.07 -- Added basic DH routines sufficient to + negotiate shared secrets + [see the manual for a complete example!] + -- Fixed rsa_import to detect when the input + could be corrupt. + -- added more to the manual. + +December 22nd, 2001 +v0.06 -- Fixed some formatting errors in + the hash functions [just source code cleaning] + -- Fixed a typo in the error message for sha256 :-) + -- Fixed an error in base64_encode() that + would fail to catch all buffer overruns + -- Test program times the RSA and symmetric cipher + routines for kicks... + -- Added the "const" modifier to alot of routines to + clear up the purpose of each function. + -- Changed the name of the library to "TomCrypt" + following a suggestion from a sci.crypt reader.... + +v0.05 -- Fixed the ROL/ROR macro to be safe on platforms + where unsigned long is not 32-bits + -- I have added a bit more to the documentation + manual "crypt.pdf" provided. + -- I have added a makefile for LCC-Win32. It should be + easy to port to other LCC platforms by changing a few lines. + -- Ran a spell checker over the manual. + -- Changed the header and library from "crypt" to "mycrypt" to not + clash with the *nix package "crypt". + +v0.04 -- Fixed a bug in the RC5,RC6,Blowfish key schedules + where if the key was not a multiple of 4 bytes it would + not get loaded correctly. + +December 21st, 2001 + +v0.03 -- Added Serpent to the list of ciphers. + +v0.02 -- Changed RC5 to only allow 12 to 24 rounds + -- Added more to the manual. + +v0.01 -- We will call this the first version. diff --git a/crypt.c b/crypt.c new file mode 100644 index 0000000..0668b23 --- /dev/null +++ b/crypt.c @@ -0,0 +1,507 @@ +#include "mycrypt.h" +#include + +struct _cipher_descriptor cipher_descriptor[32] = { +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } }; + +struct _hash_descriptor hash_descriptor[32] = { +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, NULL, NULL, NULL, NULL } }; + +struct _prng_descriptor prng_descriptor[32] = { +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL } }; + +int find_cipher(const char *name) +{ + int x; + _ARGCHK(name != NULL); + for (x = 0; x < 32; x++) { + if (cipher_descriptor[x].name != NULL && !strcmp(cipher_descriptor[x].name, name)) { + return x; + } + } + return -1; +} + +int find_hash(const char *name) +{ + int x; + _ARGCHK(name != NULL); + for (x = 0; x < 32; x++) { + if (hash_descriptor[x].name != NULL && !strcmp(hash_descriptor[x].name, name)) { + return x; + } + } + return -1; +} + +int find_prng(const char *name) +{ + int x; + _ARGCHK(name != NULL); + for (x = 0; x < 32; x++) { + if ((prng_descriptor[x].name != NULL) && !strcmp(prng_descriptor[x].name, name)) { + return x; + } + } + return -1; +} + +int find_cipher_id(unsigned char ID) +{ + int x; + for (x = 0; x < 32; x++) { + if (cipher_descriptor[x].ID == ID) { + return (cipher_descriptor[x].name == NULL) ? -1 : x; + } + } + return -1; +} + +int find_hash_id(unsigned char ID) +{ + int x; + for (x = 0; x < 32; x++) { + if (hash_descriptor[x].ID == ID) { + return (hash_descriptor[x].name == NULL) ? -1 : x; + } + } + return -1; +} + +/* idea from Wayne Scott */ +int find_cipher_any(const char *name, int blocklen, int keylen) +{ + int x; + + _ARGCHK(name != NULL); + + x = find_cipher(name); + if (x != -1) return x; + + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + if (blocklen <= (int)cipher_descriptor[x].block_length && keylen <= (int)cipher_descriptor[x].max_key_length) { + return x; + } + } + return -1; +} + +int register_cipher(const struct _cipher_descriptor *cipher) +{ + int x; + + _ARGCHK(cipher != NULL); + + /* is it already registered? */ + for (x = 0; x < 32; x++) { + if (!memcmp(&cipher_descriptor[x], cipher, sizeof(struct _cipher_descriptor))) { + return x; + } + } + + /* find a blank spot */ + for (x = 0; x < 32; x++) { + if (cipher_descriptor[x].name == NULL) { + memcpy(&cipher_descriptor[x], cipher, sizeof(struct _cipher_descriptor)); + return x; + } + } + + /* no spot */ + return -1; +} + +int unregister_cipher(const struct _cipher_descriptor *cipher) +{ + int x; + + _ARGCHK(cipher != NULL); + + /* is it already registered? */ + for (x = 0; x < 32; x++) { + if (!memcmp(&cipher_descriptor[x], cipher, sizeof(struct _cipher_descriptor))) { + cipher_descriptor[x].name = NULL; + return CRYPT_OK; + } + } + return CRYPT_ERROR; +} + +int register_hash(const struct _hash_descriptor *hash) +{ + int x; + + _ARGCHK(hash != NULL); + + /* is it already registered? */ + for (x = 0; x < 32; x++) { + if (!memcmp(&hash_descriptor[x], hash, sizeof(struct _hash_descriptor))) { + return x; + } + } + + /* find a blank spot */ + for (x = 0; x < 32; x++) { + if (hash_descriptor[x].name == NULL) { + memcpy(&hash_descriptor[x], hash, sizeof(struct _hash_descriptor)); + return x; + } + } + + /* no spot */ + return -1; +} + +int unregister_hash(const struct _hash_descriptor *hash) +{ + int x; + + _ARGCHK(hash != NULL); + + /* is it already registered? */ + for (x = 0; x < 32; x++) { + if (!memcmp(&hash_descriptor[x], hash, sizeof(struct _hash_descriptor))) { + hash_descriptor[x].name = NULL; + return CRYPT_OK; + } + } + return CRYPT_ERROR; +} + +int register_prng(const struct _prng_descriptor *prng) +{ + int x; + + _ARGCHK(prng != NULL); + + /* is it already registered? */ + for (x = 0; x < 32; x++) { + if (!memcmp(&prng_descriptor[x], prng, sizeof(struct _prng_descriptor))) { + return x; + } + } + + /* find a blank spot */ + for (x = 0; x < 32; x++) { + if (prng_descriptor[x].name == NULL) { + memcpy(&prng_descriptor[x], prng, sizeof(struct _prng_descriptor)); + return x; + } + } + + /* no spot */ + return -1; +} + +int unregister_prng(const struct _prng_descriptor *prng) +{ + int x; + + _ARGCHK(prng != NULL); + + /* is it already registered? */ + for (x = 0; x < 32; x++) { + if (!memcmp(&prng_descriptor[x], prng, sizeof(struct _prng_descriptor))) { + prng_descriptor[x].name = NULL; + return CRYPT_OK; + } + } + return CRYPT_ERROR; +} + +int cipher_is_valid(int idx) +{ + if (idx < 0 || idx > 32 || cipher_descriptor[idx].name == NULL) { + return CRYPT_INVALID_CIPHER; + } + return CRYPT_OK; +} + +int hash_is_valid(int idx) +{ + if (idx < 0 || idx > 32 || hash_descriptor[idx].name == NULL) { + return CRYPT_INVALID_HASH; + } + return CRYPT_OK; +} + +int prng_is_valid(int idx) +{ + if (idx < 0 || idx > 32 || prng_descriptor[idx].name == NULL) { + return CRYPT_INVALID_PRNG; + } + return CRYPT_OK; +} + +const char *crypt_build_settings = + "LibTomCrypt " SCRYPT "\n\n" + "Endianess: " +#if defined(ENDIAN_NEUTRAL) + "neutral\n" +#elif defined(ENDIAN_LITTLE) + "little" + #if defined(ENDIAN_32BITWORD) + " (32-bit words)\n" + #else + " (64-bit words)\n" + #endif +#elif defined(ENDIAN_BIG) + "big" + #if defined(ENDIAN_32BITWORD) + " (32-bit words)\n" + #else + " (64-bit words)\n" + #endif +#endif + "Clean stack: " +#if defined(CLEAN_STACK) + "enabled\n" +#else + "disabled\n" +#endif + "Ciphers built-in:\n" +#if defined(BLOWFISH) + " Blowfish\n" +#endif +#if defined(RC2) + " RC2\n" +#endif +#if defined(RC5) + " RC5\n" +#endif +#if defined(RC6) + " RC6\n" +#endif +#if defined(SERPENT) + " Serpent\n" +#endif +#if defined(SAFERP) + " Safer+\n" +#endif +#if defined(SAFER) + " Safer\n" +#endif +#if defined(RIJNDAEL) + " Rijndael\n" +#endif +#if defined(XTEA) + " XTEA\n" +#endif +#if defined(TWOFISH) + " Twofish " + #if defined(TWOFISH_SMALL) && defined(TWOFISH_TABLES) + "(small, tables)\n" + #elif defined(TWOFISH_SMALL) + "(small)\n" + #elif defined(TWOFISH_TABLES) + "(tables)\n" + #else + "\n" + #endif +#endif +#if defined(DES) + " DES\n" +#endif +#if defined(CAST5) + " CAST5\n" +#endif + + "\nHashes built-in:\n" +#if defined(SHA512) + " SHA-512\n" +#endif +#if defined(SHA384) + " SHA-384\n" +#endif +#if defined(SHA256) + " SHA-256\n" +#endif +#if defined(TIGER) + " TIGER\n" +#endif +#if defined(SHA1) + " SHA1\n" +#endif +#if defined(MD5) + " MD5\n" +#endif +#if defined(MD4) + " MD4\n" +#endif +#if defined(MD2) + " MD2\n" +#endif + + "\nBlock Chaining Modes:\n" +#if defined(CFB) + " CFB\n" +#endif +#if defined(OFB) + " OFB\n" +#endif +#if defined(ECB) + " ECB\n" +#endif +#if defined(CBC) + " CBC\n" +#endif +#if defined(CTR) + " CTR\n" +#endif + + "\nPRNG:\n" +#if defined(YARROW) + " Yarrow\n" +#endif +#if defined(SPRNG) + " SPRNG\n" +#endif +#if defined(RC4) + " RC4\n" +#endif + + "\nPK Algs:\n" +#if defined(MRSA) + " RSA\n" +#endif +#if defined(MDH) + " DH\n" +#endif +#if defined(MECC) + " ECC\n" +#endif + + "\nCompiler:\n" +#if defined(WIN32) + " WIN32 platform detected.\n" +#endif +#if defined(__CYGWIN__) + " CYGWIN Detected.\n" +#endif +#if defined(__DJGPP__) + " DJGPP Detected.\n" +#endif +#if defined(_MSC_VER) + " MSVC compiler detected.\n" +#endif +#if defined(__GNUC__) + " GCC compiler detected.\n" +#endif + + "\nVarious others: " +#if defined(GF) + " GF " +#endif +#if defined(BASE64) + " BASE64 " +#endif +#if defined(MPI) + " MPI " +#endif +#if defined(HMAC) + " HMAC " +#endif +#if defined(TRY_UNRANDOM_FIRST) + " TRY_UNRANDOM_FIRST " +#endif +#if defined(SMALL_PRIME_TAB) + " SMALL_PRIME_TAB " +#endif + "\n" + + "\n\n\n" + ; + diff --git a/crypt.pdf b/crypt.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b26f720ac5a27910becf03542dd47f0a324abff9 GIT binary patch literal 340546 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 z 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%0D+dlcDnn!4?EY}z+!9Z@ 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%0DL0mY$~D+okI{3NSX05|ZXFu-Q)c7`z$ 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

;Vo?xYN^xIeskHS`n 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 lxvmDc`#qD{ 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 +\newcommand{\emailaddr}[1]{\mbox{$<${#1}$>$}} +\def\twiddle{\raisebox{0.3ex}{\mbox{\tiny $\sim$}}} + +\def\gap{\vspace{0.5ex}} +\makeindex +\begin{document} +\title{A Tiny Crypto Library, \\ LibTomCrypt \\ Version 0.75} +\author{Tom St Denis \\ +Algonquin College \\ +\\ +tomstdenis@yahoo.com \\ +http://libtomcrypt.iahu.ca \\ \\ +Phone: 1-613-836-3160\\ +111 Banning Rd \\ +Kanata, Ontario \\ +K2L 1C3 \\ +Canada +} +\maketitle +\newpage +\tableofcontents +\chapter{Introduction} +\section{What is the Libtomcrypt?} +Libtomcrypt is a portable ANSI C cryptographic library that supports symmetric ciphers, one-way hashes, +pseudo-random number generators, public key cryptography (via RSA,DH or ECC/DH) and a plethora of support +routines. It is designed to compile out of the box with the GNU C Compiler (GCC) version 2.95.3 (and higher) +and with MSVC version 6 in win32. + +The library is designed so new ciphers/hashes/PRNGs can be added at runtime and the existing API (and helper API functions) will +be able to use the new designs automatically. There exist self-check functions for each cipher and hash to ensure that +they compile and execute to the published design specifications. The library also performs extensive parameter error checking +and will give verbose error messages. + +Essentially the library saves the time of having to implement the ciphers, hashes, prngs yourself. Typically implementing +useful cryptography is an error prone business which means anything that can save considerable time and effort is a good +thing. + +\subsection{What the library IS for?} + +The library typically serves as a basis for other protocols and message formats. For example, it should be possible to +take the RSA routines out of this library, apply the appropriate message padding and get PKCS compliant RSA routines. +Similarly SSL protocols could be formed on top of the low-level symmetric cipher functions. The goal of this package is +to provide these low level core functions in a robust and easy to use fashion. + +The library also serves well as a toolkit for applications where they don't need to be OpenPGP, PKCS, etc. compliant. +Included are fully operational public key routines for encryption, decryption, signature generation and verification. +These routines are fully portable but are not conformant to any known set of standards. They are all based on established +number theory and cryptography. + +\subsection{What the library IS NOT for?} + +The library is not designed to be in anyway an implementation of the SSL, PKCS or OpenPGP standards. The library is not +designed to be compliant with any known form of API or programming hierarchy. It is not a port of any other +library and it is not platform specific (like the MS CSP). So if you're looking to drop in some buzzword +compliant crypto this library is not for you. The library has been written from scratch to provide basic +functions as well as non-standard higher level functions. + +This is not to say that the library is a ``homebrew'' project. All of the symmetric ciphers and one-way hash functions +conform to published test vectors. The public key functions are derived from publicly available material and the majority +of the code has been reviewed by a growing community of developers. + +\subsubsection{Why not?} +You may be asking why I didn't choose to go all out and support standards like P1363, PKCS and the whole lot. The reason +is quite simple too much money gets in the way. I just recently tried to access the P1363 draft documents and was denied (it +requires a password). If people are supposed to support these standards they had better make them more accessible. + +\section{Why did I write it?} +You may be wondering, ``Tom, why did you write a crypto library. I already have one.''. Well the reason falls into +two categories: +\begin{enumerate} + \item I am too lazy to figure out someone else's API. I'd rather invent my own simpler API and use that. + \item It was (still is) good coding practice. +\end{enumerate} + +The idea is that I am not striving to replace OpenSSL or Crypto++ or Cryptlib or etc. I'm trying to write my +{\bf own} crypto library and hopefully along the way others will appreciate the work. + +With this library all core functions (ciphers, hashes, prngs) have the {\bf exact} same prototype definition. They all load +and store data in a format independent of the platform. This means if you encrypt with Blowfish on a PPC it should decrypt +on an x86 with zero problems. The consistent API also means that if you learn how to use blowfish with my library you +know how to use Safer+ or RC6 or Serpent or ... as well. With all of the core functions there are central descriptor tables +that can be used to make a program automatically pick between ciphers, hashes and PRNGs at runtime. That means your +application can support all ciphers/hashes/prngs without changing the source code. + +\section{License} + +All of the source code except for the following files have been written by the author or donated to the project +under the TDCAL license: + +\begin{enumerate} + \item aes.c + \item mpi.c + \item rc2.c + \item serpent.c + \item safer.c +\end{enumerate} + +``aes.c'' and ``serpent.c'' were written by Brian Gladman (gladman@seven77.demon.co.uk). They are copyrighted works +but were both granted unrestricted usage in any project (commercial or otherwise). ``mpi.c'' was written by Michael +Fromberger (sting@linguist.dartmouth.edu). Similarly it is copyrighted work but is free for all purposes. +``rc2.c'' is based on publicly available code that is not attributed to a person from the given source. ``safer.c'' +was written by Richard De Moliner (demoliner@isi.ee.ethz.ch) and is public domain. + +The rest of the code was written either by Tom St Denis or contributed to the project under the ``Tom Doesn't Care +About Licenses'' (TDCAL) license. Essentially this license grants the user unlimited distribution and usage (including +commercial usage). I assume no risk from usage of the code nor do I guarantee it works as desired or stated. + +\section{Patent Disclosure} + +The author (Tom St Denis) is not a patent lawyer so this section is not to be treated as legal advice. To the best +of the authors knowledge the only patent related issues within the library are the RC5 and RC6 symmetric block ciphers. +They can be removed from a build by simply commenting out the two appropriate lines in the makefile script. The rest +of the ciphers and hashes are patent free or under patents that have since expired. + +The RC2 and RC4 symmetric ciphers are not under patents but are under trademark regulations. This means you can use +the ciphers you just can't advertise that you are doing so. + +\section{Building the library} + +To build the library on a GCC equipped platform simply type ``make'' at your command prompt. It will build the library +file ``libtomcrypt.a''. + +To install the library copy all of the ``.h'' files into your ``\#include'' path and the single libtomcrypt.a file into +your library path. + +With MSVC you can build the library with ``make -f makefile.vc''. You must use GNU make to build it even with MSVC +due to the limitations of the MS MAKE. + +\section{Building against the library} + +To build an application against the library you obviously must first compile the library. However, an important +step is that the build options you use to build the library must be present when you build your application. For +instance if ``RC5'' is defined in the makefile when you built the library then you must ensure ``RC5'' is defined when +you build your application. + +The simplest way to work with this library is to take the makefile provided and simply add on your project to it as a +target (dependent on the library). That way you can be assured that the library and your application are in sync with +the build options you provide. + +\section{Thanks} +I would like to give thanks to the following people (in no particular order) for helping me develop this project: +\begin{enumerate} + \item Richard van de Laarschot + \item Richard Heathfield + \item Ajay K. Agrawal + \item Brian Gladman + \item Svante Seleborg + \item Clay Culver + \item Jason Klapste + \item Dobes Vandermeer + \item Daniel Richards + \item Wayne Scott + \item Andrew Tyler + \item Sky Schulz +\end{enumerate} + +\chapter{The Application Programming Interface (API)} +\section{Introduction} +\index{CRYPT\_ERROR} \index{CRYPT\_OK} + +In general the API is very simple to memorize and use. Most of the functions return either {\bf void} or {\bf int}. Functions +that return {\bf int} will return {\bf CRYPT\_OK} if the function was successful or one of the many error codes +if it failed. Certain functions that return int will return $-1$ to indicate an error. These functions will be explicitly +commented upon. When a function does return a CRYPT error code it can be translated into a string with + +\begin{verbatim} +const char *error_to_string(int errno); +\end{verbatim} + +An example of handling an error is: +\begin{verbatim} +void somefunc(void) +{ + int errno; + + /* call a cryptographic function */ + if ((errno = some_crypto_function(...)) != CRYPT_OK) { + printf("A crypto error occured, %s\n", error_to_string(errno)); + /* perform error handling */ + } + /* continue on if no error occured */ +} +\end{verbatim} + +There is no initialization routine for the library and for the most part the code is thread safe. The only thread +related issue is if you use the same symmetric cipher, hash or public key state data in multiple threads. Normally +that is not an issue. + +To include the prototypes for ``LibTomCrypt.a'' into your own program simply include ``mycrypt.h'' like so: +\begin{verbatim} +#include +int main(void) { + return 0; +} +\end{verbatim} + +The header file ``mycrypt.h'' also includes ``stdio.h'', ``string.h'', ``stdlib.h'', ``time.h'', ``ctype.h'' and ``mpi.h'' +(the bignum library routines). + +\section{Macros} + +There are a few helper macros to make the coding process a bit easier. The first set are related to loading and storing +32/64-bit words in little/big endian format. The macros are: + +\index{STORE32L} \index{STORE64L} \index{LOAD32L} \index{LOAD64L} +\index{STORE32H} \index{STORE64H} \index{LOAD32H} \index{LOAD64H} \index{BSWAP} +\begin{small} +\begin{center} +\begin{tabular}{|c|c|c|} + \hline STORE32L(x, y) & {\bf unsigned long} x, {\bf unsigned char} *y & $x \to y[0 \ldots 3]$ \\ + \hline STORE64L(x, y) & {\bf unsigned long long} x, {\bf unsigned char} *y & $x \to y[0 \ldots 7]$ \\ + \hline LOAD32L(x, y) & {\bf unsigned long} x, {\bf unsigned char} *y & $y[0 \ldots 3] \to x$ \\ + \hline LOAD64L(x, y) & {\bf unsigned long long} x, {\bf unsigned char} *y & $y[0 \ldots 7] \to x$ \\ + \hline STORE32H(x, y) & {\bf unsigned long} x, {\bf unsigned char} *y & $x \to y[3 \ldots 0]$ \\ + \hline STORE64H(x, y) & {\bf unsigned long long} x, {\bf unsigned char} *y & $x \to y[7 \ldots 0]$ \\ + \hline LOAD32H(x, y) & {\bf unsigned long} x, {\bf unsigned char} *y & $y[3 \ldots 0] \to x$ \\ + \hline LOAD64H(x, y) & {\bf unsigned long long} x, {\bf unsigned char} *y & $y[7 \ldots 0] \to x$ \\ + \hline BSWAP(x) & {\bf unsigned long} x & Swaps the byte order of x. \\ + \hline +\end{tabular} +\end{center} +\end{small} + +There are 32-bit cyclic rotations as well: +\index{ROL} \index{ROR} +\begin{center} +\begin{tabular}{|c|c|c|} + \hline ROL(x, y) & {\bf unsigned long} x, {\bf unsigned long} y & $x << y$ \\ + \hline ROR(x, y) & {\bf unsigned long} x, {\bf unsigned long} y & $x >> y$ \\ + \hline +\end{tabular} +\end{center} + +\section{Functions with Variable Length Output} +Certain functions such as (for example) ``rsa\_export()'' give an output that is variable length. To prevent buffer overflows you +must pass it the length of the buffer\footnote{Extensive error checking is not in place but it will be in future releases so it is a good idea to follow through with these guidelines.} where +the output will be stored. For example: +\begin{small} +\begin{verbatim} +#include +int main(void) { + rsa_key key; + unsigned char buffer[1024]; + unsigned long x; + int errno; + + /* ... Make up the RSA key somehow */ + + /* lets export the key, set x to the size of the output buffer */ + x = sizeof(buffer); + if ((errno = rsa_export(buffer, &x, PK_PUBLIC, &key)) != CRYPT_OK) { + printf("Export error: %s\n", error_to_string(errno)); + return -1; + } + + /* if rsa_export() was successful then x will have the size of the output */ + printf("RSA exported key takes %d bytes\n", x); + + /* ... do something with the buffer */ + + return 0; +} +\end{verbatim} +\end{small} +In the above example if the size of the RSA public key was more than 1024 bytes this function would not store anything in +either ``buffer'' or ``x'' and simply return an error code. If the function suceeds it stores the length of the output +back into ``x'' so that the calling application will know how many bytes used. + +\section{Functions that need a PRNG} +Certain functions such as ``rsa\_make\_key()'' require a PRNG. These functions do not setup the PRNG themselves so it is +the responsibility of the calling function to initialize the PRNG before calling them. + +\section{Functions that use Arrays of Octets} +Most functions require inputs that are arrays of the data type ``unsigned char''. Whether it is a symmetric key, IV +for a chaining mode or public key packet it is assumed that regardless of the actual size of ``unsigned char'' only the +lower eight bits contain data. For example, if you want to pass a 256 bit key to a symmetric ciphers setup routine +you must pass it in (a pointer to) an array of 32 ``unsigned char'' variables. Certain routines +(such as SAFER+) take special care to work properly on platforms where an ``unsigned char'' is not eight bits. + +For the purposes of this library the term ``byte'' will refer to an octet or eight bit word. Typically an array of +type ``byte'' will be synonymous with an array of type ``unsigned char''. + +\chapter{Symmetric Block Ciphers} +\section{Core Functions} + +Libtomcrypt provides several block ciphers all in a plain vanilla ECB block mode. Its important to first note that you +should never use the ECB modes directly to encrypt data. Instead you should use the ECB functions to make a chaining mode +or use one of the provided chaining modes. All of the ciphers are written as ECB interfaces since it allows the rest of +the API to grow in a modular fashion. + +All ciphers store their scheduled keys in a single data type called ``symmetric\_key''. This allows all ciphers to +have the same prototype and store their keys as naturally as possible. All ciphers provide five visible functions which +are (given that XXX is the name of the cipher): +\index{Cipher Setup} +\begin{verbatim} +int XXX_setup(const unsigned char *key, int keylen, int rounds, + symmetric_key *skey); +\end{verbatim} + +The XXX\_setup() routine will setup the cipher to be used with a given number of rounds and a given key length (in bytes). +The number of rounds can be set to zero to use the default, which is generally a good idea. + +If the function returns successfully the variable ``skey'' will have a scheduled key stored in it. Its important to note +that you should only used this scheduled key with the intended cipher. For example, if you call +``blowfish\_setup()'' do not pass the scheduled key onto ``rc5\_ecb\_encrypt()''. All setup functions do not allocate +memory off the heap so when you are done with a key you can simply discard it (e.g. they can be on the stack). + +To encrypt or decrypt a block in ECB mode there are these two functions: +\index{Cipher Encrypt} \index{Cipher Decrypt} +\begin{verbatim} +void XXX_ecb_encrypt(const unsigned char *pt, unsigned char *ct, + symmetric_key *skey); + +void XXX_ecb_decrypt(const unsigned char *ct, unsigned char *pt, + symmetric_key *skey); +\end{verbatim} +These two functions will encrypt or decrypt (respectively) a single block of text\footnote{The size of which depends on +which cipher you are using.} and store the result where you want it. It is possible that the input and output buffer are +the same buffer. For the encrypt function ``pt''\footnote{pt stands for plaintext.} is the input and ``ct'' is the output. +For the decryption function its the opposite. To test a particular cipher against test vectors\footnote{As published in their design papers.} call: \index{Cipher Testing} +\begin{verbatim} +int XXX_test(void); +\end{verbatim} +This function will return {\bf CRYPT\_OK} if the cipher matches the test vectors from the design publication it is +based upon. Finally for each cipher there is a function which will help find a desired key size: +\begin{verbatim} +int XXX_keysize(int *keysize); +\end{verbatim} +Essentially it will round the input keysize in ``keysize'' down to the next appropriate key size. This function +return {\bf CRYPT\_OK} if the key size specified is acceptable. For example: +\begin{small} +\begin{verbatim} +#include +int main(void) +{ + int keysize, errno; + + /* now given a 20 byte key what keysize does Twofish want to use? */ + keysize = 20; + if ((errno = twofish_keysize(&keysize)) != CRYPT_OK) { + printf("Error getting key size: %s\n", error_to_string(errno)); + return -1; + } + printf("Twofish suggested a key size of %d\n", keysize); + return 0; +} +\end{verbatim} +\end{small} +This should indicate a keysize of sixteen bytes is suggested. An example snippet that encodes a block with +Blowfish in ECB mode is below. + +\begin{small} +\begin{verbatim} +#include +int main(void) +{ + unsigned char pt[8], ct[8], key[8]; + symmetric_key skey; + int errno; + + /* first register Blowfish */ + if (register_cipher(&blowfish_desc) == -1) { + printf("Error registering Blowfish.\n"); + return -1; + } + + /* ... key is loaded appropriately in ``key'' ... */ + /* ... load a block of plaintext in ``pt'' ... */ + + /* schedule the key */ + if ((errno = blowfish_setup(key, 8, 0, &skey)) != CRYPT_OK) { + printf("Setup error: %s\n", error_to_string(errno)); + return -1; + } + + /* encrypt the block */ + blowfish_ecb_encrypt(pt, ct, &skey); + + /* decrypt the block */ + blowfish_ecb_decrypt(ct, pt, &skey); + + return 0; +} +\end{verbatim} +\end{small} + +\section{Key Sizes and Number of Rounds} +\index{Symmetric Keys} +As a general rule of thumb do not use symmetric keys under 80 bits if you can. Only a few of the ciphers support smaller +keys (mainly for test vectors anyways). Ideally your application should be making at least 256 bit keys. This is not +because you're supposed to be paranoid. Its because if your PRNG has a bias of any sort the more bits the better. For +example, if you have $\mbox{Pr}\left[X = 1\right] = {1 \over 2} \pm \gamma$ where $\vert \gamma \vert > 0$ then the +total amount of entropy in N bits is $N \cdot -log_2\left ({1 \over 2} + \vert \gamma \vert \right)$. So if $\gamma$ +were $0.25$ (a severe bias) a 256-bit string would have about 106 bits of entropy whereas a 128-bit string would have +only 53 bits of entropy. + +The number of rounds of most ciphers is not an option you can change. Only RC5 allows you to change the number of +rounds. By passing zero as the number of rounds all ciphers will use their default number of rounds. Generally the +ciphers are configured such that the default number of rounds provide adequate security for the given block size. + +\section{The Cipher Descriptors} +\index{Cipher Descriptor} +To facilitate automatic routines an array of cipher descriptors is provided in the array ``cipher\_descriptor''. An element +of this array has the following format: + +\begin{verbatim} +struct _cipher_descriptor { + char *name; + unsigned long min_key_length, max_key_length, + block_length, default_rounds; + int (*setup) (const unsigned char *key, int keylength, + int num_rounds, symmetric_key *skey); + void (*ecb_encrypt)(const unsigned char *pt, unsigned char *ct, + symmetric_key *key); + void (*ecb_decrypt)(const unsigned char *ct, unsigned char *pt, + symmetric_key *key); + int (*test) (void); + int (*keysize) (int *desired_keysize); +}; +\end{verbatim} + +Where ``name'' is the lower case ASCII version of the name. The fields ``min\_key\_length'', ``max\_key\_length'' and +``block\_length'' are all the number of bytes not bits. As a good rule of thumb it is assumed that the cipher supports +the min and max key lengths but not always everything in between. The ``default\_rounds'' field is the default number +of rounds that will be used. + +The remaining fields are all pointers to the core functions for each cipher. The end of the cipher\_descriptor array is +marked when ``name'' equals {\bf NULL}. + +As of this release the current cipher\_descriptors elements are + +\begin{small} +\begin{center} +\begin{tabular}{|c|c|c|c|c|c|} + \hline Name & Descriptor Name & Block Size (bytes) & Key Range (bytes) & Rounds \\ + \hline Blowfish & blowfish\_desc & 8 & 8 ... 56 & 16 \\ + \hline X-Tea & xtea\_desc & 8 & 16 & 32 \\ + \hline RC2 & rc2\_desc & 8 & 8 .. 128 & 16 \\ + \hline RC5-32/12/b & rc5\_desc & 8 & 8 ... 128 & 12 ... 24 \\ + \hline RC6-32/20/b & rc6\_desc & 16 & 8 ... 128 & 20 \\ + \hline SAFER+ & saferp\_desc &16 & 16, 24, 32 & 8, 12, 16 \\ + \hline Safer K64 & safer\_k64\_desc & 8 & 8 & 6 .. 13 \\ + \hline Safer SK64 & safer\_sk64\_desc & 8 & 8 & 6 .. 13 \\ + \hline Safer K128 & safer\_k128\_desc & 8 & 16 & 6 .. 13 \\ + \hline Safer SK128 & safer\_sk128\_desc & 8 & 16 & 6 .. 13 \\ + \hline Serpent & serpent\_desc & 16 & 16 .. 32 & 32 \\ + \hline Rijndael (AES) & rijndael\_desc & 16 & 16, 24, 32 & 10, 12, 14 \\ + \hline Twofish & twofish\_desc & 16 & 16, 24, 32 & 16 \\ + \hline DES & des\_desc & 8 & 7 & 16 \\ + \hline 3DES (EDE mode) & des3\_desc & 8 & 21 & 16 \\ + \hline CAST5 (CAST-128) & cast5\_desc & 8 & 5 .. 16 & 12, 16 \\ + \hline +\end{tabular} +\end{center} +\end{small} + +\subsection{Notes} +For the 64-bit SAFER famliy of ciphers (e.g K64, SK64, K128, SK128) the ecb\_encrypt() and ecb\_decrypt() +functions are the same. So if you want to use those functions directly just call safer\_ecb\_encrypt() +or safer\_ecb\_decrypt() respectively. + +Note that for ``DES'' and ``3DES'' they use 8 and 24 byte keys but only 7 and 21 [respectively] bytes of the keys are in +fact used for the purposes of encryption. My suggestion is just to use random 8/24 byte keys instead of trying to make a 8/24 +byte string from the real 7/21 byte key. + +Note that ``Twofish'' has additional configuration options that take place at build time. These options are found in +the file ``mycrypt\_cfg.h''. The first option is ``TWOFISH\_SMALL'' which when defined will force the Twofish code +to not pre-compute the Twofish ``$g(X)$'' function as a set of four $8 \times 32$ s-boxes. This means that a scheduled +key will require less ram but the resulting cipher will be slower. The second option is ``TWOFISH\_TABLES'' which when +defined will force the Twofish code to use pre-computed tables for the two s-boxes $q_0, q_1$ as well as the multiplication +by the polynomials 5B and EF used in the MDS multiplication. As a result the code is faster and slightly larger. The +speed increase is useful when ``TWOFISH\_SMALL'' is defined since the s-boxes and MDS multiply form the heart of the +Twofish round function. + +\begin{small} +\begin{center} +\begin{tabular}{|l|l|l|} +\hline TWOFISH\_SMALL & TWOFISH\_TABLES & Speed and Memory (per key) \\ +\hline undefined & undefined & Very fast, 4.2KB of ram. \\ +\hline undefined & defined & As above, faster keysetup, larger code (1KB more). \\ +\hline defined & undefined & Very slow, 0.2KB of ram. \\ +\hline defined & defined & Somewhat faster, 0.2KB of ram, larger code. \\ +\hline +\end{tabular} +\end{center} +\end{small} + +To work with the cipher\_descriptor array there is a function: +\begin{verbatim} +int find_cipher(char *name) +\end{verbatim} +Which will search for a given name in the array. It returns negative one if the cipher is not found, otherwise it returns +the location in the array where the cipher was found. For example, to indirectly setup Blowfish you can also use: +\begin{small} +\begin{verbatim} +#include +int main(void) +{ + unsigned char key[8]; + symmetric_key skey; + int errno; + + /* you must register a cipher before you use it */ + if (register_cipher(&blowfish_desc)) == -1) { + printf("Unable to register Blowfish cipher."); + return -1; + } + + /* generic call to function (assuming the key in key[] was already setup) */ + if ((errno = cipher_descriptor[find_cipher("blowfish")].setup(key, 8, 0, &skey)) != CRYPT_OK) { + printf("Error setting up Blowfish: %s\n", error_to_string(errno)); + return -1; + } + + /* ... use cipher ... */ +} +\end{verbatim} +\end{small} + +A good safety would be to check the return value of ``find\_cipher()'' before accessing the desired function. In order +to use a cipher with the descriptor table you must register it first using: +\begin{verbatim} +int register_cipher(const struct _cipher_descriptor *cipher); +\end{verbatim} +Which accepts a pointer to a descriptor and returns the index into the global descriptor table. If an error occurs such +as there is no more room (it can have 32 ciphers at most) it will return {\bf{-1}}. If you try to add the same cipher more +than once it will just return the index of the first copy. To remove a cipher call: +\begin{verbatim} +int unregister_cipher(const struct _cipher_descriptor *cipher); +\end{verbatim} +Which returns {\bf CRYPT\_OK} if it removes it otherwise it returns {\bf CRYPT\_ERROR}. Consider: +\begin{small} +\begin{verbatim} +#include +int main(void) +{ + int errno; + + /* register the cipher */ + if (register_cipher(&rijndael_desc) == -1) { + printf("Error registering Rijndael\n"); + return -1; + } + + /* use Rijndael */ + + /* remove it */ + if ((errno = unregister_cipher(&rijndael_desc)) != CRYPT_OK) { + printf("Error removing Rijndael: %s\n", error_to_string(errno)); + return -1; + } + + return 0; +} +\end{verbatim} +\end{small} +This snippet is a small program that registers only Rijndael only. Note you must register ciphers before +using the PK code since all of the PK code (RSA, DH and ECC) rely heavily on the descriptor tables. + +\section{Symmetric Modes of Operations} +\subsection{Background} +A typical symmetric block cipher can be used in chaining modes to effectively encrypt messages larger than the block +size of the cipher. Given a key $k$, a plaintext $P$ and a cipher $E$ we shall denote the encryption of the block +$P$ under the key $k$ as $E_k(P)$. In some modes there exists an initial vector denoted as $C_{-1}$. + +\subsubsection{ECB Mode} +ECB or Electronic Codebook Mode is the simplest method to use. It is given as: +\begin{equation} +C_i = E_k(P_i) +\end{equation} +This mode is very weak since it allows people to swap blocks and perform replay attacks if the same key is used more +than once. + +\subsubsection{CBC Mode} +CBC or Cipher Block Chaining mode is a simple mode designed to prevent trivial forms of replay and swap attacks on ciphers. +It is given as: +\begin{equation} +C_i = E_k(P_i \oplus C_{i - 1}) +\end{equation} +It is important that the initial vector be unique and preferably random for each message encrypted under the same key. + +\subsubsection{CTR Mode} +CTR or Counter Mode is a mode which only uses the encryption function of the cipher. Given a initial vector which is +treated as a large binary counter the CTR mode is given as: +\begin{eqnarray} +C_{-1} = C_{-1} + 1\mbox{ }(\mbox{mod }2^W) \nonumber \\ +C_i = P_i \oplus E_k(C_{-1}) +\end{eqnarray} +Where $W$ is the size of a block in bits (e.g. 64 for Blowfish). As long as the initial vector is random for each message +encrypted under the same key replay and swap attacks are infeasible. CTR mode may look simple but it is as secure +as the block cipher is under a chosen plaintext attack (provided the initial vector is unique). + +\subsubsection{CFB Mode} +CFB or Ciphertext Feedback Mode is a mode akin to CBC. It is given as: +\begin{eqnarray} +C_i = P_i \oplus C_{-1} \nonumber \\ +C_{-1} = E_k(C_i) +\end{eqnarray} +Note that in this library the output feedback width is equal to the size of the block cipher. That is this mode is used +to encrypt whole blocks at a time. However, the library will buffer data allowing the user to encrypt or decrypt partial +blocks without a delay. When this mode is first setup it will initially encrypt the initial vector as required. + +\subsubsection{OFB Mode} +OFB or Output Feedback Mode is a mode akin to CBC as well. It is given as: +\begin{eqnarray} +C_{-1} = E_k(C_{-1}) \nonumber \\ +C_i = P_i \oplus C_{-1} +\end{eqnarray} +Like the CFB mode the output width in CFB mode is the same as the width of the block cipher. OFB mode will also +buffer the output which will allow you to encrypt or decrypt partial blocks without delay. + +\subsection{Choice of Mode} +My personal preference is for the CTR mode since it has several key benefits: +\begin{enumerate} + \item No short cycles which is possible in the OFB and CFB modes. + \item Provably as secure as the block cipher being used under a chosen plaintext attack. + \item Technically does not require the decryption routine of the cipher. + \item Allows random access to the plaintext. + \item Allows the encryption of block sizes that are not equal to the size of the block cipher. +\end{enumerate} +The CTR, CFB and OFB routines provided allow you to encrypt block sizes that differ from the ciphers block size. They +accomplish this by buffering the data required to complete a block. This allows you to encrypt or decrypt any size +block of memory with either of the three modes. + +The ECB and CBC modes process blocks of the same size as the cipher at a time. Therefore they are less flexible than the +other modes. + +\subsection{Implementation} +\index{CBC Mode} \index{CTR Mode} +\index{OFB Mode} \index{CFB Mode} +The library provides simple support routines for handling CBC, CTR, CFB, OFB and ECB encoded messages. Assuming the mode +you want is XXX there is a structure called ``symmetric\_XXX'' that will contain the information required to +use that mode. They have identical setup routines (except ECB mode for obvious reasons): +\begin{verbatim} +int XXX_start(int cipher, const unsigned char *IV, + const unsigned char *key, int keylen, + int num_rounds, symmetric_XXX *XXX); + +int ecb_start(int cipher, const unsigned char *key, int keylen, + int num_rounds, symmetric_ECB *ecb); +\end{verbatim} + +In each case ``cipher'' is the index into the cipher\_descriptor array of the cipher you want to use. The ``IV'' value is +the initialization vector to be used with the cipher. You must fill the IV yourself and it is assumed they are the same +length as the block size\footnote{In otherwords the size of a block of plaintext for the cipher, e.g. 8 for DES, 16 for AES, etc.} +of the cipher you choose. It is important that the IV be random for each unique message you want to encrypt. The +parameters ``key'', ``keylen'' and ``num\_rounds'' are the same as in the XXX\_setup() function call. The final parameter +is a pointer to the structure you want to hold the information for the mode of operation. + +Both routines return {\bf CRYPT\_OK} if the cipher initialized correctly, otherwise they return an error code. To +actually encrypt or decrypt the following routines are provided: +\begin{verbatim} +int XXX_encrypt(const unsigned char *pt, unsigned char *ct, + symmetric_XXX *XXX); +int XXX_decrypt(const unsigned char *ct, unsigned char *pt, + symmetric_XXX *XXX); + +int YYY_encrypt(const unsigned char *pt, unsigned char *ct, + unsigned long len, symmetric_YYY *YYY); +int YYY_decrypt(const unsigned char *ct, unsigned char *pt, + unsigned long len, symmetric_YYY *YYY); +\end{verbatim} +Where ``XXX'' is one of (ecb, cbc) and ``YYY'' is one of (ctr, ofb, cfb). In the CTR, OFB and CFB cases ``len'' is the +size of the buffer (as number of chars) to encrypt or decrypt. The CTR, OFB and CFB modes are order sensitive but not +chunk sensitive. That is you can encrypt ``ABCDEF'' in three calls like ``AB'', ``CD'', ``EF'' or two like ``ABCDE'' and ``F'' +and end up with the same ciphertext. However, encrypting ``ABC'' and ``DABC'' will result in different ciphertexts. All +four of the functions return {\bf CRYPT\_OK} on success. + +To decrypt in either mode you simply perform the setup like before (recall you have to fetch the IV value you used) +and use the decrypt routine on all of the blocks. When you are done working with either mode you should wipe the +memory (using ``zeromem()'') to help prevent the key from leaking. For example: +\newpage +\begin{small} +\begin{verbatim} +#include +int main(void) +{ + unsigned char key[16], IV[16], buffer[512]; + symmetric_CTR ctr; + int x, errno; + + /* register twofish first */ + if (register_cipher(&twofish_desc) == -1) { + printf("Error registering cipher.\n"); + return -1; + } + + /* somehow fill out key and IV */ + + /* start up CTR mode */ + if ((errno = ctr_start(find_cipher("twofish"), IV, key, 16, 0, &ctr)) != CRYPT_OK) { + printf("ctr_start error: %s\n", error_to_string(errno)); + return -1; + } + + /* somehow fill buffer than encrypt it */ + if ((errno = ctr_encrypt(buffer, buffer, sizeof(buffer), &ctr)) != CRYPT_OK) { + printf("ctr_encrypt error: %s\n", error_to_string(errno)); + return -1; + } + + /* make use of ciphertext... */ + + /* clear up and return */ + zeromem(key, sizeof(key)); + zeromem(&ctr, sizeof(ctr)); + + return 0; +} +\end{verbatim} +\end{small} + +\chapter{One-Way Cryptographic Hash Functions} +\section{Core Functions} + +Like the ciphers there are hash core functions and a universal data type to hold the hash state called ``hash\_state''. +To initialize hash XXX (where XXX is the name) call: +\index{Hash Functions} +\begin{verbatim} +void XXX_init(hash_state *md); +\end{verbatim} + +This simply sets up the hash to the default state governed by the specifications of the hash. To add data to the +message being hashed call: +\begin{verbatim} +void XXX_process(hash_state *md, const unsigned char *in, unsigned long len); +\end{verbatim} + +Essentially all hash messages are virtually infinitely\footnote{Most hashes are limited to $2^{64}$ bits or 2,305,843,009,213,693,952 bytes.} long message which +are buffered. The data can be passed in any sized chunks as long as the order of the bytes are the same the message digest +(hash output) will be the same. For example, this means that: +\begin{verbatim} +md5_process(&md, "hello ", 6); +md5_process(&md, "world", 5); +\end{verbatim} +Will produce the same message digest as the single call: +\index{Message Digest} +\begin{verbatim} +md5_process(&md, "hello world", 11); +\end{verbatim} + +To finally get the message digest (the hash) call: +\begin{verbatim} +void XXX_done(hash_state *md, + unsigned char *out); +\end{verbatim} + +This function will finish up the hash and store the result in the ``out'' array. You must ensure that ``out'' is long +enough for the hash in question. Often hashes are used to get keys for symmetric ciphers so the ``XXX\_done()'' functions +will wipe the ``md'' variable before returning automatically. + +To test a hash function call: +\begin{verbatim} +int XXX_test(void); +\end{verbatim} + +This will return {\bf CRYPTO\_OK} if the hash matches the test vectors, otherwise it returns an error code. An +example snippet that hashes a message with md5 is given below. +\begin{small} +\begin{verbatim} +#include +int main(void) +{ + hash_state md; + unsigned char *in = "hello world", out[16]; + + /* setup the hash */ + md5_init(&md); + + /* add the message */ + md5_process(&md, in, strlen(in)); + + /* get the hash */ + md5_done(&md, out); + + return 0; +} +\end{verbatim} +\end{small} + +\section{Hash Descriptors} +\index{Hash Descriptors} +Like the set of ciphers the set of hashes have descriptors too. They are stored in an array called ``hash\_descriptor'' and +are defined by: +\begin{verbatim} +struct _hash_descriptor { + char *name; + unsigned long hashsize; /* digest output size in bytes */ + unsigned long blocksize; /* the block size the hash uses */ + void (*init) (hash_state *); + void (*process)(hash_state *, const unsigned char *, unsigned long); + void (*done) (hash_state *, unsigned char *); + int (*test) (void); +}; +\end{verbatim} + +Similarly ``name'' is the name of the hash function in ASCII (all lowercase). ``hashsize'' is the size of the digest output +in bytes. The remaining fields are pointers to the functions that do the respective tasks. There is a function to +search the array as well called ``int find\_hash(char *name)''. It returns -1 if the hash is not found, otherwise the +position in the descriptor table of the hash. + +You can use the table to indirectly call a hash function that is chosen at runtime. For example: +\begin{small} +\begin{verbatim} +#include +int main(void) +{ + unsigned char buffer[100], hash[MAXBLOCKSIZE]; + int idx, x; + hash_state md; + + /* register hashes .... */ + if (register_hash(&md5_desc) == -1) { + printf("Error registering MD5.\n"); + return -1; + } + + /* register other hashes ... */ + + /* prompt for name and strip newline */ + printf("Enter hash name: \n"); + fgets(buffer, sizeof(buffer), stdin); + buffer[strlen(buffer) - 1] = 0; + + /* get hash index */ + idx = find_hash(buffer); + if (idx == -1) { + printf("Invalid hash name!\n"); + return -1; + } + + /* hash input until blank line */ + hash_descriptor[idx].init(&md); + while (fgets(buffer, sizeof(buffer), stdin) != NULL) + hash_descriptor[idx].process(&md, buffer, strlen(buffer)); + hash_descriptor[idx].done(&md, hash); + + /* dump to screen */ + for (x = 0; x < hash_descriptor[idx].hashsize; x++) + printf("%02x ", hash[x]); + printf("\n"); + return 0; +} +\end{verbatim} +\end{small} + +Note the usage of ``MAXBLOCKSIZE''. In Libtomcrypt no symmetric block, key or hash digest is larger than MAXBLOCKSIZE in +length. This provides a simple size you can set your automatic arrays to that will not get overrun. + +There are three helper functions as well: +\index{hash\_memory()} \index{hash\_file()} +\begin{verbatim} +int hash_memory(int hash, const unsigned char *data, + unsigned long len, unsigned char *dst, + unsigned long *outlen); + +int hash_file(int hash, const char *fname, + unsigned char *dst, + unsigned long *outlen); + +int hash_filehandle(int hash, FILE *in, + unsigned char *dst, unsigned long *outlen); +\end{verbatim} + +Both functions return {\bf CRYPT\_OK} on success, otherwise they return an error code. The ``hash'' parameter is +the location in the descriptor table of the hash. The ``*outlen'' variable is used to keep track of the output size. You +must set it to the size of your output buffer before calling the functions. When they complete succesfully they store +the length of the message digest back in it. The functions are otherwise straightforward. The ``hash\_filehandle'' function +assumes that ``in'' is an file handle opened in binary mode. It will not reset the file position after hashing the content. + +To perform the above hash with md5 the following code could be used: +\begin{small} +\begin{verbatim} +#include +int main(void) +{ + int idx, errno; + unsigned long len; + unsigned char out[MAXBLOCKSIZE]; + + /* register the hash */ + if (register_hash(&md5_desc) == -1) { + printf("Error registering MD5.\n"); + return -1; + } + + /* get the index of the hash */ + idx = find_hash("md5"); + + /* call the hash */ + len = sizeof(out); + if ((errno = hash_memory(idx, "hello world", 11, out, &len)) != CRYPT_OK) { + printf("Error hashing data: %s\n", error_to_string(errno)); + return -1; + } + return 0; +} +\end{verbatim} +\end{small} + +The following hashes are provided as of this release: +\begin{center} +\begin{tabular}{|c|c|c|} + \hline Name & Descriptor Name & Size of Message Digest (bytes) \\ + \hline SHA-512 & sha512\_desc & 64 \\ + \hline SHA-384 & sha384\_desc & 48 \\ + \hline SHA-256 & sha256\_desc & 32 \\ + \hline TIGER-192 & tiger\_desc & 24 \\ + \hline SHA-1 & sha1\_desc & 20 \\ + \hline MD5 & md5\_desc & 16 \\ + \hline MD4 & md4\_desc & 16 \\ + \hline MD2 & md2\_desc & 16 \\ + \hline +\end{tabular} +\end{center} + +Similar to the cipher descriptor table you must register your hash algorithms before you can use them. These functions +work exactly like those of the cipher registration code. The functions are: +\begin{verbatim} +int register_hash(const struct _hash_descriptor *hash); +int unregister_hash(const struct _hash_descriptor *hash); +\end{verbatim} + +\subsection{Notice} +It is highly recommended that you not use the MD4 or MD5 hashes for the purposes of digital signatures or authentication codes. +These hashes are provided for completeness and they still can be used for the purposes of password hashing or one-way accumulators +(e.g. Yarrow). + +The other hashes such as the SHA-1, SHA-2 (that includes SHA-512, SHA-384 and SHA-256) and TIGER-192 are still considered secure +for all purposes you would normally use a hash for. + +\section{Hash based Message Authenication Codes} +Thanks to Dobes Vandermeer the library now includes support for hash based message authenication codes or HMAC for short. An HMAC +of a message is a keyed authenication code that only the owner of a private symmetric key will be able to verify. The purpose is +to allow an owner of a private symmetric key to produce an HMAC on a message then later verify if it is correct. Any impostor or +eavesdropper will not be able to verify the authenticity of a message. + +The HMAC support works much like the normal hash functions except that the initialization routine requires you to pass a key +and its length. The key is much like a key you would pass to a cipher. That is, it is simply an array of octets stored in +chars. The initialization routine is: +\begin{verbatim} +int hmac_init(hmac_state *hmac, int hash, + const unsigned char *key, unsigned long keylen); +\end{verbatim} +The ``hmac'' parameter is the state for the HMAC code. ``hash'' is the index into the descriptor table of the hash you want +to use to authenticate the message. ``key'' is the pointer to the array of chars that make up the key. ``keylen'' is the +length (in octets) of the key you want to use to authenticate the message. To send octets of a message through the HMAC system you must use the following function: +\begin{verbatim} +int hmac_process(hmac_state *hmac, const unsigned char *buf, + unsigned long len); +\end{verbatim} +``hmac'' is the HMAC state you are working with. ``buf'' is the array of octets to send into the HMAC process. ``len'' is the +number of octets to process. Like the hash process routines you can send the data in arbitrarly sized chunks. When you +are finished with the HMAC process you must call the following function to get the HMAC code: +\begin{verbatim} +int hmac_done(hmac_state *hmac, unsigned char *hash); +\end{verbatim} +``hmac'' is the HMAC state you are working with. ``hash'' is the array of octets where the HMAC code should be stored. You +must ensure that your destination array is the right size (or just make it of size MAXBLOCKSIZE to be sure). There are +two utility functions provided to make using HMACs easier todo. +\begin{verbatim} +int hmac_memory(int hash, const unsigned char *key, unsigned long keylen, + const unsigned char *data, unsigned long len, + unsigned char *dst); +\end{verbatim} +This will produce an HMAC code for the array of octets in ``data'' of length ``len''. The index into the hash descriptor table must be provided in ``hash'' +It uses the key from ``key'' with a key length of ``keylen''. The result is stored in the array of octets``dst''. +Similarly for files there is the following function: +\begin{verbatim} +int hmac_file(int hash, const char *fname, const unsigned char *key, + unsigned long keylen, unsigned char *dst); +\end{verbatim} +``hash'' is the index into the hash descriptor table of the hash you want to use. ``fname'' is the filename to process. ``key'' +is the array of octets to use as the key. ``keylen'' is the length of the key. ``dst'' is the array of octets where the result +should be stored. + +To test if the HMAC code is working there is the following function: +\begin{verbatim} +int hmac_test(void); +\end{verbatim} +Which returns {\bf CRYPT\_OK} if the code passes otherwise it returns an error code. Some example code for using the +HMAC system is given below. + +\begin{small} +\begin{verbatim} +#include +int main(void) +{ + int idx, errno; + hmac_state hmac; + unsigned char key[16], dst[MAXBLOCKSIZE]; + + /* register SHA-1 */ + if (register_hash(&sha1_desc) == -1) { + printf("Error registering SHA1\n"); + return -1; + } + + /* get index of SHA1 in hash descriptor table */ + idx = find_hash("sha1"); + + /* we would make up our symmetric key in "key[]" here */ + + /* start the HMAC */ + if ((errno = hmac_init(&hmac, idx, key, 16)) != CRYPT_OK) { + printf("Error setting up hmac: %s\n", error_to_string(errno)); + return -1; + } + + /* process a few octets */ + if((errno = hmac_process(&hmac, "hello", 5) != CRYPT_OK) { + printf("Error processing hmac: %s\n", error_to_string(errno)); + return -1; + } + + /* get result (presumably to use it somehow...) */ + if ((errno = hmac_done(&hmac, dst)) != CRYPT_OK) { + printf("Error finishing hmac: %s\n", error_to_string(errno)); + return -1; + } + + /* return */ + return 0; +} +\end{verbatim} +\end{small} + +\chapter{Pseudo-Random Number Generators} +\section{Core Functions} + +The library provides an array of core functions for Pseudo-Random Number Generators (PRNGs) as well. A cryptographic PRNG is +used to expand a shorter bit string into a longer bit string. PRNGs are used wherever random data is required such as Public Key (PK) +key generation. There is a universal structure called ``prng\_state''. To initialize a PRNG call: +\begin{verbatim} +int XXX_start(prng_state *prng); +\end{verbatim} + +This will setup the PRNG for future use and not seed it. In order +for the PRNG to be cryptographically useful you must give it entropy. Ideally you'd have some OS level source to tap +like in UNIX (see section 5.3). To add entropy to the PRNG call: +\begin{verbatim} +int XXX_add_entropy(const unsigned char *in, unsigned long len, + prng_state *prng); +\end{verbatim} + +Which returns {\bf CRYPTO\_OK} if the entropy was accepted. Once you think you have enough entropy you call another +function to put the entropy into action. +\begin{verbatim} +int XXX_ready(prng_state *prng); +\end{verbatim} + +Which returns {\bf CRYPTO\_OK} if it is ready. Finally to actually read bytes call: +\begin{verbatim} +unsigned long XXX_read(unsigned char *out, unsigned long len, + prng_state *prng); +\end{verbatim} + +Which returns the number of bytes read from the PRNG. + +\subsection{Remarks} + +It is possible to be adding entropy and reading from a PRNG at the same time. For example, if you first seed the PRNG +and call ready() you can now read from it. You can also keep adding new entropy to it. The new entropy will not be used +in the PRNG until ready() is called again. This allows the PRNG to be used and re-seeded at the same time. No real error +checking is guaranteed to see if the entropy is sufficient or if the PRNG is even in a ready state before reading. + +\subsection{Example} + +Below is a simple snippet to read 10 bytes from yarrow. Its important to note that this snippet is {\bf NOT} secure since +the entropy added is not random. + +\begin{verbatim} +#include +int main(void) +{ + prng_state prng; + unsigned char buf[10]; + int errno; + + /* start it */ + if ((errno = yarrow_start(&prng)) != CRYPT_OK) { + printf("Start error: %s\n", error_to_string(errno)); + } + /* add entropy */ + if ((errno = yarrow_add_entropy("hello world", 11, &prng)) != CRYPT_OK) { + printf("Add_entropy error: %s\n", error_to_string(errno)); + } + /* ready and read */ + if ((errno = yarrow_ready(&prng)) != CRYPT_OK) { + printf("Ready error: %s\n", error_to_string(errno)); + } + printf("Read %lu bytes from yarrow\n", yarrow_read(buf, 10, &prng)); + return 0; +} +\end{verbatim} + +\section{PRNG Descriptors} +\index{PRNG Descriptor} +PRNGs have descriptors too (surprised?). Stored in the structure ``prng\_descriptor''. The format of an element is: +\begin{verbatim} +struct _prng_descriptor { + char *name; + int (*start) (prng_state *); + int (*add_entropy)(const unsigned char *, unsigned long, prng_state *); + int (*ready) (prng_state *); + unsigned long (*read)(unsigned char *, unsigned long len, prng_state *); +}; +\end{verbatim} + +There is a ``int find\_prng(char *name)'' function as well. Returns -1 if the PRNG is not found, otherwise it returns +the position in the prng\_descriptor array. + +Just like the ciphers and hashes you must register your prng before you can use it. The two functions provided work +exactly as those for the cipher registry functions. They are: +\begin{verbatim} +int register_prng(const struct _prng_descriptor *prng); +int unregister_prng(const struct _prng_descriptor *prng); +\end{verbatim} + +\subsubsection{PRNGs Provided} +Currently Yarrow (yarrow\_desc), RC4 (rc4\_desc) and the secure RNG (sprng\_desc) are provided as PRNGs within the +library. + +RC4 is provided with a PRNG interface because it is a stream cipher and not well suited for the symmetric block cipher +interface. You provide the key for RC4 via the rc4\_add\_entropy() function. By calling rc4\_ready() the key will be used +to setup the RC4 state for encryption or decryption. The rc4\_read() function has been modified from RC4 since it will +XOR the output of the RC4 keystream generator against the input buffer you provide. The following snippet will demonstrate +how to encrypt a buffer with RC4: + +\begin{small} +\begin{verbatim} +#include +int main(void) +{ + prng_state prng; + unsigned char buf[32]; + int errno; + + if ((errno = rc4_start(&prng)) != CRYPT_OK) { + printf("RC4 init error: %s\n", error_to_string(errno)); + exit(-1); + } + + /* use ``key'' as the key */ + if ((errno = rc4_add_entropy("key", 3, &prng)) != CRYPT_OK) { + printf("RC4 add entropy error: %s\n", error_to_string(errno)); + exit(-1); + } + + /* setup RC4 for use */ + if ((errno = rc4_ready(&prng)) != CRYPT_OK) { + printf("RC4 ready error: %s\n", error_to_string(errno)); + exit(-1); + } + + /* encrypt buffer */ + strcpy(buf,"hello world"); + if (rc4_read(buf, 11, &prng) != 11) { + printf("RC4 read error\n"); + exit(-1); + } + return 0; +} +\end{verbatim} +\end{small} +To decrypt you have to do the exact same steps. + +\section{The Secure RNG} +\index{Secure RNG} +An RNG is related to a PRNG except that it doesn't expand a smaller seed to get the data. They generate their random bits +by performing some computation on fresh input bits. Possibly the hardest thing to get correctly in a cryptosystem is the +PRNG. Computers are deterministic beasts that try hard not to stray from pre-determined paths. That makes gathering +entropy needed to seed the PRNG a hard task. + +There is one small function that may help on certain platforms: +\index{rng\_get\_bytes()} +\begin{verbatim} +unsigned long rng_get_bytes(unsigned char *buf, unsigned long len, + void (*callback)(void)); +\end{verbatim} + +Which will try one of three methods of getting random data. The first is to open the popular ``/dev/random'' device which +on most *NIX platforms provides cryptographic random bits\footnote{This device is available in Windows through the Cygwin compiler suite. It emulates ``/dev/random'' via the Microsoft CSP.}. +The second method is to try the Microsoft Cryptographic Service Provider and read the RNG. The third method is an ANSI C +clock drift method that is also somewhat popular but gives bits of lower entropy. The ``callback'' parameter is a pointer to a function that returns void. Its used when the slower ANSI C RNG must be +used so the calling application can still work. This is useful since the ANSI C RNG has a throughput of three +bytes a second. The callback pointer may be set to {\bf NULL} to avoid using it if you don't want to. The function +returns the number of bytes actually read from any RNG source. There is a function to help setup a PRNG as well: +\index{rng\_make\_prng()} +\begin{verbatim} +int rng_make_prng(int bits, int wprng, prng_state *prng, + void (*callback)(void)); +\end{verbatim} +This will try to setup the prng with a state of at least ``bits'' of entropy. The ``callback'' parameter works much like +the callback in ``rng\_get\_bytes()''. It is highly recommended that you use this function to setup your PRNGs unless you have a +platform where the RNG doesn't work well. Example usage of this function is given below. + +\begin{small} +\begin{verbatim} +#include +int main(void) +{ + ecc_key mykey; + prng_state prng; + int errno; + + /* register yarrow */ + if (register_prng(&yarrow_desc) == -1) { + printf("Error registering Yarrow\n"); + return -1; + } + + /* setup the PRNG */ + if ((errno = rng_make_prng(128, find_prng("yarrow"), &prng, NULL)) != CRYPT_OK) { + printf("Error setting up PRNG, %s\n", error_to_string(errno)); + return -1; + } + + /* make a 192-bit ECC key */ + if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 24, &mykey)) != CRYPT_OK) { + printf("Error making key: %s\n", error_to_string(errno)); + return -1; + } + return 0; +} +\end{verbatim} +\end{small} + +\subsection{The Secure PRNG Interface} +It is possible to access the secure RNG through the PRNG interface and in turn use it within dependent functions such +as the PK API. This simplifies the cryptosystem on platforms where the secure RNG is fast. The secure PRNG never +requires to be started, that is you need not call the start, add\_entropy or ready functions. For example, consider +the previous example using this PRNG. + +\begin{small} +\begin{verbatim} +#include +int main(void) +{ + ecc_key mykey; + int errno; + + /* register SPRNG */ + if (register_prng(&sprng_desc) == -1) { + printf("Error registering SPRNG\n"); + return -1; + } + + /* make a 192-bit ECC key */ + if ((errno = ecc_make_key(NULL, find_prng("sprng"), 24, &mykey)) != CRYPT_OK) { + printf("Error making key: %s\n", error_to_string(errno)); + return -1; + } + return 0; +} +\end{verbatim} +\end{small} + +\chapter{RSA Routines} + +\section{Background} + +RSA is a public key algorithm that is based on the inability to find the ``e-th'' root modulo a composite of unknown +factorization. Normally the difficulty of breaking RSA is associated with the integer factoring problem but they are +not strictly equivalent. + +The system begins with with two primes $p$ and $q$ and their product $N = pq$. The order or ``Euler totient'' of the +multiplicative sub-group formed modulo $N$ is given as $\phi(N) = (p - 1)(q - 1)$ which can be reduced to +$\mbox{lcm}(p - 1, q - 1)$. The public key consists of the composite $N$ and some integer $e$ such that +$\mbox{gcd}(e, \phi(N)) = 1$. The private key consists of the composite $N$ and the inverse of $e$ modulo $\phi(N)$ +often simply denoted as $de \equiv 1\mbox{ }(\mbox{mod }\phi(N))$. + +A person who wants to encrypt with your public key simply forms an integer (the plaintext) $M$ such that +$1 < M < N-2$ and computes the ciphertext $C = M^e\mbox{ }(\mbox{mod }N)$. Since finding the inverse exponent $d$ +given only $N$ and $e$ appears to be intractable only the owner of the private key can decrypt the ciphertext and compute +$C^d \equiv \left (M^e \right)^d \equiv M^1 \equiv M\mbox{ }(\mbox{mod }N)$. Similarly the owner of the private key +can sign a message by ``decrypting'' it. Others can verify it by ``encrypting'' it. + +Currently RSA is a difficult system to cryptanalyze provided that both primes are large and not close to each other. +Ideally $e$ should be larger than $100$ to prevent direct analysis. For example, if $e$ is three and you do not pad +the plaintext to be encrypted than it is possible that $M^3 < N$ in which case finding the cube-root would be trivial. +The most often suggested value for $e$ is $65537$ since it is large enough to make such attacks impossible and also well +designed for fast exponentiation (requires 16 squarings and one multiplication). + +It is important to pad the input to RSA since it has particular mathematical structure. For instance +$M_1^dM_2^d = (M_1M_2)^d$ which can be used to forge a signature. Suppose $M_3 = M_1M_2$ is a message you want +to have a forged signature for. Simply get the signatures for $M_1$ and $M_2$ on their own and multiply the result +together. Similar tricks can be used to deduce plaintexts from ciphertexts. It is important not only to sign +the hash of documents only but also to pad the inputs with data to remove such structure. + +\section{Core Functions} + +For RSA routines a single ``rsa\_key'' structure is used. To make a new RSA key call: +\index{rsa\_make\_key()} +\begin{verbatim} +int rsa_make_key(prng_state *prng, + int wprng, int size, + long e, rsa_key *key); +\end{verbatim} + +Where ``wprng'' is the index into the PRNG descriptor array. ``size'' is the size in bytes of the RSA modulus desired. +``e'' is the encryption exponent desired, typical values are 3, 17, 257 and 65537. I suggest you stick with 65537 since its big +enough to prevent trivial math attacks and not super slow. ``key'' is where the key is placed. All keys must be at +least 128 bytes and no more than 512 bytes in size (that is from 1024 to 4096 bits). + +Note that the ``rsa\_make\_key()'' function allocates memory at runtime when you make the key. Make sure to call +``rsa\_free()'' (see below) when you are finished with the key. If ``rsa\_make\_key()'' fails it will automatically +free the ram allocated itself. + +There are three types of RSA keys. The types are {\bf PK\_PRIVATE\_OPTIMIZED}, {\bf PK\_PRIVATE} and {\bf PK\_PUBLIC}. The first +two are private keys where the ``optimized'' type uses the Chinese Remainder Theorem to speed up decryption/signatures. By +default all new keys are of the ``optimized'' type. The non-optimized private type is provided for backwards compatibility +as well as to save space since the optimized key requires about four times as much memory. + +To do raw work with the RSA function call: +\index{rsa\_exptmod()} +\begin{verbatim} +int rsa_exptmod(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + int which, rsa_key *key); +\end{verbatim} +This loads the bignum from ``in'' as a big endian word, raises it to either ``e'' or ``d'' and stores the result +in ``out'' and the size of the result in ``outlen''. ``which'' is set to {\bf PK\_PUBLIC} to use ``e'' +(i.e. for encryption/verifying) and set to {\bf PK\_PRIVATE} to use ``d'' as the exponent (i.e. for decrypting/signing). + +\section{Packet Routines} +The remaining RSA functions are non-standard but should (to the best of my knowledge) be secure if used correctly. To +encrypt a buffer of memory in a hybrid fashion call: +\index{rsa\_encrypt()} +\begin{verbatim} +int rsa_encrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, int cipher, + rsa_key *key); +\end{verbatim} +This will encrypt the message with the cipher specified by ``cipher'' under a random key made by a PRNG specified by +``wprng'' and RSA encrypt the symmetric key with ``key''. This stores all the relevant information in ``out'' and sets +the length in ``outlen''. You must ensure that ``outlen'' is set to the buffer size before calling this. + +The rsa\_encrypt() function will use up to a 256-bit symmetric key (limited by the max key length of the cipher being +used). To decrypt packets made by this routine call: +\index{rsa\_decrypt()} +\begin{verbatim} +int rsa_decrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + rsa_key *key); +\end{verbatim} +Which works akin to rsa\_encrypt(). ``in'' is the ciphertext and ``out'' is where the plaintext will be stored. Similarly +to sign/verify there are: +\index{rsa\_sign()} \index{rsa\_verify()} +\begin{verbatim} +int rsa_sign(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + int hash, rsa_key *key); + +int rsa_verify(const unsigned char *sig, + const unsigned char *msg, + unsigned long inlen, int *stat, + rsa_key *key); +\end{verbatim} + +The verify function sets ``stat'' to 1 if it passes or to 0 if it fails. The ``sig'' parameter is the output of the +rsa\_sign() function and ``msg'' is the original msg that was signed. An important fact to note is that with +the padding scheme used in ``rsa\_sign()'' you cannot use the SHA-384 or SHA-512 hash function with 1024 bit +RSA keys. This is because the padding makes the values too large to fit in the space allowed. You can use SHA-384 +with 1160 and above bit RSA keys. You can use SHA-512 with 1544 and above bit RSA keys. + +There are related functions to sign and verify hashes. +\begin{verbatim} +int rsa_sign_hash(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + rsa_key *key); + +int rsa_verify_hash(const unsigned char *sig, const unsigned char *hash, + int *stat, rsa_key *key); +\end{verbatim} +Which works just like the two previous functions except the data is not hashed before being signed. + +There are times where you may want to encrypt a message to multiple recipients via RSA public keys. The simplest way to +accomplish this is to make up your own symmetric key and then RSA encrypt the symmetric key using all of the recipients +public keys. To facilitate this task two functions\footnote{Donated by Clay Culver.} are available: +\begin{verbatim} +int rsa_encrypt_key(const unsigned char *inkey, unsigned long inlen, + unsigned char *outkey, unsigned long *outlen, + prng_state *prng, int wprng, rsa_key *key); + +int rsa_decrypt_key(const unsigned char *in, unsigned char *outkey, + unsigned long *keylen, rsa_key *key); +\end{verbatim} + +The ``rsa\_encrypt\_key()'' function accepts a symmetric key (limited to 32 bytes) as input in ``inkey''. ``inlen'' +is the size of the input key in bytes. The function will then ``rsa\_pad()'' the key and encrypt it using the RSA +algorithm. It will store the result in ``outkey'' along with the length in ``outlen''. The ``rsa\_decrypt\_key()'' function +performs the opposite. The ``in'' variable is where the RSA packet goes and it will store the original symmetric key in +the ``outkey'' variable along with its length in ``keylen''. + +To import/export RSA keys as a memory buffer (e.g. to store them to disk) call: +\begin{verbatim} +int rsa_export(unsigned char *out, unsigned long *outlen, + int type, rsa_key *key); + +int rsa_import(const unsigned char *in, rsa_key *key); +\end{verbatim} + +The ``type'' parameter is {\bf PK\_PUBLIC}, {\bf PK\_PRIVATE} or {\bf PK\_PRIVATE\_OPTIMIZED} to export either a public or +private key. The latter type will export a key with the optimized parameters. To free the memory used by an RSA key call: +\index{rsa\_free()} +\begin{verbatim} +void rsa_free(rsa_key *key); +\end{verbatim} + +Note that if the key fails to ``rsa\_import()'' you do not have to free the memory allocated for it. + +\section{Remarks} +It is important that you match your RSA key size with the function you are performing. The internal padding for both +signatures and encryption triple the size of the plaintext you send to rsa\_exptmod(). This means to encrypt or sign +a message of N bytes with rsa\_exptmod() you must have a modulus of 1+3N bytes. Note that this doesn't affect the length +of the plaintext you pass into functions like rsa\_encrypt(). This restriction applies only to data that is passed through +RSA directly. + +The following table gives the size requirements for various hashes. +\begin{center} +\begin{tabular}{|c|c|c|} + \hline Name & Size of Message Digest (bytes) & RSA Key Size (bits)\\ + \hline SHA-512 & 64 & 1544\\ + \hline SHA-384 & 48 & 1160 \\ + \hline SHA-256 & 32 & 776\\ + \hline TIGER-192 & 24 & 584\\ + \hline SHA-1 & 20 & 488\\ + \hline MD5 & 16 & 392\\ + \hline MD4 & 16 & 392\\ + \hline +\end{tabular} +\end{center} + +The symmetric ciphers will use at a maximum a 256-bit key which means at the least a 776-bit RSA key is +required to use all of the symmetric ciphers with the RSA routines. It is suggested that you make keys that +are at a minimum 1024 bits in length. If you want to use any of the large size message digests +(SHA-512 or SHA-384) you will have to use a larger key. + +\chapter{Diffie-Hellman Key Exchange} + +\section{Background} + +Diffie-Hellman was the original public key system proposed. The system is based upon the group structure +of finite fields. For Diffie-Hellman a prime $p$ is chosen and a ``base'' $b$ such that $b^x\mbox{ }(\mbox{mod }p)$ +generates a large sub-group of prime order (for unique values of $x$). + +A secret key is an exponent $x$ and a public key is the value of $y \equiv g^x\mbox{ }(\mbox{mod }p)$. The term +``discrete logarithm'' denotes the action of finding $x$ given only $y$, $g$ and $p$. The key exchange part of +Diffie-Hellman arises from the fact that two users A and B with keys $(A_x, A_y)$ and $(B_x, B_y)$ can exchange +a shared key $K \equiv B_y^{A_x} \equiv A_y^{B_x} \equiv g^{A_xB_x}\mbox{ }(\mbox{mod }p)$. + +From this public encryption and signatures can be developed. The trivial way to encrypt (for example) using a public key +$y$ is to perform the key exchange offline. The sender invents a key $k$ and its public copy +$k' \equiv g^k\mbox{ }(\mbox{mod }p)$ and uses $K \equiv k'^{A_x}\mbox{ }(\mbox{mod }p)$ as a key to encrypt +the message with. Typically $K$ would be sent to a one-way hash and the message digested used as a key in a +symmetric cipher. + +It is important that the order of the sub-group that $g$ generates not only be large but also prime. There are +discrete logarithm algorithms that take $\sqrt r$ time given the order $r$. The discrete logarithm can be computed +modulo each prime factor of $r$ and the results combined using the Chinese Remainder Theorem. In the cases where +$r$ is ``B-Smooth'' (e.g. all small factors or powers of small prime factors) the solution is trivial to find. + +To thwart such attacks the primes and bases in the library have been designed and fixed. Given a prime $p$ the order of + the sub-group generated is a large prime namely ${p - 1} \over 2$. Such primes are known as ``strong primes'' and the +smaller prime (e.g. the order of the base) are known as Sophie-Germaine primes. + +\section{Core Functions} + +This library also provides core Diffie-Hellman functions so you can negotiate keys over insecure mediums. The routines +provided are relatively easy to use and only take two function calls to negotiate a shared key. There is a structure +called ``dh\_key'' which stores the Diffie-Hellman key in a format these routines can use. The first routine is to +make a Diffie-Hellman private key pair: +\index{dh\_make\_key()} +\begin{verbatim} +int dh_make_key(prng_state *prng, int wprng, + int keysize, dh_key *key); +\end{verbatim} +The ``keysize'' is the size of the modulus you want in bytes. Currently support sizes are 64 to 512 bytes which correspond +to key sizes of 512 to 4096 bits. The smaller the key the faster it is to use however it will be less secure. When +specifying a size not explicitly supported by the library it will round {\em up} to the next key size. If the size is +above 512 it will return an error. So if you pass ``keysize == 32'' it will use a 512 bit key but if you pass +``keysize == 20000'' it will return an error. The primes and generators used are built-into the library and were designed +to meet very specific goals. The primes are strong primes which means that if $p$ is the prime then +$p-1$ is equal to $2r$ where $r$ is a large prime. The bases are chosen to generate a group of order $r$ to prevent +leaking a bit of the key. This means the bases generate a very large prime order group which is good to make cryptanalysis +hard. + +As for Diffie-Hellman key sizes its recommended that you use at least a 768-bit key. Since a 512-bit key has never been broken (its much +harder than 512-bit RSA to attack) a 512-bit key setting is supported. You can use it if you want I just suggest you don't. + +The next two routines are for exporting/importing Diffie-Hellman keys in a binary format. This is useful for transport +over communication mediums. + +\index{dh\_export()} \index{dh\_import()} +\begin{verbatim} +int dh_export(unsigned char *out, unsigned long *outlen, + int type, dh_key *key); + +int dh_import(const unsigned char *in, dh_key *key); +\end{verbatim} + +These two functions work just like the ``rsa\_export()'' and ``rsa\_import()'' functions except these work with +Diffie-Hellman keys. Its important to note you do not have to free the ram for a ``dh\_key'' if an import fails. You can free a +``dh\_key'' using: +\begin{verbatim} +void dh_free(dh_key *key); +\end{verbatim} +After you have exported a copy of your public key (using {\bf PK\_PUBLIC} as ``type'') you can now create a shared secret +with the other user using: +\index{dh\_shared\_secret()} +\begin{verbatim} +int dh_shared_secret(dh_key *private_key, + dh_key *public_key, + unsigned char *out, unsigned long *outlen); +\end{verbatim} + +Where ``private\_key'' is the key you made and ``public\_key'' is the copy of the public key the other user sent you. The result goes +into ``out'' and the length into ``outlen''. If all went correctly the data in ``out'' should be identical for both parties. It is important to +note that the two keys have to be the same size in order for this to work. There is a function to get the size of a +key: +\index{dh\_get\_size()} +\begin{verbatim} +int dh_get_size(dh_key *key); +\end{verbatim} +This returns the size in bytes of the modulus chosen for that key. + +\subsection{Remarks on Usage} +Its important that you hash the shared key before trying to use it as a key for a symmetric cipher or something. An +example program that communicates over sockets, using MD5 and 1024-bit DH keys is\footnote{This function is a small example. It is suggested that proper packaging be used. For example, if the public key sent is truncated these routines will not detect that.}: +\newpage +\begin{small} +\begin{verbatim} +int establish_secure_socket(int sock, int mode, unsigned char *key, + prng_state *prng, int wprng) +{ + unsigned char buf[4096], buf2[4096]; + unsigned long x, len; + int res, errno; + dh_key mykey, theirkey; + + /* make up our private key */ + if ((errno = dh_make_key(prng, wprng, 128, &mykey)) != CRYPT_OK) { + return errno; + } + + /* export our key as public */ + x = sizeof(buf); + if ((errno = dh_export(buf, &x, PK_PUBLIC, &mykey)) != CRYPT_OK) { + res = errno; + goto done2; + } + + if (mode == 0) { + /* mode 0 so we send first */ + if (send(sock, buf, x, 0) != x) { + res = CRYPT_ERROR; + goto done2; + } + + /* get their key */ + if (recv(sock, buf2, sizeof(buf2), 0) <= 0) { + res = CRYPT_ERROR; + goto done2; + } + } else { + /* mode >0 so we send second */ + if (recv(sock, buf2, sizeof(buf2), 0) <= 0) { + res = CRYPT_ERROR; + goto done2; + } + + if (send(sock, buf, x, 0) != x) { + res = CRYPT_ERROR; + goto done2; + } + } + + if ((errno = dh_import(buf2, &theirkey)) != CRYPT_OK) { + res = errno; + goto done2; + } + + /* make shared secret */ + x = sizeof(buf); + if ((errno = dh_shared_secret(&mykey, &theirkey, buf, &x)) != CRYPT_OK) { + res = errno; + goto done; + } + + /* hash it */ + len = 16; /* default is MD5 so "key" must be at least 16 bytes long */ + if ((errno = hash_memory(find_hash("md5"), buf, x, key, &len)) != CRYPT_OK) { + res = errno; + goto done; + } + + /* clean up and return */ + res = CRYPT_OK; +done: + dh_free(&theirkey); +done2: + dh_free(&mykey); + zeromem(buf, sizeof(buf)); + zeromem(buf2, sizeof(buf2)); + return res; +} +\end{verbatim} +\end{small} +\newpage +\subsection{Remarks on The Snippet} +When the above code snippet is done (assuming all went well) their will be a shared 128-bit key in the ``key'' array +passed to ``establish\_secure\_socket()''. + +\section{Other Diffie-Hellman Functions} +In order to test the Diffie-Hellman function internal workings (e.g. the primes and bases) their is a test function made +available: +\index{dh\_test()} +\begin{verbatim} +int dh_test(void); +\end{verbatim} + +This function returns {\bf CRYPT\_OK} if the bases and primes in the library are correct. There is one last helper +function: +\index{dh\_sizes()} +\begin{verbatim} +void dh_sizes(int *low, int *high); +\end{verbatim} +Which stores the smallest and largest key sizes support into the two variables. + +\section{DH Packet} +There are routines to perform the work similar to that of ``rsa\_encrypt()'' and ``rsa\_decrypt()'' for DH keys as well. +The encrypt routine will make up a random key, attach the public key to the message and used the shared secret to encrypt +the message with a cipher you choose (and hash the shared secret into a symmetric key with a hash you choose). The encrypt +function is a bit long to call but its worth it. +\index{dh\_encrypt()} +\begin{verbatim} +int dh_encrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, int cipher, int hash, + dh_key *key); +\end{verbatim} +Where ``in'' is the plaintext and ``out'' is where the ciphertext will go. Make sure you set the ``outlen'' value before +calling. The ``key'' is the public DH key of the user you want to encrypt to not your private key. It will randomly make up +a Diffie-Hellman key, export the public copy, hash the shared key with the hash you specify and use the message digest in a +cipher you specify to encrypt the message. To decrypt one of these packets call: +\index{dh\_decrypt()} +\begin{verbatim} +int dh_decrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + dh_key *key); +\end{verbatim} +Where ``in'' is the ciphertext and len is the length of the ciphertext. ``out'' is where the plaintext should be stored +and ``outlen'' is the length of the output (you must first set it to the size of your buffer). + +To facilate encrypting to multiple parties the follow two functions are provided: +\begin{verbatim} +int dh_encrypt_key(const unsigned char *inkey, unsigned long keylen, + unsigned char *out, unsigned long *len, + prng_state *prng, int wprng, int hash, + dh_key *key); + +int dh_decrypt_key(const unsigned char *in, unsigned char *outkey, + unsigned long *keylen, dh_key *key); +\end{verbatim} +Where ``inkey'' is an input symmetric key of no more than 32 bytes. Essentially these routines created a random public key +and find the hash of the shared secret. The message digest is than XOR'ed against the symmetric key. All of the required +data is placed in ``out'' by ``dh\_encrypt\_key()''. The hash must produce a message digest at least as large +as the symmetric key you are trying to share. + +To sign with a Diffie-Hellman key call: +\index{dh\_sign()} +\begin{verbatim} +int dh_sign(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, int hash, + prng_state *prng, int wprng, dh_key *key); +\end{verbatim} +Where ``in'' is the message to size of length ``inlen'' bytes. ``out'' is where the signature is placed and ``outlen'' +is the length of the signature (you must first set it to the size of your buffer). To verify call: +\index{dh\_verify()} +\begin{verbatim} +int dh_verify(const unsigned char *sig, + const unsigned char *msg, + unsigned long inlen, int *stat, dh_key *key); +\end{verbatim} +Where ``sig'' is the output of ''dh\_sign()`` and ``msg'' is the message of length ``inlen''. It stores a zero in ``stat'' +if the signature is invalid otherwise it puts a one in there. + +Similar to the RSA system you can sign and verify a pre-hashed block as well using: +\begin{verbatim} +int dh_sign_hash(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, dh_key *key); + +int dh_verify_hash(const unsigned char *sig, const unsigned char *hash, + unsigned long inlen, int *stat, + dh_key *key); +\end{verbatim} + +\chapter{Elliptic Curve Cryptography} + +\section{Background} +The library provides a set of core ECC functions as well that are designed to be the Elliptic Curve analogy of all of the +Diffie-Hellman routines in the previous chapter. Elliptic curves (of certain forms) have the benefit that they are harder +to attack (no sub-exponential attacks exist unlike normal DH crypto) in fact the fastest attack requires the square root +of the order of the base point in time. That means if you use a base point of order $2^{192}$ (which would represent a +192-bit key) then the work factor is $2^{96}$ in order to find the secret key. + +The curves in this library are taken from the following website: +\begin{verbatim} +http://csrc.nist.gov/cryptval/dss.htm +\end{verbatim} + +They are all curves over the integers modulo a prime. The curves have the basic equation that is: +\begin{equation} +y^2 = x^3 - 3x + b\mbox{ }(\mbox{mod }p) +\end{equation} + +The variable $b$ is chosen such that the number of points is nearly maximal. In fact the order of the base points $\beta$ +provided are very close to $p$ that is $\vert \vert \phi(\beta) \vert \vert \approx \vert \vert p \vert \vert$. The curves +range in order from $\approx 2^{192}$ points to $\approx 2^{521}$. According to the source document any key size greater +than or equal to 256-bits is sufficient for long term security. + +\section{Core Functions} + +Like the DH routines there is a key structure ``ecc\_key'' used by the functions. There is a function to make a key: +\index{ecc\_make\_key()} +\begin{verbatim} +int ecc_make_key(prng_state *prng, int wprng, + int keysize, ecc_key *key); +\end{verbatim} + +The ``keysize'' is the size of the modulus in bytes desired. Currently directly supported values are 20, 24, 28, 32, 48 and 65 bytes which +correspond to key sizes of 160, 192, 224, 256, 384 and 521 bits respectively. If you pass a key size that is between any key size +it will round the keysize up to the next available one. The rest of the parameters work like they do in the ``dh\_make\_key()'' function. +To free the ram allocated by a key call: +\index{ecc\_free()} +\begin{verbatim} +void ecc_free(ecc_key *key); +\end{verbatim} + +To import and export a key there are: +\index{ecc\_export()} +\index{ecc\_import()} +\begin{verbatim} +int ecc_export(unsigned char *out, unsigned long *outlen, + int type, ecc_key *key); + +int ecc_import(const unsigned char *in, ecc_key *key); +\end{verbatim} +These two work exactly like there DH counterparts. Finally when you share your public key you can make a shared secret +with: +\index{ecc\_shared\_secret()} +\begin{verbatim} +int ecc_shared_secret(ecc_key *private_key, + ecc_key *public_key, + unsigned char *out, unsigned long *outlen); +\end{verbatim} +Which works exactly like the DH counterpart, the ``private\_key'' is your own key and ``public\_key'' is the key the other +user sent you. Note that this function stores both $x$ and $y$ co-ordinates of the shared +elliptic point. You should hash the output to get a shared key in a more compact and useful form (most of the entropy is +in $x$ anyways). Both keys have to be the same size for this to work, to help there is a function to get the size in bytes + of a key. +\index{ecc\_get\_size()} +\begin{verbatim} +int ecc_get_size(ecc_key *key); +\end{verbatim} + +To test the ECC routines and to get the minimum and maximum key sizes there are these two functions: +\index{ecc\_test()} +\begin{verbatim} +int ecc_test(void); +void ecc_sizes(int *low, int *high); +\end{verbatim} +Which both work like their DH counterparts. + +\section{ECC Packet} +There are routines to perform the work similar to that of ``rsa\_encrypt()'' and ``rsa\_decrypt()'' for ECC keys as well. +The encrypt routine will make up a random key, attach the public key to the message and used the shared secret to encrypt +the message with a cipher you choose (and hash the shared secret into a symmetric key with a hash you choose). The encrypt +function is a bit long to call but its worth it. +\index{ecc\_encrypt()} +\begin{verbatim} +int ecc_encrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + prng_state *prng, + int wprng, int cipher, int hash, + ecc_key *key); +\end{verbatim} +Where ``in'' is the plaintext and ``out'' is where the ciphertext will go. Make sure you set the ``outlen'' value before +calling. The ``key'' is the public ECC key of the user you want to encrypt too. To decrypt one of these packets call: +\index{ecc\_decrypt()} +\begin{verbatim} +int ecc_decrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + ecc_key *key); +\end{verbatim} +Similar to the DH code there are two functions to facilate multi-party code. They work exactly like the DH code and are +given as: +\begin{verbatim} +int ecc_encrypt_key(const unsigned char *inkey, unsigned long keylen, + unsigned char *out, unsigned long *len, + prng_state *prng, int wprng, int hash, + ecc_key *key); + +int ecc_decrypt_key(const unsigned char *in, unsigned char *outkey, + unsigned long *keylen, ecc_key *key); +\end{verbatim} +You can sign messages with the ECC routines as well, to sign a message call: +\index{ecc\_sign()} +\begin{verbatim} +int ecc_sign(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + int hash, prng_state *prng, int wprng, + ecc_key *key); +\end{verbatim} +Where ``in'' is the message to sign and ``out'' is where the signature will go. ``hash'' is the index into the descriptor +table of which hash function you want to use (e.g. use ``find\_hash()''). You must set ``outlen'' to the size of the +output buffer before calling. To verify a signature call: +\index{ecc\_verify()} +\begin{verbatim} +int ecc_verify(const unsigned char *sig, const unsigned char *msg, + unsigned long inlen, int *stat, ecc_key *key); +\end{verbatim} +Where ``sig'' is the signature from ``ecc\_sign()'' and ``msg'' is the input message. It sets ``stat'' to 0 if the signature +is invalid and it sets ``stat'' to 1 if its valid. To sign or verify pre-hashed blocks use +\begin{verbatim} +int ecc_sign_hash(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, ecc_key *key); + +int ecc_verify_hash(const unsigned char *sig, const unsigned char *hash, + unsigned long inlen, int *stat, + ecc_key *key); +\end{verbatim} + +\chapter{Public Keyrings} +\section{Introduction} +In order to simplify the usage of the public key algorithms a set of keyring routines have been developed. They let the +developer manage asymmetric keys by providing load, save, export, import routines as well as encrypt, decrypt, sign, verify +routines in a unified API. That is all three types of PK systems can be used within the same keyring with the same API. + +To define types of keys there are four enumerations used globaly: +\begin{verbatim} +enum { + NON_KEY=0, + RSA_KEY, + DH_KEY, + ECC_KEY +}; +\end{verbatim} + +To make use of the system the developer has to know how link-lists work. The main structure that the keyring routines use +is the ``pk\_key'' defined as: +\begin{small} +\begin{verbatim} +typedef struct Pk_key { + int key_type, /* PUBLIC, PRIVATE, PRIVATE_OPTIMIZED */ + system; /* RSA, ECC or DH ? */ + + char name[MAXLEN], /* various info's about this key */ + email[MAXLEN], + description[MAXLEN]; + + unsigned long ID; /* CRC32 of the name/email/description together */ + + _pk_key key; + + struct Pk_key *next; /* linked list chain */ +} pk_key; +\end{verbatim} +\end{small} + +The list is chained via the ``next'' member and terminated with the node of the list that has ``system'' equal to +{\bf NON\_KEY}. + +\section{The Keyring API} +To initialize a blank keyring the function ``kr\_init()'' is used. +\begin{verbatim} +int kr_init(pk_key **pk); +\end{verbatim} +You pass it a pointer to a pointer of type ``pk\_key'' where it will allocate ram for one node of the keyring and sets the +pointer. + +Now instead of calling the PK specific ``make\_key'' functions there is one function that can make all three types of keys. +\begin{verbatim} +int kr_make_key(pk_key *pk, prng_state *prng, int wprng, + int system, int keysize, const char *name, + const char *email, const char *description); +\end{verbatim} +The ``name'', ``email'' and ``description'' parameters are simply little pieces of information that you can tag along with a +key. They can each be either blank or any string less than 256 bytes. ``system'' is one of the enumeration elements, that +is {\bf RSA\_KEY}, {\bf DH\_KEY} or {\bf ECC\_KEY}. ``keysize'' is the size of the key you desire which is regulated by +the individual systems, for example, RSA keys are limited in keysize from 128 to 512 bytes. + +To find keys along a keyring there are two functions provided: +\begin{verbatim} +pk_key *kr_find(pk_key *pk, unsigned long ID); + +pk_key *kr_find_name(pk_key *pk, const char *name); +\end{verbatim} +The first searches by the 32-bit ID provided and the latter checks the name against the keyring. They both return a pointer +to the node in the ring of a match or {\bf NULL} if no match is found. + +To export or import a single node of a keyring the two functions are provided: +\begin{verbatim} +int kr_export(pk_key *pk, unsigned long ID, int key_type, + unsigned char *out, unsigned long *outlen); + +int kr_import(pk_key *pk, const unsigned char *in); +\end{verbatim} +The export function exports the key with an ID provided and of a specific type much like the normal PK export routines. The +``key\_type'' is one of {\bf PK\_PUBLIC} or {\bf PK\_PRIVATE}. In this function with RSA keys the type +{\bf PK\_PRIVATE\_OPTIMIZED} is the same as the {\bf PK\_PRIVATE} type. The import function will read in a packet and +add it to the keyring. + +To load and save whole keyrings from disk: +\begin{verbatim} +int kr_load(pk_key **pk, FILE *in, symmetric_CTR *ctr); + +int kr_save(pk_key *pk, FILE *out, symmetric_CTR *ctr); +\end{verbatim} +Both take file pointers to allow the user to pre-append data to the stream. The ``ctr'' parameter should be setup with +``ctr\_start'' or set to NULL. This parameter lets the user encrypt the keyring as its written to disk, if it is set +to NULL the data is written without being encrypted. The load function assumes the list has not been initialized yet +and will reset the pointer given to it. + +There are the four encrypt, decrypt, sign and verify functions as well +\begin{verbatim} +int kr_encrypt_key(pk_key *pk, unsigned long ID, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, int hash); + +int kr_decrypt_key(pk_key *pk, const unsigned char *in, + unsigned char *out, unsigned long *outlen); +\end{verbatim} + +The kr\_encrypt\_key() routine is designed to encrypt a symmetric key with a specified users public key. The symmetric +key is then used with a block cipher to encode the message. The recipient can call kr\_decrypt\_key() to get the original +symmetric key back and decode the message. The hash specified must produce a message digest longer than symmetric key +provided. + +\begin{verbatim} +int kr_sign_hash(pk_key *pk, unsigned long ID, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng); + +int kr_verify_hash(pk_key *pk, const unsigned char *in, + const unsigned char *hash, unsigned long hashlen, + int *stat); +\end{verbatim} + +Similar to the two previous these are used to sign a message digest or verify one. This requires hashing the message +first then passing the output in. + +To delete keys and clear rings there are: +\begin{verbatim} +int kr_del(pk_key **_pk, unsigned long ID); +int kr_clear(pk_key **pk); +\end{verbatim} +``kr\_del'' will try to remove a key with a given ID from the ring and ``kr\_clear'' will completely empty a list and free +the memory associated with it. Below is small example using the keyring API: + +\begin{small} +\begin{verbatim} +#include +int main(void) +{ + pk_key *kr; + unsigned char buf[4096], buf2[4096]; + unsigned long len; + int errno; + + /* make a new list */ + if ((errno = kr_init(&kr)) != CRYPT_OK) { + printf("kr_init: %s\n", error_to_string(errno)); + exit(-1); + } + + /* add a key to it */ + register_prng(&sprng_desc); + if ((errno = kr_make_key(kr, NULL, find_prng("sprng"), RSA_KEY, 128, + "TomBot", "tomstdenis@yahoo.com", "test key")) == CRYPT_OK) { + printf("kr_make_key: %s\n", error_to_string(errno)); + exit(-1); + } + + /* export the first key */ + len = sizeof(buf); + if ((errno = kr_export(kr, kr->ID, PK_PRIVATE, buf, &len)) != CRYPT_OK) { + printf("kr_export: %s\n", error_to_string(errno)); + exit(-1); + } + + /* ... */ +} +\end{verbatim} +\end{small} + +\chapter{$GF(2^w)$ Math Routines} + +The library provides a set of polynomial-basis $GF(2^w)$ routines to help facilitate algorithms such as ECC over such +fields. Note that the current implementation of ECC in the library is strictly over the integers only. The routines +are simple enough to use for other purposes outside of ECC. + +At the heart of all of the GF routines is the data type ``gf\_int'. It is simply a type definition for an array of +$L$ 32-bit words. You can configure the maximum size $L$ of the ``gf\_int'' type by opening the file ``mycrypt.h'' and +changing ``LSIZE''. Note that if you set it to $n$ then you can only multiply upto two $n \over 2$ bit polynomials without +an overflow. The type ``gf\_intp'' is associated with a pointer to an ``unsigned long'' as required in the algorithms. + +There are no initialization routines for ``gf\_int'' variables and you can simply use them after declaration. There are five +low level functions: +\index{gf\_copy()} \index{gf\_zero()} \index{gf\_iszero()} \index{gf\_isone()} +\index{gf\_deg()} +\begin{verbatim} +void gf_copy(gf_intp a, gf_intp b); +void gf_zero(gf_intp a); +int gf_iszero(gf_intp a); +int gf_isone(gf_intp a); +int gf_deg(gf_intp a); +\end{verbatim} +There are all fairly self-explanatory. ``gf\_copy(a, b)'' copies the contents of ``a'' into ``b''. ``gf\_zero()'' simply +zeroes the entire polynomial. ``gf\_iszero()'' tests to see if the polynomial is all zero and ``gf\_isone()'' tests to see +if the polynomial is equal to the multiplicative identity. ``gf\_deg()'' returns the degree of the polynomial or $-1$ if its +a zero polynomial. + +There are five core math routines as well: +\index{gf\_shl()} \index{gf\_shr()} \index{gf\_add()} \index{gf\_mul()} \index{gf\_div()} +\begin{verbatim} +void gf_shl(gf_intp a, gf_intp b); +void gf_shr(gf_intp a, gf_intp b); +void gf_add(gf_intp a, gf_intp b, gf_intp c); +void gf_mul(gf_intp a, gf_intp b, gf_intp c); +void gf_div(gf_intp a, gf_intp b, gf_intp q, gf_intp r); +\end{verbatim} + +Which are all fairly obvious. ``gf\_shl(a,b)'' multiplies the polynomial ``a'' by $x$ and stores it in ``b''. +``gf\_shl(a,b)'' divides the polynomial ``a'' by $x$ and stores it in ``b''. ``gf\_add(a,b,c)'' adds the polynomial +``a'' to ``b'' and stores the sum in ``c''. Similarly for ``gf\_mul(a,b,c)''. The ``gf\_div(a,b,q,r)'' function divides +``a'' by ``b'' and stores the quotient in ``q'' and the remainder in ``r''. + +There are six number theoretic functions as well: +\index{gf\_mod()} \index{gf\_mulmod()} \index{gf\_invmod()} \index{gf\_gcd()} \index{gf\_is\_prime()} +\index{gf\_sqrt()} +\begin{verbatim} +void gf_mod(gf_intp a, gf_intp m, gf_intp b); +void gf_mulmod(gf_intp a, gf_intp b, gf_intp m, gf_intp c); +void gf_invmod(gf_intp A, gf_intp M, gf_intp B); +void gf_sqrt(gf_intp a, gf_intp m, gf_intp b); +void gf_gcd(gf_intp A, gf_intp B, gf_intp c); +int gf_is_prime(gf_intp a); +\end{verbatim} + +Which all work similarly except for ``gf\_mulmod(a,b,m,c)'' which computes $c = ab\mbox{ }(\mbox{mod }m)$. The +``gf\_is\_prime()'' function returns one if the polynomial is primitive, otherwise it returns zero. + +Finally to read/store a ``gf\_int'' in a binary string use: +\index{gf\_size()} \index{gf\_toraw()} \index{gf\_readraw()} +\begin{verbatim} +int gf_size(gf_intp a); +void gf_toraw(gf_intp a, unsigned char *dst); +void gf_readraw(gf_intp a, unsigned char *str, int len); +\end{verbatim} +Where ``gf\_size()'' returns the size in bytes required for the data. ``gf\_toraw(a,b)'' stores the polynomial in ``b'' +in binary format (endian neutral). ``gf\_readraw(a,b,c)'' reads the binary string in ``b'' back. Note that the length +you pass it must be the same as returned by ``gf\_size()'' or it will not load correctly. + +\chapter{Miscellaneous} +\section{Base64 Encoding and Decoding} +The library provides functions to encode and decode a RFC1521 base64 coding scheme. This means that it can decode what it +encodes but the format used does not comply to any known standard. The characters used in the mappings are: +\begin{verbatim} +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ +\end{verbatim} +Those characters should are supported in virtually any 7-bit ASCII system which means they can be used for transport over +common e-mail, usenet and HTTP mediums. The format of an encoded stream is just a literal sequence of ASCII characters +where a group of four represent 24-bits of input. The first four chars of the encoders output is the length of the +original input. After the first four characters is the rest of the message. + +Often it is desirable to line wrap the output to fit nicely in an e-mail or usenet posting. The decoder allows you to +put any character (that is not in the above sequence) in between any character of the encoders output. You may not however, +break up the first four characters. + +To encode a binary string in base64 call: +\index{base64\_encode()} \index{base64\_decode()} +\begin{verbatim} +int base64_encode(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen); +\end{verbatim} +Where ``in'' is the binary string and ``out'' is where the ASCII output is placed. You must set the value of ``outlen'' prior +to calling this function and it sets the length of the base64 output in ``outlen'' when it is done. To decode a base64 +string call: +\begin{verbatim} +int base64_decode(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen); +\end{verbatim} + +\section{The Multiple Precision Integer Library (MPI)} +The library comes with a copy of Michael Fromberger's\footnote{Michael J. Fromberger, sting@linguist.Thayer.dartmouth.edu} multiple +precision integer library MPI. MPI is a trivial to use ANSI C compatible large integer library. It is free for all uses and +is distributed freely. + +At the heart of all MPI functions is the data type ``mp\_int'' (defined in mpi.h). This data type is what will hold all large +integers. In order to use an mp\_int one must initialize it first, for example: +\begin{verbatim} +#include /* mycrypt.h includes mpi.h automatically */ +int main(void) +{ + mp_int bignum; + + /* initialize it */ + mp_init(&bignum); + + return 0; +} +\end{verbatim} +If you are unfamiliar with the syntax of C the \& symbol is used to pass the address of ``bignum'' to the function. All +MPI functions require the address of the parameters. To free the memory of a mp\_int use (for example): +\begin{verbatim} +mp_clear(&bignum); +\end{verbatim} + +All MPI functions have the basic form of one of the following: +\begin{verbatim} +mp_XXX(mp_int *a); +mp_XXX(mp_int *a, mp_int *b, mp_int *c); +mp_XXX(mp_int *a, mp_int *b, mp_int *c, mp_int *d); +\end{verbatim} + +Where they perform some operation and store the result in the mp\_int variable passed on the far right. For example, to +compute $c = a + b \mbox{ }(\mbox{mod }m)$ you would call: +\begin{verbatim} +mp_addmod(&a, &b, &m, &c); +\end{verbatim} + +The simplest way to get a complete listing of all MPI functions is to open ``mpi.h'' and look. They're all fairly +well documented. + +\subsection{Binary Forms of ``mp\_int'' Variables} + +Often it is required to store a ``mp\_int'' in binary form for transport (e.g. exporting a key, packet encryption, etc.). +MPI includes two functions to help when exporting numbers: +\begin{verbatim} +int mp_raw_size(mp_int *num); +mp_toraw(&num, buf); +\end{verbatim} + +The former function gives the size in bytes of the raw format and the latter function actually stores the raw data. All +``mp\_int'' numbers are stored in big endian form (like PKCS demands) with the first byte being the sign of the number. The +``rsa\_exptmod()'' function differs slightly since it will take the input in the form exactly as PKCS demands (without the +leading sign byte). All other functions include the sign byte (since its much simpler just to include it). The sign byte +must be zero for positive numbers and non-zero for negative numbers. For example, +the sequence: +\begin{verbatim} +00 FF 30 04 +\end{verbatim} +Represents the integer $255 \cdot 256^2 + 48 \cdot 256^1 + 4 \cdot 256^0$ or 16,723,972. + +To read a binary string back into a ``mp\_int'' call: +\begin{verbatim} +mp_read_raw(mp_int *num, unsigned char *str, int len); +\end{verbatim} +Where ``num'' is where to store it, ``str'' is the binary string (including the leading sign byte) and ``len'' is the +length of the binary string. + +\subsection{Primality Testing} +\index{Primality Testing} +The library includes primality testing and random prime functions as well. The primality tester will perform the test in +two phases. First it will perform trial division by the first few primes. Second it will perform sixteen rounds of the +Rabin-Miller primality testing algorithm. If the candidate passes both phases it is declared prime otherwise it is declared +composite. No prime number will fail the two phases but composites can. Each round of the Rabin-Miller algorithm reduces +the probability of a pseudo-prime by $1 \over 4$ therefore after sixteen rounds the probability is no more than +$\left ( { 1 \over 4 } \right )^{16} = 2^{-32}$. Even if a composite did make it through it would most likely cause the +the algorithm trying to use it to fail. For instance, in RSA two primes $p$ and $q$ are required. The order of the +multiplicative sub-group (modulo $pq$) is given as $\phi(pq)$ or $(p - 1)(q - 1)$. The decryption exponent $d$ is found +as $de \equiv 1\mbox{ }(\mbox{mod } \phi(pq))$. If either $p$ or $q$ is composite the value of $d$ will be incorrect and the user +will not be able to sign or decrypt messages at all. Suppose $p$ was prime and $q$ was composite this is just a variation of +the multi-prime RSA. Suppose $q = rs$ for two primes $r$ and $s$ then $\phi(pq) = (p - 1)(r - 1)(s - 1)$ which clearly is +not equal to $(p - 1)(rs - 1)$. + +These are not technically part of the MPI +library\footnote{As written by Michael Fromberger} but this is the best place to document them. To test if a ``mp\_int'' is +prime call: +\begin{verbatim} +int is_prime(mp_int *N, int *result); +\end{verbatim} +This puts a one in ``result'' if the number is probably prime, otherwise it places a zero in it. It is assumed that if +it returns an error that the value in ``result'' is undefined. To make +a random prime call: +\begin{verbatim} +int rand_prime(mp_int *N, unsigned long len, prng_state *prng, int wprng); +\end{verbatim} +Where ``len'' is the size of the prime in bytes ($2 \le len \le 1024$). You can set ``len'' to the negative size you want +to get a prime of the form $p \equiv 3\mbox{ }(\mbox{mod } 4)$. So if you want a 1024-bit prime of this sort pass +``len = -128'' to the function. Upon success it will return {\bf CRYPT\_OK} and ``N'' will contain an integer which +is very likely prime. + +\chapter{Programming Guidelines} + +\section{Secure Pseudo Random Number Generators} +Probably the singal most vulnerable point of any cryptosystem is the PRNG. Without one generating and protecting secrets +would be impossible. The requirement that one be setup correctly is vitally important and to address this point the library +does provide two RNG sources that will address the largest amount of end users as possible. The ``sprng'' PRNG provided +provides and easy to access source of entropy for any application on a *NIX or Windows computer. + +However, when the end user is not on one of these platforms the application developer must address the issue of finding +entropy. This manual is not designed to be a text on cryptography. I would just like to highlight that when you design +a cryptosystem make sure the first problem you solve is getting a fresh source of entropy. + +\section{Preventing Trivial Errors} +Two simple ways to prevent trivial errors is to prevent overflows and to check the return values. All of the functions +which output variable length strings will require you to pass the length of the destination. If the size of your output +buffer is smaller than the output it will report an error. Therefore, make sure the size you pass is correct! + +Also virtually all of the functions return an error code or {\bf CRYPT\_OK}. You should detect all errors as simple +typos or such can cause algorithms to fail to work as desired. + +\section{Registering Your Algorithms} +To avoid linking and other runtime errors it is important to register the ciphers, hashes and PRNGs you intend to use +before you try to use them. This includes any function which would use an algorithm indirectly through a descriptor table. + +A neat bonus to the registry system is that you can add external algorithms that are not part of the library without +having to hack the library. For example, suppose you have a hardware specific PRNG on your system. You could easily +write the few functions required plus a descriptor. After registering your PRNG all of the library functions that +need a PRNG can instantly take advantage of it. + +\section{Key Sizes} + +\subsection{Symmetric Ciphers} +For symmetric ciphers use as large as of a key as possible. For the most part ``bits are cheap'' so using a 256-bit key +is not a hard thing todo. + +\subsection{Assymetric Ciphers} +The following chart gives the work factor for solving a DH/RSA public key using the NFS. The work factor for a key of order +$n$ is estimated to be +\begin{equation} +e^{1.923 \cdot ln(n)^{1 \over 3} \cdot ln(ln(n))^{2 \over 3}} +\end{equation} + +Note that $n$ is not the bit-length but the magnitude. For example, for a 1024-bit key $n = 2^{1024}$. The work required +is: +\begin{center} +\begin{tabular}{|c|c|} + \hline RSA/DH Key Size (bits) & Work Factor ($log_2$) \\ + \hline 512 & 63.92 \\ + \hline 768 & 76.50 \\ + \hline 1024 & 86.76 \\ + \hline 1536 & 103.37 \\ + \hline 2048 & 116.88 \\ + \hline 2560 & 128.47 \\ + \hline 3072 & 138.73 \\ + \hline 4096 & 156.49 \\ + \hline +\end{tabular} +\end{center} + +The work factor for ECC keys is much higher since the best attack is still fully exponentional. Given a key of magnitude +$n$ it requires $\sqrt n$ work. The following table sumarizes the work required: +\begin{center} +\begin{tabular}{|c|c|} + \hline ECC Key Size (bits) & Work Factor ($log_2$) \\ + \hline 160 & 80 \\ + \hline 192 & 96 \\ + \hline 224 & 112 \\ + \hline 256 & 128 \\ + \hline 384 & 192 \\ + \hline 521 & 260.5 \\ + \hline +\end{tabular} +\end{center} + +Using the above tables the following suggestions for key sizes seems appropriate: +\begin{center} +\begin{tabular}{|c|c|c|} + \hline Security Goal & RSA/DH Key Size (bits) & ECC Key Size (bits) \\ + \hline Short term (less than a year) & 1024 & 160 \\ + \hline Short term (less than five years) & 1536 & 192 \\ + \hline Long Term (less than ten years) & 2560 & 256 \\ + \hline +\end{tabular} +\end{center} + +\section{Thread Safety} +The library is not thread safe but several simple precautions can be taken to avoid any problems. The registry functions +such as register\_cipher() are not thread safe no matter what you do. Its best to call them from your programs initializtion +code before threads are initiated. + +The rest of the code uses state variables you must pass it such as hash\_state, hmac\_state, etc. This means that if each +thread has its own state variables then they will not affect each other. This is fairly simple with symmetric ciphers +and hashes. However, the keyring and PRNG support is something the threads will want to share. The simplest workaround +is create semaphores or mutexes around calls to those functions. + +Since C does not have standard semaphores this support is not native to Libtomcrypt. Even a C based semaphore is not entire +possible as some compilers may ignore the ``volatile'' keyword or have multiple processors. Provide your host application +is modular enough putting the locks in the right place should not bloat the code significantly and will solve all thread +safety issues within the library. + +\chapter{Configuring the Library} +\section{Introduction} +The library is fairly flexible about how it can be built, used and generally distributed. Additions are being made with +each new release that will make the library even more flexible. Most options are placed in the makefile and others +are in ``mycrypt\_cfg.h''. All are used when the library is built from scratch. + +For GCC platforms the file ``makefile'' is the makefile to be used. On MSVC platforms ``makefile.vc'' and on PS2 platforms +``makefile.ps2''. + +\section{mycrypt\_cfg.h} +The file ``mycrypt\_cfg.h'' is what lets you control what functionality you want to remove from the library. By default, +everything the library has to offer it built. + +\subsubsection{ARGTYPE} +This lets you control how the \_ARGCHK macro will behave. The macro is used to check pointers inside the functions against +NULL. There are three settings for ARGTYPE. When set to 0 it will have the default behaviour of printing a message to +stderr and raising a SIGABRT signal. This is provided so all platforms that use libtomcrypt can have an error that functions +similarly. When set to 1 it will simply pass on to the assert() macro. When set to 2 it will resolve to a empty macro +and no error checking will be performed. + +\subsubsection{Endianess} +There are five macros related to endianess issues. For little endian platforms define, ENDIAN\_LITTLE. For big endian +platforms define ENDIAN\_BIG. Similarly when the default word size of an ``unsigned long'' is 32-bits define ENDIAN\_32BITWORD +or define ENDIAN\_64BITWORD when its 64-bits. If you do not define any of them the library will automatically use ENDIAN\_NEUTRAL +which will work on all platforms. Currently the system will automatically detect GCC or MSVC on a windows platform as well +as GCC on a PS2 platform. + +\section{The makefile} +There are also options you can specify from the makefiles themselves. + +\subsubsection{X memory routines} +The makefiles must define three macros denoted as XMALLOC, XCALLOC and XFREE which resolve to the name of the respective +functions. This lets you substitute in your own memory routines. If you substitute in your own functions they must behave +like the standard C library functions in terms of what they expect as input and output. By default the library uses the +standard C routines. + +\subsubsection{X clock routines} +The rng\_get\_bytes() function can call a function that requires the clock() function. These macros let you override +the default clock() used with a replacement. By default the standard C library clock() function is used. + +\subsubsection{NO\_FILE} +During the build if NO\_FILE is defined then any function in the library that uses file I/O will not call the file I/O +functions and instead simply return CRYPT\_ERROR. This should help resolve any linker errors stemming from a lack of +file I/O on embedded platforms. + +\subsubsection{CLEAN\_STACK} +When this functions is defined the functions that store key material on the stack will clean up afterwards. Assumes that +you have no memory paging with the stack. + +\subsubsection{Symmetric Ciphers, One-way Hashes, PRNGS and Public Key Functions} +There are a plethora of macros for the ciphers, hashes, PRNGs and public key functions which are fairly self-explanatory. +When they are defined the functionality is included otherwise it is not. There are some dependency issues which are +noted in the file. For instance, Yarrow requires CTR chaining mode, a block cipher and a hash function. + +\subsubsection{TWOFISH\_SMALL and TWOFISH\_TABLES} +Twofish is a 128-bit symmetric block cipher that is provided within the library. The cipher itself is flexible enough +to allow some tradeoffs in the implementation. When TWOFISH\_SMALL is defined the scheduled symmetric key for Twofish +requires only 200 bytes of memory. This is achieved by not pre-computing the substitution boxes. Having this +defined will also greatly slow down the cipher. When this macro is not defined Twofish will pre-compute the +tables at a cost of 4KB of memory. The cipher will be much faster as a result. + +When TWOFISH\_TABLES is defined the cipher will use pre-computed (and fixed in code) tables required to work. This is +useful when TWOFISH\_SMALL is defined as the table values are computed on the fly. When this is defined the code size +will increase by approximately 500 bytes. If this is defined but TWOFISH\_SMALL is not the cipher will still work but +it will not speed up the encryption or decryption functions. + +\subsubsection{SAFERP\_SMALL and RIJNDAEL\_SMALL} +These two build options let you use slower versions of the ciphers which are also much smaller. In the case of the SAFER+ +implementation it ends up being 1/6th the size. As for Rijndael its roughly half the size. + + +\end{document} diff --git a/ctr.c b/ctr.c new file mode 100644 index 0000000..67fc285 --- /dev/null +++ b/ctr.c @@ -0,0 +1,77 @@ +#include "mycrypt.h" + +#ifdef CTR + +int ctr_start(int cipher, const unsigned char *count, const unsigned char *key, int keylen, + int num_rounds, symmetric_CTR *ctr) +{ + int x, errno; + + _ARGCHK(count != NULL); + _ARGCHK(key != NULL); + _ARGCHK(ctr != NULL); + + /* bad param? */ + if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) { + return errno; + } + + /* setup cipher */ + if ((errno = cipher_descriptor[cipher].setup(key, keylen, num_rounds, &ctr->key)) != CRYPT_OK) { + return errno; + } + + /* copy ctr */ + ctr->blocklen = cipher_descriptor[cipher].block_length; + ctr->cipher = cipher; + ctr->padlen = 0; + for (x = 0; x < ctr->blocklen; x++) { + ctr->ctr[x] = count[x]; + } + cipher_descriptor[ctr->cipher].ecb_encrypt(ctr->ctr, ctr->pad, &ctr->key); + return CRYPT_OK; +} + +int ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CTR *ctr) +{ + int x, errno; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(ctr != NULL); + + if ((errno = cipher_is_valid(ctr->cipher)) != CRYPT_OK) { + return errno; + } + + while (len--) { + /* is the pad empty? */ + if (ctr->padlen == ctr->blocklen) { + /* increment counter */ + for (x = 0; x < ctr->blocklen; x++) { + ctr->ctr[x] = (ctr->ctr[x] + 1) & 255; + if (ctr->ctr[x] != 0) { + break; + } + } + + /* encrypt it */ + cipher_descriptor[ctr->cipher].ecb_encrypt(ctr->ctr, ctr->pad, &ctr->key); + ctr->padlen = 0; + } + *ct++ = *pt++ ^ ctr->pad[ctr->padlen++]; + } + return CRYPT_OK; +} + +int ctr_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CTR *ctr) +{ + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(ctr != NULL); + + return ctr_encrypt(ct, pt, len, ctr); +} + +#endif + diff --git a/demos/encrypt.c b/demos/encrypt.c new file mode 100644 index 0000000..de8fd94 --- /dev/null +++ b/demos/encrypt.c @@ -0,0 +1,202 @@ +/* encrypt V1.1 Fri Oct 18 04:28:03 NZDT 2002 */ +/* File de/encryption, using libtomcrypt */ +/* Written by Daniel Richards */ +/* Help from Tom St Denis with various bits */ +/* This code is public domain, no rights reserved. */ +/* Encrypts by default, -d flag enables decryption */ +/* ie: ./encrypt blowfish story.txt story.ct */ +/* ./encrypt -d blowfish story.ct story.pt */ + +#include + +int errno; + +static const struct _cipher_descriptor *ciphers[] = { + &blowfish_desc, &xtea_desc, &rc5_desc, &rc6_desc, + &saferp_desc, &serpent_desc, &rijndael_desc, + &twofish_desc, &safer_k64_desc, &safer_sk64_desc, + &safer_k128_desc, &safer_sk128_desc, &rc2_desc, + &des_desc, &des3_desc, &cast5_desc, NULL +}; + +int usage(void) +{ + int x; + + printf("Usage: ./crypt [-d](ecrypt) cipher infile outfile\nCiphers:\n"); + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + printf("%s\n",cipher_descriptor[x].name); + } + exit(1); +} + +void register_algs(void) +{ + int x; + + for (x = 0; ciphers[x] != NULL; x++) { + if (register_cipher(ciphers[x]) == -1) { + printf("Error registering cipher\n"); + exit(-1); + } + } + + if (register_hash(&sha256_desc) == -1) { + printf("Error registering SHA256\n"); + exit(-1); + } + + if (register_prng(&yarrow_desc) == -1) { + printf("Error registering yarrow PRNG\n"); + exit(-1); + } + + if (register_prng(&sprng_desc) == -1) { + printf("Error registering sprng PRNG\n"); + exit(-1); + } +} + +int main(int argc, char *argv[]) +{ + unsigned char plaintext[512],ciphertext[512]; + unsigned char tmpkey[512], key[MAXBLOCKSIZE], IV[MAXBLOCKSIZE]; + unsigned char inbuf[512]; /* i/o block size */ + unsigned long outlen, y, ivsize, x, decrypt; + symmetric_CTR ctr; + int cipher_idx, hash_idx, ks; + char *infile, *outfile, *cipher; + prng_state prng; + FILE *fdin, *fdout; + + /* register algs, so they can be printed */ + register_algs(); + + if (argc < 4) { + return usage(); + } + + if (!strcmp(argv[1], "-d")) { + decrypt = 1; + cipher = argv[2]; + infile = argv[3]; + outfile = argv[4]; + } else { + decrypt = 0; + cipher = argv[1]; + infile = argv[2]; + outfile = argv[3]; + } + + /* file handles setup */ + fdin = fopen(infile,"rb"); + if (fdin == NULL) { + perror("Can't open input for reading"); + exit(-1); + } + + fdout = fopen(outfile,"wb"); + if (fdout == NULL) { + perror("Can't open output for writing"); + exit(-1); + } + + cipher_idx = find_cipher(cipher); + if (cipher_idx == -1) { + printf("Invalid cipher entered on command line.\n"); + exit(-1); + } + + hash_idx = find_hash("sha256"); + if (hash_idx == -1) { + printf("SHA256 not found...?\n"); + exit(-1); + } + + ivsize = cipher_descriptor[cipher_idx].block_length; + ks = hash_descriptor[hash_idx].hashsize; + if (cipher_descriptor[cipher_idx].keysize(&ks) != CRYPT_OK) { + printf("Invalid keysize???\n"); + exit(-1); + } + + printf("\nEnter key: "); + fgets(tmpkey,sizeof(tmpkey), stdin); + outlen = sizeof(key); + if ((errno = hash_memory(hash_idx,tmpkey,strlen(tmpkey),key,&outlen)) != CRYPT_OK) { + printf("Error hashing key: %s\n", error_to_string(errno)); + exit(-1); + } + + if (decrypt) { + /* Need to read in IV */ + if (fread(IV,1,ivsize,fdin) != ivsize) { + printf("Error reading IV from input.\n"); + exit(-1); + } + + if ((errno = ctr_start(cipher_idx,IV,key,ks,0,&ctr)) != CRYPT_OK) { + printf("ctr_start error: %s\n",error_to_string(errno)); + exit(-1); + } + + /* IV done */ + do { + y = fread(inbuf,1,sizeof(inbuf),fdin); + + if ((errno = ctr_decrypt(inbuf,plaintext,y,&ctr)) != CRYPT_OK) { + printf("ctr_decrypt error: %s\n", error_to_string(errno)); + exit(-1); + } + + if (fwrite(plaintext,1,y,fdout) != y) { + printf("Error writing to file.\n"); + exit(-1); + } + } while (y == sizeof(inbuf)); + fclose(fdin); + fclose(fdout); + + } else { /* encrypt */ + /* Setup yarrow for random bytes for IV */ + + if ((errno = rng_make_prng(128, find_prng("yarrow"), &prng, NULL)) != CRYPT_OK) { + printf("Error setting up PRNG, %s\n", error_to_string(errno)); + } + + /* You can use rng_get_bytes on platforms that support it */ + /* x = rng_get_bytes(IV,ivsize,NULL);*/ + x = yarrow_read(IV,ivsize,&prng); + if (x != ivsize) { + printf("Error reading PRNG for IV required.\n"); + exit(-1); + } + + if (fwrite(IV,1,ivsize,fdout) != ivsize) { + printf("Error writing IV to output.\n"); + exit(-1); + } + + if ((errno = ctr_start(cipher_idx,IV,key,ks,0,&ctr)) != CRYPT_OK) { + printf("ctr_start error: %s\n",error_to_string(errno)); + exit(-1); + } + + do { + y = fread(inbuf,1,sizeof(inbuf),fdin); + + if ((errno = ctr_encrypt(inbuf,ciphertext,y,&ctr)) != CRYPT_OK) { + printf("ctr_encrypt error: %s\n", error_to_string(errno)); + exit(-1); + } + + if (fwrite(ciphertext,1,y,fdout) != y) { + printf("Error writing to output.\n"); + exit(-1); + } + } while (y == sizeof(inbuf)); + fclose(fdout); + fclose(fdin); + } + return 0; +} diff --git a/demos/hashsum.c b/demos/hashsum.c new file mode 100644 index 0000000..237467f --- /dev/null +++ b/demos/hashsum.c @@ -0,0 +1,77 @@ +/* + * Written by Daniel Richards 6/7/2002 + * hash.c: This app uses libtomcrypt to hash either stdin or a file + * This file is Public Domain. No rights are reserved. + * Compile with 'gcc hashsum.c -o hashsum -ltomcrypt' + * This example isn't really big enough to warrent splitting into + * more functions ;) +*/ + +#include + +int errno; + +void register_algs(); + +int main(int argc, char **argv) +{ + int idx, x, z; + unsigned long w; + unsigned char hash_buffer[MAXBLOCKSIZE]; + hash_state md; + + /* You need to register algorithms before using them */ + register_algs(); + if (argc < 2) { + printf("usage: ./hash algorithm file [file ...]\n"); + printf("Algorithms:\n"); + for (x = 0; hash_descriptor[x].name != NULL; x++) { + printf(" %s\n", hash_descriptor[x].name); + } + exit(EXIT_SUCCESS); + } + + idx = find_hash(argv[1]); + if (idx == -1) { + fprintf(stderr, "\nInvalid hash specified on command line.\n"); + return -1; + } + + if (argc == 2) { + hash_descriptor[idx].init(&md); + do { + x = fread(hash_buffer, 1, sizeof(hash_buffer), stdin); + hash_descriptor[idx].process(&md, hash_buffer, x); + } while (x == sizeof(hash_buffer)); + hash_descriptor[idx].done(&md, hash_buffer); + for (x = 0; x < (int)hash_descriptor[idx].hashsize; x++) { + printf("%02x",hash_buffer[x]); + } + printf(" (stdin)\n"); + } else { + for (z = 2; z < argc; z++) { + w = sizeof(hash_buffer); + if ((errno = hash_file(idx,argv[z],hash_buffer,&w)) != CRYPT_OK) { + printf("File hash error: %s\n", error_to_string(errno)); + } else { + for (x = 0; x < (int)hash_descriptor[idx].hashsize; x++) { + printf("%02x",hash_buffer[x]); + } + printf(" %s\n", argv[z]); + } + } + } + return EXIT_SUCCESS; +} + +void register_algs(void) +{ + register_hash(&sha512_desc); + register_hash(&sha384_desc); + register_hash(&sha256_desc); + register_hash(&sha1_desc); + register_hash(&md5_desc); + register_hash(&md4_desc); + register_hash(&tiger_desc); + register_hash(&md2_desc); +} diff --git a/demos/small.c b/demos/small.c new file mode 100644 index 0000000..bb4bfdb --- /dev/null +++ b/demos/small.c @@ -0,0 +1,11 @@ +// small demo app that just includes a cipher/hash/prng + +#include + +int main(void) +{ + register_cipher(&rijndael_desc); + register_prng(&yarrow_desc); + register_hash(&sha1_desc); + return 0; +} diff --git a/demos/test.c b/demos/test.c new file mode 100644 index 0000000..39d966e --- /dev/null +++ b/demos/test.c @@ -0,0 +1,1586 @@ +/* This is the worst code you have ever seen written on purpose.... this code is just a big hack to test +out the functionality of the library */ + +#ifdef SONY_PS2 +#include +#include +#include "timer.h" +#endif + +#include "../mycrypt.h" + +int errno; + + +int null_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + return CRYPT_OK; +} + +void null_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + memcpy(ct, pt, 8); +} + +void null_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +{ + memcpy(pt, ct, 8); +} + +int null_test(void) +{ + return CRYPT_OK; +} + +int null_keysize(int *desired_keysize) +{ + return CRYPT_OK; +} + +const struct _cipher_descriptor null_desc = +{ + "memcpy()", + 255, + 8, 8, 8, 1, + &null_setup, + &null_ecb_encrypt, + &null_ecb_decrypt, + &null_test, + &null_keysize +}; + + +prng_state prng; + +void store_tests(void) +{ + unsigned char buf[8]; + unsigned long L; + ulong64 LL; + + printf("LOAD32/STORE32 tests\n"); + L = 0x12345678UL; + STORE32L(L, &buf[0]); + L = 0; + LOAD32L(L, &buf[0]); + if (L != 0x12345678UL) printf("LOAD/STORE32 Little don't work\n"); + LL = CONST64(0x01020304050607); + STORE64L(LL, &buf[0]); + LL = 0; + LOAD64L(LL, &buf[0]) + if (LL != CONST64(0x01020304050607)) printf("LOAD/STORE64 Little don't work\n"); + + L = 0x12345678UL; + STORE32H(L, &buf[0]); + L = 0; + LOAD32H(L, &buf[0]); + if (L != 0x12345678UL) printf("LOAD/STORE32 High don't work\n"); + LL = CONST64(0x01020304050607); + STORE64H(LL, &buf[0]); + LL = 0; + LOAD64H(LL, &buf[0]) + if (LL != CONST64(0x01020304050607)) printf("LOAD/STORE64 High don't work\n"); +} + +void cipher_tests(void) { + int x; + + printf("Ciphers compiled in\n"); + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + printf(" %12s (%2d) Key Size: %4ld to %4ld, Block Size: %3ld, Default # of rounds: %2ld\n", cipher_descriptor[x].name, + cipher_descriptor[x].ID, + cipher_descriptor[x].min_key_length*8,cipher_descriptor[x].max_key_length*8, + cipher_descriptor[x].block_length*8, cipher_descriptor[x].default_rounds); + } + +} + +void ecb_tests(void) +{ + int x; + + printf("ECB tests\n"); + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + printf(" %12s: ", + cipher_descriptor[x].name); + if ((errno = cipher_descriptor[x].test()) != CRYPT_OK) + printf(" **failed** Reason: %s\n", error_to_string(errno)); + else + printf("passed\n"); + } +} + +#ifdef CBC +void cbc_tests(void) +{ + symmetric_CBC cbc; + int x, y; + unsigned char blk[32], ct[32], key[32], IV[32]; + const unsigned char test[] = { 0XFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + printf("CBC tests\n"); + /* ---- CBC ENCODING ---- */ + /* make up a block and IV */ + for (x = 0; x < 32; x++) blk[x] = IV[x] = x; + + /* now lets start a cbc session */ + if ((errno = cbc_start(find_cipher("blowfish"), IV, key, 16, 0, &cbc)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) + cbc_encrypt(blk+8*x, ct+8*x, &cbc); + + zeromem(blk, sizeof(blk)); + + /* ---- CBC DECODING ---- */ + /* make up a IV */ + for (x = 0; x < 32; x++) IV[x] = x; + + /* now lets start a cbc session */ + if ((errno = cbc_start(find_cipher("blowfish"), IV, key, 16, 0, &cbc)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) + cbc_decrypt(ct+8*x, blk+8*x, &cbc); + + /* print output */ + for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1; + printf(" %s\n", y?"failed":"passed"); + + /* lets actually check the bytes */ + memset(IV, 0, 8); IV[0] = 0xFF; /* IV = FF 00 00 00 00 00 00 00 */ + memset(blk, 0, 32); blk[8] = 0xFF; /* BLK = 00 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 */ + cbc_start(find_cipher("memcpy()"), IV, key, 8, 0, &cbc); + cbc_encrypt(blk, ct, &cbc); /* expect: FF 00 00 00 00 00 00 00 */ + cbc_encrypt(blk+8, ct+8, &cbc); /* expect: 00 00 00 00 00 00 00 00 */ + if (memcmp(ct, test, 16)) { + printf("CBC failed logical testing.\n"); + for (x = 0; x < 16; x++) printf("%02x ", ct[x]); + printf("\n"); + } else { + printf("CBC passed logical testing.\n"); + } +} +#else +void cbc_tests(void) { printf("CBC not compiled in\n"); } +#endif + +#ifdef OFB +void ofb_tests(void) +{ + symmetric_OFB ofb; + int x, y; + unsigned char blk[32], ct[32], key[32], IV[32]; + + printf("OFB tests\n"); + /* ---- ofb ENCODING ---- */ + /* make up a block and IV */ + for (x = 0; x < 32; x++) blk[x] = IV[x] = x; + + /* now lets start a ofb session */ + if ((errno = ofb_start(find_cipher("blowfish"), IV, key, 16, 0, &ofb)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) + ofb_encrypt(blk+8*x, ct+8*x, 8, &ofb); + + zeromem(blk, sizeof(blk)); + + /* ---- ofb DECODING ---- */ + /* make up a IV */ + for (x = 0; x < 32; x++) IV[x] = x; + + /* now lets start a ofb session */ + if ((errno = ofb_start(find_cipher("blowfish"), IV, key, 16, 0, &ofb)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) + ofb_decrypt(ct+8*x, blk+8*x, 8, &ofb); + + /* print output */ + for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1; + printf(" %s\n", y?"failed":"passed"); +} +#else +void ofb_tests(void) { printf("OFB not compiled in\n"); } +#endif + +#ifdef CFB +void cfb_tests(void) +{ + symmetric_CFB cfb; + int x, y; + unsigned char blk[32], ct[32], key[32], IV[32]; + + printf("CFB tests\n"); + /* ---- cfb ENCODING ---- */ + /* make up a block and IV */ + for (x = 0; x < 32; x++) blk[x] = IV[x] = x; + + /* now lets start a cfb session */ + if ((errno = cfb_start(find_cipher("blowfish"), IV, key, 16, 0, &cfb)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) + cfb_encrypt(blk+8*x, ct+8*x, 8, &cfb); + + zeromem(blk, sizeof(blk)); + + /* ---- cfb DECODING ---- */ + /* make up ahash_descriptor[prng->yarrow.hash].hashsize IV */ + for (x = 0; x < 32; x++) IV[x] = x; + + /* now lets start a cfb session */ + if ((errno = cfb_start(find_cipher("blowfish"), IV, key, 16, 0, &cfb)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) + cfb_decrypt(ct+8*x, blk+8*x, 8, &cfb); + + /* print output */ + for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1; + printf(" %s\n", y?"failed":"passed"); +} +#else +void cfb_tests(void) { printf("CFB not compiled in\n"); } +#endif + +#ifdef CTR +void ctr_tests(void) +{ + symmetric_CTR ctr; + int x, y; + unsigned char blk[32], ct[32], key[32], count[32]; + const unsigned char test[] = { 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0 }; + + printf("CTR tests\n"); + /* ---- CTR ENCODING ---- */ + /* make up a block and IV */ + for (x = 0; x < 32; x++) blk[x] = count[x] = x; + + /* now lets start a ctr session */ + if ((errno = ctr_start(find_cipher("rijndael"), count, key, 16, 0, &ctr)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) + ctr_encrypt(blk+8*x, ct+8*x, 8, &ctr); + + zeromem(blk, sizeof(blk)); + + /* ---- CTR DECODING ---- */ + /* make up a IV */ + for (x = 0; x < 32; x++) count[x] = x; + + /* now lets start a cbc session */ + if ((errno = ctr_start(find_cipher("rijndael"), count, key, 16, 0, &ctr)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) + ctr_decrypt(ct+8*x, blk+8*x, 8, &ctr); + + /* print output */ + for (x = y = 0; x < 32; x++) if (blk[x] != x) y = 1; + printf(" %s\n", y?"failed":"passed"); + + /* lets actually check the bytes */ + memset(count, 0, 8); count[0] = 0xFF; /* IV = FF 00 00 00 00 00 00 00 */ + memset(blk, 0, 32); blk[9] = 2; /* BLK = 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 */ + ctr_start(find_cipher("memcpy()"), count, key, 8, 0, &ctr); + ctr_encrypt(blk, ct, 8, &ctr); /* expect: FF 00 00 00 00 00 00 00 */ + ctr_encrypt(blk+8, ct+8, 8, &ctr); /* expect: 00 03 00 00 00 00 00 00 */ + if (memcmp(ct, test, 16)) { + printf("CTR failed logical testing.\n"); + for (x = 0; x < 16; x++) printf("%02x ", ct[x]); + printf("\n"); + } else { + printf("CTR passed logical testing.\n"); + } + +} +#else +void ctr_tests(void) { printf("CTR not compiled in\n"); } +#endif + +void hash_tests(void) +{ + int x; + printf("Hash tests\n"); + for (x = 0; hash_descriptor[x].name != NULL; x++) { + printf(" %10s (%2d) ", hash_descriptor[x].name, hash_descriptor[x].ID); + if (hash_descriptor[x].test() != CRYPT_OK) + printf("**failed** Reason: %s\n", error_to_string(errno)); + else + printf("passed\n"); + } +} + +#ifdef MRSA +void pad_test(void) +{ + unsigned char in[100], out[100]; + unsigned long x, y; + + /* make a dummy message */ + for (x = 0; x < 16; x++) in[x] = (unsigned char)x; + + /* pad the message so that random filler is placed before and after it */ + y = 100; + if ((errno = rsa_pad(in, 16, out, &y, find_prng("yarrow"), &prng)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + + /* depad the message to get the original content */ + memset(in, 0, sizeof(in)); + x = 100; + if ((errno = rsa_depad(out, y, in, &x)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + + /* check outcome */ + printf("rsa_pad: "); + if (x != 16) { printf("Failed. Wrong size.\n"); return; } + for (x = 0; x < 16; x++) if (in[x] != x) { printf("Failed. Expected %02lx and got %02x.\n", x, in[x]); return; } + printf("passed.\n"); +} + +void rsa_test(void) +{ + unsigned char in[4096], out[4096]; + unsigned long x, y, z, limit; + int stat; + rsa_key key; + clock_t t; + + /* ---- SINGLE ENCRYPT ---- */ + /* encrypt a short 8 byte string */ + if ((errno = rsa_make_key(&prng, find_prng("yarrow"), 1024/8, 65537, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + for (x = 0; x < 8; x++) in[x] = (unsigned char)(x+1); + y = sizeof(in); + if ((errno = rsa_exptmod(in, 8, out, &y, PK_PUBLIC, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + + /* decrypt it */ + zeromem(in, sizeof(in)); + x = sizeof(out); + if ((errno = rsa_exptmod(out, y, in, &x, PK_PRIVATE, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + + /* compare */ + printf("RSA : "); + for (x = 0; x < 8; x++) if (in[x] != (x+1)) { printf("Failed. x==%02lx, in[%ld]==%02x\n", x, x, in[x]); } + printf("passed.\n"); + +#ifdef PK_PACKET + /* ---- BLOCK ENCRYPT ---- */ + /* now lets test rsa_encrypt() */ + for (x = 0; x < 8; x++) in[x] = (unsigned char)x; + x = sizeof(out); + if ((errno = rsa_encrypt(in, 8, out, &x, &prng, find_prng("yarrow"), find_cipher("rijndael"), &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + + /* test rsa_decrypt() */ + zeromem(in, sizeof(in)); + y = sizeof(in); + if ((errno = rsa_decrypt(out, x, in, &y, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("rsa_encrypt()/rsa_decrypt(): "); + for (y = 0; y < 8; y++) if (in[y] != y) { printf("failed.\n"); return; } + printf("Passed.\n"); + + /* ---- SIGNATURES ---- */ + x = sizeof(in); + if ((errno = rsa_sign("hello", 5, in, &x, find_hash("md5"), &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + if ((errno = rsa_verify(in, "hello", 5, &stat, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("RSA Signatures: %s, ", (stat==1)?"pass":"fail"); + if ((errno = rsa_verify(in, "abcde", 5, &stat, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("%s\n", (stat==0)?"pass":"fail"); + + /* ---- EXPORT/IMPORT ---- */ + x = sizeof(out); + if ((errno = rsa_export(out, &x, PK_PRIVATE_OPTIMIZED, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("RSA Export takes %lu bytes\n", x); + rsa_free(&key); + if ((errno = rsa_import(out, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("RSA Import: "); + if ((errno = rsa_verify(in, "hello", 5, &stat, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("%s, ", (stat==1)?"pass":"fail"); + if ((errno = rsa_verify(in, "abcde", 5, &stat, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("%s\n", (stat==0)?"pass":"fail"); +#endif + + /* test the rsa_encrypt_key functions */ + for (x = 0; x < 16; x++) in[x] = x; + y = sizeof(out); + if ((errno = rsa_encrypt_key(in, 16, out, &y, &prng, find_prng("yarrow"), &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + zeromem(in, sizeof(in)); + x = sizeof(in); + if ((errno = rsa_decrypt_key(out, in, &x, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("RSA en/de crypt key routines: "); + if (x != 16) { printf("Failed (length)\n"); return; } + for (x = 0; x < 16; x++) if (in[x] != x) { printf("Failed (contents)\n"); return; } + printf("Passed\n"); + + /* test sign_hash functions */ + for (x = 0; x < 16; x++) in[x] = x; + x = sizeof(in); + if ((errno = rsa_sign_hash(in, 16, out, &x, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("RSA signed hash: %lu bytes\n", x); + if ((errno = rsa_verify_hash(out, in, &stat, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("Verify hash: %s, ", stat?"passed":"failed"); + in[0] ^= 1; + if ((errno = rsa_verify_hash(out, in, &stat, &key)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("%s\n", (!stat)?"passed":"failed"); + rsa_free(&key); + + /* make a RSA key */ +#ifdef SONY_PS2 + limit = 1024; +#else + limit = 2048; +#endif + + for (z = 1024; z <= limit; z += 512) { + t = XCLOCK(); + if ((errno = rsa_make_key(&prng, find_prng("yarrow"), z/8, 65537, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + t = XCLOCK() - t; + printf("Took %.0f ms to make a %ld-bit RSA key.\n", 1000.0 * ((double)t / (double)XCLOCKS_PER_SEC), z); + + /* time encryption */ + y = sizeof(in); + t = XCLOCK(); + if ((errno = rsa_exptmod(in, 8, out, &y, PK_PUBLIC, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + t = XCLOCK() - t; + printf("Took %.0f ms to encrypt with a %ld-bit RSA key.\n", 1000.0 * ((double)t / (double)XCLOCKS_PER_SEC), z); + + /* time decryption */ + x = sizeof(out); + t = XCLOCK(); + if ((errno = rsa_exptmod(out, y, in, &x, PK_PRIVATE, &key)) != CRYPT_OK) { printf("Error: %s\n", error_to_string(errno)); return; } + t = XCLOCK() - t; + printf("Took %.0f ms to decrypt with a %ld-bit RSA key.\n", 1000.0 * ((double)t / (double)XCLOCKS_PER_SEC), z); + rsa_free(&key); + } + + + +} +#else +void pad_test(void) { printf("MRSA not compiled in\n"); } +void rsa_test(void) { printf("MRSA not compiled in\n"); } +#endif + +#ifdef BASE64 +void base64_test(void) +{ + unsigned char buf[2][100]; + unsigned long x, y; + + printf("Base64 tests\n"); + zeromem(buf, sizeof(buf)); + for (x = 0; x < 16; x++) buf[0][x] = (unsigned char)x; + + x = 100; + if (base64_encode(buf[0], 16, buf[1], &x) != CRYPT_OK) { + printf(" error: %s\n", error_to_string(errno)); + return; + } + printf(" encoded 16 bytes to %ld bytes...[%s]\n", x, buf[1]); + memset(buf[0], 0, 100); + y = 100; + if (base64_decode(buf[1], x, buf[0], &y) != CRYPT_OK) { + printf(" error: %s\n", error_to_string(errno)); + return; + } + printf(" decoded %ld bytes to %ld bytes\n", x, y); + for (x = 0; x < 16; x++) if (buf[0][x] != x) { + printf(" **failed**\n"); + return; + } + printf(" passed\n"); +} +#else +void base64_test(void) { printf("Base64 not compiled in\n"); } +#endif + +void time_hash(void) +{ + clock_t t1; + int x, y; + unsigned long z; + unsigned char input[4096], out[MAXBLOCKSIZE]; + printf("Hash Time Trials (4KB blocks):\n"); + for (x = 0; hash_descriptor[x].name != NULL; x++) { + t1 = XCLOCK(); + z = sizeof(out); + y = 0; + while (XCLOCK() - t1 < (3 * XCLOCKS_PER_SEC)) { + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); + hash_memory(x, input, 4096, out, &z); y += 16; + } + t1 = XCLOCK() - t1; + printf("%-20s: Hash at %5.2f Mbit/sec\n", hash_descriptor[x].name, + ((8.0 * 4096.0) * ((double)y / ((double)t1 / (double)XCLOCKS_PER_SEC))) / 1000000.0); + } +} + +void time_ecb(void) +{ + clock_t t1, t2; + long x, y1, y2; + unsigned char pt[32], key[32]; + symmetric_key skey; + void (*func)(const unsigned char *, unsigned char *, symmetric_key *); + + printf("ECB Time Trials for the Symmetric Ciphers:\n"); + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + cipher_descriptor[x].setup(key, cipher_descriptor[x].min_key_length, 0, &skey); + +#define DO1 func(pt,pt,&skey); +#define DO2 DO1 DO1 +#define DO4 DO2 DO2 +#define DO8 DO4 DO4 +#define DO16 DO8 DO8 +#define DO32 DO16 DO16 +#define DO64 DO32 DO32 +#define DO128 DO64 DO64 +#define DO256 DO128 DO128 + + func = cipher_descriptor[x].ecb_encrypt; + y1 = 0; + t1 = XCLOCK(); + while (XCLOCK() - t1 < 2*XCLOCKS_PER_SEC) { + DO256; y1 += 256; + } + t1 = XCLOCK() - t1; + + func = cipher_descriptor[x].ecb_decrypt; + y2 = 0; + t2 = XCLOCK(); + while (XCLOCK() - t2 < 2*XCLOCKS_PER_SEC) { + DO256; y2 += 256; + } + t2 = XCLOCK() - t2; + printf("%-20s: Encrypt at %5.2f Mbit/sec and Decrypt at %5.2f Mbit/sec\n", + cipher_descriptor[x].name, + ((8.0 * (double)cipher_descriptor[x].block_length) * ((double)y1 / ((double)t1 / (double)XCLOCKS_PER_SEC))) / 1000000.0, + ((8.0 * (double)cipher_descriptor[x].block_length) * ((double)y2 / ((double)t2 / (double)XCLOCKS_PER_SEC))) / 1000000.0); + +#undef DO256 +#undef DO128 +#undef DO64 +#undef DO32 +#undef DO16 +#undef DO8 +#undef DO4 +#undef DO2 +#undef DO1 + } +} + +#ifdef MDH +void dh_tests(void) +{ + unsigned char buf[3][4096]; + unsigned long x, y, z; + int low, high, stat, stat2; + dh_key usera, userb; + clock_t t1; + +/* if ((errno = dh_test()) != CRYPT_OK) printf("DH Error: %s\n", error_to_string(errno)); */ + + dh_sizes(&low, &high); + printf("DH Keys from %d to %d supported.\n", low*8, high*8); + + /* make up two keys */ + if ((errno = dh_make_key(&prng, find_prng("yarrow"), 96, &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + if ((errno = dh_make_key(&prng, find_prng("yarrow"), 96, &userb)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + + /* make the shared secret */ + x = 4096; + if ((errno = dh_shared_secret(&usera, &userb, buf[0], &x)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + + y = 4096; + if ((errno = dh_shared_secret(&userb, &usera, buf[1], &y)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + if (y != x) { printf("DH Shared keys are not same size.\n"); return; } + if (memcmp(buf[0], buf[1], x)) { printf("DH Shared keys not same contents.\n"); return; } + + /* now export userb */ + y = 4096; + if ((errno = dh_export(buf[1], &y, PK_PUBLIC, &userb)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + dh_free(&userb); + + /* import and make the shared secret again */ + if ((errno = dh_import(buf[1], &userb)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + z = 4096; + if ((errno = dh_shared_secret(&usera, &userb, buf[2], &z)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + + printf("DH routines: "); + if (z != x) { printf("failed. Size don't match?\n"); return; } + if (memcmp(buf[0], buf[2], x)) { printf("Failed. Content didn't match.\n"); return; } + printf("Passed\n"); + dh_free(&usera); + dh_free(&userb); + +/* time stuff */ + t1 = XCLOCK(); + dh_make_key(&prng, find_prng("yarrow"), 64, &usera); + t1 = XCLOCK() - t1; + printf("Make dh-512 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); + dh_free(&usera); + + t1 = XCLOCK(); + dh_make_key(&prng, find_prng("yarrow"), 96, &usera); + t1 = XCLOCK() - t1; + printf("Make dh-768 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); + dh_free(&usera); + + t1 = XCLOCK(); + dh_make_key(&prng, find_prng("yarrow"), 128, &usera); + t1 = XCLOCK() - t1; + printf("Make dh-1024 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); + dh_free(&usera); + +#ifndef SONY_PS2 + t1 = XCLOCK(); + dh_make_key(&prng, find_prng("yarrow"), 160, &usera); + t1 = XCLOCK() - t1; + printf("Make dh-1280 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); + dh_free(&usera); + + t1 = XCLOCK(); + dh_make_key(&prng, find_prng("yarrow"), 192, &usera); + t1 = XCLOCK() - t1; + printf("Make dh-1536 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); + dh_free(&usera); + + t1 = XCLOCK(); + dh_make_key(&prng, find_prng("yarrow"), 224, &usera); + t1 = XCLOCK() - t1; + printf("Make dh-1792 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); + dh_free(&usera); + + t1 = XCLOCK(); + dh_make_key(&prng, find_prng("yarrow"), 256, &usera); + t1 = XCLOCK() - t1; + printf("Make dh-2048 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); + dh_free(&usera); + + t1 = XCLOCK(); + dh_make_key(&prng, find_prng("yarrow"), 320, &usera); + t1 = XCLOCK() - t1; + printf("Make dh-2560 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); + dh_free(&usera); +#endif + +#ifdef PK_PACKET +/* try dh packet stuff */ + for (x = 0; x < 16; x++) buf[0][x] = (unsigned char)x; + dh_make_key(&prng, find_prng("yarrow"), 24, &usera); + + x = 4096; + if (dh_encrypt(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), find_cipher("rijndael"), + find_hash("sha1"), &usera) != CRYPT_OK) { + printf("dh_encrypt says %s\n", error_to_string(errno)); + return; + } + printf("dh encrypted 16 bytes into %ld bytes!\n", x); + + y = 4096; + if ((errno = dh_decrypt(buf[1], x, buf[2], &y, &usera)) != CRYPT_OK) { + printf("dh_decrypt says %s\n", error_to_string(errno)); + return; + } + + printf("dh packet: "); + if (16 != y) { printf("Failed: Sizes different! 16 vs %ld\n", y); return; } + if (memcmp(buf[0], buf[2], 16)) { printf("Failed; Content mismatch.\n"); return; } + printf("Passed!\n"); + dh_free(&usera); + +/* try dh signatures */ + dh_make_key(&prng, find_prng("yarrow"), 96, &usera); + x = 4096; + if ((errno = dh_sign("hello", 5, buf[0], &x, find_hash("sha1"), &prng, find_prng("yarrow"), &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + + printf("dh-768 Signature took %ld bytes\n", x); + + if ((errno = dh_verify(buf[0], "hello", 5, &stat, &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + if ((errno = dh_verify(buf[0], "hellp", 5, &stat2, &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + + printf("dh Signatures: %s (%d,%d)\n", ((stat==1)&&(stat2==0))?"passed":"failed", stat,stat2); + dh_free(&usera); +#endif + +/* test encrypt_key */ + dh_make_key(&prng, find_prng("yarrow"), 96, &usera); + for (x = 0; x < 16; x++) buf[0][x] = x; + y = sizeof(buf[1]); + if ((errno = dh_encrypt_key(buf[0], 16, buf[1], &y, &prng, find_prng("yarrow"), find_hash("md5"), &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + zeromem(buf[0], sizeof(buf[0])); + x = sizeof(buf[0]); + if ((errno = dh_decrypt_key(buf[1], buf[0], &x, &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("DH en/de crypt key routines: "); + if (x != 16) { printf("Failed (length)\n"); return; } + for (x = 0; x < 16; x++) if (buf[0][x] != x) { printf("Failed (contents)\n"); return; } + printf("Passed (size %lu)\n", y); + +/* test sign_hash */ + for (x = 0; x < 16; x++) buf[0][x] = x; + x = sizeof(buf[1]); + if ((errno = dh_sign_hash(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + if (dh_verify_hash(buf[1], buf[0], 16, &stat, &usera)) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + buf[0][0] ^= 1; + if (dh_verify_hash(buf[1], buf[0], 16, &stat2, &usera)) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("dh_sign/verify_hash: %s (%d,%d)\n", ((stat==1)&&(stat2==0))?"passed":"failed", stat,stat2); + dh_free(&usera); +} +#else +void dh_tests(void) { printf("MDH not compiled in\n"); } +#endif + +int callback_x = 0; +void callback(void) +{ + printf("%c\x08", "-\\|/"[++callback_x & 3]); +#ifndef SONY_PS2 + fflush(stdout); +#endif +} + +void rng_tests(void) +{ + unsigned char buf[16]; + clock_t t1; + int x, y; + + printf("RNG tests\n"); + t1 = XCLOCK(); + x = rng_get_bytes(buf, sizeof(buf), &callback); + t1 = XCLOCK() - t1; + printf(" %f bytes per second...", + (double)x / ((double)t1 / (double)XCLOCKS_PER_SEC)); + printf("read %d bytes.\n ", x); + for (y = 0; y < x; y++) + printf("%02x ", buf[y]); + printf("\n"); + +#ifdef YARROW + if ((errno = rng_make_prng(128, find_prng("yarrow"), &prng, &callback)) != CRYPT_OK) { + printf(" starting yarrow error: %s\n", error_to_string(errno)); + exit(-1); + } +#endif +} + +#ifdef MECC +void ecc_tests(void) +{ + unsigned char buf[4][4096]; + unsigned long x, y, z; + int stat, stat2, low, high; + ecc_key usera, userb; + clock_t t1; + + if ((errno = ecc_test()) != CRYPT_OK) printf("ecc Error: %s\n", error_to_string(errno)); + + ecc_sizes(&low, &high); + printf("ecc Keys from %d to %d supported.\n", low*8, high*8); + + /* make up two keys */ + if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 24, &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + if ((errno = ecc_make_key(&prng, find_prng("yarrow"), 24, &userb)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + + /* make the shared secret */ + x = 4096; + if ((errno = ecc_shared_secret(&usera, &userb, buf[0], &x)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + + y = 4096; + if ((errno = ecc_shared_secret(&userb, &usera, buf[1], &y)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + + if (y != x) { printf("ecc Shared keys are not same size.\n"); return; } + + if (memcmp(buf[0], buf[1], x)) { printf("ecc Shared keys not same contents.\n"); return; } + + /* now export userb */ + y = 4096; + if ((errno = ecc_export(buf[1], &y, PK_PUBLIC, &userb)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + ecc_free(&userb); + printf("ECC-192 export took %ld bytes\n", y); + + /* import and make the shared secret again */ + if ((errno = ecc_import(buf[1], &userb)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + + z = 4096; + if ((errno = ecc_shared_secret(&usera, &userb, buf[2], &z)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + + printf("ecc routines: "); + if (z != x) { printf("failed. Size don't match?\n"); return; } + if (memcmp(buf[0], buf[2], x)) { printf("Failed. Content didn't match.\n"); return; } + printf("Passed\n"); + ecc_free(&usera); + ecc_free(&userb); + +/* time stuff */ + t1 = XCLOCK(); + ecc_make_key(&prng, find_prng("yarrow"), 20, &usera); + t1 = XCLOCK() - t1; + printf("Make ECC-160 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); + ecc_free(&usera); + + t1 = XCLOCK(); + ecc_make_key(&prng, find_prng("yarrow"), 24, &usera); + t1 = XCLOCK() - t1; + printf("Make ECC-192 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); + ecc_free(&usera); + + t1 = XCLOCK(); + ecc_make_key(&prng, find_prng("yarrow"), 28, &usera); + t1 = XCLOCK() - t1; + printf("Make ECC-224 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); + ecc_free(&usera); + +#ifndef SONY_PS2 + t1 = XCLOCK(); + ecc_make_key(&prng, find_prng("yarrow"), 32, &usera); + t1 = XCLOCK() - t1; + printf("Make ECC-256 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); + ecc_free(&usera); + + t1 = XCLOCK(); + ecc_make_key(&prng, find_prng("yarrow"), 48, &usera); + t1 = XCLOCK() - t1; + printf("Make ECC-384 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); + ecc_free(&usera); + + t1 = XCLOCK(); + ecc_make_key(&prng, find_prng("yarrow"), 65, &usera); + t1 = XCLOCK() - t1; + printf("Make ECC-521 key took %f msec\n", 1000.0 * ((double)t1 / (double)XCLOCKS_PER_SEC)); + ecc_free(&usera); +#endif + +#ifdef PK_PACKET +/* try ECC packet stuff */ + for (x = 0; x < 16; x++) buf[0][x] = (unsigned char)x; + ecc_make_key(&prng, find_prng("yarrow"), 20, &usera); + + x = 4096; + if (ecc_encrypt(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), find_cipher("rijndael"), + find_hash("tiger"), &usera) != CRYPT_OK) { + printf("ecc_encrypt says %s\n", error_to_string(errno)); + return; + } + printf("Ecc encrypted 16 bytes into %ld bytes!\n", x); + + y = 4096; + if ((errno = ecc_decrypt(buf[1], x, buf[2], &y, &usera)) != CRYPT_OK) { + printf("ecc_decrypt says %s\n", error_to_string(errno)); + return; + } + + printf("ECC packet: "); + if (16 != y) { printf("Failed: Sizes different! 16 vs %ld\n", y); return; } + if (memcmp(buf[0], buf[2], 16)) { printf("Failed; Content mismatch.\n"); return; } + printf("Passed!\n"); + ecc_free(&usera); + +/* try ECC signatures */ + ecc_make_key(&prng, find_prng("yarrow"), 20, &usera); + x = 4096; + if ((errno = ecc_sign("hello", 5, buf[0], &x, find_hash("sha1"), &prng, find_prng("yarrow"), &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + + printf("ECC-160 Signature took %ld bytes\n", x); + + if ((errno = ecc_verify(buf[0], "hello", 5, &stat, &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + if ((errno = ecc_verify(buf[0], "hellp", 5, &stat2, &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + + printf("ECC Signatures: %s (%d,%d)\n", ((stat==1)&&(stat2==0))?"passed":"failed", stat,stat2); + ecc_free(&usera); +#endif + +/* test encrypt_key */ + ecc_make_key(&prng, find_prng("yarrow"), 32, &usera); + for (x = 0; x < 16; x++) buf[0][x] = x; + y = sizeof(buf[1]); + if ((errno = ecc_encrypt_key(buf[0], 16, buf[1], &y, &prng, find_prng("yarrow"), find_hash("md5"), &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + zeromem(buf[0], sizeof(buf[0])); + x = sizeof(buf[0]); + if ((errno = ecc_decrypt_key(buf[1],buf[0], &x, &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("ECC en/de crypt key routines: "); + if (x != 16) { printf("Failed (length)\n"); return; } + for (x = 0; x < 16; x++) if (buf[0][x] != x) { printf("Failed (contents)\n"); return; } + printf("Passed (size: %lu)\n", y); +/* test sign_hash */ + for (x = 0; x < 16; x++) buf[0][x] = x; + x = sizeof(buf[1]); + if ((errno = ecc_sign_hash(buf[0], 16, buf[1], &x, &prng, find_prng("yarrow"), &usera)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + if (ecc_verify_hash(buf[1], buf[0], 16, &stat, &usera)) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + buf[0][0] ^= 1; + if (ecc_verify_hash(buf[1], buf[0], 16, &stat2, &usera)) { + printf("Error: %s\n", error_to_string(errno)); + return; + } + printf("ecc_sign/verify_hash: %s (%d,%d)\n", ((stat==1)&&(stat2==0))?"passed":"failed", stat,stat2); + ecc_free(&usera); +} +#else +void ecc_tests(void) { printf("MECC not compiled in\n"); } +#endif + +#ifdef GF +void gf_tests(void) +{ + gf_int a, b, c, d; + int n; + unsigned char buf[1024]; + + printf("GF tests\n"); + gf_zero(a);gf_zero(b);gf_zero(c);gf_zero(d); + + /* a == 0x18000000b */ + a[1] = 1; + a[0] = 0x8000000bUL; + + /* b == 0x012345678 */ + b[0] = 0x012345678UL; + + /* find 1/b mod a */ + gf_invmod(b,a,c); + + /* find 1/1/b mod a */ + gf_invmod(c,a,d); + + /* display them */ + printf(" %08lx %08lx\n", c[0], d[0]); + + /* store as binary string */ + n = gf_size(a); + printf(" a takes %d bytes\n", n); + gf_toraw(a, buf); + gf_readraw(a, buf, n); + printf(" a == %08lx%08lx\n", a[1], a[0]); + + /* primality testing */ + gf_zero(a); + a[0] = 0x169; + printf(" GF prime: %s, ", gf_is_prime(a)?"passed":"failed"); + a[0] = 0x168; + printf(" %s\n", gf_is_prime(a)?"failed":"passed"); + + /* test sqrt code */ + gf_zero(a); + a[1] = 0x00000001; + a[0] = 0x8000000bUL; + gf_zero(b); + b[0] = 0x12345678UL; + + gf_sqrt(b, a, c); + gf_mulmod(c, c, a, b); + printf(" (%08lx)^2 = %08lx (mod %08lx%08lx) \n", c[0], b[0], a[1], a[0]); +} +#else +void gf_tests(void) { printf("GF not compiled in\n"); } +#endif + +#ifdef MPI +void test_prime(void) +{ + unsigned char buf[1024]; + mp_int a; + int x; + + /* make a 1024 bit prime */ + mp_init(&a); + rand_prime(&a, 128, &prng, find_prng("yarrow")); + + /* dump it */ + mp_todecimal(&a, buf); + printf("1024-bit prime:\n"); + for (x = 0; x < (int)strlen(buf); ) { + printf("%c", buf[x]); + if (!(++x % 60)) printf("\\ \n"); + } + printf("\n\n"); + + mp_clear(&a); +} +#else +void test_prime(void) { printf("MPI not compiled in\n"); } +#endif + +void register_all_algs(void) +{ +#ifdef BLOWFISH + register_cipher(&blowfish_desc); +#endif +#ifdef XTEA + register_cipher(&xtea_desc); +#endif +#ifdef RC5 + register_cipher(&rc5_desc); +#endif +#ifdef RC6 + register_cipher(&rc6_desc); +#endif +#ifdef SAFERP + register_cipher(&saferp_desc); +#endif +#ifdef SERPENT + register_cipher(&serpent_desc); +#endif +#ifdef RIJNDAEL + register_cipher(&rijndael_desc); +#endif +#ifdef SAFER + register_cipher(&safer_k64_desc); + register_cipher(&safer_sk64_desc); + register_cipher(&safer_k128_desc); + register_cipher(&safer_sk128_desc); +#endif +#ifdef TWOFISH + register_cipher(&twofish_desc); +#endif +#ifdef RC2 + register_cipher(&rc2_desc); +#endif +#ifdef CAST5 + register_cipher(&cast5_desc); +#endif +#ifdef DES + register_cipher(&des_desc); + register_cipher(&des3_desc); +#endif + + register_cipher(&null_desc); + +#ifdef SHA256 + register_hash(&sha256_desc); +#endif +#ifdef TIGER + register_hash(&tiger_desc); +#endif +#ifdef SHA1 + register_hash(&sha1_desc); +#endif +#ifdef MD5 + register_hash(&md5_desc); +#endif +#ifdef SHA384 + register_hash(&sha384_desc); +#endif +#ifdef SHA512 + register_hash(&sha512_desc); +#endif +#ifdef MD4 + register_hash(&md4_desc); +#endif +#ifdef MD2 + register_hash(&md2_desc); +#endif + +#ifdef YARROW + register_prng(&yarrow_desc); +#endif +#ifdef SPRNG + register_prng(&sprng_desc); +#endif +} + +void kr_display(pk_key *kr) +{ + static const char *system[] = { "NON-KEY", "RSA", "DH", "ECC" }; + static const char *type[] = { "PRIVATE", "PUBLIC", "PRIVATE_OPTIMIZED" }; + + while (kr->system != NON_KEY) { + printf("CRC [%08lx], System [%10s], Type [%20s], %s, %s, %s\n", kr->ID, system[kr->system], type[kr->key_type], kr->name, kr->email, kr->description); + kr = kr->next; + } + printf("\n"); +} + +void kr_test_makekeys(pk_key **kr) +{ + if ((errno = kr_init(kr)) != CRYPT_OK) { + printf("KR init error %s\n", error_to_string(errno)); + exit(-1); + } + + /* make a ECC key */ + printf("KR: Making ECC key...\n"); + if ((errno = kr_make_key(*kr, &prng, find_prng("yarrow"), ECC_KEY, 24, "ecckey", "ecc@ecc.ecc", "ecckey one")) != CRYPT_OK) { + printf("Make key error: %s\n", error_to_string(errno)); + exit(-1); + } + + /* make a RSA key */ + printf("KR: Making RSA key...\n"); + if ((errno = kr_make_key(*kr, &prng, find_prng("yarrow"), RSA_KEY, 128, "rsakey", "rsa@rsa.rsa", "rsakey one")) != CRYPT_OK) { + printf("Make key error: %s\n", error_to_string(errno)); + exit(-1); + } + + /* make a DH key */ + printf("KR: Making DH key...\n"); + if ((errno = kr_make_key(*kr, &prng, find_prng("yarrow"), DH_KEY, 128, "dhkey", "dh@dh.dh", "dhkey one")) != CRYPT_OK) { + printf("Make key error: %s\n", error_to_string(errno)); + exit(-1); + } +} + +void kr_test(void) +{ + pk_key *kr, *_kr; + unsigned char buf[8192], buf2[8192], buf3[8192]; + unsigned long len; + int i, j, stat; +#ifndef NO_FILE + FILE *f; +#endif + + kr_test_makekeys(&kr); + + printf("The original list:\n"); + kr_display(kr); + + for (i = 0; i < 3; i++) { + len = sizeof(buf); + if ((errno = kr_export(kr, kr->ID, kr->key_type, buf, &len)) != CRYPT_OK) { + printf("Error exporting key %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + printf("Exported key was: %lu bytes\n", len); + if ((errno = kr_del(&kr, kr->ID)) != CRYPT_OK) { + printf("Error deleting key %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + kr_display(kr); + if ((errno = kr_import(kr, buf)) != CRYPT_OK) { + printf("Error importing key %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + kr_display(kr); + } + + for (i = 0; i < 3; i++) { + len = sizeof(buf); + if ((errno = kr_export(kr, kr->ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) { + printf("Error exporting key %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + printf("Exported key was: %lu bytes\n", len); + if ((errno = kr_del(&kr, kr->ID)) != CRYPT_OK) { + printf("Error deleting key %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + kr_display(kr); + if ((errno = kr_import(kr, buf)) != CRYPT_OK) { + printf("Error importing key %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + kr_display(kr); + } + + if ((errno = kr_clear(&kr)) != CRYPT_OK) { + printf("Error clearing ring: %s\n", error_to_string(errno)); + exit(-1); + } + + +/* TEST output to file */ +#ifndef NO_FILE + + if ((errno = kr_init(&kr)) != CRYPT_OK) { + printf("KR init error %s\n", error_to_string(errno)); + exit(-1); + } + kr_test_makekeys(&kr); + + /* save to file */ + f = fopen("ring.dat", "wb"); + if ((errno = kr_save(kr, f, NULL)) != CRYPT_OK) { + printf("kr_save error %s\n", error_to_string(errno)); + exit(-1); + } + fclose(f); + + /* delete and load */ + if ((errno = kr_clear(&kr)) != CRYPT_OK) { + printf("clear error: %s\n", error_to_string(errno)); + exit(-1); + } + + f = fopen("ring.dat", "rb"); + if ((errno = kr_load(&kr, f, NULL)) != CRYPT_OK) { + printf("kr_load error %s\n", error_to_string(errno)); + exit(-1); + } + fclose(f); + remove("ring.dat"); + printf("After load and save...\n"); + kr_display(kr); + + if ((errno = kr_clear(&kr)) != CRYPT_OK) { + printf("clear error: %s\n", error_to_string(errno)); + exit(-1); + } + +#endif + +/* test the packet encryption/sign stuff */ + for (i = 0; i < 16; i++) buf[i] = i; + kr_test_makekeys(&kr); + _kr = kr; + for (i = 0; i < 3; i++) { + printf("Testing a key with system %d, type %d:\t", _kr->system, _kr->key_type); + len = sizeof(buf2); + if ((errno = kr_encrypt_key(kr, _kr->ID, buf, 16, buf2, &len, &prng, find_prng("yarrow"), find_hash("md5"))) != CRYPT_OK) { + printf("Encrypt error, %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + len = sizeof(buf3); + if ((errno = kr_decrypt_key(kr, buf2, buf3, &len)) != CRYPT_OK) { + printf("decrypt error, %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + if (len != 16 || memcmp(buf3, buf, 16)) { + printf("kr_decrypt_key failed, %i, %lu\n", i, len); + exit(-1); + } + printf("kr_encrypt_key passed, "); + + len = sizeof(buf2); + if ((errno = kr_sign_hash(kr, _kr->ID, buf, 16, buf2, &len, &prng, find_prng("yarrow"))) != CRYPT_OK) { + printf("kr_sign_hash failed, %i, %lu\n", i, len); + exit(-1); + } + printf("kr_sign_hash: "); + if ((errno = kr_verify_hash(kr, buf2, buf, 16, &stat)) != CRYPT_OK) { + printf("kr_sign_hash failed, %i, %lu\n", i, len); + exit(-1); + } + printf("%s, ", stat?"passed":"failed"); + buf[15] ^= 1; + if ((errno = kr_verify_hash(kr, buf2, buf, 16, &stat)) != CRYPT_OK) { + printf("kr_sign_hash failed, %i, %lu\n", i, len); + exit(-1); + } + printf("%s\n", (!stat)?"passed":"failed"); + buf[15] ^= 1; + + len = sizeof(buf); + if ((errno = kr_fingerprint(kr, _kr->ID, find_hash("sha1"), buf, &len)) != CRYPT_OK) { + printf("kr_fingerprint failed, %i, %lu\n", i, len); + exit(-1); + } + printf("Fingerprint: "); + for (j = 0; j < 20; j++) { + printf("%02x", buf[j]); + if (j < 19) printf(":"); + } + printf("\n\n"); + + _kr = _kr->next; + } + +/* Test encrypting/decrypting to a public key */ +/* first dump the other two keys */ + kr_del(&kr, kr->ID); + kr_del(&kr, kr->ID); + kr_display(kr); + + /* now export it as public and private */ + len = sizeof(buf); + if ((errno = kr_export(kr, kr->ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) { + printf("Error exporting key %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + + /* check boundaries */ + memset(buf+len, 0, sizeof(buf)-len); + + len = sizeof(buf2); + if ((errno = kr_export(kr, kr->ID, PK_PRIVATE, buf2, &len)) != CRYPT_OK) { + printf("Error exporting key %s\n", error_to_string(errno)); + exit(-1); + } + + /* check boundaries */ + memset(buf2+len, 0, sizeof(buf2)-len); + + /* delete the key and import the public */ + kr_clear(&kr); + kr_init(&kr); + kr_display(kr); + if ((errno = kr_import(kr, buf)) != CRYPT_OK) { + printf("Error importing key %s\n", error_to_string(errno)); + exit(-1); + } + kr_display(kr); + + /* now encrypt a buffer */ + for (i = 0; i < 16; i++) buf[i] = i; + len = sizeof(buf3); + if ((errno = kr_encrypt_key(kr, kr->ID, buf, 16, buf3, &len, &prng, find_prng("yarrow"), find_hash("md5"))) != CRYPT_OK) { + printf("Encrypt error, %d, %s\n", i, error_to_string(errno)); + exit(-1); + } + + /* now delete the key and import the private one */ + kr_clear(&kr); + kr_init(&kr); + kr_display(kr); + if ((errno = kr_import(kr, buf2)) != CRYPT_OK) { + printf("Error importing key %s\n", error_to_string(errno)); + exit(-1); + } + kr_display(kr); + + /* now decrypt */ + len = sizeof(buf2); + if ((errno = kr_decrypt_key(kr, buf3, buf2, &len)) != CRYPT_OK) { + printf("decrypt error, %s\n", error_to_string(errno)); + exit(-1); + } + + printf("KR encrypt to public, decrypt with private: "); + if (len == 16 && !memcmp(buf2, buf, 16)) { + printf("passed\n"); + } else { + printf("failed\n"); + } + + kr_clear(&kr); + +} + +void test_errs(void) +{ + #define ERR(x) printf("%25s => %s\n", #x, error_to_string(x)); + + ERR(CRYPT_OK); + ERR(CRYPT_ERROR); + + ERR(CRYPT_INVALID_KEYSIZE); + ERR(CRYPT_INVALID_ROUNDS); + ERR(CRYPT_FAIL_TESTVECTOR); + + ERR(CRYPT_BUFFER_OVERFLOW); + ERR(CRYPT_INVALID_PACKET); + + ERR(CRYPT_INVALID_PRNGSIZE); + ERR(CRYPT_ERROR_READPRNG); + + ERR(CRYPT_INVALID_CIPHER); + ERR(CRYPT_INVALID_HASH); + ERR(CRYPT_INVALID_PRNG); + + ERR(CRYPT_MEM); + + ERR(CRYPT_PK_TYPE_MISMATCH); + ERR(CRYPT_PK_NOT_PRIVATE); + + ERR(CRYPT_INVALID_ARG); + + ERR(CRYPT_PK_INVALID_TYPE); + ERR(CRYPT_PK_INVALID_SYSTEM); + ERR(CRYPT_PK_DUP); + ERR(CRYPT_PK_NOT_FOUND); + ERR(CRYPT_PK_INVALID_SIZE); + + ERR(CRYPT_INVALID_PRIME_SIZE); +} + + + +int main(void) +{ +#ifdef SONY_PS2 + TIMER_Init(); +#endif + + register_all_algs(); + + if ((errno = yarrow_start(&prng)) != CRYPT_OK) { + printf("yarrow_start: %s\n", error_to_string(errno)); + } + if ((errno = yarrow_add_entropy("hello", 5, &prng)) != CRYPT_OK) { + printf("yarrow_add_entropy: %s\n", error_to_string(errno)); + } + if ((errno = yarrow_ready(&prng)) != CRYPT_OK) { + printf("yarrow_ready: %s\n", error_to_string(errno)); + } + + printf(crypt_build_settings); + test_errs(); + + +#ifdef HMAC + printf("HMAC: %s\n", hmac_test() == CRYPT_OK ? "passed" : "failed"); +#endif + + store_tests(); + cipher_tests(); + hash_tests(); + + ecb_tests(); + cbc_tests(); + ctr_tests(); + ofb_tests(); + cfb_tests(); + + rng_tests(); + //test_prime(); + + kr_test(); + rsa_test(); + pad_test(); + ecc_tests(); + dh_tests(); + + gf_tests(); + base64_test(); + + time_ecb(); + time_hash(); + +#ifdef SONY_PS2 + TIMER_Shutdown(); +#endif + + return 0; +} diff --git a/demos/timer.c b/demos/timer.c new file mode 100644 index 0000000..2b2939b --- /dev/null +++ b/demos/timer.c @@ -0,0 +1,7 @@ +/* + * The working version of this file can be found + * at the PlayStation(r)2 Developer Network website + * under the libtomcrypt project. + */ + +#error Please download the implemented version of this file from the PlayStation(r)2 Developer Network website diff --git a/demos/timer.h b/demos/timer.h new file mode 100644 index 0000000..4368dbf --- /dev/null +++ b/demos/timer.h @@ -0,0 +1,51 @@ +#ifndef __TIMER_H__ +#define __TIMER_H__ +/**************************************************************************** +* +* Copyright (c) 2000, Sony Computer Entertainment of America Inc. +* All rights reserved +* SCEA Confidential +* +* Document: TIMER.H +* Author: Ben Wiggins +* Date: 7/15/2002 +* Header: Timer stuff +* +****************************************************************************/ +/*============================================================================ += INTERFACE REQUIRED HEADERS +============================================================================*/ +/*============================================================================ += INTERFACE DEFINITIONS / ENUMERATIONS / SIMPLE TYPEDEFS +============================================================================*/ +/*============================================================================ += INTERFACE STRUCTURES / UTILITY CLASSES +============================================================================*/ +/*============================================================================ += INTERFACE DATA DECLARATIONS +============================================================================*/ +/*============================================================================ += INTERFACE FUNCTION PROTOTYPES +============================================================================*/ +void TIMER_Init(void); +void TIMER_Shutdown(void); +double TIMER_GetTime(void); + +#include +#ifdef CLOCKS_PER_SEC +#undef CLOCKS_PER_SEC +#endif +#define CLOCKS_PER_SEC 576000 +extern clock_t TIMER_clock(void); + +/*============================================================================ += INTERFACE TRAILING HEADERS +============================================================================*/ + +/**************************************************************************** +* +* END HEADER TIMER.H +* +****************************************************************************/ +#endif // __TIMER_H__ + diff --git a/des.c b/des.c new file mode 100644 index 0000000..6edda71 --- /dev/null +++ b/des.c @@ -0,0 +1,728 @@ +/* DES code submitted by Dobes Vandermeer */ +#include "mycrypt.h" + +#ifdef DES + +#define EN0 0 +#define DE1 1 + +const struct _cipher_descriptor des_desc = +{ + "des", + 13, + 8, 8, 8, 16, + &des_setup, + &des_ecb_encrypt, + &des_ecb_decrypt, + &des_test, + &des_keysize +}; + +const struct _cipher_descriptor des3_desc = +{ + "3des", + 14, + 24, 24, 8, 16, + &des3_setup, + &des3_ecb_encrypt, + &des3_ecb_decrypt, + &des3_test, + &des3_keysize +}; + +static const unsigned char Df_Key[24] = +{ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67 +}; + +static const unsigned short bytebit[8] = +{ + 0200, 0100, 040, 020, 010, 04, 02, 01 +}; + +static const unsigned long bigbyte[24] = +{ + 0x800000L, 0x400000L, 0x200000L, 0x100000L, + 0x80000L, 0x40000L, 0x20000L, 0x10000L, + 0x8000L, 0x4000L, 0x2000L, 0x1000L, + 0x800L, 0x400L, 0x200L, 0x100L, + 0x80L, 0x40L, 0x20L, 0x10L, + 0x8L, 0x4L, 0x2L, 0x1L +}; + +/* Use the key schedule specific in the standard (ANSI X3.92-1981) */ + +static const unsigned char pc1[56] = { + 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, + 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, + 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, + 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 +}; + +static const unsigned char totrot[16] = { + 1, 2, 4, 6, + 8, 10, 12, 14, + 15, 17, 19, 21, + 23, 25, 27, 28 +}; + +static const unsigned char pc2[48] = { + 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, + 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, + 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, + 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 +}; + + +static const unsigned long SP1[64] = +{ + 0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L, + 0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L, + 0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L, + 0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L, + 0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L, + 0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L, + 0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L, + 0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L, + 0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L, + 0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L, + 0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L, + 0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L, + 0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L, + 0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L, + 0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L, + 0x00010004L, 0x00010400L, 0x00000000L, 0x01010004 +}; + +static const unsigned long SP2[64] = +{ + 0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L, + 0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L, + 0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L, + 0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L, + 0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L, + 0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L, + 0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L, + 0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L, + 0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L, + 0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L, + 0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L, + 0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L, + 0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L, + 0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L, + 0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L, + 0x80000000L, 0x80100020L, 0x80108020L, 0x00108000 +}; + +static const unsigned long SP3[64] = +{ + 0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L, + 0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L, + 0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L, + 0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L, + 0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L, + 0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L, + 0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L, + 0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L, + 0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L, + 0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L, + 0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L, + 0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L, + 0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L, + 0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L, + 0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L, + 0x00020208L, 0x00000008L, 0x08020008L, 0x00020200 +}; + +static const unsigned long SP4[64] = +{ + 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, + 0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L, + 0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L, + 0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L, + 0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L, + 0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L, + 0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L, + 0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L, + 0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L, + 0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L, + 0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L, + 0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L, + 0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L, + 0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L, + 0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L, + 0x00000080L, 0x00800000L, 0x00002000L, 0x00802080 +}; + +static const unsigned long SP5[64] = +{ + 0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L, + 0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L, + 0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L, + 0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L, + 0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L, + 0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L, + 0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L, + 0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L, + 0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L, + 0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L, + 0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L, + 0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L, + 0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L, + 0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L, + 0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L, + 0x00000000L, 0x40080000L, 0x02080100L, 0x40000100 +}; + +static const unsigned long SP6[64] = +{ + 0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L, + 0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L, + 0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L, + 0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L, + 0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L, + 0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L, + 0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L, + 0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L, + 0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L, + 0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L, + 0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L, + 0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L, + 0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L, + 0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L, + 0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L, + 0x20404000L, 0x20000000L, 0x00400010L, 0x20004010 +}; + +static const unsigned long SP7[64] = +{ + 0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L, + 0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L, + 0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L, + 0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L, + 0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L, + 0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L, + 0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L, + 0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L, + 0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L, + 0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L, + 0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L, + 0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L, + 0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L, + 0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L, + 0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L, + 0x04000002L, 0x04000800L, 0x00000800L, 0x00200002 +}; + +static const unsigned long SP8[64] = +{ + 0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L, + 0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L, + 0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L, + 0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L, + 0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L, + 0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L, + 0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L, + 0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L, + 0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L, + 0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L, + 0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L, + 0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L, + 0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L, + 0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L, + 0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L, + 0x00001040L, 0x00040040L, 0x10000000L, 0x10041000 +}; + + +static void cookey(const unsigned long *raw1, unsigned long *keyout); + +#ifdef CLEAN_STACK +void _deskey(const unsigned char *key, short edf, unsigned long *keyout) +#else +void deskey(const unsigned char *key, short edf, unsigned long *keyout) +#endif +{ + int i, j, l, m, n; + unsigned char pc1m[56], pcr[56]; + unsigned long kn[32]; + + for(j=0; j < 56; j++) + { + l = pc1[j]; + m = l & 07; + pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0; + } + + for(i=0; i < 16; i++) + { + if(edf == DE1) m = (15 - i) << 1; + else m = i << 1; + n = m + 1; + kn[m] = kn[n] = 0L; + for(j=0; j < 28; j++) + { + l = j + totrot[i]; + if(l < 28) pcr[j] = pc1m[l]; + else pcr[j] = pc1m[l - 28]; + } + for(/*j = 28*/; j < 56; j++) + { + l = j + totrot[i]; + if(l < 56) pcr[j] = pc1m[l]; + else pcr[j] = pc1m[l - 28]; + } + for(j=0; j < 24; j++) + { + if(pcr[pc2[j]]) kn[m] |= bigbyte[j]; + if(pcr[pc2[j+24]]) kn[n] |= bigbyte[j]; + } + } + + cookey(kn, keyout); +} + +#ifdef CLEAN_STACK +void deskey(const unsigned char *key, short edf, unsigned long *keyout) +{ + _deskey(key, edf, keyout); + burn_stack(sizeof(int)*5 + sizeof(unsigned long)*32 + sizeof(unsigned char)*112); +} +#endif + +#ifdef CLEAN_STACK +static void _cookey(const unsigned long *raw1, unsigned long *keyout) +#else +static void cookey(const unsigned long *raw1, unsigned long *keyout) +#endif +{ + unsigned long *cook; + const unsigned long *raw0; + unsigned long dough[32]; + int i; + + cook = dough; + for(i=0; i < 16; i++, raw1++) + { + raw0 = raw1++; + *cook = (*raw0 & 0x00fc0000L) << 6; + *cook |= (*raw0 & 0x00000fc0L) << 10; + *cook |= (*raw1 & 0x00fc0000L) >> 10; + *cook++ |= (*raw1 & 0x00000fc0L) >> 6; + *cook = (*raw0 & 0x0003f000L) << 12; + *cook |= (*raw0 & 0x0000003fL) << 16; + *cook |= (*raw1 & 0x0003f000L) >> 4; + *cook++ |= (*raw1 & 0x0000003fL); + } + + memcpy(keyout, dough, sizeof dough); +} + +#ifdef CLEAN_STACK +static void cookey(const unsigned long *raw1, unsigned long *keyout) +{ + _cookey(raw1, keyout); + burn_stack(sizeof(unsigned long *) * 2 + sizeof(unsigned long)*32 + sizeof(int)); +} +#endif + +#ifndef CLEAN_STACK +static void desfunc(unsigned long *block, const unsigned long *keys) +#else +static void _desfunc(unsigned long *block, const unsigned long *keys) +#endif +{ + unsigned long fval, work, right, leftt; + int round; + + leftt = block[0]; + right = block[1]; + + work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; + right ^= work; + leftt ^= (work << 4); + + work = ((leftt >> 16) ^ right) & 0x0000ffffL; + right ^= work; + leftt ^= (work << 16); + + work = ((right >> 2) ^ leftt) & 0x33333333L; + leftt ^= work; + right ^= (work << 2); + + work = ((right >> 8) ^ leftt) & 0x00ff00ffL; + leftt ^= work; + right ^= (work << 8); + + right = ((right << 1) | ((right >> 31) & 1L)) & 0xFFFFFFFFL; + work = (leftt ^ right) & 0xaaaaaaaaL; + + leftt ^= work; + right ^= work; + leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL; + + for( round = 0; round < 8; round++) + { + work = ((right << 28) | (right >> 4)) ^ *keys++; + fval = SP7[ work & 0x3fL] + | SP5[(work >> 8) & 0x3fL] + | SP3[(work >> 16) & 0x3fL] + | SP1[(work >> 24) & 0x3fL]; + work = right ^ *keys++; + fval |= SP8[ work & 0x3fL] + | SP6[(work >> 8) & 0x3fL] + | SP4[(work >> 16) & 0x3fL] + | SP2[(work >> 24) & 0x3fL]; + leftt ^= fval; + + work = ((leftt << 28) | (leftt >> 4)) ^ *keys++; + fval = SP7[ work & 0x3fL] + | SP5[(work >> 8) & 0x3fL] + | SP3[(work >> 16) & 0x3fL] + | SP1[(work >> 24) & 0x3fL]; + work = leftt ^ *keys++; + fval |= SP8[ work & 0x3fL] + | SP6[(work >> 8) & 0x3fL] + | SP4[(work >> 16) & 0x3fL] + | SP2[(work >> 24) & 0x3fL]; + right ^= fval; + } + right = (right << 31) | (right >> 1); + work = (leftt ^ right) & 0xaaaaaaaaL; + leftt ^= work; + right ^= work; + leftt = (leftt << 31) | (leftt >> 1); + work = ((leftt >> 8) ^ right) & 0x00ff00ffL; + right ^= work; + leftt ^= (work << 8); + // -- + work = ((leftt >> 2) ^ right) & 0x33333333L; + right ^= work; + leftt ^= (work << 2); + work = ((right >> 16) ^ leftt) & 0x0000ffffL; + leftt ^= work; + right ^= (work << 16); + work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; + leftt ^= work; + right ^= (work << 4); + + block[0] = right; + block[1] = leftt; +} + +#ifdef CLEAN_STACK +static void desfunc(unsigned long *block, const unsigned long *keys) +{ + _desfunc(block, keys); + burn_stack(sizeof(unsigned long) * 4 + sizeof(int)); +} +#endif + + +int des_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + if (num_rounds != 0 && num_rounds != 16) { + return CRYPT_INVALID_ROUNDS; + } + + if (keylen != 8) { + return CRYPT_INVALID_KEYSIZE; + } + + deskey(key, EN0, skey->des.ek); + deskey(key, DE1, skey->des.dk); + + return CRYPT_OK; +} + +int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + if( num_rounds != 0 && num_rounds != 16) { + return CRYPT_INVALID_ROUNDS; + } + + if (keylen != 24) { + return CRYPT_INVALID_KEYSIZE; + } + + deskey(key, EN0, skey->des3.ek[0]); + deskey(key+8, DE1, skey->des3.ek[1]); + deskey(key+16, EN0, skey->des3.ek[2]); + + deskey(key, DE1, skey->des3.dk[2]); + deskey(key+8, EN0, skey->des3.dk[1]); + deskey(key+16, DE1, skey->des3.dk[0]); + + return CRYPT_OK; +} + +void des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + unsigned long work[2]; + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + LOAD32H(work[0], pt+0); + LOAD32H(work[1], pt+4); + desfunc(work, key->des.ek); + STORE32H(work[0],ct+0); + STORE32H(work[1],ct+4); +} + +void des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +{ + unsigned long work[2]; + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + LOAD32H(work[0], ct+0); + LOAD32H(work[1], ct+4); + desfunc(work, key->des.dk); + STORE32H(work[0],pt+0); + STORE32H(work[1],pt+4); +} + +void des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + unsigned long work[2]; + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + LOAD32H(work[0], pt+0); + LOAD32H(work[1], pt+4); + desfunc(work, key->des3.ek[0]); + desfunc(work, key->des3.ek[1]); + desfunc(work, key->des3.ek[2]); + STORE32H(work[0],ct+0); + STORE32H(work[1],ct+4); +} + +void des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +{ + unsigned long work[2]; + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + LOAD32H(work[0], ct+0); + LOAD32H(work[1], ct+4); + desfunc(work, key->des3.dk[0]); + desfunc(work, key->des3.dk[1]); + desfunc(work, key->des3.dk[2]); + STORE32H(work[0],pt+0); + STORE32H(work[1],pt+4); +} + +int des_test(void) +{ + int errno; + static const struct des_test_case { + int num, mode; // mode 1 = encrypt + unsigned char key[8], txt[8], out[8]; + } cases[] = { + { 1, 1, { 0x10, 0x31, 0x6E, 0x02, 0x8C, 0x8F, 0x3B, 0x4A }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x82, 0xDC, 0xBA, 0xFB, 0xDE, 0xAB, 0x66, 0x02 } }, + { 2, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00 }, + { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 3, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0xDD, 0x7F, 0x12, 0x1C, 0xA5, 0x01, 0x56, 0x19 }, + { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 4, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x2E, 0x86, 0x53, 0x10, 0x4F, 0x38, 0x34, 0xEA }, + { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 5, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x4B, 0xD3, 0x88, 0xFF, 0x6C, 0xD8, 0x1D, 0x4F }, + { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 6, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x20, 0xB9, 0xE7, 0x67, 0xB2, 0xFB, 0x14, 0x56 }, + { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 7, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x55, 0x57, 0x93, 0x80, 0xD7, 0x71, 0x38, 0xEF }, + { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 8, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x6C, 0xC5, 0xDE, 0xFA, 0xAF, 0x04, 0x51, 0x2F }, + { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 9, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x0D, 0x9F, 0x27, 0x9B, 0xA5, 0xD8, 0x72, 0x60 }, + { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + {10, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0xD9, 0x03, 0x1B, 0x02, 0x71, 0xBD, 0x5A, 0x0A }, + { 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + + { 1, 0, { 0x10, 0x31, 0x6E, 0x02, 0x8C, 0x8F, 0x3B, 0x4A }, + { 0x82, 0xDC, 0xBA, 0xFB, 0xDE, 0xAB, 0x66, 0x02 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 2, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00 } }, + { 3, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xDD, 0x7F, 0x12, 0x1C, 0xA5, 0x01, 0x56, 0x19 } }, + { 4, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x2E, 0x86, 0x53, 0x10, 0x4F, 0x38, 0x34, 0xEA } }, + { 5, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x4B, 0xD3, 0x88, 0xFF, 0x6C, 0xD8, 0x1D, 0x4F } }, + { 6, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x20, 0xB9, 0xE7, 0x67, 0xB2, 0xFB, 0x14, 0x56 } }, + { 7, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x55, 0x57, 0x93, 0x80, 0xD7, 0x71, 0x38, 0xEF } }, + { 8, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x6C, 0xC5, 0xDE, 0xFA, 0xAF, 0x04, 0x51, 0x2F } }, + { 9, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x0D, 0x9F, 0x27, 0x9B, 0xA5, 0xD8, 0x72, 0x60 } }, + {10, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xD9, 0x03, 0x1B, 0x02, 0x71, 0xBD, 0x5A, 0x0A } } + + /*** more test cases you could add if you are not convinced (the above test cases aren't really too good): + + key plaintext ciphertext + 0000000000000000 0000000000000000 8CA64DE9C1B123A7 + FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 7359B2163E4EDC58 + 3000000000000000 1000000000000001 958E6E627A05557B + 1111111111111111 1111111111111111 F40379AB9E0EC533 + 0123456789ABCDEF 1111111111111111 17668DFC7292532D + 1111111111111111 0123456789ABCDEF 8A5AE1F81AB8F2DD + 0000000000000000 0000000000000000 8CA64DE9C1B123A7 + FEDCBA9876543210 0123456789ABCDEF ED39D950FA74BCC4 + 7CA110454A1A6E57 01A1D6D039776742 690F5B0D9A26939B + 0131D9619DC1376E 5CD54CA83DEF57DA 7A389D10354BD271 + 07A1133E4A0B2686 0248D43806F67172 868EBB51CAB4599A + 3849674C2602319E 51454B582DDF440A 7178876E01F19B2A + 04B915BA43FEB5B6 42FD443059577FA2 AF37FB421F8C4095 + 0113B970FD34F2CE 059B5E0851CF143A 86A560F10EC6D85B + 0170F175468FB5E6 0756D8E0774761D2 0CD3DA020021DC09 + 43297FAD38E373FE 762514B829BF486A EA676B2CB7DB2B7A + 07A7137045DA2A16 3BDD119049372802 DFD64A815CAF1A0F + 04689104C2FD3B2F 26955F6835AF609A 5C513C9C4886C088 + 37D06BB516CB7546 164D5E404F275232 0A2AEEAE3FF4AB77 + 1F08260D1AC2465E 6B056E18759F5CCA EF1BF03E5DFA575A + 584023641ABA6176 004BD6EF09176062 88BF0DB6D70DEE56 + 025816164629B007 480D39006EE762F2 A1F9915541020B56 + 49793EBC79B3258F 437540C8698F3CFA 6FBF1CAFCFFD0556 + 4FB05E1515AB73A7 072D43A077075292 2F22E49BAB7CA1AC + 49E95D6D4CA229BF 02FE55778117F12A 5A6B612CC26CCE4A + 018310DC409B26D6 1D9D5C5018F728C2 5F4C038ED12B2E41 + 1C587F1C13924FEF 305532286D6F295A 63FAC0D034D9F793 + 0101010101010101 0123456789ABCDEF 617B3A0CE8F07100 + 1F1F1F1F0E0E0E0E 0123456789ABCDEF DB958605F8C8C606 + E0FEE0FEF1FEF1FE 0123456789ABCDEF EDBFD1C66C29CCC7 + 0000000000000000 FFFFFFFFFFFFFFFF 355550B2150E2451 + FFFFFFFFFFFFFFFF 0000000000000000 CAAAAF4DEAF1DBAE + 0123456789ABCDEF 0000000000000000 D5D44FF720683D0D + FEDCBA9876543210 FFFFFFFFFFFFFFFF 2A2BB008DF97C2F2 + + http://www.ecs.soton.ac.uk/~prw99r/ez438/vectors.txt + ***/ + }; + int i, failed=0; + unsigned char out[8]; + symmetric_key des; + + for(i=0; i < (int)(sizeof(cases)/sizeof(cases[0])); i++) + { + if ((errno = des_setup(cases[i].key, 8, 0, &des)) != CRYPT_OK) { + return errno; + } + if (cases[i].mode) { + des_ecb_encrypt(cases[i].txt, out, &des); + } else { + des_ecb_decrypt(cases[i].txt, out, &des); + } + + if (memcmp(cases[i].out, out, sizeof out) != 0) { +#if 0 + int j; + printf("DES test #%d failed!\n", cases[i].num); + + printf( "got: "); + for (j=0; j < (int)sizeof out; j++) { + printf("%02x ", out[j] & 0xff); + } + printf("\nwanted: "); + for(j=0; j < (int)sizeof out; j++) { + printf("%02x ", cases[i].out[j] & 0xff); + } + printf("\n"); +#endif + + failed++; + } + } + + if(failed > 0) { + return CRYPT_FAIL_TESTVECTOR; + } + + return CRYPT_OK; +} + +int des3_test(void) +{ + unsigned char key[24], pt[8], ct[8], tmp[8]; + symmetric_key skey; + int x, errno; + + if ((errno = des_test()) != CRYPT_OK) { + return errno; + } + + for (x = 0; x < 8; x++) { + pt[x] = x; + } + + for (x = 0; x < 24; x++) { + key[x] = x; + } + + if ((errno = des3_setup(key, 24, 0, &skey)) != CRYPT_OK) { + return errno; + } + + des3_ecb_encrypt(pt, ct, &skey); + des3_ecb_decrypt(ct, tmp, &skey); + + if (memcmp(pt, tmp, 8)) { + return CRYPT_FAIL_TESTVECTOR; + } + + return CRYPT_OK; +} + +int des_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize != NULL); + if(*desired_keysize < 8) { + return CRYPT_INVALID_KEYSIZE; + } + *desired_keysize = 8; + return CRYPT_OK; +} + +int des3_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize != NULL); + if(*desired_keysize < 24) { + return CRYPT_INVALID_KEYSIZE; + } + *desired_keysize = 24; + return CRYPT_OK; +} + +#endif + diff --git a/dh.c b/dh.c new file mode 100644 index 0000000..5eb3825 --- /dev/null +++ b/dh.c @@ -0,0 +1,489 @@ +#include "mycrypt.h" + +#ifdef MDH + +static const struct { + int size; + char *name, *base, *prime; +} sets[] = { +#ifdef DH512 +{ + 64, + "DH-512", + "3", + "1793360119486011337223707056216512835002732007217684422667328794587337075124" + "5439587792371960615073855669274087805055507977323024886880985062002853331424" + "203" +}, +#endif +#ifdef DH768 +{ + 96, + "DH-768", + "2", + "2893527720709661239493896562339544088620375736490408468011883030469939904368" + "0860923364582982212457078989335831907131881773994018526277492109945959747917" + "8279025394653904396221302707492255957231214118178743427870878320796645901947" + "9487" +}, +#endif +#ifdef DH1024 +{ + 128, + "DH-1024", + "2", + "3477431594398766260792527967974222231775354473882066076071816639030459075912" + "0194047822362172211817327089848758298713770865641434468581617942085516098634" + "0457973820182883508387588163122354089264395604796675278966117567294812714812" + "7968205965648764507160662831267200108590414847865290564578963676831229604111" + "36319" +}, +#endif +#ifdef DH1280 +{ + 160, + "DH-1280", + "2", + "2618298020488323341377089635550383393554460131909411928885489146533597039863" + "5379029297773089246854323581071445272213255646852180580463169755159411503866" + "4190218001872082125570169842848154404911652982668791288605239288293106162305" + "7236093554796242806887062958692596037823904832542385180840218330924392268465" + "0197244314233248991982159235832322194332167923655574170280697353556560854901" + "280047" +}, +#endif +#ifdef DH1536 +{ + 192, + "DH-1536", + "3", + "2992593690703251306835100868059076484222548092264611010748654597096560864537" + "1704684310938824733433085888971827086341295918925237859522548192211945291282" + "1170570153374563548621496076860061698150233114892317627457427359445435608693" + "5625000902194809114890745455404045166957722404567939575618007347432055137282" + "3291711752537781447636541738638119983678441628437171377508654097130147131310" + "9209393805685590941710151477648542896503595482724205166251069428524927527085" + "2602467" +}, +#endif +#ifdef DH1792 +{ + 224, + "DH-1792", + "2", + "3210090394251532205679207425273650879078185529033544241951292722086520015900" + "0402371844205168176419829949232601235193754977706171541009393172204470047690" + "6659627844880912479392592056697278305733615369406596661203184035142652643118" + "1379603333858737848321053048184938839622944591194935387992479717305577175500" + "2554620614907177847128950276247571809502831255425929468853285490357704941968" + "3407102520889651917659577334897408316217748346860775479727332331727022096550" + "7718799868459391361770854814013613619048768630587629568449528005570971478547" + "34960319" +}, +#endif +#ifdef DH2048 +{ + 256, + "DH-2048", + "2", + "4726642895635639316469736509812041897640060270607231273592407174543853221823" + "7979333351774907308168340693326687317443721193266215155735814510792148768576" + "4984911991227443513994894535335532038333186916782632419417062569961974604240" + "2901241901263467186228353234265630967717360250949841797609150915436003989316" + "5037637034737020327399910409885798185771003505320583967737293415979917317338" + "9858373857347474783642420203804168920566508414708692945275435973492502995396" + "8243060517332102902655554683247304860032703684578197028928889831788842751736" + "4945316709081173840186150794397479045034008257793436817683392375274635794835" + "245695887" +}, +#endif +#ifdef DH2560 +{ + 320, + "DH-2560", + "3", + "4364638085059577685748948703943497396233464406019459611612544400721432981520" + "4010567649104824811014627875285783993051576616744140702150122992472133564455" + "7342265864606569000117714935185566842453630868849121480179691838399545644365" + "5711067577313173717585579907818806913366955847993133136872874688941488237617" + "8558298254958618375680644901754262226787427510387748147553499120184991222267" + "0102069951687572917937634467778042874315463238062009202992087620963771759666" + "4482665328580794026699200252242206134194410697184828373996126449788399252071" + "0987084027819404215874884544513172913711709852902888677006373648742061314404" + "5836803985635654192482395882603511950547826439092832800532152534003936926017" + "6124466061356551464456206233957889787267447285030586700468858762515271223502" + "75750995227" +}, +#endif +#ifdef DH3072 +{ + 384, + "DH-3072", + "2", + "1142416747335183639807830604262436227795642944052113706188970261176634876069" + "2206243140413411077394583180726863277012016602279290144126785129569474909173" + "5847898223419867427192303319460727303195559844849117167970588759054009995043" + "0587724584911968750902323279027363746682105257685923245298206183100977078603" + "1785669030271542286603956118755585683996118896215213488875253101894663403069" + "6777459483058938495054342017637452328957807119724320113448575216910178963168" + "6140320644942133224365885545343578400651720289418164056243357539082138421096" + "0117518650374602256601091379644034244332285065935413233557998331562749140202" + "9658442193362989700115138825649355387042894469683222814519074873620465114612" + "2132979989735099337056069750580968643878203623537213701573130477907243026098" + "6460269894522159103008260495503005267165927542949439526272736586626709581721" + "0321895327263896436255906801057848442461527026701693042037830722750891947548" + "89511973916207" +}, +#endif +#ifdef DH4096 +{ + 512, + "DH-4096", + "3", + "1214855636816562637502584060163403830270705000634713483015101384881871978446" + "8012247985361554068958233050354675916325310675478909486951171720769542207270" + "7568804875102242119871203284889005635784597424656074834791863005085393369779" + "2254955890439720297560693579400297062396904306270145886830719309296352765295" + "7121830407731464190228751653827780070401099576097395898755908857011261979060" + "6362013395489321661267883850754077713843779770560245371955901763398648664952" + "3611975865005712371194067612263330335590526176087004421363598470302731349138" + "7732059014477046821815179040647356365184624522427916765417252923789255682968" + "5801015185232631677751193503753101741391050692192245066693320227848902452126" + "3798482237150056835746454842662048692127173834433089016107854491097456725016" + "3277096631997382384421648431471327891537255132571679155551620949708535844479" + "9312548860769600816980737473671129700747381225627224548940589847029717873802" + "9484459690836250560495461579533254473316340608217876781986188705928270735695" + "7528308255279638383554197625162460286802809880204019145518254873499903069763" + "0409310938445143881325121105159739212749146489879740678917545306796007200859" + "0614886532333015881171367104445044718144312416815712216611576221546455968770" + "801413440778423979" +}, +#endif +{ + 0, + NULL, + NULL, + NULL +} +}; + +static int is_valid_idx(int n) +{ + int x; + + for (x = 0; sets[x].size; x++); + if ((n < 0) || (n >= x)) { + return 0; + } + return 1; +} + +int dh_test(void) +{ + mp_int p, g, tmp; + int x, res, primality; + + if (mp_init_multi(&p, &g, &tmp, NULL) != MP_OKAY) { goto error; } + + for (x = 0; sets[x].size; x++) { +#if 0 + printf("dh_test():testing size %d-bits\n", sets[x].size * 8); +#endif + /* see if g^((p-1)/2) == 1 mod p. */ + if (mp_read_radix(&g, sets[x].base, 10) != MP_OKAY) { goto error; } + if (mp_read_radix(&p, sets[x].prime, 10) != MP_OKAY) { goto error; } + + /* ensure p is prime */ + if ((res = is_prime(&p, &primality)) != CRYPT_OK) { goto done; } + if (primality == 0) { + res = CRYPT_FAIL_TESTVECTOR; + goto done; + } + + if (mp_sub_d(&p, 1, &tmp) != MP_OKAY) { goto error; } + if (mp_div_2(&tmp, &tmp) != MP_OKAY) { goto error; } + + /* ensure (p-1)/2 is prime */ + if ((res = is_prime(&tmp, &primality)) != CRYPT_OK) { goto done; } + if (primality == 0) { + res = CRYPT_FAIL_TESTVECTOR; + goto done; + } + + /* now see if g^((p-1)/2) mod p is in fact 1 */ + if (mp_exptmod(&g, &tmp, &p, &tmp) != MP_OKAY) { goto error; } + if (mp_cmp_d(&tmp, 1)) { + res = CRYPT_FAIL_TESTVECTOR; + goto done; + } + } + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +done: + mp_clear_multi(&tmp, &g, &p, NULL); + return res; +} + +void dh_sizes(int *low, int *high) +{ + int x; + _ARGCHK(low != NULL); + _ARGCHK(high != NULL); + *low = INT_MAX; + *high = 0; + for (x = 0; sets[x].size; x++) { + if (*low > sets[x].size) *low = sets[x].size; + if (*high < sets[x].size) *high = sets[x].size; + } +} + +int dh_get_size(dh_key *key) +{ + _ARGCHK(key != NULL); + if (is_valid_idx(key->idx)) + return sets[key->idx].size; + else + return INT_MAX; /* large value that would cause dh_make_key() to fail */ +} + +int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key) +{ + unsigned char buf[768]; + unsigned long x; + mp_int p, g; + int res, errno; + + _ARGCHK(key != NULL); + + /* good prng? */ + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + /* find key size */ + for (x = 0; (keysize > sets[x].size) && (sets[x].size); x++); +#ifdef FAST_PK + keysize = MIN(sets[x].size, 32); +#else + keysize = sets[x].size; +#endif + + if (sets[x].size == 0) { + return CRYPT_INVALID_KEYSIZE; + } + key->idx = x; + + /* make up random string */ + buf[0] = 0; + if (prng_descriptor[wprng].read(buf+1, keysize, prng) != (unsigned long)keysize) { + return CRYPT_ERROR_READPRNG; + } + + /* init parameters */ + if (mp_init_multi(&g, &p, &key->x, &key->y, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + if (mp_read_radix(&g, sets[x].base, 10) != MP_OKAY) { goto error2; } + if (mp_read_radix(&p, sets[x].prime, 10) != MP_OKAY) { goto error2; } + + /* load the x value */ + mp_read_raw(&key->x, buf, keysize+1); + if (mp_exptmod(&g, &key->x, &p, &key->y) != MP_OKAY) { goto error2; } + key->type = PK_PRIVATE; + + /* free up ram */ + res = CRYPT_OK; + goto done2; +error2: + res = CRYPT_MEM; + mp_clear_multi(&key->x, &key->y, NULL); +done2: + mp_clear_multi(&p, &g, NULL); + zeromem(buf, sizeof(buf)); + return res; +} + +void dh_free(dh_key *key) +{ + _ARGCHK(key != NULL); + mp_clear_multi(&key->x, &key->y, NULL); +} + +#define OUTPUT_BIGNUM(num, buf2, y, z) \ +{ \ + z = mp_raw_size(num); \ + STORE32L(z, buf2+y); \ + y += 4; \ + mp_toraw(num, buf2+y); \ + y += z; \ +} + + +#define INPUT_BIGNUM(num, in, x, y) \ +{ \ + /* load value */ \ + LOAD32L(x, in+y); \ + y += 4; \ + \ + /* sanity check... */ \ + if (x > 1024) { \ + errno = CRYPT_ERROR; \ + goto error; \ + } \ + \ + /* load it */ \ + if (mp_read_raw(num, (unsigned char *)in+y, x) != MP_OKAY) {\ + return CRYPT_MEM; \ + goto error; \ + } \ + y += x; \ +} + + +int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key) +{ + unsigned char buf2[1536]; + unsigned long y, z; + + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + if (type == PK_PRIVATE && key->type != PK_PRIVATE) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* header */ + y = PACKET_SIZE; + + /* header */ + buf2[y++] = type; + buf2[y++] = key->idx; + + /* export y */ + OUTPUT_BIGNUM(&key->y, buf2, y, z); + + if (type == PK_PRIVATE) { + /* export x */ + OUTPUT_BIGNUM(&key->x, buf2, y, z); + } + + /* check for overflow */ + if (*outlen < y) { + #ifdef CLEAN_STACK + zeromem(buf2, sizeof(buf2)); + #endif + return CRYPT_BUFFER_OVERFLOW; + } + + /* store header */ + packet_store_header(buf2, PACKET_SECT_DH, PACKET_SUB_KEY, y); + + /* output it */ + *outlen = y; + memcpy(out, buf2, y); + + /* clear mem */ + zeromem(buf2, sizeof(buf2)); + return CRYPT_OK; +} + +int dh_import(const unsigned char *in, dh_key *key) +{ + long x, y; + int errno; + + _ARGCHK(in != NULL); + _ARGCHK(key != NULL); + + /* check type byte */ + if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_KEY)) != CRYPT_OK) { + return errno; + } + + /* init */ + if (mp_init_multi(&key->x, &key->y, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + y = PACKET_SIZE; + key->type = in[y++]; + key->idx = in[y++]; + + /* type check both values */ + if ((key->type != PK_PUBLIC) && (key->type != PK_PRIVATE)) { + errno = CRYPT_PK_TYPE_MISMATCH; + goto error; + } + + /* is the key idx valid? */ + if (!is_valid_idx(key->idx)) { + errno = CRYPT_PK_TYPE_MISMATCH; + goto error; + } + + /* load public value g^x mod p*/ + INPUT_BIGNUM(&key->y, in, x, y); + + if (key->type == PK_PRIVATE) { + INPUT_BIGNUM(&key->x, in, x, y); + } + return CRYPT_OK; +error: + mp_clear_multi(&key->y, &key->x, NULL); + return errno; +} + +int dh_shared_secret(dh_key *private_key, dh_key *public_key, + unsigned char *out, unsigned long *outlen) +{ + mp_int tmp, p; + unsigned long x; + int res; + + _ARGCHK(private_key != NULL); + _ARGCHK(public_key != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* types valid? */ + if (private_key->type != PK_PRIVATE) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* same idx? */ + if (private_key->idx != public_key->idx) { + return CRYPT_PK_TYPE_MISMATCH; + } + + /* compute y^x mod p */ + if (mp_init_multi(&tmp, &p, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + if (mp_read_radix(&p, sets[private_key->idx].prime, 10) != MP_OKAY) { goto error; } + if (mp_exptmod(&public_key->y, &private_key->x, &p, &tmp) != MP_OKAY) { goto error; } + + /* enough space for output? */ + x = mp_raw_size(&tmp); + if (*outlen < x) { + res = CRYPT_BUFFER_OVERFLOW; + goto done; + } + mp_toraw(&tmp, out); + *outlen = x; + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +done: + mp_clear_multi(&p, &tmp, NULL); + return res; +} + +#include "dh_sys.c" + +#endif + diff --git a/dh_sys.c b/dh_sys.c new file mode 100644 index 0000000..b5652a9 --- /dev/null +++ b/dh_sys.c @@ -0,0 +1,774 @@ +#ifdef PK_PACKET + +int dh_encrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, int cipher, int hash, + dh_key *key) +{ + unsigned char pub_expt[1536], dh_shared[1536], IV[MAXBLOCKSIZE], skey[MAXBLOCKSIZE]; + dh_key pubkey; + unsigned long x, y, z, hashsize, blocksize, pubkeysize; + int keysize, errno; + symmetric_CTR ctr; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* check that wprng/cipher/hash are not invalid */ + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + if ((errno = hash_is_valid(hash)) != CRYPT_OK) { + return errno; + } + + if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) { + return errno; + } + + /* make a random key and export the public copy */ + if ((errno = dh_make_key(prng, wprng, dh_get_size(key), &pubkey)) != CRYPT_OK) { + return errno; + } + + pubkeysize = sizeof(pub_expt); + if ((errno = dh_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { + dh_free(&pubkey); + return errno; + } + + /* now check if the out buffer is big enough */ + if (*outlen < (10 + PACKET_SIZE + pubkeysize + cipher_descriptor[cipher].block_length + len)) { + dh_free(&pubkey); + return CRYPT_BUFFER_OVERFLOW; + } + + /* make random key */ + blocksize = cipher_descriptor[cipher].block_length; + hashsize = hash_descriptor[hash].hashsize; + keysize = hashsize; + if ((errno = cipher_descriptor[cipher].keysize(&keysize)) != CRYPT_OK) { + dh_free(&pubkey); + return errno; + } + + x = sizeof(dh_shared); + if ((errno = dh_shared_secret(&pubkey, key, dh_shared, &x)) != CRYPT_OK) { + dh_free(&pubkey); + return errno; + } + dh_free(&pubkey); + + z = sizeof(skey); + if ((errno = hash_memory(hash, dh_shared, x, skey, &z)) != CRYPT_OK) { + return errno; + } + + /* make up IV */ + if (prng_descriptor[wprng].read(IV, cipher_descriptor[cipher].block_length, prng) != + cipher_descriptor[cipher].block_length) { + return CRYPT_ERROR_READPRNG; + } + + /* setup CTR mode */ + if ((errno = ctr_start(cipher, IV, skey, keysize, 0, &ctr)) != CRYPT_OK) { + return errno; + } + + /* output header */ + y = PACKET_SIZE; + + /* size of cipher name and the name itself */ + out[y++] = cipher_descriptor[cipher].ID; + + /* size of hash name and the name itself */ + out[y++] = hash_descriptor[hash].ID; + + /* length of DH pubkey and the key itself */ + STORE32L(pubkeysize, out+y); + y += 4; + for (x = 0; x < pubkeysize; x++, y++) { + out[y] = pub_expt[x]; + } + + /* cipher IV */ + for (x = 0; x < blocksize; x++, y++) { + out[y] = IV[x]; + } + + /* length of ciphertext */ + STORE32L(len, out+y); + y += 4; + + /* encrypt the message */ + if ((errno = ctr_encrypt(in, out+y, len, &ctr)) != CRYPT_OK) { + return errno; + } + y += len; + + /* store header */ + packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_ENCRYPTED, y); + +#ifdef CLEAN_STACK + /* clean up */ + zeromem(pub_expt, sizeof(pub_expt)); + zeromem(dh_shared, sizeof(dh_shared)); + zeromem(skey, sizeof(skey)); + zeromem(IV, sizeof(IV)); + zeromem(&ctr, sizeof(ctr)); +#endif + *outlen = y; + return CRYPT_OK; +} + +int dh_decrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + dh_key *key) +{ + unsigned char shared_secret[1536], skey[MAXBLOCKSIZE]; + unsigned long x, y, z, res, hashsize, blocksize; + int hash, cipher, keysize, errno; + dh_key pubkey; + symmetric_CTR ctr; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* right key type? */ + if (key->type != PK_PRIVATE) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* is header correct? */ + if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_ENCRYPTED)) != CRYPT_OK) { + return errno; + } + + /* now lets get the cipher name */ + y = PACKET_SIZE; + cipher = find_cipher_id(in[y++]); + if (cipher == -1) { + return CRYPT_INVALID_CIPHER; + } + + /* now lets get the hash name */ + hash = find_hash_id(in[y++]); + if (hash == -1) { + return CRYPT_INVALID_HASH; + } + + /* common values */ + blocksize = cipher_descriptor[cipher].block_length; + hashsize = hash_descriptor[hash].hashsize; + keysize = hashsize; + if ((errno = cipher_descriptor[cipher].keysize(&keysize)) != CRYPT_OK) { + return errno; + } + + /* get public key */ + LOAD32L(x, in+y); + y += 4; + if ((errno = dh_import(in+y, &pubkey)) != CRYPT_OK) { + return errno; + } + y += x; + + /* make shared key */ + x = sizeof(shared_secret); + if ((errno = dh_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) { + dh_free(&pubkey); + return errno; + } + dh_free(&pubkey); + + z = sizeof(skey); + if ((errno = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) { + return errno; + } + + /* setup CTR mode */ + if ((errno = ctr_start(cipher, in+y, skey, keysize, 0, &ctr)) != CRYPT_OK) { + res = errno; + goto done; + } + + /* skip over the IV */ + y += blocksize; + + /* get length */ + LOAD32L(len,in+y); + y += 4; + + /* buffer overflow? */ + if (len > *outlen) { + res = CRYPT_BUFFER_OVERFLOW; + goto done; + } + + /* decrypt message */ + if ((errno = ctr_decrypt(in+y, out, len, &ctr)) != CRYPT_OK) { + res = errno; + goto done; + } + *outlen = len; + + res = CRYPT_OK; +done: +#ifdef CLEAN_STACK + zeromem(shared_secret, sizeof(shared_secret)); + zeromem(skey, sizeof(skey)); + zeromem(&ctr, sizeof(ctr)); +#endif + return res; +} + +int dh_sign(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + int hash, prng_state *prng, int wprng, + dh_key *key) +{ + mp_int a, b, k, m, g, p, p1, tmp; + unsigned char buf[1536], md[MAXBLOCKSIZE]; + unsigned long x, y, z; + int res, errno; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* check parameters */ + if (key->type != PK_PRIVATE) { + return CRYPT_PK_NOT_PRIVATE; + } + + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + if ((errno = hash_is_valid(hash)) != CRYPT_OK) { + return errno; + } + + /* hash the message */ + z = sizeof(md) - 1; + md[0] = 0; + if ((errno = hash_memory(hash, in, inlen, md+1, &z)) != CRYPT_OK) { + return errno; + } + + /* make up a random value k, + * since the order of the group is prime + * we need not check if gcd(k, r) is 1 + */ + buf[0] = 0; + if (prng_descriptor[wprng].read(buf+1, sets[key->idx].size-1, prng) != (unsigned long)(sets[key->idx].size-1)) { + return CRYPT_ERROR_READPRNG; + } + + /* init bignums */ + if (mp_init_multi(&a, &b, &k, &m, &p, &g, &p1, &tmp, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + /* load k and m */ + if (mp_read_raw(&m, md, 1+hash_descriptor[hash].hashsize) != MP_OKAY) { goto error; } + if (mp_read_raw(&k, buf, sets[key->idx].size) != MP_OKAY) { goto error; } + + /* load g, p and p1 */ + if (mp_read_radix(&g, sets[key->idx].base, 10) != MP_OKAY) { goto error; } + if (mp_read_radix(&p, sets[key->idx].prime, 10) != MP_OKAY) { goto error; } + if (mp_sub_d(&p, 1, &p1) != MP_OKAY) { goto error; } /* p1 = p-1 */ + if (mp_div_2(&p1, &p1) != MP_OKAY) { goto error; } /* p1 = (p-1)/2 */ + + /* now get a = g^k mod p */ + if (mp_exptmod(&g, &k, &p, &a) != MP_OKAY) { goto error; } /* a = g^k mod p */ + + /* now find M = xa + kb mod p1 or just b = (M - xa)/k mod p1 */ + if (mp_invmod(&k, &p1, &k) != MP_OKAY) { goto error; } /* k = 1/k mod p1 */ + if (mp_mulmod(&a, &key->x, &p1, &tmp) != MP_OKAY) { goto error; } /* tmp = xa */ + if (mp_submod(&m, &tmp, &p1, &tmp) != MP_OKAY) { goto error; } /* tmp = M - xa */ + if (mp_mulmod(&k, &tmp, &p1, &b) != MP_OKAY) { goto error; } /* b = (M - xa)/k */ + + /* store header */ + y = PACKET_SIZE; + + /* store length and name of hash */ + buf[y++] = hash_descriptor[hash].ID; /* store hash ID */ + + /* now store them both (a,b) */ + x = mp_raw_size(&a); /* get raw size of a */ + STORE32L(x, buf+y); y += 4; /* store size of a */ + mp_toraw(&a, buf+y); y += x; /* store a itself */ + + x = mp_raw_size(&b); /* get raw size of b */ + STORE32L(x, buf+y); y += 4; /* store size of b */ + mp_toraw(&b, buf+y); y += x; /* store b itself */ + + /* check if size too big */ + if (*outlen < y) { goto error; } + + /* store header */ + packet_store_header(buf, PACKET_SECT_DH, PACKET_SUB_SIGNED, y); + + /* store it */ + memcpy(out, buf, y); + *outlen = y; + +#ifdef CLEAN_STACK + zeromem(md, sizeof(md)); + zeromem(buf, sizeof(buf)); +#endif + + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +done: + mp_clear_multi(&tmp, &p1, &g, &p, &m, &k, &b, &a, NULL); + return res; +} + +int dh_verify(const unsigned char *sig, const unsigned char *msg, + unsigned long inlen, int *stat, + dh_key *key) +{ + mp_int a, b, p, g, m, tmp; + unsigned char md[MAXBLOCKSIZE]; + unsigned long x, y, z; + int hash, res, errno; + + _ARGCHK(sig != NULL); + _ARGCHK(msg != NULL); + _ARGCHK(stat != NULL); + _ARGCHK(key != NULL); + + /* default to invalid */ + *stat = 0; + + /* header ok? */ + if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_DH, PACKET_SUB_SIGNED)) != CRYPT_OK) { + return errno; + } + + /* get hash out of packet */ + y = PACKET_SIZE; + hash = find_hash_id(sig[y++]); + + if (hash == -1) { + return CRYPT_INVALID_HASH; + } + + /* hash the message */ + md[0] = 0; + z = sizeof(md) - 1; + if ((errno = hash_memory(hash, msg, inlen, md+1, &z)) != CRYPT_OK) { + return errno; + } + + /* init all bignums */ + if (mp_init_multi(&a, &p, &b, &g, &m, &tmp, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + /* load a and b */ + LOAD32L(x, sig+y); + y += 4; + if (mp_read_raw(&a, (unsigned char *)sig+y, x) != MP_OKAY) { goto error; } + y += x; + + LOAD32L(x, sig+y); + y += 4; + if (mp_read_raw(&b, (unsigned char *)sig+y, x) != MP_OKAY) { goto error; } + y += x; + + /* load p and g */ + if (mp_read_radix(&p, sets[key->idx].prime, 10) != MP_OKAY) { goto error; } + if (mp_read_radix(&g, sets[key->idx].base, 10) != MP_OKAY) { goto error; } + + /* load m */ + if (mp_read_raw(&m, md, hash_descriptor[hash].hashsize + 1) != MP_OKAY) { goto error; } + + /* find g^m mod p */ + if (mp_exptmod(&g, &m, &p, &m) != MP_OKAY) { goto error; } /* m = g^m mod p */ + + /* find y^a * a^b */ + if (mp_exptmod(&key->y, &a, &p, &tmp) != MP_OKAY) { goto error; } /* tmp = y^a mod p */ + if (mp_exptmod(&a, &b, &p, &a) != MP_OKAY) { goto error; } /* a = a^b mod p */ + if (mp_mulmod(&a, &tmp, &p, &a) != MP_OKAY) { goto error; } /* a = y^a * a^b mod p */ + + /* y^a * a^b == g^m ??? */ + if (mp_cmp(&a, &m) == 0) { + *stat = 1; + } + + /* clean up */ + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +done: + mp_clear_multi(&tmp, &m, &g, &p, &b, &a, NULL); +#ifdef CLEAN_STACK + zeromem(md, sizeof(md)); +#endif + return res; +} + +#endif + +int dh_encrypt_key(const unsigned char *inkey, unsigned long keylen, + unsigned char *out, unsigned long *len, + prng_state *prng, int wprng, int hash, + dh_key *key) +{ + unsigned char pub_expt[1536], dh_shared[1536], skey[MAXBLOCKSIZE]; + dh_key pubkey; + unsigned long x, y, z, hashsize, pubkeysize; + int errno; + + _ARGCHK(inkey != NULL); + _ARGCHK(out != NULL); + _ARGCHK(len != NULL); + _ARGCHK(key != NULL); + + /* check that wprng/hash are not invalid */ + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + if ((errno = hash_is_valid(hash)) != CRYPT_OK) { + return errno; + } + + if (keylen > hash_descriptor[hash].hashsize) { + return CRYPT_INVALID_ARG; + } + + /* make a random key and export the public copy */ + if ((errno = dh_make_key(prng, wprng, dh_get_size(key), &pubkey)) != CRYPT_OK) { + return errno; + } + + pubkeysize = sizeof(pub_expt); + if ((errno = dh_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { + dh_free(&pubkey); + return errno; + } + + /* now check if the out buffer is big enough */ + if (*len < (9 + PACKET_SIZE + pubkeysize + keylen)) { + dh_free(&pubkey); + return CRYPT_BUFFER_OVERFLOW; + } + + /* make random key */ + hashsize = hash_descriptor[hash].hashsize; + + x = sizeof(dh_shared); + if ((errno = dh_shared_secret(&pubkey, key, dh_shared, &x)) != CRYPT_OK) { + dh_free(&pubkey); + return errno; + } + dh_free(&pubkey); + + z = sizeof(skey); + if ((errno = hash_memory(hash, dh_shared, x, skey, &z)) != CRYPT_OK) { + return errno; + } + + /* output header */ + y = PACKET_SIZE; + + /* size of hash name and the name itself */ + out[y++] = hash_descriptor[hash].ID; + + /* length of DH pubkey and the key itself */ + STORE32L(pubkeysize, out+y); + y += 4; + for (x = 0; x < pubkeysize; x++, y++) { + out[y] = pub_expt[x]; + } + + /* Store the encrypted key */ + STORE32L(keylen, out+y); + y += 4; + + for (x = 0; x < keylen; x++, y++) { + out[y] = skey[x] ^ inkey[x]; + } + + /* store header */ + packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_ENC_KEY, y); + +#ifdef CLEAN_STACK + /* clean up */ + zeromem(pub_expt, sizeof(pub_expt)); + zeromem(dh_shared, sizeof(dh_shared)); + zeromem(skey, sizeof(skey)); +#endif + + *len = y; + return CRYPT_OK; +} + +int dh_decrypt_key(const unsigned char *in, unsigned char *outkey, + unsigned long *keylen, dh_key *key) +{ + unsigned char shared_secret[1536], skey[MAXBLOCKSIZE]; + unsigned long x, y, z, res, hashsize, keysize; + int hash, errno; + dh_key pubkey; + + _ARGCHK(in != NULL); + _ARGCHK(outkey != NULL); + _ARGCHK(keylen != NULL); + _ARGCHK(key != NULL); + + /* right key type? */ + if (key->type != PK_PRIVATE) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* is header correct? */ + if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_ENC_KEY)) != CRYPT_OK) { + return errno; + } + + /* now lets get the hash name */ + y = PACKET_SIZE; + hash = find_hash_id(in[y++]); + if (hash == -1) { + return CRYPT_INVALID_HASH; + } + + /* common values */ + hashsize = hash_descriptor[hash].hashsize; + + /* get public key */ + LOAD32L(x, in+y); + y += 4; + if ((errno = dh_import(in+y, &pubkey)) != CRYPT_OK) { + return errno; + } + y += x; + + /* make shared key */ + x = sizeof(shared_secret); + if ((errno = dh_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) { + dh_free(&pubkey); + return errno; + } + dh_free(&pubkey); + + z = sizeof(skey); + if ((errno = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) { + return errno; + } + + /* load in the encrypted key */ + LOAD32L(keysize, in+y); + if (keysize > *keylen) { + res = CRYPT_BUFFER_OVERFLOW; + goto done; + } + y += 4; + + *keylen = keysize; + + for (x = 0; x < keysize; x++, y++) { + outkey[x] = skey[x] ^ in[y]; + } + + res = CRYPT_OK; +done: +#ifdef CLEAN_STACK + zeromem(shared_secret, sizeof(shared_secret)); + zeromem(skey, sizeof(skey)); +#endif + return res; +} + + +int dh_sign_hash(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, dh_key *key) +{ + mp_int a, b, k, m, g, p, p1, tmp; + unsigned char buf[1536], md[MAXBLOCKSIZE]; + unsigned long x, y; + int res, errno; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* check parameters */ + if (key->type != PK_PRIVATE) { + return CRYPT_PK_NOT_PRIVATE; + } + + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + /* hash the message */ + md[0] = 0; + memcpy(md+1, in, MIN(sizeof(md) - 1, inlen)); + + /* make up a random value k, + * since the order of the group is prime + * we need not check if gcd(k, r) is 1 + */ + buf[0] = 0; + if (prng_descriptor[wprng].read(buf+1, sets[key->idx].size-1, prng) != + (unsigned long)(sets[key->idx].size-1)) { + return CRYPT_ERROR_READPRNG; + } + + /* init bignums */ + if (mp_init_multi(&a, &b, &k, &m, &p, &g, &p1, &tmp, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + /* load k and m */ + if (mp_read_raw(&m, md, 1+MIN(sizeof(md) - 1, inlen)) != MP_OKAY) { goto error; } + if (mp_read_raw(&k, buf, sets[key->idx].size) != MP_OKAY) { goto error; } + + /* load g, p and p1 */ + if (mp_read_radix(&g, sets[key->idx].base, 10) != MP_OKAY) { goto error; } + if (mp_read_radix(&p, sets[key->idx].prime, 10) != MP_OKAY) { goto error; } + if (mp_sub_d(&p, 1, &p1) != MP_OKAY) { goto error; } + if (mp_div_2(&p1, &p1) != MP_OKAY) { goto error; } /* p1 = (p-1)/2 */ + + /* now get a = g^k mod p */ + if (mp_exptmod(&g, &k, &p, &a) != MP_OKAY) { goto error; } + + /* now find M = xa + kb mod p1 or just b = (M - xa)/k mod p1 */ + if (mp_invmod(&k, &p1, &k) != MP_OKAY) { goto error; } /* k = 1/k mod p1 */ + if (mp_mulmod(&a, &key->x, &p1, &tmp) != MP_OKAY) { goto error; } /* tmp = xa */ + if (mp_submod(&m, &tmp, &p1, &tmp) != MP_OKAY) { goto error; } /* tmp = M - xa */ + if (mp_mulmod(&k, &tmp, &p1, &b) != MP_OKAY) { goto error; } /* b = (M - xa)/k */ + + /* store header */ + y = PACKET_SIZE; + + /* now store them both (a,b) */ + x = mp_raw_size(&a); + STORE32L(x, buf+y); y += 4; + mp_toraw(&a, buf+y); y += x; + + x = mp_raw_size(&b); + STORE32L(x, buf+y); y += 4; + mp_toraw(&b, buf+y); y += x; + + /* check if size too big */ + if (*outlen < y) { + res = CRYPT_BUFFER_OVERFLOW; + goto done; + } + + /* store header */ + packet_store_header(buf, PACKET_SECT_DH, PACKET_SUB_SIGNED, y); + + /* store it */ + memcpy(out, buf, y); + *outlen = y; +#ifdef CLEAN_STACK + zeromem(md, sizeof(md)); + zeromem(buf, sizeof(buf)); +#endif + + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +done: + mp_clear_multi(&tmp, &p1, &g, &p, &m, &k, &b, &a, NULL); + return res; +} + +int dh_verify_hash(const unsigned char *sig, const unsigned char *hash, + unsigned long inlen, int *stat, + dh_key *key) +{ + mp_int a, b, p, g, m, tmp; + unsigned char md[MAXBLOCKSIZE]; + unsigned long x, y; + int res, errno; + + _ARGCHK(sig != NULL); + _ARGCHK(hash != NULL); + _ARGCHK(stat != NULL); + _ARGCHK(key != NULL); + + /* default to invalid */ + *stat = 0; + + /* header ok? */ + if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_DH, PACKET_SUB_SIGNED)) != CRYPT_OK) { + return errno; + } + + /* get hash out of packet */ + y = PACKET_SIZE; + + /* hash the message */ + md[0] = 0; + memcpy(md+1, hash, MIN(sizeof(md) - 1, inlen)); + + /* init all bignums */ + if (mp_init_multi(&a, &p, &b, &g, &m, &tmp, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + /* load a and b */ + LOAD32L(x, sig+y); + y += 4; + if (mp_read_raw(&a, (unsigned char *)sig+y, x) != MP_OKAY) { goto error; } + y += x; + + LOAD32L(x, sig+y); + y += 4; + if (mp_read_raw(&b, (unsigned char *)sig+y, x) != MP_OKAY) { goto error; } + y += x; + + /* load p and g */ + if (mp_read_radix(&p, sets[key->idx].prime, 10) != MP_OKAY) { goto error; } + if (mp_read_radix(&g, sets[key->idx].base, 10) != MP_OKAY) { goto error; } + + /* load m */ + if (mp_read_raw(&m, md, 1+MIN(sizeof(md)-1, inlen)) != MP_OKAY) { goto error; } + + /* find g^m mod p */ + if (mp_exptmod(&g, &m, &p, &m) != MP_OKAY) { goto error; } /* m = g^m mod p */ + + /* find y^a * a^b */ + if (mp_exptmod(&key->y, &a, &p, &tmp) != MP_OKAY) { goto error; } /* tmp = y^a mod p */ + if (mp_exptmod(&a, &b, &p, &a) != MP_OKAY) { goto error; } /* a = a^b mod p */ + if (mp_mulmod(&a, &tmp, &p, &a) != MP_OKAY) { goto error; } /* a = y^a * a^b mod p */ + + /* y^a * a^b == g^m ??? */ + if (mp_cmp(&a, &m) == 0) { + *stat = 1; + } + + /* clean up */ + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +done: + mp_clear_multi(&tmp, &m, &g, &p, &b, &a, NULL); +#ifdef CLEAN_STACK + zeromem(md, sizeof(md)); +#endif + return res; +} + diff --git a/ecb.c b/ecb.c new file mode 100644 index 0000000..b85452e --- /dev/null +++ b/ecb.c @@ -0,0 +1,49 @@ +#include "mycrypt.h" + +#ifdef ECB + +int ecb_start(int cipher, const unsigned char *key, int keylen, int num_rounds, symmetric_ECB *ecb) +{ + int errno; + _ARGCHK(key != NULL); + _ARGCHK(ecb != NULL); + + if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) { + return errno; + } + ecb->cipher = cipher; + ecb->blocklen = cipher_descriptor[cipher].block_length; + return cipher_descriptor[cipher].setup(key, keylen, num_rounds, &ecb->key); +} + +int ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ECB *ecb) +{ + int errno; + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(ecb != NULL); + + if ((errno = cipher_is_valid(ecb->cipher)) != CRYPT_OK) { + return errno; + } + cipher_descriptor[ecb->cipher].ecb_encrypt(pt, ct, &ecb->key); + return CRYPT_OK; +} + +int ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_ECB *ecb) +{ + int errno; + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(ecb != NULL); + + if ((errno = cipher_is_valid(ecb->cipher)) != CRYPT_OK) { + return errno; + } + cipher_descriptor[ecb->cipher].ecb_decrypt(ct, pt, &ecb->key); + return CRYPT_OK; +} + +#endif + + diff --git a/ecc.c b/ecc.c new file mode 100644 index 0000000..e2cae85 --- /dev/null +++ b/ecc.c @@ -0,0 +1,827 @@ +/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b + * + * All curves taken from NIST recommendation paper of July 1999 + * Available at http://csrc.nist.gov/cryptval/dss.htm + */ + +#include "mycrypt.h" + +#ifdef MECC + +static const struct { + int size; + char *name, *prime, *B, *order, *Gx, *Gy; +} sets[] = { +#ifdef ECC160 +{ + 20, + "ECC-160", + /* prime */ + "1461501637330902918203684832716283019655932542983", + /* B */ + "1C9E7C2E5891CBE097BD46", + /* order */ + "1461501637330902918203686297565868358251373258181", + /* Gx */ + "2DCF462904B478D868A7FF3F2BF1FCD9", + /* Gy */ + "DFFAF2EE3848FA75FB967CEC7B9A399E085ACED8", +}, +#endif +#ifdef ECC192 +{ + 24, + "ECC-192", + /* prime */ + "6277101735386680763835789423207666416083908700390324961279", + + /* B */ + "64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", + + /* order */ + "6277101735386680763835789423176059013767194773182842284081", + + /* Gx */ + "188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", + + /* Gy */ + "07192b95ffc8da78631011ed6b24cdd573f977a11e794811" +}, +#endif +#ifdef ECC224 +{ + 28, + "ECC-224", + + /* prime */ + "26959946667150639794667015087019630673637144422540572481103610249951", + + /* B */ + "2051BA041508CED34B3", + + /* order */ + "26959946667150639794667015087019637467111563745054605861463538557247", + + /* Gx */ + "2DCF462904B478D868A7FF3F2BF1FCD9", + + /* Gy */ + "CF337F320BC44A15C3EDB8C4258BB958E57A0CAFA73EB46E9C4BA9AE", +}, +#endif +#ifdef ECC256 +{ + 32, + "ECC-256", + /* Prime */ + "115792089210356248762697446949407573530086143415290314195533631308867097853951", + + /* B */ + "5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", + + /* Order */ + "115792089210356248762697446949407573529996955224135760342422259061068512044369", + + /* Gx */ + "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", + + /* Gy */ + "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5" +}, +#endif +#ifdef ECC384 +{ + 48, + "ECC-384", + /* prime */ + "394020061963944792122790401001436138050797392704654466679482934042457217714968" + "70329047266088258938001861606973112319", + + /* B */ + "b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed1" + "9d2a85c8edd3ec2aef", + + /* Order */ + "394020061963944792122790401001436138050797392704654466679469052796276593991132" + "63569398956308152294913554433653942643", + + /* Gx and Gy */ + "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf5529" + "6c3a545e3872760ab7", + "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e81" + "9d7a431d7c90ea0e5f" +}, +#endif +#ifdef ECC521 +{ + 65, + "ECC-521", + /* prime */ + "686479766013060971498190079908139321726943530014330540939446345918554318339765" + "6052122559640661454554977296311391480858037121987999716643812574028291115057151", + + /* B */ + "051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7" + "e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", + + /* Order */ + "686479766013060971498190079908139321726943530014330540939446345918554318339765" + "5394245057746333217197532963996371363321113864768612440380340372808892707005449", + + /* Gx and Gy */ + "c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe7" + "5928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", + "11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef" + "42640c550b9013fad0761353c7086a272c24088be94769fd16650", +}, +#endif +{ + 0, + NULL, NULL, NULL, NULL, NULL, NULL +} +}; + +#if 0 + +/* you plug in a prime and B value and it finds a pseudo-random base point */ +void ecc_find_base(void) +{ + static char *prime = "26959946667150639794667015087019630673637144422540572481103610249951"; + static char *order = "26959946667150639794667015087019637467111563745054605861463538557247"; + static char *b = "9538957348957353489587"; + mp_int pp, p, r, B, tmp1, tmp2, tx, ty, x, y; + char buf[4096]; + int i; + + mp_init_multi(&tx, &ty, &x, &y, &p, &pp, &r, &B, &tmp1, &tmp2, NULL); + mp_read_radix(&p, prime, 10); + mp_read_radix(&r, order, 10); + mp_read_radix(&B, b, 10); + + /* get (p+1)/4 */ + mp_add_d(&p, 1, &pp); + mp_div_2(&pp, &pp); + mp_div_2(&pp, &pp); + + buf[0] = 0; + do { + printf("."); fflush(stdout); + /* make a random value of x */ + for (i = 0; i < 16; i++) buf[i+1] = rand() & 255; + mp_read_raw(&x, buf, 17); + mp_copy(&x, &tx); + + /* now compute x^3 - 3x + b */ + mp_expt_d(&x, 3, &tmp1); + mp_mul_d(&x, 3, &tmp2); + mp_sub(&tmp1, &tmp2, &tmp1); + mp_add(&tmp1, &B, &tmp1); + mp_mod(&tmp1, &p, &tmp1); + + /* now compute sqrt via x^((p+1)/4) */ + mp_exptmod(&tmp1, &pp, &p, &tmp2); + mp_copy(&tmp2, &ty); + + /* now square it */ + mp_sqrmod(&tmp2, &p, &tmp2); + + /* tmp2 should equal tmp1 */ + } while (mp_cmp(&tmp1, &tmp2)); + + /* now output values in way that libtomcrypt wants */ + mp_todecimal(&p, buf); + printf("\n\np==%s\n", buf); + mp_tohex(&B, buf); + printf("b==%s\n", buf); + mp_todecimal(&r, buf); + printf("r==%s\n", buf); + mp_tohex(&tx, buf); + printf("Gx==%s\n", buf); + mp_tohex(&ty, buf); + printf("Gy==%s\n", buf); + + mp_clear_multi(&tx, &ty, &x, &y, &p, &pp, &r, &B, &tmp1, &tmp2, NULL); +} + +#endif + +static int is_valid_idx(int n) +{ + int x; + + for (x = 0; sets[x].size; x++); + if ((n < 0) || (n >= x)) { + return 0; + } + return 1; +} + +static ecc_point *new_point(void) +{ + ecc_point *p; + p = XMALLOC(sizeof(ecc_point)); + if (p == NULL) { + return NULL; + } + if (mp_init_multi(&p->x, &p->y, NULL) != MP_OKAY) { + XFREE(p); + return NULL; + } + return p; +} + +static void del_point(ecc_point *p) +{ + mp_clear_multi(&p->x, &p->y, NULL); + XFREE(p); +} + + +/* double a point R = 2P, R can be P*/ +static int dbl_point(ecc_point *P, ecc_point *R, mp_int *modulus) +{ + mp_int s, tmp, tmpx; + int res; + + if (mp_init_multi(&s, &tmp, &tmpx, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + /* s = (3Xp^2 + a) / (2Yp) */ + if (mp_mul_2(&P->y, &tmp) != MP_OKAY) { goto error; } /* tmp = 2*y */ + if (mp_invmod(&tmp, modulus, &tmp) != MP_OKAY) { goto error; } /* tmp = 1/tmp mod modulus */ + if (mp_sqr(&P->x, &s) != MP_OKAY) { goto error; } /* s = x^2 */ + if (mp_mul_d(&s, 3, &s) != MP_OKAY) { goto error; } /* s = 3*(x^2) */ + if (mp_sub_d(&s, 3, &s) != MP_OKAY) { goto error; } /* s = 3*(x^2) - 3 */ + if (mp_mulmod(&s, &tmp, modulus, &s) != MP_OKAY) { goto error; } /* s = tmp * s mod modulus */ + + /* Xr = s^2 - 2Xp */ + if (mp_sqr(&s, &tmpx) != MP_OKAY) { goto error; } /* tmpx = s^2 */ + if (mp_sub(&tmpx, &P->x, &tmpx) != MP_OKAY) { goto error; } /* tmpx = tmpx - x */ + if (mp_submod(&tmpx, &P->x, modulus, &tmpx) != MP_OKAY) { goto error; } /* tmpx = tmpx - x mod modulus */ + + /* Yr = -Yp + s(Xp - Xr) */ + if (mp_sub(&P->x, &tmpx, &tmp) != MP_OKAY) { goto error; } /* tmp = x - tmpx */ + if (mp_mul(&tmp, &s, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp * s */ + if (mp_submod(&tmp, &P->y, modulus, &R->y) != MP_OKAY) { goto error; } /* y = tmp - y mod modulus */ + if (mp_copy(&tmpx, &R->x) != MP_OKAY) { goto error; } /* x = tmpx */ + + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +done: + mp_clear_multi(&tmpx, &tmp, &s, NULL); + return res; +} + +/* add two different points over Z/pZ, R = P + Q, note R can equal either P or Q */ +static int add_point(ecc_point *P, ecc_point *Q, ecc_point *R, mp_int *modulus) +{ + mp_int s, tmp, tmpx; + int res; + + if (mp_init(&tmp) != MP_OKAY) { + return CRYPT_MEM; + } + + /* is P==Q or P==-Q? */ + mp_neg(&Q->y, &tmp); + mp_mod(&tmp, modulus, &tmp); + if (!mp_cmp(&P->x, &Q->x)) + if (!mp_cmp(&P->y, &Q->y) || !mp_cmp(&P->y, &tmp)) { + mp_clear(&tmp); + return dbl_point(P, R, modulus); + } + + if (mp_init_multi(&tmpx, &s, NULL) != MP_OKAY) { + mp_clear(&tmp); + return CRYPT_MEM; + } + + /* get s = (Yp - Yq)/(Xp-Xq) mod p */ + if (mp_submod(&P->x, &Q->x, modulus, &tmp) != MP_OKAY) { goto error; } /* tmp = Px - Qx mod modulus */ + if (mp_invmod(&tmp, modulus, &tmp) != MP_OKAY) { goto error; } /* tmp = 1/tmp mod modulus */ + if (mp_sub(&P->y, &Q->y, &s) != MP_OKAY) { goto error; } /* s = Py - Qy mod modulus */ + if (mp_mulmod(&s, &tmp, modulus, &s) != MP_OKAY) { goto error; } /* s = s * tmp mod modulus */ + + /* Xr = s^2 - Xp - Xq */ + if (mp_sqrmod(&s, modulus, &tmp) != MP_OKAY) { goto error; } /* tmp = s^2 mod modulus */ + if (mp_sub(&tmp, &P->x, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp - Px */ + if (mp_sub(&tmp, &Q->x, &tmpx) != MP_OKAY) { goto error; } /* tmpx = tmp - Qx */ + + /* Yr = -Yp + s(Xp - Xr) */ + if (mp_sub(&P->x, &tmpx, &tmp) != MP_OKAY) { goto error; } /* tmp = Px - tmpx */ + if (mp_mul(&tmp, &s, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp * s */ + if (mp_submod(&tmp, &P->y, modulus, &R->y) != MP_OKAY) { goto error; } /* Ry = tmp - Py mod modulus */ + if (mp_mod(&tmpx, modulus, &R->x) != MP_OKAY) { goto error; } /* Rx = tmpx mod modulus */ + + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +done: + mp_clear_multi(&s, &tmpx, &tmp, NULL); + return res; +} + +/* perform R = kG where k == integer and G == ecc_point */ +static int ecc_mulmod(mp_int *k, ecc_point *G, ecc_point *R, mp_int *modulus, int idx) +{ + ecc_point *tG; + int i, j, z, first, res; + mp_digit d; + unsigned char bits[768]; + + /* get bits of k */ + for (z = i = 0; z < (int)USED(k); z++) { + d = DIGIT(k, z); + +#define DO1 bits[i++] = d&1; d >>= 1; +#define DO2 DO1 DO1 +#define DO4 DO2 DO2 + + DO4; DO4; DO4; DO4 + +#undef DO4 +#undef DO2 +#undef DO1 + } + + /* make a copy of G incase R==G */ + tG = new_point(); + if (tG == NULL) { + return CRYPT_MEM; + } + + /* tG = G */ + if (mp_copy(&G->x, &tG->x) != MP_OKAY) { goto error; } + if (mp_copy(&G->y, &tG->y) != MP_OKAY) { goto error; } + + /* set result to G, R = G */ + if (mp_copy(&G->x, &R->x) != MP_OKAY) { goto error; } + if (mp_copy(&G->y, &R->y) != MP_OKAY) { goto error; } + first = 0; + + /* now do dbl+add through all the bits */ + for (j = i-1; j >= 0; j--) { + if (first) { + if (dbl_point(R, R, modulus) != CRYPT_OK) { goto error; } + } + if (bits[j] == 1) { + if (first) { + if (add_point(R, tG, R, modulus) != CRYPT_OK) { goto error; } + } + first = 1; + } + } + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +done: + del_point(tG); +#ifdef CLEAN_STACK + zeromem(bits, sizeof(bits)); +#endif + return res; +} + +int ecc_test(void) +{ + mp_int modulus, order; + ecc_point *G, *GG; + int i, res, primality; + + if (mp_init_multi(&modulus, &order, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + G = new_point(); + if (G == NULL) { + mp_clear_multi(&modulus, &order, NULL); + return CRYPT_MEM; + } + + GG = new_point(); + if (GG == NULL) { + mp_clear_multi(&modulus, &order, NULL); + del_point(G); + return CRYPT_MEM; + } + + for (i = 0; sets[i].size; i++) { + if (mp_read_radix(&modulus, (unsigned char *)sets[i].prime, 10) != MP_OKAY) { goto error; } + if (mp_read_radix(&order, (unsigned char *)sets[i].order, 10) != MP_OKAY) { goto error; } + + /* is prime actually prime? */ + if (is_prime(&modulus, &primality) != CRYPT_OK) { goto error; } + if (primality == 0) { + res = CRYPT_FAIL_TESTVECTOR; + goto done1; + } + + /* is order prime ? */ + if (is_prime(&order, &primality) != CRYPT_OK) { goto error; } + if (primality == 0) { + res = CRYPT_FAIL_TESTVECTOR; + goto done1; + } + + if (mp_read_radix(&G->x, (unsigned char *)sets[i].Gx, 16) != MP_OKAY) { goto error; } + if (mp_read_radix(&G->y, (unsigned char *)sets[i].Gy, 16) != MP_OKAY) { goto error; } + + /* then we should have G == (order + 1)G */ + if (mp_add_d(&order, 1, &order) != MP_OKAY) { goto error; } + if (ecc_mulmod(&order, G, GG, &modulus, i) != CRYPT_OK) { goto error; } + if (mp_cmp(&G->x, &GG->x) || mp_cmp(&G->y, &GG->y)) { + res = CRYPT_FAIL_TESTVECTOR; + goto done1; + } + } + res = CRYPT_OK; + goto done1; +error: + res = CRYPT_MEM; +done1: + del_point(GG); + del_point(G); + mp_clear_multi(&order, &modulus, NULL); + return res; +} + +void ecc_sizes(int *low, int *high) +{ + int i; + _ARGCHK(low != NULL); + _ARGCHK(high != NULL); + + *low = INT_MAX; + *high = 0; + for (i = 0; sets[i].size; i++) { + if (sets[i].size < *low) { + *low = sets[i].size; + } + if (sets[i].size > *high) { + *high = sets[i].size; + } + } +} + +int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key) +{ + int x, res, errno; + ecc_point *base; + mp_int prime; + unsigned char buf[4096]; + + _ARGCHK(key != NULL); + + /* good prng? */ + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + /* find key size */ + for (x = 0; (keysize > sets[x].size) && (sets[x].size); x++); + keysize = sets[x].size; + + if (sets[x].size == 0) { + return CRYPT_INVALID_KEYSIZE; + } + key->idx = x; + + /* make up random string */ + buf[0] = 0; + if (prng_descriptor[wprng].read(buf+1, keysize, prng) != (unsigned long)keysize) { + return CRYPT_ERROR_READPRNG; + } + + /* setup the key variables */ + if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->k, &prime, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + base = new_point(); + if (base == NULL) { + mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->k, &prime, NULL); + return CRYPT_MEM; + } + + /* read in the specs for this key */ + if (mp_read_radix(&prime, (unsigned char *)sets[x].prime, 10) != MP_OKAY) { goto error; } + if (mp_read_radix(&base->x, (unsigned char *)sets[x].Gx, 16) != MP_OKAY) { goto error; } + if (mp_read_radix(&base->y, (unsigned char *)sets[x].Gy, 16) != MP_OKAY) { goto error; } + if (mp_read_raw(&key->k, (unsigned char *)buf, keysize+1) != MP_OKAY) { goto error; } + + /* make the public key */ + if (ecc_mulmod(&key->k, base, &key->pubkey, &prime, x) != CRYPT_OK) { goto error; } + key->type = PK_PRIVATE; + + /* free up ram */ + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +done: + del_point(base); + mp_clear(&prime); +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + return res; +} + +void ecc_free(ecc_key *key) +{ + _ARGCHK(key != NULL); + mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->k, NULL); +} + +static int compress_y_point(ecc_point *pt, int idx, int *result) +{ + mp_int tmp, tmp2, p; + int res; + + _ARGCHK(pt != NULL); + _ARGCHK(result != NULL); + + if (mp_init_multi(&tmp, &tmp2, &p, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + /* get x^3 - 3x + b */ + if (mp_read_radix(&p, (unsigned char *)sets[idx].B, 16) != MP_OKAY) { goto error; } /* p = B */ + if (mp_expt_d(&pt->x, 3, &tmp) != MP_OKAY) { goto error; } /* tmp = pX^3 */ + if (mp_mul_d(&pt->x, 3, &tmp2) != MP_OKAY) { goto error; } /* tmp2 = 3*pX^3 */ + if (mp_sub(&tmp, &tmp2, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp - tmp2 */ + if (mp_add(&tmp, &p, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp + p */ + if (mp_read_radix(&p, (unsigned char *)sets[idx].prime, 10) != MP_OKAY) { goto error; } /* p = prime */ + if (mp_mod(&tmp, &p, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp mod p */ + + /* now find square root */ + if (mp_add_d(&p, 1, &tmp2) != MP_OKAY) { goto error; } /* tmp2 = p + 1 */ + if (mp_div_2(&tmp2, &tmp2) != MP_OKAY) { goto error; } /* tmp2 = tmp2/2 */ + if (mp_div_2(&tmp2, &tmp2) != MP_OKAY) { goto error; } /* tmp2 = (p+1)/4 */ + if (mp_exptmod(&tmp, &tmp2, &p, &tmp) != MP_OKAY) { goto error; } /* tmp = (x^3 - 3x + b)^((p+1)/4) mod p */ + + /* if tmp equals the y point give a 0, otherwise 1 */ + if (mp_cmp(&tmp, &pt->y) == 0) + *result = 0; + else + *result = 1; + + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +done: + mp_clear_multi(&p, &tmp, &tmp2, NULL); + return res; +} + +static int expand_y_point(ecc_point *pt, int idx, int result) +{ + mp_int tmp, tmp2, p; + int res; + + _ARGCHK(pt != NULL); + + if (mp_init_multi(&tmp, &tmp2, &p, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + /* get x^3 - 3x + b */ + if (mp_read_radix(&p, (unsigned char *)sets[idx].B, 16) != MP_OKAY) { goto error; } /* p = B */ + if (mp_expt_d(&pt->x, 3, &tmp) != MP_OKAY) { goto error; } /* tmp = pX^3 */ + if (mp_mul_d(&pt->x, 3, &tmp2) != MP_OKAY) { goto error; } /* tmp2 = 3*pX^3 */ + if (mp_sub(&tmp, &tmp2, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp - tmp2 */ + if (mp_add(&tmp, &p, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp + p */ + if (mp_read_radix(&p, (unsigned char *)sets[idx].prime, 10) != MP_OKAY) { goto error; } /* p = prime */ + if (mp_mod(&tmp, &p, &tmp) != MP_OKAY) { goto error; } /* tmp = tmp mod p */ + + /* now find square root */ + if (mp_add_d(&p, 1, &tmp2) != MP_OKAY) { goto error; } /* tmp2 = p + 1 */ + if (mp_div_2(&tmp2, &tmp2) != MP_OKAY) { goto error; } /* tmp2 = tmp2/2 */ + if (mp_div_2(&tmp2, &tmp2) != MP_OKAY) { goto error; } /* tmp2 = (p+1)/4 */ + if (mp_exptmod(&tmp, &tmp2, &p, &tmp) != MP_OKAY) { goto error; } /* tmp = (x^3 - 3x + b)^((p+1)/4) mod p */ + + /* if result==0, then y==tmp, otherwise y==p-tmp */ + if (result == 0) { + if (mp_copy(&tmp, &pt->y) != MP_OKAY) { goto error; } + } else { + if (mp_sub(&p, &tmp, &pt->y) != MP_OKAY) { goto error; } + } + + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +done: + mp_clear_multi(&p, &tmp, &tmp2, NULL); + return res; +} + +#define OUTPUT_BIGNUM(num, buf2, y, z) \ +{ \ + z = mp_raw_size(num); \ + STORE32L(z, buf2+y); \ + y += 4; \ + mp_toraw(num, buf2+y); \ + y += z; \ +} + + +#define INPUT_BIGNUM(num, in, x, y) \ +{ \ + /* load value */ \ + LOAD32L(x, in+y); \ + y += 4; \ + \ + /* sanity check... */ \ + if (x > 1024) { \ + goto error; \ + } \ + \ + /* load it */ \ + if (mp_read_raw(num, (unsigned char *)in+y, x) != MP_OKAY) {\ + goto error; \ + } \ + y += x; \ +} + +int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key) +{ + unsigned long y, z; + int res, errno; + unsigned char buf2[512]; + + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* type valid? */ + if (key->type != PK_PRIVATE && type == PK_PRIVATE) { + return CRYPT_PK_TYPE_MISMATCH; + } + + /* output type and magic byte */ + y = PACKET_SIZE; + buf2[y++] = type; + buf2[y++] = key->idx; + + /* output x coordinate */ + OUTPUT_BIGNUM(&(key->pubkey.x), buf2, y, z); + + /* compress y and output it */ + if ((errno = compress_y_point(&key->pubkey, key->idx, &res)) != CRYPT_OK) { + return errno; + } + buf2[y++] = res; + + if (type == PK_PRIVATE) { + OUTPUT_BIGNUM(&key->k, buf2, y, z); + } + + /* check size */ + if (*outlen < y) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* store header */ + packet_store_header(buf2, PACKET_SECT_ECC, PACKET_SUB_KEY, y); + + memcpy(out, buf2, y); + *outlen = y; + + #ifdef CLEAN_STACK + zeromem(buf2, sizeof(buf2)); + #endif + return CRYPT_OK; +} + +int ecc_import(const unsigned char *in, ecc_key *key) +{ + unsigned long x, y; + int res, errno; + + _ARGCHK(in != NULL); + _ARGCHK(key != NULL); + + /* check type */ + if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_ECC, PACKET_SUB_KEY)) != CRYPT_OK) { + return errno; + } + + /* init key */ + if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->k, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + y = PACKET_SIZE; + key->type = in[y++]; + key->idx = in[y++]; + + /* type check both values */ + if ((key->type != PK_PUBLIC) && (key->type != PK_PRIVATE)) { + res = CRYPT_INVALID_PACKET; + goto error2; + } + + /* is the key idx valid? */ + if (!is_valid_idx(key->idx)) { + res = CRYPT_INVALID_PACKET; + goto error2; + } + + /* load x coordinate */ + INPUT_BIGNUM(&key->pubkey.x, in, x, y); + + /* load y */ + x = in[y++]; + if ((errno = expand_y_point(&key->pubkey, key->idx, x)) != CRYPT_OK) { res = errno; goto error2; } + + if (key->type == PK_PRIVATE) { + /* load private key */ + INPUT_BIGNUM(&key->k, in, x, y); + } + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +error2: + mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->k, NULL); +done: + return res; +} + +int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, + unsigned char *out, unsigned long *outlen) +{ + unsigned long x, y; + ecc_point *result; + mp_int prime; + int res, errno; + + _ARGCHK(private_key != NULL); + _ARGCHK(public_key != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* type valid? */ + if (private_key->type != PK_PRIVATE) { + return CRYPT_PK_NOT_PRIVATE; + } + + if (private_key->idx != public_key->idx) { + return CRYPT_PK_TYPE_MISMATCH; + } + + /* make new point */ + result = new_point(); + if (result == NULL) { + return CRYPT_MEM; + } + + if (mp_init(&prime) != MP_OKAY) { + del_point(result); + return CRYPT_MEM; + } + + if (mp_read_radix(&prime, (unsigned char *)sets[private_key->idx].prime, 10) != MP_OKAY) { goto error; } + if ((errno = ecc_mulmod(&private_key->k, &public_key->pubkey, result, &prime, private_key->idx)) != CRYPT_OK) { res = errno; goto done1; } + + x = mp_raw_size(&result->x); + y = mp_raw_size(&result->y); + + if (*outlen < (x+y)) { + res = CRYPT_BUFFER_OVERFLOW; + goto done1; + } + *outlen = x+y; + mp_toraw(&result->x, out); + mp_toraw(&result->y, out+x); + + res = CRYPT_OK; + goto done1; +error: + res = CRYPT_MEM; +done1: + mp_clear(&prime); + del_point(result); + return res; +} + +int ecc_get_size(ecc_key *key) +{ + _ARGCHK(key != NULL); + if (is_valid_idx(key->idx)) + return sets[key->idx].size; + else + return INT_MAX; /* large value known to cause it to fail when passed to ecc_make_key() */ +} + +#include "ecc_sys.c" + +#endif + + diff --git a/ecc_sys.c b/ecc_sys.c new file mode 100644 index 0000000..c698e57 --- /dev/null +++ b/ecc_sys.c @@ -0,0 +1,862 @@ +#ifdef PK_PACKET + +int ecc_encrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, int cipher, int hash, + ecc_key *key) +{ + unsigned char pub_expt[512], ecc_shared[256], IV[MAXBLOCKSIZE], skey[MAXBLOCKSIZE]; + ecc_key pubkey; + unsigned long x, y, z, pubkeysize; + int keysize, blocksize, hashsize, errno; + symmetric_CTR ctr; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* check that wprng/cipher/hash are not invalid */ + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) { + return errno; + } + + if ((errno = hash_is_valid(hash)) != CRYPT_OK) { + return errno; + } + + /* make a random key and export the public copy */ + if ((errno = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { + return errno; + } + + pubkeysize = sizeof(pub_expt); + if ((errno = ecc_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { + ecc_free(&pubkey); + return errno; + } + + /* now check if the out buffer is big enough */ + if (*outlen < (10 + PACKET_SIZE + pubkeysize + + cipher_descriptor[cipher].block_length + len)) { + ecc_free(&pubkey); + return CRYPT_BUFFER_OVERFLOW; + } + + /* make random key */ + blocksize = cipher_descriptor[cipher].block_length; + hashsize = hash_descriptor[hash].hashsize; + keysize = hashsize; + if ((errno = cipher_descriptor[cipher].keysize(&keysize)) != CRYPT_OK) { + ecc_free(&pubkey); + return errno; + } + x = sizeof(ecc_shared); + if ((errno = ecc_shared_secret(&pubkey, key, ecc_shared, &x)) != CRYPT_OK) { + ecc_free(&pubkey); + return errno; + } + ecc_free(&pubkey); + + z = sizeof(skey); + if ((errno = hash_memory(hash, ecc_shared, x, skey, &z)) != CRYPT_OK) { + return errno; + } + + /* make up IV */ + if (prng_descriptor[wprng].read(IV, cipher_descriptor[cipher].block_length, prng) != + (unsigned long)cipher_descriptor[cipher].block_length) { + return CRYPT_ERROR_READPRNG; + } + + /* setup CTR mode */ + if ((errno = ctr_start(cipher, IV, skey, keysize, 0, &ctr)) != CRYPT_OK) { + return errno; + } + + /* output header */ + y = PACKET_SIZE; + + /* size of cipher name and the name itself */ + out[y++] = cipher_descriptor[cipher].ID; + + /* size of hash name and the name itself */ + out[y++] = hash_descriptor[hash].ID; + + /* length of ECC pubkey and the key itself */ + STORE32L(pubkeysize, out+y); + y += 4; + for (x = 0; x < (unsigned)pubkeysize; x++, y++) { + out[y] = pub_expt[x]; + } + + /* cipher IV */ + for (x = 0; x < (unsigned)blocksize; x++, y++) { + out[y] = IV[x]; + } + + /* length of ciphertext */ + STORE32L(len, out+y); + y += 4; + + /* encrypt the message */ + if ((errno = ctr_encrypt(in, out+y, len, &ctr)) != CRYPT_OK) { + return errno; + } + y += len; + + /* store header */ + packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_ENCRYPTED, y); + +#ifdef CLEAN_STACK + /* clean up */ + zeromem(pub_expt, sizeof(pub_expt)); + zeromem(ecc_shared, sizeof(ecc_shared)); + zeromem(skey, sizeof(skey)); + zeromem(IV, sizeof(IV)); + zeromem(&ctr, sizeof(ctr)); +#endif + + *outlen = y; + return CRYPT_OK; +} + +int ecc_decrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + ecc_key *key) +{ + unsigned char shared_secret[256], skey[MAXBLOCKSIZE]; + unsigned long x, y, z, res, hashsize, blocksize; + int cipher, hash, keysize, errno; + ecc_key pubkey; + symmetric_CTR ctr; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* right key type? */ + if (key->type != PK_PRIVATE) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* is header correct? */ + if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_ECC, PACKET_SUB_ENCRYPTED)) != CRYPT_OK) { + return errno; + } + + /* now lets get the cipher name */ + y = PACKET_SIZE; + cipher = find_cipher_id(in[y++]); + if (cipher == -1) { + return CRYPT_INVALID_CIPHER; + } + + /* now lets get the hash name */ + hash = find_hash_id(in[y++]); + if (hash == -1) { + return CRYPT_INVALID_HASH; + } + + /* common values */ + blocksize = cipher_descriptor[cipher].block_length; + hashsize = hash_descriptor[hash].hashsize; + keysize = hashsize; + if ((errno = cipher_descriptor[cipher].keysize(&keysize)) != CRYPT_OK) { + return errno; + } + + /* get public key */ + LOAD32L(x, in+y); + y += 4; + if ((errno = ecc_import(in+y, &pubkey)) != CRYPT_OK) { + return errno; + } + y += x; + + /* make shared key */ + x = sizeof(shared_secret); + if ((errno = ecc_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) { + ecc_free(&pubkey); + return errno; + } + ecc_free(&pubkey); + + z = sizeof(skey); + if ((errno = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) { + res = errno; + goto done; + } + + /* setup CTR mode */ + if ((errno = ctr_start(cipher, in+y, skey, keysize, 0, &ctr)) != CRYPT_OK) { + res = errno; + goto done; + } + y += blocksize; + + /* get length */ + LOAD32L(len,in+y); + y += 4; + + /* buffer overflow? */ + if (len > *outlen) { + res = CRYPT_BUFFER_OVERFLOW; + goto done; + } + + /* decrypt message */ + if ((errno = ctr_decrypt(in+y, out, len, &ctr)) != CRYPT_OK) { + res = errno; + goto done; + } + *outlen = len; + + res = CRYPT_OK; +done: +#ifdef CLEAN_STACK + zeromem(shared_secret, sizeof(shared_secret)); + zeromem(skey, sizeof(skey)); + zeromem(&ctr, sizeof(ctr)); +#endif + return res; +} + +/* Signatures + * + * Signatures are performed using a slightly modified ElGamal protocol. + * In these notes uppercase letters are points and lowercase letters are + * scalars. The users private key is 'x' and public key is Y = xG. + * The order of the curve is 'r'. + * + * + * To sign a message 'm' the user does this + +1. Makes up a random 'k' and finds kG [basically makes up a ecc_key], we will let A = kG +2. Finds b such that b = (m - x)/k mod r +3. Outputs (A, b) as the signature + +To verify a user computes mG and compares that to (bA + Y). Note that (bA + Y) is equal to + += ((m - x)/k)(kG) + xG += (m - x)G + xG += mG + +In theory, assuming the ECC Discrete Log is a hard problem an attacker +cannot find 'x' from (A, b). 'b' is perfectly decorrelated and reveals no +information. A reveals what kG is but not 'k' directly. Therefore, +assuming finding 'k' given kG is hard, finding 'x' from b is hard too. + +*/ + +int ecc_sign(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + int hash, prng_state *prng, int wprng, + ecc_key *key) +{ + ecc_key pubkey; + mp_int b, p; + unsigned char epubkey[256], er[256], md[MAXBLOCKSIZE]; + unsigned long x, y, z, pubkeysize, rsize; + int res, errno; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* is this a private key? */ + if (key->type != PK_PRIVATE) { + return CRYPT_PK_NOT_PRIVATE; + } + + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + if ((errno = hash_is_valid(hash)) != CRYPT_OK) { + return errno; + } + + /* make up a key and export the public copy */ + if ((errno = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { + return errno; + } + + pubkeysize = sizeof(epubkey); + if ((errno = ecc_export(epubkey, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { + ecc_free(&pubkey); + return errno; + } + + /* get the hash and load it as a bignum into 'b' */ + md[0] = 0; + z = sizeof(md)-1; + if ((errno = hash_memory(hash, in, inlen, md+1, &z)) != CRYPT_OK) { + ecc_free(&pubkey); + return errno; + } + + /* init the bignums */ + if (mp_init_multi(&b, &p, NULL) != MP_OKAY) { + ecc_free(&pubkey); + return CRYPT_MEM; + } + if (mp_read_radix(&p, sets[key->idx].order, 10) != MP_OKAY) { goto error; } + if (mp_read_raw(&b, md, 1+hash_descriptor[hash].hashsize) != MP_OKAY) { goto error; } + + /* find b = (m - x)/k */ + if (mp_invmod(&pubkey.k, &p, &pubkey.k) != MP_OKAY) { goto error; } /* k = 1/k */ + if (mp_submod(&b, &key->k, &p, &b) != MP_OKAY) { goto error; } /* b = m - x */ + if (mp_mulmod(&b, &pubkey.k, &p, &b) != MP_OKAY) { goto error; } /* b = (m - x)/k */ + + /* export it */ + rsize = mp_raw_size(&b); + if (rsize > sizeof(er)) { + goto error; + } + mp_toraw(&b, er); + + /* now lets check the outlen before we write */ + if (*outlen < (9 + PACKET_SIZE + rsize + pubkeysize)) { + res = CRYPT_BUFFER_OVERFLOW; + goto done1; + } + + /* lets output */ + y = PACKET_SIZE; + + /* length of hash name plus NULL */ + out[y++] = hash_descriptor[hash].ID; + + /* size of public key */ + STORE32L(pubkeysize, out+y); + y += 4; + + /* copy the public key */ + for (x = 0; x < pubkeysize; x++, y++) { + out[y] = epubkey[x]; + } + + /* size of 'r' */ + STORE32L(rsize, out+y); + y += 4; + + /* copy r */ + for (x = 0; x < rsize; x++, y++) { + out[y] = er[x]; + } + + /* store header */ + packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_SIGNED, y); + + /* clear memory */ + *outlen = y; + res = CRYPT_OK; + goto done1; +error: + res = CRYPT_MEM; +done1: + mp_clear_multi(&b, &p, NULL); + ecc_free(&pubkey); +#ifdef CLEAN_STACK + zeromem(er, sizeof(er)); + zeromem(epubkey, sizeof(epubkey)); + zeromem(md, sizeof(md)); +#endif + return res; +} + +/* verify that mG = (bA + Y) */ +int ecc_verify(const unsigned char *sig, const unsigned char *msg, + unsigned long inlen, int *stat, + ecc_key *key) +{ + ecc_point *mG; + ecc_key pubkey; + mp_int b, p, m; + unsigned long x, y, z; + int hash, res, errno; + unsigned char md[MAXBLOCKSIZE]; + + _ARGCHK(sig != NULL); + _ARGCHK(msg != NULL); + _ARGCHK(stat != NULL); + _ARGCHK(key != NULL); + + /* default to invalid signature */ + *stat = 0; + + /* is the message format correct? */ + if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_ECC, PACKET_SUB_SIGNED)) != CRYPT_OK) { + return errno; + } + + /* get hash name */ + y = PACKET_SIZE; + hash = find_hash_id(sig[y++]); + if (hash == -1) { + return CRYPT_INVALID_HASH; + } + + /* get size of public key */ + LOAD32L(x, sig+y); + y += 4; + + /* load the public key */ + if ((errno = ecc_import((unsigned char*)sig+y, &pubkey)) != CRYPT_OK) { + return errno; + } + y += x; + + /* load size of 'b' */ + LOAD32L(x, sig+y); + y += 4; + + /* init values */ + if (mp_init_multi(&b, &m, &p, NULL) != MP_OKAY) { + ecc_free(&pubkey); + return CRYPT_MEM; + } + + mG = new_point(); + if (mG == NULL) { + mp_clear_multi(&b, &m, &p, NULL); + ecc_free(&pubkey); + return CRYPT_MEM; + } + + /* load b */ + if (mp_read_raw(&b, (unsigned char *)sig+y, x) != MP_OKAY) { goto error; } + y += x; + + /* get m in binary a bignum */ + md[0] = 0; + z = sizeof(md)-1; + if ((errno = hash_memory(hash, msg, inlen, md+1, &z)) != CRYPT_OK) { + res = errno; + goto done1; + } + if (mp_read_raw(&m, md, hash_descriptor[hash].hashsize + 1) != MP_OKAY) { goto error; } + + /* load prime */ + if (mp_read_radix(&p, sets[key->idx].prime, 10) != MP_OKAY) { goto error; } + + /* get bA */ + if (ecc_mulmod(&b, &pubkey.pubkey, &pubkey.pubkey, &p, key->idx) != CRYPT_OK) { goto error; } + + /* get bA + Y */ + if (add_point(&pubkey.pubkey, &key->pubkey, &pubkey.pubkey, &p) != CRYPT_OK) { goto error; } + + /* get mG */ + if (mp_read_radix(&mG->x, sets[key->idx].Gx, 16) != MP_OKAY) { goto error; } + if (mp_read_radix(&mG->y, sets[key->idx].Gy, 16) != MP_OKAY) { goto error; } + if (ecc_mulmod(&m, mG, mG, &p, key->idx) != CRYPT_OK) { goto error; } + + /* compare mG to bA + Y */ + if (!mp_cmp(&mG->x, &pubkey.pubkey.x) && !mp_cmp(&mG->y, &pubkey.pubkey.y)) { + *stat = 1; + } + + /* clear up and return */ + res = CRYPT_OK; + goto done1; +error: + res = CRYPT_MEM; +done1: + del_point(mG); + ecc_free(&pubkey); + mp_clear_multi(&p, &m, &b, NULL); +#ifdef CLEAN_STACK + zeromem(md, sizeof(md)); +#endif + return CRYPT_OK; +} + +#endif + +int ecc_encrypt_key(const unsigned char *inkey, unsigned long keylen, + unsigned char *out, unsigned long *len, + prng_state *prng, int wprng, int hash, + ecc_key *key) +{ + unsigned char pub_expt[256], ecc_shared[256], skey[MAXBLOCKSIZE]; + ecc_key pubkey; + unsigned long x, y, z, hashsize, pubkeysize; + int errno; + + _ARGCHK(inkey != NULL); + _ARGCHK(out != NULL); + _ARGCHK(len != NULL); + _ARGCHK(key != NULL); + + /* check that wprng/cipher/hash are not invalid */ + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + if ((errno = hash_is_valid(hash)) != CRYPT_OK) { + return errno; + } + + if (keylen > hash_descriptor[hash].hashsize) { + return CRYPT_INVALID_HASH; + } + + /* make a random key and export the public copy */ + if ((errno = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { + return errno; + } + + pubkeysize = sizeof(pub_expt); + if ((errno = ecc_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { + ecc_free(&pubkey); + return errno; + } + + /* now check if the out buffer is big enough */ + if (*len < (9 + PACKET_SIZE + pubkeysize + hash_descriptor[hash].hashsize)) { + ecc_free(&pubkey); + return CRYPT_BUFFER_OVERFLOW; + } + + /* make random key */ + hashsize = hash_descriptor[hash].hashsize; + x = sizeof(ecc_shared); + if ((errno = ecc_shared_secret(&pubkey, key, ecc_shared, &x)) != CRYPT_OK) { + ecc_free(&pubkey); + return errno; + } + ecc_free(&pubkey); + z = sizeof(skey); + if ((errno = hash_memory(hash, ecc_shared, x, skey, &z)) != CRYPT_OK) { + return errno; + } + + /* Encrypt the key */ + for (x = 0; x < keylen; x++) { + skey[x] ^= inkey[x]; + } + + /* output header */ + y = PACKET_SIZE; + + /* size of hash name and the name itself */ + out[y++] = hash_descriptor[hash].ID; + + /* length of ECC pubkey and the key itself */ + STORE32L(pubkeysize, out+y); + y += 4; + + for (x = 0; x < pubkeysize; x++, y++) { + out[y] = pub_expt[x]; + } + + STORE32L(keylen, out+y); + y += 4; + + /* Store the encrypted key */ + for (x = 0; x < keylen; x++, y++) { + out[y] = skey[x]; + } + + /* store header */ + packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_ENC_KEY, y); + +#ifdef CLEAN_STACK + /* clean up */ + zeromem(pub_expt, sizeof(pub_expt)); + zeromem(ecc_shared, sizeof(ecc_shared)); + zeromem(skey, sizeof(skey)); +#endif + *len = y; + return CRYPT_OK; +} + +int ecc_decrypt_key(const unsigned char *in, unsigned char *outkey, + unsigned long *keylen, ecc_key *key) +{ + unsigned char shared_secret[256], skey[MAXBLOCKSIZE]; + unsigned long x, y, z, res, hashsize, keysize; + int hash, errno; + ecc_key pubkey; + + _ARGCHK(in != NULL); + _ARGCHK(outkey != NULL); + _ARGCHK(keylen != NULL); + _ARGCHK(key != NULL); + + /* right key type? */ + if (key->type != PK_PRIVATE) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* is header correct? */ + if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_ECC, PACKET_SUB_ENC_KEY)) != CRYPT_OK) { + return errno; + } + + /* now lets get the hash name */ + y = PACKET_SIZE; + hash = find_hash_id(in[y++]); + if (hash == -1) { + return CRYPT_INVALID_HASH; + } + + /* common values */ + hashsize = hash_descriptor[hash].hashsize; + + /* get public key */ + LOAD32L(x, in+y); + y += 4; + if ((errno = ecc_import(in+y, &pubkey)) != CRYPT_OK) { + return errno; + } + y += x; + + /* make shared key */ + x = sizeof(shared_secret); + if ((errno = ecc_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) { + ecc_free(&pubkey); + return errno; + } + ecc_free(&pubkey); + + z = sizeof(skey); + if ((errno = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) { + return errno; + } + + LOAD32L(keysize, in+y); + y += 4; + + if (*keylen < keysize) { + res = CRYPT_BUFFER_OVERFLOW; + goto done; + } + + /* Decrypt the key */ + for (x = 0; x < keysize; x++, y++) { + outkey[x] = skey[x] ^ in[y]; + } + + *keylen = keysize; + + res = CRYPT_OK; +done: +#ifdef CLEAN_STACK + zeromem(shared_secret, sizeof(shared_secret)); + zeromem(skey, sizeof(skey)); +#endif + return res; +} + +int ecc_sign_hash(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, ecc_key *key) +{ + ecc_key pubkey; + mp_int b, p; + unsigned char epubkey[256], er[256], md[MAXBLOCKSIZE]; + unsigned long x, y, pubkeysize, rsize; + int res, errno; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* is this a private key? */ + if (key->type != PK_PRIVATE) { + return CRYPT_PK_NOT_PRIVATE; + } + + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + /* make up a key and export the public copy */ + if ((errno = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { + return errno; + } + + pubkeysize = sizeof(epubkey); + if ((errno = ecc_export(epubkey, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { + ecc_free(&pubkey); + return errno; + } + + /* get the hash and load it as a bignum into 'b' */ + md[0] = 0; + memcpy(md+1, in, MIN(sizeof(md)-1,inlen)); + + /* init the bignums */ + if (mp_init_multi(&b, &p, NULL) != MP_OKAY) { + ecc_free(&pubkey); + return CRYPT_MEM; + } + if (mp_read_radix(&p, (unsigned char *)sets[key->idx].order, 10) != MP_OKAY) { goto error; } + if (mp_read_raw(&b, md, 1+MIN(sizeof(md)-1,inlen)) != MP_OKAY) { goto error; } + + /* find b = (m - x)/k */ + if (mp_invmod(&pubkey.k, &p, &pubkey.k) != MP_OKAY) { goto error; } /* k = 1/k */ + if (mp_submod(&b, &key->k, &p, &b) != MP_OKAY) { goto error; } /* b = m - x */ + if (mp_mulmod(&b, &pubkey.k, &p, &b) != MP_OKAY) { goto error; } /* b = (m - x)/k */ + + /* export it */ + rsize = mp_raw_size(&b); + if (rsize > sizeof(er)) { + goto error; + } + mp_toraw(&b, er); + + /* now lets check the outlen before we write */ + if (*outlen < (12 + rsize + pubkeysize)) { + res = CRYPT_BUFFER_OVERFLOW; + goto done1; + } + + /* lets output */ + y = PACKET_SIZE; + + /* size of public key */ + STORE32L(pubkeysize, out+y); + y += 4; + + /* copy the public key */ + for (x = 0; x < pubkeysize; x++, y++) { + out[y] = epubkey[x]; + } + + /* size of 'r' */ + STORE32L(rsize, out+y); + y += 4; + + /* copy r */ + for (x = 0; x < rsize; x++, y++) { + out[y] = er[x]; + } + + /* store header */ + packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_SIGNED, y); + + /* clear memory */ + *outlen = y; + res = CRYPT_OK; + goto done1; +error: + res = CRYPT_MEM; +done1: + mp_clear_multi(&b, &p, NULL); + ecc_free(&pubkey); +#ifdef CLEAN_STACK + zeromem(er, sizeof(er)); + zeromem(epubkey, sizeof(epubkey)); + zeromem(md, sizeof(md)); +#endif + return res; +} + +/* verify that mG = (bA + Y) */ +int ecc_verify_hash(const unsigned char *sig, const unsigned char *hash, + unsigned long inlen, int *stat, + ecc_key *key) +{ + ecc_point *mG; + ecc_key pubkey; + mp_int b, p, m; + unsigned long x, y; + int res, errno; + unsigned char md[MAXBLOCKSIZE]; + + _ARGCHK(sig != NULL); + _ARGCHK(hash != NULL); + _ARGCHK(hash != NULL); + _ARGCHK(key != NULL); + + /* default to invalid signature */ + *stat = 0; + + /* is the message format correct? */ + if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_ECC, PACKET_SUB_SIGNED)) != CRYPT_OK) { + return errno; + } + + /* get hash name */ + y = PACKET_SIZE; + + /* get size of public key */ + LOAD32L(x, sig+y); + y += 4; + + /* load the public key */ + if ((errno = ecc_import((unsigned char*)sig+y, &pubkey)) != CRYPT_OK) { + return errno; + } + y += x; + + /* load size of 'b' */ + LOAD32L(x, sig+y); + y += 4; + + /* init values */ + if (mp_init_multi(&b, &m, &p, NULL) != MP_OKAY) { + ecc_free(&pubkey); + return CRYPT_MEM; + } + + mG = new_point(); + if (mG == NULL) { + mp_clear_multi(&b, &m, &p, NULL); + ecc_free(&pubkey); + return CRYPT_MEM; + } + + /* load b */ + if (mp_read_raw(&b, (unsigned char *)sig+y, x) != MP_OKAY) { goto error; } + y += x; + + /* get m in binary a bignum */ + md[0] = 0; + memcpy(md+1,hash,MIN(sizeof(md)-1,inlen)); + if (mp_read_raw(&m, md, 1+MIN(sizeof(md)-1,inlen)) != MP_OKAY) { goto error; } + + /* load prime */ + if (mp_read_radix(&p, (unsigned char *)sets[key->idx].prime, 10) != MP_OKAY) { goto error; } + + /* get bA */ + if (ecc_mulmod(&b, &pubkey.pubkey, &pubkey.pubkey, &p, key->idx) != CRYPT_OK) { goto error; } + + /* get bA + Y */ + if (add_point(&pubkey.pubkey, &key->pubkey, &pubkey.pubkey, &p) != CRYPT_OK) { goto error; } + + /* get mG */ + if (mp_read_radix(&mG->x, (unsigned char *)sets[key->idx].Gx, 16) != MP_OKAY) { goto error; } + if (mp_read_radix(&mG->y, (unsigned char *)sets[key->idx].Gy, 16) != MP_OKAY) { goto error; } + if (ecc_mulmod(&m, mG, mG, &p, key->idx) != CRYPT_OK) { goto error; } + + /* compare mG to bA + Y */ + if (!mp_cmp(&mG->x, &pubkey.pubkey.x) && !mp_cmp(&mG->y, &pubkey.pubkey.y)) { + *stat = 1; + } + + /* clear up and return */ + res = CRYPT_OK; + goto done; +error: + res = CRYPT_ERROR; +done: + del_point(mG); + ecc_free(&pubkey); + mp_clear_multi(&p, &m, &b, NULL); +#ifdef CLEAN_STACK + zeromem(md, sizeof(md)); +#endif + return CRYPT_OK; +} + diff --git a/gf.c b/gf.c new file mode 100644 index 0000000..47f9255 --- /dev/null +++ b/gf.c @@ -0,0 +1,295 @@ +/* polynomial basis GF(2^w) routines */ +#include "mycrypt.h" + +#ifdef GF + +#define FORLOOP for (i = 0; i < LSIZE; i++) + +/* c = a + b */ +void gf_add(gf_intp a, gf_intp b, gf_intp c) +{ + int i; + FORLOOP c[i] = a[i]^b[i]; +} + +/* b = a */ +void gf_copy(gf_intp a, gf_intp b) +{ + int i; + FORLOOP b[i] = a[i]; +} + +/* a = 0 */ +void gf_zero(gf_intp a) +{ + int i; + FORLOOP a[i] = 0; +} + +/* is a zero? */ +int gf_iszero(gf_intp a) +{ + int i; + FORLOOP if (a[i]) { + return 0; + } + return 1; +} + +/* is a one? */ +int gf_isone(gf_intp a) +{ + int i; + for (i = 1; i < LSIZE; i++) { + if (a[i]) { + return 0; + } + } + return a[0] == 1; +} + +/* b = a << 1*/ +void gf_shl(gf_intp a, gf_intp b) +{ + int i; + gf_int tmp; + + gf_copy(a, tmp); + for (i = LSIZE-1; i > 0; i--) + b[i] = ((tmp[i]<<1)|((tmp[i-1]&0xFFFFFFFFUL)>>31))&0xFFFFFFFFUL; + b[0] = (tmp[0] << 1)&0xFFFFFFFFUL; + gf_zero(tmp); +} + +/* b = a >> 1 */ +void gf_shr(gf_intp a, gf_intp b) +{ + int i; + gf_int tmp; + + gf_copy(a, tmp); + for (i = 0; i < LSIZE-1; i++) + b[i] = (((tmp[i]&0xFFFFFFFFUL)>>1)|(tmp[i+1]<<31))&0xFFFFFFFFUL; + b[LSIZE-1] = (tmp[LSIZE-1]&0xFFFFFFFFUL)>>1; + gf_zero(tmp); +} + +/* returns -1 if its zero, otherwise degree of a */ +int gf_deg(gf_intp a) +{ + int i, ii; + unsigned long t; + + ii = -1; + for (i = LSIZE-1; i >= 0; i--) + if (a[i]) { + for (t = a[i], ii = 0; t; t >>= 1, ++ii); + break; + } + if (i == -1) i = 0; + return (i<<5)+ii; +} + +/* c = ab */ +void gf_mul(gf_intp a, gf_intp b, gf_intp c) +{ + gf_int ta, tb; + int i, n; + + gf_copy(a, ta); + gf_copy(b, tb); + gf_zero(c); + n = gf_deg(ta)+1; + for (i = 0; i < n; i++) { + if (ta[i>>5]&(1<<(i&31))) + gf_add(c, tb, c); + gf_shl(tb, tb); + } + gf_zero(ta); + gf_zero(tb); +} + +/* q = a/b, r = a%b */ +void gf_div(gf_intp a, gf_intp b, gf_intp q, gf_intp r) +{ + gf_int ta, tb, shifts[LSIZE*32]; + int i, magb, mag; + + mag = gf_deg(a); + magb = gf_deg(b); + + /* special cases */ + if (magb > mag) { + gf_copy(a, r); + gf_zero(q); + return; + } + if (magb == -1) { + return; + } + + /* copy locally */ + gf_copy(a, ta); + gf_copy(b, tb); + gf_zero(q); + + /* make shifted versions of "b" */ + gf_copy(tb, shifts[0]); + for (i = 1; i <= (mag-magb); i++) + gf_shl(shifts[i-1], shifts[i]); + + while (mag >= magb) { + i = (mag - magb); + q[i>>5] |= (1<<(i&31)); + gf_add(ta, shifts[i], ta); + mag = gf_deg(ta); + } + gf_copy(ta, r); + gf_zero(ta); + gf_zero(tb); + zeromem(shifts, sizeof(shifts)); +} + +/* b = a mod m */ +void gf_mod(gf_intp a, gf_intp m, gf_intp b) +{ + gf_int tmp; + gf_div(a,m,tmp,b); + gf_zero(tmp); +} + +/* c = ab (mod m) */ +void gf_mulmod(gf_intp a, gf_intp b, gf_intp m, gf_intp c) +{ + gf_int tmp; + gf_mul(a, b, tmp); + gf_mod(tmp, m, c); + gf_zero(tmp); +} + +/* B = 1/A mod M */ +void gf_invmod(gf_intp A, gf_intp M, gf_intp B) +{ + gf_int m, n, p0, p1, p2, r, q, tmp; + + /* put all variables in known setup state */ + gf_zero(p0); + gf_zero(p2); + gf_copy(M, m); + gf_copy(A, n); + p0[0] = 1; + gf_div(m, n, p1, r); + gf_copy(p1, q); + + /* loop until r == 0 */ + while (!gf_iszero(r)) { + gf_copy(n, m); + gf_copy(r, n); + gf_div(m, n, q, r); + gf_mul(q, p1, tmp); + gf_add(tmp, p0, p2); + gf_copy(p1, p0); + gf_copy(p2, p1); + } + gf_copy(p0, B); + gf_zero(p0); +} + +/* find a square root modulo a prime. Note the number of + * elements is 2^k - 1, so we must square k-2 times to get the + * square root.. + */ +void gf_sqrt(gf_intp a, gf_intp M, gf_intp b) +{ + int k; + k = gf_deg(M)-2; + gf_copy(a, b); + while (k--) + gf_mulmod(b, b, M, b); +} + +/* c = gcd(A,B) */ +void gf_gcd(gf_intp A, gf_intp B, gf_intp c) +{ + gf_int a, b, r; + int n; + + gf_add(A, B, r); + n = gf_deg(r); + if (gf_deg(A) > n) { + gf_copy(A, a); + gf_copy(B, b); + } else { + gf_copy(A, b); + gf_copy(B, a); + } + + do { + gf_mod(a, b, r); + gf_copy(b, a); + gf_copy(r, b); + } while (!gf_iszero(r)); + gf_copy(a, c); + gf_zero(a); + gf_zero(b); +} + +/* returns non-zero if 'a' is irreducible */ +int gf_is_prime(gf_intp a) +{ + gf_int u, tmp; + int m, n; + + gf_zero(u); + u[0] = 2; /* u(x) = x */ + m = gf_deg(a); + for (n = 0; n < (m/2); n++) { + gf_mulmod(u, u, a, u); /* u(x) = u(x)^2 mod a(x) */ + gf_copy(u, tmp); + tmp[0] ^= 2; /* tmp(x) = u(x) - x */ + gf_gcd(tmp, a, tmp); /* tmp(x) = gcd(a(x), u(x) - x) */ + if (!gf_isone(tmp)) { + return 0; + } + } + return 1; +} + +/* returns bytes required to store a gf_int */ +int gf_size(gf_intp a) +{ + int n; + + n = gf_deg(a); + if (n == -1) { + return 4; + } + n = n + (32 - (n&31)); + return n/8; +} + +/* store a gf_int */ +void gf_toraw(gf_intp a, unsigned char *dst) +{ + int x, n; + n = gf_size(a)/4; + for (x = 0; x < n; x++) { + STORE32L(a[x], dst); + dst += 4; + } +} + +/* read a gf_int (len == in bytes) */ +void gf_readraw(gf_intp a, unsigned char *str, int len) +{ + int x; + gf_zero(a); + for (x = 0; x < len/4; x++) { + LOAD32L(a[x], str); + str += 4; + } +} + +#endif + + diff --git a/hash.c b/hash.c new file mode 100644 index 0000000..dc756ab --- /dev/null +++ b/hash.c @@ -0,0 +1,93 @@ +#include "mycrypt.h" + +int hash_memory(int hash, const unsigned char *data, unsigned long len, unsigned char *dst, unsigned long *outlen) +{ + hash_state md; + int errno; + + _ARGCHK(data != NULL); + _ARGCHK(dst != NULL); + _ARGCHK(outlen != NULL); + + if ((errno = hash_is_valid(hash)) != CRYPT_OK) { + return errno; + } + + if (*outlen < hash_descriptor[hash].hashsize) { + return CRYPT_BUFFER_OVERFLOW; + } + *outlen = hash_descriptor[hash].hashsize; + + hash_descriptor[hash].init(&md); + hash_descriptor[hash].process(&md, data, len); + hash_descriptor[hash].done(&md, dst); + return CRYPT_OK; +} + +int hash_filehandle(int hash, FILE *in, unsigned char *dst, unsigned long *outlen) +{ +#ifdef NO_FILE + return CRYPT_ERROR; +#else + hash_state md; + unsigned char buf[512]; + int x, errno; + + _ARGCHK(dst != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(in != NULL); + + if ((errno = hash_is_valid(hash)) != CRYPT_OK) { + return errno; + } + + if (*outlen < hash_descriptor[hash].hashsize) { + return CRYPT_BUFFER_OVERFLOW; + } + *outlen = hash_descriptor[hash].hashsize; + + hash_descriptor[hash].init(&md); + do { + x = fread(buf, 1, sizeof(buf), in); + hash_descriptor[hash].process(&md, buf, x); + } while (x == sizeof(buf)); + hash_descriptor[hash].done(&md, dst); + +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + return CRYPT_OK; +#endif +} + + +int hash_file(int hash, const char *fname, unsigned char *dst, unsigned long *outlen) +{ +#ifdef NO_FILE + return CRYPT_ERROR; +#else + FILE *in; + int errno; + _ARGCHK(fname != NULL); + _ARGCHK(dst != NULL); + _ARGCHK(outlen != NULL); + + if ((errno = hash_is_valid(hash)) != CRYPT_OK) { + return errno; + } + + in = fopen(fname, "rb"); + if (in == NULL) { + return CRYPT_INVALID_ARG; + } + + if ((errno = hash_filehandle(hash, in, dst, outlen)) != CRYPT_OK) { + fclose(in); + return errno; + } + fclose(in); + + return CRYPT_OK; +#endif +} + diff --git a/hmac.c b/hmac.c new file mode 100644 index 0000000..5379507 --- /dev/null +++ b/hmac.c @@ -0,0 +1,478 @@ +/* Submited by Dobes Vandermeer (dobes@smartt.com) */ + +#include "mycrypt.h" + +/* + (1) append zeros to the end of K to create a B byte string + (e.g., if K is of length 20 bytes and B=64, then K will be + appended with 44 zero bytes 0x00) + (2) XOR (bitwise exclusive-OR) the B byte string computed in step + (1) with ipad (ipad = the byte 0x36 repeated B times) + (3) append the stream of data 'text' to the B byte string resulting + from step (2) + (4) apply H to the stream generated in step (3) + (5) XOR (bitwise exclusive-OR) the B byte string computed in + step (1) with opad (opad = the byte 0x5C repeated B times.) + (6) append the H result from step (4) to the B byte string + resulting from step (5) + (7) apply H to the stream generated in step (6) and output + the result +*/ + +#ifdef HMAC + +#define HMAC_BLOCKSIZE hash_descriptor[hash].blocksize + +int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen) +{ + unsigned char buf[MAXBLOCKSIZE]; + unsigned long hashsize; + unsigned long i, z; + int errno; + + _ARGCHK(hmac != NULL); + _ARGCHK(key != NULL); + + if ((errno = hash_is_valid(hash)) != CRYPT_OK) { + return errno; + } + + if(key == NULL || keylen == 0) { + return CRYPT_INVALID_KEYSIZE; + } + + hmac->hash = hash; + + // (1) make sure we have a large enough key + hmac->hashsize = hashsize = hash_descriptor[hash].hashsize; + if(keylen > HMAC_BLOCKSIZE) { + z = sizeof(hmac->key); + if ((errno = hash_memory(hash, key, keylen, hmac->key, &z)) != CRYPT_OK) { + return errno; + } + if(hashsize < HMAC_BLOCKSIZE) { + zeromem(hmac->key+hashsize, HMAC_BLOCKSIZE - hashsize); + } + } else { + memcpy(hmac->key, key, keylen); + if(keylen < HMAC_BLOCKSIZE) { + zeromem(hmac->key + keylen, HMAC_BLOCKSIZE - keylen); + } + } + + // Create the initial vector for step (3) + for(i=0; i < keylen; i++) { + buf[i] = hmac->key[i] ^ 0x36; + } + + for( ; i < HMAC_BLOCKSIZE; i++) { + buf[i] = 0x36; + } + + // Pre-pend that to the hash data + hash_descriptor[hash].init(&hmac->md); + hash_descriptor[hash].process(&hmac->md, buf, HMAC_BLOCKSIZE); + + return CRYPT_OK; +} + +int hmac_process(hmac_state *hmac, const unsigned char *buf, unsigned long len) +{ + int errno; + _ARGCHK(hmac != NULL); + _ARGCHK(buf != NULL); + if ((errno = hash_is_valid(hmac->hash)) != CRYPT_OK) { + return errno; + } + hash_descriptor[hmac->hash].process(&hmac->md, buf, len); + return CRYPT_OK; +} + +int hmac_done(hmac_state *hmac, unsigned char *hashOut) +{ + unsigned char buf[MAXBLOCKSIZE]; + unsigned char isha[MAXBLOCKSIZE]; + unsigned long hashsize, i; + int hash, errno; + + _ARGCHK(hmac != NULL); + _ARGCHK(hashOut != NULL); + + hash = hmac->hash; + if((errno = hash_is_valid(hash)) != CRYPT_OK) { + return errno; + } + + // Get the hash of the first HMAC vector plus the data + hash_descriptor[hash].done(&hmac->md, isha); + + // Create the second HMAC vector vector for step (3) + hashsize = hash_descriptor[hash].hashsize; + for(i=0; i < HMAC_BLOCKSIZE; i++) { + buf[i] = hmac->key[i] ^ 0x5C; + } + + // Now calculate the "outer" hash for step (5), (6), and (7) + hash_descriptor[hash].init(&hmac->md); + hash_descriptor[hash].process(&hmac->md, buf, HMAC_BLOCKSIZE); + hash_descriptor[hash].process(&hmac->md, isha, hashsize); + hash_descriptor[hash].done(&hmac->md, hashOut); + +#ifdef CLEAN_STACK + zeromem(hmac->key, sizeof(hmac->key)); +#endif + return CRYPT_OK; +} + +int hmac_memory(int hash, const unsigned char *key, unsigned long keylen, + const unsigned char *data, unsigned long len, unsigned char *dst) +{ + hmac_state hmac; + int errno; + + _ARGCHK(key != NULL); + _ARGCHK(data != NULL); + _ARGCHK(dst != NULL); + + if ((errno = hmac_init(&hmac, hash, key, keylen)) != CRYPT_OK) { + return errno; + } + + if ((errno = hmac_process(&hmac, data, len)) != CRYPT_OK) { + return errno; + } + + if ((errno = hmac_done(&hmac, dst)) != CRYPT_OK) { + return errno; + } + return CRYPT_OK; +} + +/* hmac_file added by Tom St Denis */ +int hmac_file(int hash, const char *fname, const unsigned char *key, + unsigned long keylen, unsigned char *dst) +{ +#ifdef NO_FILE + return CRYPT_ERROR; +#else + hmac_state hmac; + FILE *in; + unsigned char buf[512]; + int x, errno; + + _ARGCHK(fname != NULL); + _ARGCHK(key != NULL); + _ARGCHK(dst != NULL); + + if ((errno = hmac_init(&hmac, hash, key, keylen)) != CRYPT_OK) { + return errno; + } + + in = fopen(fname, "rb"); + if (in == NULL) { + return CRYPT_INVALID_ARG; + } + + /* process the file contents */ + do { + x = fread(buf, 1, sizeof(buf), in); + if ((errno = hmac_process(&hmac, buf, x)) != CRYPT_OK) { + fclose(in); + return errno; + } + } while (x == sizeof(buf)); + fclose(in); + + /* get final hmac */ + if ((errno = hmac_done(&hmac, dst)) != CRYPT_OK) { + return errno; + } + +#ifdef CLEAN_STACK + /* clear memory */ + zeromem(buf, sizeof(buf)); +#endif + return CRYPT_OK; +#endif +} + +/* + + TEST CASES SOURCE: + +Network Working Group P. Cheng +Request for Comments: 2202 IBM +Category: Informational R. Glenn + NIST + September 1997 + + Test Cases for HMAC-MD5 and HMAC-SHA-1 +*/ + + +int hmac_test(void) +{ + unsigned char digest[MAXBLOCKSIZE]; + int i; + + struct hmac_test_case { + int num; + char *algo; + unsigned char key[128]; + int keylen; + unsigned char data[128]; + int datalen; + unsigned char digest[MAXBLOCKSIZE]; + } cases[] = { + /* + 3. Test Cases for HMAC-SHA-1 + + test_case = 1 + key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b + key_len = 20 + data = "Hi Ther 20 + digest = 0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04 + digest-96 = 0x4c1a03424b55e07fe7f27be1 + */ + { 5, "sha1", + {0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c}, 20, + "Test With Truncation", 20, + {0x4c, 0x1a, 0x03, 0x42, 0x4b, 0x55, 0xe0, 0x7f, 0xe7, 0xf2, + 0x7b, 0xe1, 0xd5, 0x8b, 0xb9, 0x32, 0x4a, 0x9a, 0x5a, 0x04} }, + + /* + test_case = 6 + key = 0xaa repeated 80 times + key_len = 80 + data = "Test Using Larger Than Block-Size Key - Hash Key First" + data_len = 54 + digest = 0xaa4ae5e15272d00e95705637ce8a3b55ed402112 + */ + { 6, "sha1", + {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 80, + "Test Using Larger Than Block-Size Key - Hash Key First", 54, + {0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e, + 0x95, 0x70, 0x56, 0x37, 0xce, 0x8a, 0x3b, 0x55, + 0xed, 0x40, 0x21, 0x12} }, + + /* + test_case = 7 + key = 0xaa repeated 80 times + key_len = 80 + data = "Test Using Larger Than Block-Size Key and Larger + Than One Block-Size Data" + data_len = 73 + digest = 0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91 + */ + { 7, "sha1", + {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 80, + "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 73, + {0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23, 0x7d, 0x78, 0x6d, + 0x6b, 0xba, 0xa7, 0x96, 0x5c, 0x78, 0x08, 0xbb, 0xff, 0x1a, 0x91} }, + + /* + 2. Test Cases for HMAC-MD5 + + test_case = 1 + key = 0x0b 0b 0b 0b + 0b 0b 0b 0b + 0b 0b 0b 0b + 0b 0b 0b 0b + key_len = 16 + data = "Hi There" + data_len = 8 + digest = 0x92 94 72 7a + 36 38 bb 1c + 13 f4 8e f8 + 15 8b fc 9d + */ + { 1, "md5", + {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}, 16, + "Hi There", 8, + {0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c, + 0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d} }, + /* + test_case = 2 + key = "Jefe" + key_len = 4 + data = "what do ya want for nothing?" + data_len = 28 + digest = 0x750c783e6ab0b503eaa86e310a5db738 + */ + { 2, "md5", + "Jefe", 4, + "what do ya want for nothing?", 28, + {0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03, + 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38} }, + + /* + test_case = 3 + key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + key_len 16 + data = 0xdd repeated 50 times + data_len = 50 + digest = 0x56be34521d144c88dbb8c733f0e8b3f6 + */ + { 3, "md5", + {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 16, + {0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd}, 50, + {0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88, + 0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6} }, + /* + + test_case = 4 + key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819 + key_len 25 + data = 0xcd repeated 50 times + data_len = 50 + digest = 0x697eaf0aca3a3aea3a75164746ffaa79 + */ + { 4, "md5", + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19}, 25, + {0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd}, 50, + {0x69, 0x7e, 0xaf, 0x0a, 0xca, 0x3a, 0x3a, 0xea, + 0x3a, 0x75, 0x16, 0x47, 0x46, 0xff, 0xaa, 0x79} }, + + + /* + + test_case = 5 + key = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c + key_len = 16 + data = "Test With Truncation" + data_len = 20 + digest = 0x56461ef2342edc00f9bab995690efd4c + digest-96 0x56461ef2342edc00f9bab995 + */ + { 5, "md5", + {0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c}, 16, + "Test With Truncation", 20, + {0x56, 0x46, 0x1e, 0xf2, 0x34, 0x2e, 0xdc, 0x00, + 0xf9, 0xba, 0xb9, 0x95, 0x69, 0x0e, 0xfd, 0x4c} }, + + /* + + test_case = 6 + key = 0xaa repeated 80 times + key_len = 80 + data = "Test Using Larger Than Block-Size Key - Hash +Key First" + data_len = 54 + digest = 0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd + */ + { 6, "md5", + {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 80, + "Test Using Larger Than Block-Size Key - Hash Key First", 54, + {0x6b, 0x1a, 0xb7, 0xfe, 0x4b, 0xd7, 0xbf, 0x8f, + 0x0b, 0x62, 0xe6, 0xce, 0x61, 0xb9, 0xd0, 0xcd} }, + + /* + + test_case = 7 + key = 0xaa repeated 80 times + key_len = 80 + data = "Test Using Larger Than Block-Size Key and Larger + Than One Block-Size Data" + data_len = 73 + digest = 0x6f630fad67cda0ee1fb1f562db3aa53e + */ + { 7, "md5", + {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 80, + "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 73, + {0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee, + 0x1f, 0xb1, 0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e} } + }; + + int errno; + int failed=0; + for(i=0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) { + int hash = find_hash(cases[i].algo); + if((errno = hmac_memory(hash, cases[i].key, cases[i].keylen, cases[i].data, cases[i].datalen, digest)) != CRYPT_OK) { +#if 0 + printf("HMAC-%s test #%d\n", cases[i].algo, cases[i].num); +#endif + return errno; + } + + if(memcmp(digest, cases[i].digest, hash_descriptor[hash].hashsize) != 0) { +#if 0 + unsigned int j; + printf("\nHMAC-%s test #%d:\n", cases[i].algo, cases[i].num); + printf( "Result: 0x"); + for(j=0; j < hash_descriptor[hash].hashsize; j++) { + printf("%2x ", digest[j]); + } + printf("\nCorrect: 0x"); + for(j=0; j < hash_descriptor[hash].hashsize; j++) { + printf("%2x ", cases[i].digest[j]); + } + printf("\n"); +#endif + failed++; + //return CRYPT_ERROR; + } else { + /* printf("HMAC-%s test #%d: Passed\n", cases[i].algo, cases[i].num); */ + } + } + + if(failed) { + return CRYPT_FAIL_TESTVECTOR; + } + + return CRYPT_OK; +} + +#endif + diff --git a/keyring.c b/keyring.c new file mode 100644 index 0000000..7ede24d --- /dev/null +++ b/keyring.c @@ -0,0 +1,840 @@ +/* Provides keyring functionality for libtomcrypt, Tom St Denis */ +#include + +#ifdef KR + +static const unsigned char key_magic[4] = { 0x12, 0x34, 0x56, 0x78 }; +static const unsigned char file_magic[4] = { 0x9A, 0xBC, 0xDE, 0xF0 }; +static const unsigned char sign_magic[4] = { 0x87, 0x56, 0x43, 0x21 }; +static const unsigned char enc_magic[4] = { 0x0F, 0xED, 0xCB, 0xA9 }; + +static const unsigned long crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +static unsigned long crc32 (unsigned long crc, const unsigned char *buf, unsigned long len) +{ + crc = crc ^ 0xffffffffL; + while (len >= 8) + { + DO8 (buf); + len -= 8; + } + if (len) + do + { + DO1 (buf); + } + while (--len); + return crc ^ 0xffffffffUL; +} + +int kr_init(pk_key **pk) +{ + _ARGCHK(pk != NULL); + + *pk = XCALLOC(1, sizeof(pk_key)); + if (*pk == NULL) { + return CRYPT_MEM; + } + (*pk)->system = NON_KEY; + return CRYPT_OK; +} + +unsigned long kr_crc(const unsigned char *name, const unsigned char *email, const unsigned char *description) +{ + unsigned long crc; + _ARGCHK(name != NULL); + _ARGCHK(email != NULL); + _ARGCHK(description != NULL); + crc = crc32(0, NULL, 0); + crc = crc32(crc, name, MIN(MAXLEN, strlen((char *)name))); + crc = crc32(crc, email, MIN(MAXLEN, strlen((char *)email))); + return crc32(crc, description, MIN(MAXLEN, strlen((char *)description))); +} + +pk_key *kr_find(pk_key *pk, unsigned long ID) +{ + _ARGCHK(pk != NULL); + + while (pk != NULL) { + if (pk->system != NON_KEY && pk->ID == ID) { + return pk; + } + pk = pk->next; + } + return NULL; +} + +pk_key *kr_find_name(pk_key *pk, const char *name) +{ + _ARGCHK(pk != NULL); + _ARGCHK(name != NULL); + + while (pk != NULL) { + if (pk->system != NON_KEY && !strncmp((char *)pk->name, (char *)name, sizeof(pk->name)-1)) { + return pk; + } + pk = pk->next; + } + return NULL; +} + + +int kr_add(pk_key *pk, int key_type, int system, const unsigned char *name, + const unsigned char *email, const unsigned char *description, const _pk_key *key) +{ + _ARGCHK(pk != NULL); + _ARGCHK(name != NULL); + _ARGCHK(email != NULL); + _ARGCHK(description != NULL); + _ARGCHK(key != NULL); + + /* check parameters */ + if (key_type != PK_PRIVATE && key_type != PK_PRIVATE_OPTIMIZED && key_type != PK_PUBLIC) { + return CRYPT_PK_INVALID_TYPE; + } + + if (system != RSA_KEY && system != DH_KEY && system != ECC_KEY) { + return CRYPT_PK_INVALID_SYSTEM; + } + + /* see if its a dupe */ + if (kr_find(pk, kr_crc(name, email, description)) != NULL) { + return CRYPT_PK_DUP; + } + + /* find spot in key ring */ + while (pk->system != NON_KEY) { + if (pk->next == NULL) { + return CRYPT_ERROR; + } + pk = pk->next; + } + + /* now we have a spot make a next spot */ + pk->next = XCALLOC(1, sizeof(pk_key)); + if (pk->next == NULL) { + return CRYPT_MEM; + } + pk->next->system = NON_KEY; + + /* now add this new data to this ring spot */ + pk->key_type = key_type; + pk->system = system; + strncpy((char *)pk->name, (char *)name, sizeof(pk->name)-1); + strncpy((char *)pk->email, (char *)email, sizeof(pk->email)-1); + strncpy((char *)pk->description, (char *)description, sizeof(pk->description)-1); + pk->ID = kr_crc(pk->name, pk->email, pk->description); + + /* clear the memory area */ + zeromem(&(pk->key), sizeof(pk->key)); + + /* copy the key */ + switch (system) { + case RSA_KEY: + memcpy(&(pk->key.rsa), &(key->rsa), sizeof(key->rsa)); + break; + case DH_KEY: + memcpy(&(pk->key.dh), &(key->dh), sizeof(key->dh)); + break; + case ECC_KEY: + memcpy(&(pk->key.ecc), &(key->ecc), sizeof(key->ecc)); + break; + } + return CRYPT_OK; +} + +int kr_del(pk_key **_pk, unsigned long ID) +{ + pk_key *ppk, *pk; + + _ARGCHK(_pk != NULL); + + pk = *_pk; + ppk = NULL; + while (pk->system != NON_KEY && pk->ID != ID) { + ppk = pk; + pk = pk->next; + if (pk == NULL) { + return CRYPT_PK_NOT_FOUND; + } + } + + switch (pk->system) { + case RSA_KEY: + rsa_free(&(pk->key.rsa)); + break; + case DH_KEY: + dh_free(&(pk->key.dh)); + break; + case ECC_KEY: + ecc_free(&(pk->key.ecc)); + break; + } + + if (ppk == NULL) { /* the first element matches the ID */ + ppk = pk->next; /* get the 2nd element */ + XFREE(pk); /* free the first */ + *_pk = ppk; /* make the first element the second */ + } else { /* (not) first element matches the ID */ + ppk->next = pk->next; /* make the previous'es next point to the current next */ + XFREE(pk); /* free the element */ + } + return CRYPT_OK; +} + +int kr_clear(pk_key **pk) +{ + int errno; + _ARGCHK(pk != NULL); + + while ((*pk)->system != NON_KEY) { + if ((errno = kr_del(pk, (*pk)->ID)) != CRYPT_OK) { + return errno; + } + } + XFREE(*pk); + *pk = NULL; + return CRYPT_OK; +} + +static unsigned long _write(unsigned char *buf, unsigned long len, FILE *f, symmetric_CTR *ctr) +{ +#ifdef NO_FILE + return 0; +#else + _ARGCHK(buf != NULL); + _ARGCHK(f != NULL); + if (ctr != NULL) { + if (ctr_encrypt(buf, buf, len, ctr) != CRYPT_OK) { + return 0; + } + } + return fwrite(buf, 1, len, f); +#endif +} + +static unsigned long _read(unsigned char *buf, unsigned long len, FILE *f, symmetric_CTR *ctr) +{ +#ifdef NO_FILE + return 0; +#else + unsigned long y; + _ARGCHK(buf != NULL); + _ARGCHK(f != NULL); + y = fread(buf, 1, len, f); + if (ctr != NULL) { + if (ctr_decrypt(buf, buf, y, ctr) != CRYPT_OK) { + return 0; + } + } + return y; +#endif +} + +int kr_export(pk_key *pk, unsigned long ID, int key_type, unsigned char *out, unsigned long *outlen) +{ + unsigned char buf[8192], *obuf; + pk_key *ppk; + unsigned long len; + int errno; + + _ARGCHK(pk != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* find the desired key */ + ppk = kr_find(pk, ID); + if (ppk == NULL) { + return CRYPT_PK_NOT_FOUND; + } + + if (ppk->key_type == PK_PUBLIC && key_type != PK_PUBLIC) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* this makes PK_PRIVATE an alias for PK_PRIVATE_OPTIMIZED type */ + if (ppk->key_type == PK_PRIVATE_OPTIMIZED && key_type == PK_PRIVATE) { + key_type = PK_PRIVATE_OPTIMIZED; + } + + /* now copy the header and various other details */ + memcpy(buf, key_magic, 4); /* magic info */ + buf[4] = key_type; /* key type */ + buf[5] = ppk->system; /* system */ + STORE32L(ppk->ID, buf+6); /* key ID */ + memcpy(buf+10, ppk->name, MAXLEN); /* the name */ + memcpy(buf+10+MAXLEN, ppk->email, MAXLEN); /* the email */ + memcpy(buf+10+MAXLEN+MAXLEN, ppk->description, MAXLEN); /* the description */ + + /* export key */ + len = sizeof(buf) - (6 + 4 + MAXLEN*3); + obuf = buf+6+4+MAXLEN*3; + switch (ppk->system) { + case RSA_KEY: + if ((errno = rsa_export(obuf, &len, key_type, &(ppk->key.rsa))) != CRYPT_OK) { + return errno; + } + break; + case DH_KEY: + if ((errno = dh_export(obuf, &len, key_type, &(ppk->key.dh))) != CRYPT_OK) { + return errno; + } + break; + case ECC_KEY: + if ((errno = ecc_export(obuf, &len, key_type, &(ppk->key.ecc))) != CRYPT_OK) { + return errno; + } + break; + } + + /* get the entire length of the packet */ + len += 6 + 4 + 3*MAXLEN; + + if (*outlen < len) { + #ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); + #endif + return CRYPT_BUFFER_OVERFLOW; + } else { + *outlen = len; + memcpy(out, buf, len); + #ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); + #endif + return CRYPT_OK; + } +} + +int kr_import(pk_key *pk, const unsigned char *in) +{ + _pk_key key; + int system, key_type, errno; + unsigned long ID; + + _ARGCHK(pk != NULL); + _ARGCHK(in != NULL); + + if (memcmp(in, key_magic, 4)) { + return CRYPT_INVALID_PACKET; + } + key_type = in[4]; /* get type */ + system = in[5]; /* get system */ + LOAD32L(ID,in+6); /* the ID */ + + if (ID != kr_crc(in+10, in+10+MAXLEN, in+10+MAXLEN+MAXLEN)) { + return CRYPT_INVALID_PACKET; + } + + zeromem(&key, sizeof(key)); + switch (system) { + case RSA_KEY: + if ((errno = rsa_import(in+10+3*MAXLEN, &(key.rsa))) != CRYPT_OK) { + return errno; + } + break; + case DH_KEY: + if ((errno = dh_import(in+10+3*MAXLEN, &(key.dh))) != CRYPT_OK) { + return errno; + } + break; + case ECC_KEY: + if ((errno = ecc_import(in+10+3*MAXLEN, &(key.ecc))) != CRYPT_OK) { + return errno; + } + break; + } + return kr_add(pk, key_type, system, + in+10, /* the name */ + in+10+MAXLEN, /* email address */ + in+10+MAXLEN+MAXLEN, /* description */ + &key); +} + + +int kr_load(pk_key **pk, FILE *in, symmetric_CTR *ctr) +{ + unsigned char buf[8192], blen[4]; + unsigned long len; + int res, errno; + + _ARGCHK(pk != NULL); + _ARGCHK(in != NULL); + + /* init keyring */ + if ((errno = kr_init(pk)) != CRYPT_OK) { + return errno; + } + + /* read in magic bytes */ + if (_read(buf, 6, in, ctr) != 6) { goto done2; } + + if (memcmp(buf, file_magic, 4)) { + return CRYPT_INVALID_PACKET; + } + + len = (unsigned long)buf[4] | ((unsigned long)buf[5] << 8); + if (len > CRYPT) { + return CRYPT_INVALID_PACKET; + } + + /* while there are lengths to read... */ + while (_read(blen, 4, in, ctr) == 4) { + /* get length */ + LOAD32L(len, blen); + + if (len > sizeof(buf)) { + return CRYPT_INVALID_PACKET; + } + + if (_read(buf, len, in, ctr) != len) { goto done2; } + if ((errno = kr_import(*pk, buf)) != CRYPT_OK) { + return errno; + } + } + + res = CRYPT_OK; + goto done; +done2: + res = CRYPT_ERROR; +done: +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + return res; +} + +int kr_save(pk_key *pk, FILE *out, symmetric_CTR *ctr) +{ + unsigned char buf[8192], blen[4]; + unsigned long len; + int res, errno; + + _ARGCHK(pk != NULL); + _ARGCHK(out != NULL); + + /* write out magic bytes */ + memcpy(buf, file_magic, 4); + buf[4] = CRYPT&255; + buf[5] = (CRYPT>>8)&255; + if (_write(buf, 6, out, ctr) != 6) { goto done2; } + + while (pk->system != NON_KEY) { + len = sizeof(buf); + if ((errno = kr_export(pk, pk->ID, pk->key_type, buf, &len)) != CRYPT_OK) { + return errno; + } + + STORE32L(len, blen); + if (_write(blen, 4, out, ctr) != 4) { goto done2; } + if (_write(buf, len, out, ctr) != len) { goto done2; } + + pk = pk->next; + } + + res = CRYPT_OK; + goto done; +done2: + res = CRYPT_ERROR; +done: +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + return res; +} + +int kr_make_key(pk_key *pk, prng_state *prng, int wprng, + int system, int keysize, const unsigned char *name, + const unsigned char *email, const unsigned char *description) +{ + _pk_key key; + int key_type, errno; + + _ARGCHK(pk != NULL); + _ARGCHK(name != NULL); + _ARGCHK(email != NULL); + _ARGCHK(description != NULL); + + /* valid PRNG? */ + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + /* make the key first */ + zeromem(&key, sizeof(key)); + switch (system) { + case RSA_KEY: + if ((errno = rsa_make_key(prng, wprng, keysize, 65537, &(key.rsa))) != CRYPT_OK) { + return errno; + } + key_type = key.rsa.type; + break; + case DH_KEY: + if ((errno = dh_make_key(prng, wprng, keysize, &(key.dh))) != CRYPT_OK) { + return errno; + } + key_type = key.dh.type; + break; + case ECC_KEY: + if ((errno = ecc_make_key(prng, wprng, keysize, &(key.ecc))) != CRYPT_OK) { + return errno; + } + key_type = key.ecc.type; + break; + default: + return CRYPT_PK_INVALID_SYSTEM; + } + + /* now add the key */ + if ((errno = kr_add(pk, key_type, system, name, email, description, &key)) != CRYPT_OK) { + return errno; + } + +#ifdef CLEAN_STACK + zeromem(&key, sizeof(key)); +#endif + return CRYPT_OK; +} + +int kr_encrypt_key(pk_key *pk, unsigned long ID, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, int hash) +{ + unsigned char buf[8192]; + unsigned long len; + pk_key *kr; + int errno; + + _ARGCHK(pk != NULL); + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* find the key */ + kr = kr_find(pk, ID); + if (kr == NULL) { + return CRYPT_PK_NOT_FOUND; + } + + /* store the header */ + memcpy(buf, enc_magic, 4); + + /* now store the ID */ + STORE32L(kr->ID,buf+4); + + /* now encrypt it */ + len = sizeof(buf)-8; + switch (kr->system) { + case RSA_KEY: + if ((errno = rsa_encrypt_key(in, inlen, buf+8, &len, prng, wprng, &(kr->key.rsa))) != CRYPT_OK) { + return errno; + } + break; + case DH_KEY: + if ((errno = dh_encrypt_key(in, inlen, buf+8, &len, prng, wprng, hash, &(kr->key.dh))) != CRYPT_OK) { + return errno; + } + break; + case ECC_KEY: + if ((errno = ecc_encrypt_key(in, inlen, buf+8, &len, prng, wprng, hash, &(kr->key.ecc))) != CRYPT_OK) { + return errno; + } + break; + } + len += 8; + + if (len > *outlen) { + #ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); + #endif + return CRYPT_BUFFER_OVERFLOW; + } else { + memcpy(out, buf, len); + #ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); + #endif + *outlen = len; + return CRYPT_OK; + } +} + +int kr_decrypt_key(pk_key *pk, const unsigned char *in, + unsigned char *out, unsigned long *outlen) +{ + unsigned char buf[8192]; + unsigned long len, ID; + pk_key *kr; + int errno; + + _ARGCHK(pk != NULL); + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* check magic header */ + if (memcmp(in, enc_magic, 4)) { + return CRYPT_INVALID_PACKET; + } + + /* now try to find key */ + LOAD32L(ID,in+4); + kr = kr_find(pk, ID); + if (kr == NULL) { + return CRYPT_PK_NOT_FOUND; + } + + /* is it public? */ + if (kr->key_type == PK_PUBLIC) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* now try and decrypt it */ + len = sizeof(buf); + switch (kr->system) { + case RSA_KEY: + if ((errno = rsa_decrypt_key(in+8, buf, &len, &(kr->key.rsa))) != CRYPT_OK) { + return errno; + } + break; + case DH_KEY: + if ((errno = dh_decrypt_key(in+8, buf, &len, &(kr->key.dh))) != CRYPT_OK) { + return errno; + } + break; + case ECC_KEY: + if ((errno = ecc_decrypt_key(in+8, buf, &len, &(kr->key.ecc))) != CRYPT_OK) { + return errno; + } + break; + } + + if (len > *outlen) { + #ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); + #endif + return CRYPT_BUFFER_OVERFLOW; + } else { + memcpy(out, buf, len); + #ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); + #endif + *outlen = len; + return CRYPT_OK; + } +} + +int kr_sign_hash(pk_key *pk, unsigned long ID, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng) +{ + unsigned char buf[8192]; + unsigned long len; + pk_key *kr; + int errno; + + _ARGCHK(pk != NULL); + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* find the key */ + kr = kr_find(pk, ID); + if (kr == NULL) { + return CRYPT_PK_NOT_FOUND; + } + + /* is it public? */ + if (kr->key_type == PK_PUBLIC) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* store the header */ + memcpy(buf, sign_magic, 4); + + /* now store the ID */ + STORE32L(kr->ID,buf+4); + + /* now sign it */ + len = sizeof(buf)-12; + switch (kr->system) { + case RSA_KEY: + if ((errno = rsa_sign_hash(in, inlen, buf+12, &len, &(kr->key.rsa))) != CRYPT_OK) { + return errno; + } + break; + case DH_KEY: + if ((errno = dh_sign_hash(in, inlen, buf+12, &len, prng, wprng, &(kr->key.dh))) != CRYPT_OK) { + return errno; + } + break; + case ECC_KEY: + if ((errno = ecc_sign_hash(in, inlen, buf+12, &len, prng, wprng, &(kr->key.ecc))) != CRYPT_OK) { + return errno; + } + break; + } + STORE32L(inlen,buf+8); + len += 12; + + if (len > *outlen) { + #ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); + #endif + return CRYPT_BUFFER_OVERFLOW; + } else { + memcpy(out, buf, len); + #ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); + #endif + *outlen = len; + return CRYPT_OK; + } +} + +int kr_verify_hash(pk_key *pk, const unsigned char *in, const unsigned char *hash, + unsigned long hashlen, int *stat) +{ + unsigned long inlen, ID; + pk_key *kr; + int errno; + + _ARGCHK(pk != NULL); + _ARGCHK(in != NULL); + _ARGCHK(hash != NULL); + _ARGCHK(stat != NULL); + + /* default to not match */ + *stat = 0; + + /* check magic header */ + if (memcmp(in, sign_magic, 4)) { + return CRYPT_INVALID_PACKET; + } + + /* now try to find key */ + LOAD32L(ID,in+4); + kr = kr_find(pk, ID); + if (kr == NULL) { + return CRYPT_PK_NOT_FOUND; + } + + /* now try and verify it */ + LOAD32L(inlen,in+8); /* this is the length of the original inlen */ + if (inlen != hashlen) { /* size doesn't match means the signature is invalid */ + return CRYPT_OK; + } + + switch (kr->system) { + case RSA_KEY: + if ((errno = rsa_verify_hash(in+12, hash, stat, &(kr->key.rsa))) != CRYPT_OK) { + return errno; + } + break; + case DH_KEY: + if ((errno = dh_verify_hash(in+12, hash, inlen, stat, &(kr->key.dh))) != CRYPT_OK) { + return errno; + } + break; + case ECC_KEY: + if ((errno = ecc_verify_hash(in+12, hash, inlen, stat, &(kr->key.ecc))) != CRYPT_OK) { + return errno; + } + break; + } + return CRYPT_OK; +} + +int kr_fingerprint(pk_key *pk, unsigned long ID, int hash, + unsigned char *out, unsigned long *outlen) +{ + unsigned char buf[8192]; + unsigned long len; + int errno; + + _ARGCHK(pk != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* valid hash? */ + if ((errno = hash_is_valid(hash)) != CRYPT_OK) { + return errno; + } + + len = sizeof(buf); + if ((errno = kr_export(pk, ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) { + return errno; + } + + /* now hash it */ + if ((errno = hash_memory(hash, buf, len, out, outlen)) != CRYPT_OK) { + return errno; + } + +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + return CRYPT_OK; +} + +#endif + + diff --git a/makefile b/makefile new file mode 100644 index 0000000..53de606 --- /dev/null +++ b/makefile @@ -0,0 +1,262 @@ +# MAKEFILE for linux GCC +# +# Tom St Denis +# Modified by Clay Culver +# +# NOTE: This should later be replaced by autoconf/automake scripts, but for +# the time being this is actually pretty clean. The only ugly part is +# handling CFLAGS so that the x86 specific optimizations don't break +# a build. This is easy to remedy though, for those that have problems. + +# The version +VERSION=0.75 + +#Compiler and Linker Names +CC=gcc +LD=ld + +#Archiver [makes .a files] +AR=ar +ARFLAGS=rs + +#here you can set the malloc/calloc/free functions you want +XMALLOC=malloc +XCALLOC=calloc +XFREE=free + +#you can redefine the clock +XCLOCK=clock +XCLOCKS_PER_SEC=CLOCKS_PER_SEC + +#Compilation flags. Note the += does not write over the user's CFLAGS! +CFLAGS += -c -I./ -Wall -Wsign-compare -W -Wno-unused -Werror \ + -DXMALLOC=$(XMALLOC) -DXCALLOC=$(XCALLOC) -DXFREE=$(XFREE) -DXCLOCK=$(XCLOCK) \ + -DXCLOCKS_PER_SEC=$(XCLOCKS_PER_SEC) + +#optimize for SPEED (comment out SIZE/DEBUG line as well) +#CFLAGS += -O3 -fomit-frame-pointer -funroll-loops + +#optimize for SIZE (comment out SPEED/DEBUG line as well) +CFLAGS += -O2 + +#compile for DEBUGGING +#CFLAGS += -g3 + +#These flags control how the library gets built. + +#no file support, when defined the library will not have any functions that can read/write files +#(comment out to have file support) +#CFLAGS += -DNO_FILE + +#Support the UNIX /dev/random or /dev/urandom +CFLAGS += -DDEVRANDOM + +# Use /dev/urandom first on devices where /dev/random is too slow */ +#CFLAGS += -DTRY_URANDOM_FIRST + +# Clean the stack after sensitive functions. Not always required... +# With this defined most of the ciphers and hashes will clean their stack area +# after usage with a (sometimes) huge penalty in speed. Normally this is not +# required if you simply lock your stack and wipe it when your program is done. +# +#CFLAGS += -DCLEAN_STACK + +# What algorithms to include? comment out and rebuild to remove em +CFLAGS += -DBLOWFISH +CFLAGS += -DRC2 +CFLAGS += -DRC5 +CFLAGS += -DRC6 +CFLAGS += -DSERPENT +CFLAGS += -DSAFERP +CFLAGS += -DSAFER +CFLAGS += -DRIJNDAEL +CFLAGS += -DXTEA +CFLAGS += -DTWOFISH +CFLAGS += -DDES +CFLAGS += -DCAST5 + +#You can also customize the Twofish code. All four combinations +#of the flags are possible but only three of them make sense. +# +#Both undefined: Very fast, requires ~4.2KB of ram per scheduled key +#Both defined : Slow, requires only ~100 bytes of ram per scheduled key +# +#If defined on their own +#_SMALL defined: Very Slow, small code only ~100 bytes of ram +#_TABLES defined: Very fast, not faster than if both were undefined. Code is ~1KB bigger +# faster keysetup though... + +# Small Ram Variant of Twofish. For this you must have TWOFISH defined. This +# variant requires about 4kb less memory but is considerably slower. It is ideal +# when high throughput is less important than conserving memory. By default it is +# not defined which means the larger ram (about 4.2Kb used) variant is built. +#CFLAGS += -DTWOFISH_SMALL + +# Tell Twofish to use precomputed tables. If you want to use the small table +# variant of Twofish you may want to turn this on. Essentially it tells Twofish to use +# precomputed S-boxes (Q0 and Q1) as well as precomputed GF multiplications [in the MDS]. +# This speeds up the cipher somewhat. +#CFLAGS += -DTWOFISH_TABLES + +#Small code variant of the SAFER+ cipher, uses same RAM but less code space +#With this defined the cipher is slower. On my x86 with GCC 3.2 it required 50KB less space +CFLAGS += -DSAFERP_SMALL + +#Small Rijndael [saves 13KB on an x86] +#With this defined the cipher is slower (by 50Mbit/sec on an Athon XP) +CFLAGS += -DRIJNDAEL_SMALL + +#Use fast PK routines. Basically this limits the size of the private key in the +#DH system to 256 bits. The group order remains unchanged so the best +#attacks are still GNFS (for DH upto 2560-bits) +# +#This will only speed up the key generation and encryption routines. It lowers the +#security so its by default not turned on. USE AT YOUR RISK! +#CFLAGS += -DFAST_PK + +#Include the PK Packet functions (e.g. dh_encrypt) +#Does not affect the key/hash routines (e.g. ecc_sign_hash) +#CFLAGS += -DPK_PACKET + +# Chaining modes +CFLAGS += -DCFB +CFLAGS += -DOFB +CFLAGS += -DECB +CFLAGS += -DCBC +CFLAGS += -DCTR + +#One-way hashes +CFLAGS += -DSHA512 +CFLAGS += -DSHA384 +CFLAGS += -DSHA256 +CFLAGS += -DTIGER +CFLAGS += -DSHA1 +CFLAGS += -DMD5 +CFLAGS += -DMD4 +CFLAGS += -DMD2 + +# base64 +CFLAGS += -DBASE64 + +# prngs +CFLAGS += -DYARROW +CFLAGS += -DSPRNG +CFLAGS += -DRC4 + +# PK code +CFLAGS += -DMRSA +CFLAGS += -DMDH +CFLAGS += -DMECC +CFLAGS += -DKR + +# include GF math routines? (not currently used by anything internally) +#CFLAGS += -DGF + +# include large integer math routines? (required by the PK code) +CFLAGS += -DMPI + +# Use a small prime table? It greatly reduces the size of prime.c at a little impact +# in speed. +# +CFLAGS += -DSMALL_PRIME_TAB + +# include HMAC support +CFLAGS += -DHMAC + +#Output filenames for various targets. +LIBNAME=libtomcrypt.a +TEST=test +HASH=hashsum +CRYPT=encrypt +SMALL=small + +#LIBPATH-The directory for libtomcrypt to be installed to. +#INCPATH-The directory to install the header files for libtomcrypt. +LIBPATH=/usr/lib +INCPATH=/usr/include + +#List of objects to compile. +OBJECTS=keyring.o gf.o mem.o sprng.o ecc.o base64.o dh.o rsa.o \ +bits.o yarrow.o cfb.o ofb.o ecb.o ctr.o cbc.o hash.o tiger.o sha1.o \ +md5.o md4.o md2.o sha256.o sha512.o xtea.o aes.o serpent.o des.o \ +safer_tab.o safer.o safer+.o rc4.o rc2.o rc6.o rc5.o cast5.o blowfish.o crypt.o \ +ampi.o mpi.o prime.o twofish.o packet.o hmac.o strings.o + +TESTOBJECTS=demos/test.o +HASHOBJECTS=demos/hashsum.o +CRYPTOBJECTS=demos/encrypt.o +SMALLOBJECTS=demos/small.o + +#Files left over from making the crypt.pdf. +LEFTOVERS=*.dvi *.log *.aux *.toc *.idx *.ilg *.ind + +#Compressed filenames +COMPRESSED=crypt.tar.bz2 crypt.zip crypt.tar.gz + +#Header files used by libtomcrypt. +HEADERS=mpi-types.h mpi-config.h mpi.h \ +mycrypt_cfg.h mycrypt_gf.h mycrypt_kr.h \ +mycrypt_misc.h mycrypt_prng.h mycrypt_cipher.h mycrypt_hash.h \ +mycrypt_macros.h mycrypt_pk.h mycrypt.h mycrypt_argchk.h + +#The default rule for make builds the libtomcrypt library. +default:library mycrypt.h mycrypt_cfg.h + +#These are the rules to make certain object files. +rsa.o: rsa.c rsa_sys.c +ecc.o: ecc.c ecc_sys.c +dh.o: dh.c dh_sys.c +aes.o: aes.c aes_tab.c +sha512.o: sha512.c sha384.c + +#This rule makes the libtomcrypt library. +library: $(OBJECTS) + $(AR) $(ARFLAGS) $(LIBNAME) $(OBJECTS) + +#This rule makes the test program included with libtomcrypt +test: library $(TESTOBJECTS) + $(CC) $(TESTOBJECTS) $(LIBNAME) -o $(TEST) $(WARN) + +#This rule makes the hash program included with libtomcrypt +hashsum: library $(HASHOBJECTS) + $(CC) $(HASHOBJECTS) $(LIBNAME) -o $(HASH) $(WARN) + +#makes the crypt program +crypt: library $(CRYPTOBJECTS) + $(CC) $(CRYPTOBJECTS) $(LIBNAME) -o $(CRYPT) $(WARN) + +#makes the small program +small: library $(SMALLOBJECTS) + $(CC) $(SMALLOBJECTS) $(LIBNAME) -o $(SMALL) $(WARN) + +#This rule installs the library and the header files. This must be run +#as root in order to have a high enough permission to write to the correct +#directories and to set the owner and group to root. +install: library + install -g root -o root $(LIBNAME) $(LIBPATH) + install -g root -o root $(HEADERS) $(INCPATH) + +#This rule cleans the source tree of all compiled code, not including the pdf +#documentation. +clean: + rm -f $(OBJECTS) $(TESTOBJECTS) $(HASHOBJECTS) $(CRYPTOBJECTS) $(SMALLOBJECTS) $(LEFTOVERS) $(LIBNAME) + rm -f $(TEST) $(HASH) $(COMPRESSED) + rm -f *stackdump *.lib *.exe *.obj demos/*.obj zlib/*.obj *.bat + +#This builds the crypt.pdf file. Note that the rm -f *.pdf has been removed +#from the clean command! This is because most people would like to keep the +#nice pre-compiled crypt.pdf that comes with libtomcrypt! We only need to +#delete it if we are rebuilding it. +docs: crypt.tex + rm -f crypt.pdf + rm -f $(LEFTOVERS) + latex crypt > /dev/null + makeindex crypt > /dev/null + pdflatex crypt > /dev/null + rm -f $(LEFTOVERS) + +#zipup the project (take that!) +zipup: clean docs + chdir .. ; rm -rf crypt* libtomcrypt-$(VERSION) ; mkdir libtomcrypt-$(VERSION) ; \ + cp -R ./libtomcrypt/* ./libtomcrypt-$(VERSION)/ ; tar -c libtomcrypt-$(VERSION)/* > crypt-$(VERSION).tar ; \ + bzip2 -9vv crypt-$(VERSION).tar ; zip -9 -r crypt-$(VERSION).zip libtomcrypt-$(VERSION)/* \ No newline at end of file diff --git a/makefile.ps2 b/makefile.ps2 new file mode 100644 index 0000000..932a17e --- /dev/null +++ b/makefile.ps2 @@ -0,0 +1,293 @@ +# MAKEFILE for linux GCC +# +# Tom St Denis +# Modified by Clay Culver +# +# NOTE: This should later be replaced by autoconf/automake scripts, but for +# the time being this is actually pretty clean. The only ugly part is +# handling CFLAGS so that the x86 specific optimizations don't break +# a build. This is easy to remedy though, for those that have problems. + +#Compiler and Linker Names +CC=ee-gcc +LD=ee-ld + +# PlayStation(tm) 2 specifics +TOP = /usr/local/sce/ee +LIBDIR = $(TOP)/lib +INCDIR = $(TOP)/include/ +COMMONDIR = $(TOP)/../common/include/ +LCFILE = $(LIBDIR)/app.cmd +LDFLAGS = -DSONY_PS2 -DSONY_PS2_EE -Wl,-Map,$(@).map -mno-crt0 -L$(LIBDIR) -lm +AS = ee-gcc +ASFLAGS = -DSONY_PS2 -DSONY_PS2_EE -c -xassembler-with-cpp -Wa,-al +EXT = .elf +CFLAGS += -DSONY_PS2 -DSONY_PS2_EE -Wa,-al -Wno-unused -Werror \ + -fno-common -fno-strict-aliasing -I$(INCDIR) -I$(COMMONDIR) + +#Archiver [makes .a files] +AR=ee-ar +ARFLAGS=rs + +#here you can set the malloc/calloc/free functions you want +XMALLOC=malloc +XCALLOC=calloc +XFREE=free + +#you can redefine the clock +XCLOCK=TIMER_clock +XCLOCKS_PER_SEC=576000 + +#Compilation flags. Note the += does not write over the user's CFLAGS! +CFLAGS += -c -I./ -Wall -Wsign-compare -W -Wno-unused -Werror \ + -DXMALLOC=$(XMALLOC) -DXCALLOC=$(XCALLOC) -DXFREE=$(XFREE) -DXCLOCK=$(XCLOCK) \ + -DXCLOCKS_PER_SEC=$(XCLOCKS_PER_SEC) + +#no file support, when defined the library will not have any functions that can read/write files +#(comment out to have file support) +CFLAGS += -DNO_FILE + +#optimize for SPEED (comment out SIZE line as well) +#CFLAGS += -O3 -fomit-frame-pointer -funroll-loops + +#optimize for SIZE (comment out SPEED line as well) +CFLAGS += -O2 + +#These flags control how the library gets built. + +# Clean the stack after sensitive functions. Not always required... +# With this defined most of the ciphers and hashes will clean their stack area +# after usage with a (sometimes) huge penalty in speed. Normally this is not +# required if you simply lock your stack and wipe it when your program is done. +# +#CFLAGS += -DCLEAN_STACK + +# What algorithms to include? comment out and rebuild to remove em +CFLAGS += -DBLOWFISH +CFLAGS += -DRC2 +#CFLAGS += -DRC5 +#CFLAGS += -DRC6 +CFLAGS += -DSERPENT +CFLAGS += -DSAFERP +CFLAGS += -DSAFER +CFLAGS += -DRIJNDAEL +CFLAGS += -DXTEA +CFLAGS += -DTWOFISH +CFLAGS += -DDES +CFLAGS += -DCAST5 + +#You can also customize the Twofish code. All four combinations +#of the flags are possible but only three of them make sense. +# +#Both undefined: Very fast, requires ~4.2KB of ram per scheduled key +#Both defined : Slow, requires only ~100 bytes of ram per scheduled key +# +#If defined on their own +#_SMALL defined: Very Slow, small code only ~100 bytes of ram +#_TABLES defined: Very fast, not faster than if both were undefined. Code is ~1KB bigger +# faster keysetup though... + +# Small Ram Variant of Twofish. For this you must have TWOFISH defined. This +# variant requires about 4kb less memory but is considerably slower. It is ideal +# when high throughput is less important than conserving memory. By default it is +# not defined which means the larger ram (about 4.2Kb used) variant is built. +# CFLAGS += -DTWOFISH_SMALL + +# Tell Twofish to use precomputed tables. If you want to use the small table +# variant of Twofish you may want to turn this on. Essentially it tells Twofish to use +# precomputed S-boxes (Q0 and Q1) as well as precomputed GF multiplications [in the MDS]. +# This speeds up the cipher somewhat. +# CFLAGS += -DTWOFISH_TABLES + +#Small code variant of the SAFER+ cipher, uses same RAM but less code space +#With this defined the cipher is slower. On my x86 with GCC 3.2 it required 50KB less space +CFLAGS += -DSAFERP_SMALL + +#Small Rijndael [saves 13KB on an x86] +#With this defined the cipher is slower (by 50Mbit/sec on an Athon XP) +CFLAGS += -DRIJNDAEL_SMALL + +#Use fast PK routines. Basically this limits the size of the private key in the +#DH system to 256 bits. The group order remains unchanged so the best +#attacks are still GNFS (for DH upto 2560-bits) +# +#This will only speed up the key generation and encryption routines. It lowers the +#security so its by default not turned on. USE AT YOUR RISK! +#CFLAGS += -DFAST_PK + +#Include the PK Packet functions (e.g. dh_encrypt) +#Does not affect the key/hash routines (e.g. ecc_sign_hash) +#CFLAGS += -DPK_PACKET + +# Chaining modes +CFLAGS += -DCFB +CFLAGS += -DOFB +CFLAGS += -DECB +CFLAGS += -DCBC +CFLAGS += -DCTR + +#One-way hashes +CFLAGS += -DSHA512 +CFLAGS += -DSHA384 +CFLAGS += -DSHA256 +CFLAGS += -DTIGER +CFLAGS += -DSHA1 +CFLAGS += -DMD5 +CFLAGS += -DMD4 +CFLAGS += -DMD2 + +# base64 +CFLAGS += -DBASE64 + +# prngs +CFLAGS += -DYARROW +CFLAGS += -DSPRNG +CFLAGS += -DRC4 + +# PK code +CFLAGS += -DMRSA +CFLAGS += -DMDH +CFLAGS += -DMECC +CFLAGS += -DKR + +# include GF math routines? (not currently used by anything internally) +#CFLAGS += -DGF + +# include large integer math routines? (required by the PK code) +CFLAGS += -DMPI + +# Use a small prime table? It greatly reduces the size of prime.c at a little impact +# in speed. +# +CFLAGS += -DSMALL_PRIME_TAB + +# include HMAC support +CFLAGS += -DHMAC + +# Have /dev/random or /dev/urandom? +#CFLAGS += -DDEVRANDOM + +#Output filenames for various targets. +LIBNAME=libtomcrypt.a +TEST=test$(EXT) +HASH=hashsum$(EXT) +CRYPT=encrypt$(EXT) +SMALL=small$(EXT) + +#LIBPATH-The directory for libtomcrypt to be installed to. +#INCPATH-The directory to install the header files for libtomcrypt. +LIBPATH=/usr/lib +INCPATH=/usr/include + +#List of objects to compile. +OBJECTS=keyring.o gf.o mem.o sprng.o ecc.o base64.o dh.o rsa.o \ +bits.o yarrow.o cfb.o ofb.o ecb.o ctr.o cbc.o hash.o tiger.o sha1.o \ +md5.o md4.o md2.o sha256.o sha512.o xtea.o aes.o serpent.o des.o \ +safer_tab.o safer.o safer+.o rc4.o rc2.o rc6.o rc5.o cast5.o blowfish.o crypt.o \ +ampi.o mpi.o prime.o twofish.o packet.o hmac.o strings.o + +# PlayStation(tm) 2 C run-time startup module +PS2CRT0=crt0.o + +TESTOBJECTS=$(PS2CRT0) demos/test.o demos/timer.o +HASHOBJECTS=$(PS2CRT0) demos/hashsum.o +CRYPTOBJECTS=$(PS2CRT0) demos/encrypt.o +SMALLOBJECTS=$(PS2CRT0) demos/small.o + +#Files left over from making the crypt.pdf. +LEFTOVERS=*.dvi *.log *.aux *.toc *.idx *.ilg *.ind + +#Compressed filenames +COMPRESSED=crypt.tar.bz2 crypt.zip crypt.tar.gz + +#Header files used by libtomcrypt. +HEADERS=mpi-types.h mpi-config.h mpi.h \ +mycrypt_cfg.h mycrypt_gf.h mycrypt_kr.h \ +mycrypt_misc.h mycrypt_prng.h mycrypt_cipher.h mycrypt_hash.h \ +mycrypt_macros.h mycrypt_pk.h mycrypt.h mycrypt_argchk.h + +#The default rule for make builds the libtomcrypt library. +default:library mycrypt.h mycrypt_cfg.h + +#These are the rules to make certain object files. +rsa.o: rsa.c rsa_sys.c +ecc.o: ecc.c ecc_sys.c +dh.o: dh.c dh_sys.c +aes.o: aes.c aes_tab.c +sha512.o: sha512.c sha384.c + +#This rule makes the libtomcrypt library. +library: $(OBJECTS) + $(AR) $(ARFLAGS) $(LIBNAME) $(OBJECTS) + +#This rule makes the test program included with libtomcrypt +test: library $(TESTOBJECTS) + $(CC) -o $(TEST) -T $(LCFILE) $(LDFLAGS) $(TESTOBJECTS) $(LIBNAME) + +#This rule makes the hash program included with libtomcrypt +hashsum: library $(HASHOBJECTS) + $(CC) -o $(HASH) -T $(LCFILE) $(LDFLAGS) $(HASHOBJECTS) $(LIBNAME) + +#makes the crypt program +crypt: library $(CRYPTOBJECTS) + $(CC) -o $(CRYPT) -T $(LCFILE) $(LDFLAGS) $(CRYPTOBJECTS) $(LIBNAME) + +#makes the small program +small: library $(SMALLOBJECTS) + $(CC) -o $(SMALL) -T $(LCFILE) $(LDFLAGS) $(SMALLOBJECTS) $(LIBNAME) + +# makes the PlayStation(tm) 2 CRT 0 module +$(PS2CRT0): $(LIBDIR)/crt0.s + $(AS) $(ASFLAGS) $(TMPFLAGS) -o $@ $< > $*.lst + +#This rule installs the library and the header files. This must be run +#as root in order to have a high enough permission to write to the correct +#directories and to set the owner and group to root. +install: library + install -g root -o root $(LIBNAME) $(LIBPATH) + install -g root -o root $(HEADERS) $(INCPATH) + +#This rule cleans the source tree of all compiled code, not including the pdf +#documentation. +clean: + rm -f $(OBJECTS) $(TESTOBJECTS) $(HASHOBJECTS) $(CRYPTOBJECTS) $(SMALLOBJECTS) $(LEFTOVERS) $(LIBNAME) + rm -f $(TEST) $(HASH) $(COMPRESSED) + rm -f *stackdump *.lib *.exe *.obj demos/*.obj zlib/*.obj + rm -f *.o *.lst demos/*.o demos/*.lst + +#This builds the crypt.pdf file. Note that the rm -f *.pdf has been removed +#from the clean command! This is because most people would like to keep the +#nice pre-compiled crypt.pdf that comes with libtomcrypt! We only need to +#delete it if we are rebuilding it. +docs: crypt.tex + rm -f crypt.pdf + rm -f $(LEFTOVERS) + latex crypt > /dev/null + makeindex crypt > /dev/null + pdflatex crypt > /dev/null + rm -f $(LEFTOVERS) + +#This used to be the zipup target. I have split it into two seperate targets: +#bz and zip. bz builds a crypt.tar.bz2 package, while zip builds a crypt.zip +#package. I have removed the dos2unix commands, as this is a Linux makefile, +#and these should not be needed. I also made it output the target to the +#current directory instead of the root (/) directory. (Bad Tom!) We are +#almost assured write permission in the current directory, but not in the root +#directory. This means any user can now build a BZ image or a zip. +#NOTE: This removes all pre-built compressed archives during clean. +bz: clean docs + chdir .. ; rm -f crypt.tar.bz2 ; tar -c libtomcrypt/* > crypt.tar ; bzip2 -9v crypt.tar + +zip: clean docs + chdir .. ; rm -f crypt.zip ; zip -9 -r crypt.zip libtomcrypt/* + +#Makes a tar/gz archive of the library. +gz: clean docs + chdir .. ; rm -f crypt.tar.gz ; tar -c libtomcrypt/* > crypt.tar ; gzip -9v crypt.tar + +#makes a tar/SZIP archive [slightly better than bzip2] +szip: clean docs + chdir .. ; rm -f crypt.tar.szp ; tar -c libtomcrypt/* > crypt.tar ; szip -b41o64v255 crypt.tar crypt.tar.szp + +.c.o: + $(CC) $(CFLAGS) $(TMPFLAGS) -c $< -o $*.o > $*.lst diff --git a/makefile.vc b/makefile.vc new file mode 100644 index 0000000..37d99af --- /dev/null +++ b/makefile.vc @@ -0,0 +1,254 @@ +# MAKEFILE for MSVC 6.0 SP5 +# +# Tom St Denis, tomstdenis@yahoo.com +# +CC=cl +AR=lib + +#here you can set the malloc/calloc/free functions you want +XMALLOC=malloc +XCALLOC=calloc +XFREE=free + +#you can redefine the clock +XCLOCK=clock +XCLOCKS_PER_SEC=CLOCKS_PER_SEC + +CFLAGS = /c /Ogisy1 /Gs /I. /W3 /DWIN32 /DXMALLOC=$(XMALLOC) /DXCALLOC=$(XCALLOC) /DXFREE=$(XFREE) /DXCLOCK=$(XCLOCK) /DXCLOCKS_PER_SEC=$(XCLOCKS_PER_SEC) + +#These flags control how the library gets built. + +#no file support, when defined the library will not have any functions that can read/write files +#(comment out to have file support) +#CFLAGS += /DNO_FILE + +#Support the UNIX /dev/random or /dev/urandom +#CFLAGS += /DDEVRANDOM + +# Use /dev/urandom first on devices where /dev/random is too slow */ +#CFLAGS += /DTRY_URANDOM_FIRST + +# Clean the stack after sensitive functions. Not always required... +# With this defined most of the ciphers and hashes will clean their stack area +# after usage with a (sometimes) huge penalty in speed. Normally this is not +# required if you simply lock your stack and wipe it when your program is done. +# +#CFLAGS += /DCLEAN_STACK + +# What algorithms to include? comment out and rebuild to remove em +CFLAGS += /DBLOWFISH +CFLAGS += /DRC2 +CFLAGS += /DRC5 +CFLAGS += /DRC6 +CFLAGS += /DSERPENT +CFLAGS += /DSAFERP +CFLAGS += /DSAFER +CFLAGS += /DRIJNDAEL +CFLAGS += /DXTEA +CFLAGS += /DTWOFISH +CFLAGS += /DDES +CFLAGS += /DCAST5 + +#You can also customize the Twofish code. All four combinations +#of the flags are possible but only three of them make sense. +# +#Both undefined: Very fast, requires ~4.2KB of ram per scheduled key +#Both defined : Slow, requires only ~100 bytes of ram per scheduled key +# +#If defined on their own +#_SMALL defined: Very Slow, small code only ~100 bytes of ram +#_TABLES defined: Very fast, not faster than if both were undefined. Code is ~1KB bigger +# faster keysetup though... + +# Small Ram Variant of Twofish. For this you must have TWOFISH defined. This +# variant requires about 4kb less memory but is considerably slower. It is ideal +# when high throughput is less important than conserving memory. By default it is +# not defined which means the larger ram (about 4.2Kb used) variant is built. +# CFLAGS += /DTWOFISH_SMALL + +# Tell Twofish to use precomputed tables. If you want to use the small table +# variant of Twofish you may want to turn this on. Essentially it tells Twofish to use +# precomputed S-boxes (Q0 and Q1) as well as precomputed GF multiplications [in the MDS]. +# This speeds up the cipher somewhat. +# CFLAGS += /DTWOFISH_TABLES + +#Small code variant of the SAFER+ cipher, uses same RAM but less code space +#With this defined the cipher is slower. On my x86 with GCC 3.2 it required 50KB less space +CFLAGS += /DSAFERP_SMALL + +#Small Rijndael [saves 13KB on an x86] +#With this defined the cipher is slower (by 50Mbit/sec on an Athon XP) +CFLAGS += /DRIJNDAEL_SMALL + +#Use fast PK routines. Basically this limits the size of the private key in the +#DH system to 256 bits. The group order remains unchanged so the best +#attacks are still GNFS (for DH upto 2560-bits) +# +#This will only speed up the key generation and encryption routines. It lowers the +#security so its by default not turned on. USE AT YOUR RISK! +#CFLAGS += /DFAST_PK + +#Include the PK Packet functions (e.g. dh_encrypt) +#Does not affect the key/hash routines (e.g. ecc_sign_hash) +#CFLAGS += /DPK_PACKET + +# Chaining modes +CFLAGS += /DCFB +CFLAGS += /DOFB +CFLAGS += /DECB +CFLAGS += /DCBC +CFLAGS += /DCTR + +#One-way hashes +CFLAGS += /DSHA512 +CFLAGS += /DSHA384 +CFLAGS += /DSHA256 +CFLAGS += /DTIGER +CFLAGS += /DSHA1 +CFLAGS += /DMD5 +CFLAGS += /DMD4 +CFLAGS += /DMD2 + +# base64 +CFLAGS += /DBASE64 + +# prngs +CFLAGS += /DYARROW +CFLAGS += /DSPRNG +CFLAGS += /DRC4 + +# PK code +CFLAGS += /DMRSA +CFLAGS += /DMDH +CFLAGS += /DMECC +CFLAGS += /DKR + +# include GF math routines? (not currently used by anything internally) +#CFLAGS += /DGF + +# include large integer math routines? (required by the PK code) +CFLAGS += /DMPI + +# Use a small prime table? It greatly reduces the size of prime.c at a little impact +# in speed. +# +CFLAGS += /DSMALL_PRIME_TAB + +# include HMAC support +CFLAGS += /DHMAC + +default: tomcrypt.lib + +keyring.obj: keyring.c + $(CC) $(CFLAGS) keyring.c +ampi.obj: ampi.c + $(CC) $(CFLAGS) ampi.c +mpi.obj: mpi.c + $(CC) $(CFLAGS) mpi.c +blowfish.obj: blowfish.c + $(CC) $(CFLAGS) blowfish.c +crypt.obj: crypt.c + $(CC) $(CFLAGS) crypt.c +sha512.obj: sha512.c sha384.c + $(CC) $(CFLAGS) sha512.c +sha256.obj: sha256.c + $(CC) $(CFLAGS) sha256.c +hash.obj: hash.c + $(CC) $(CFLAGS) hash.c +md5.obj: md5.c + $(CC) $(CFLAGS) md5.c +md4.obj: md4.c + $(CC) $(CFLAGS) md4.c +sha1.obj: sha1.c + $(CC) $(CFLAGS) sha1.c +cfb.obj: cfb.c + $(CC) $(CFLAGS) cfb.c +ofb.obj: ofb.c + $(CC) $(CFLAGS) ofb.c +ecb.obj: ecb.c + $(CC) $(CFLAGS) ecb.c +ctr.obj: ctr.c + $(CC) $(CFLAGS) ctr.c +prime.obj: prime.c + $(CC) $(CFLAGS) prime.c +base64.obj: base64.c + $(CC) $(CFLAGS) base64.c +sprng.obj: sprng.c + $(CC) $(CFLAGS) sprng.c +mem.obj: mem.c + $(CC) $(CFLAGS) mem.c +gf.obj: gf.c + $(CC) $(CFLAGS) gf.c +ecc.obj: ecc.c ecc_sys.c + $(CC) $(CFLAGS) ecc.c +yarrow.obj: yarrow.c + $(CC) $(CFLAGS) yarrow.c +bits.obj: bits.c + $(CC) $(CFLAGS) bits.c +rsa.obj: rsa.c + $(CC) $(CFLAGS) rsa.c +rc6.obj: rc6.c + $(CC) $(CFLAGS) rc6.c +des.obj: des.c + $(CC) $(CFLAGS) des.c +tiger.obj: tiger.c + $(CC) $(CFLAGS) tiger.c +dh.obj: dh.c dh_sys.c + $(CC) $(CFLAGS) dh.c +serpent.obj: serpent.c + $(CC) $(CFLAGS) serpent.c +aes.obj: aes.c aes_tab.c + $(CC) $(CFLAGS) aes.c +rc5.obj: rc5.c + $(CC) $(CFLAGS) rc5.c +rc2.obj: rc2.c + $(CC) $(CFLAGS) rc2.c +cbc.obj: cbc.c + $(CC) $(CFLAGS) cbc.c +safer+.obj: safer+.c + $(CC) $(CFLAGS) safer+.c +safer.obj: safer.c + $(CC) $(CFLAGS) safer.c +safer_tab.obj: safer_tab.c + $(CC) $(CFLAGS) safer_tab.c +xtea.obj: xtea.c + $(CC) $(CFLAGS) xtea.c +twofish.obj: twofish.c + $(CC) $(CFLAGS) twofish.c +packet.obj: packet.c + $(CC) $(CFLAGS) packet.c +pack.obj: pack.c + $(CC) $(CFLAGS) pack.c +hmac.obj: hmac.c + $(CC) $(CFLAGS) hmac.c +strings.obj: strings.c + $(CC) $(CFLAGS) strings.c +md2.obj: md2.c + $(CC) $(CFLAGS) md2.c +cast5.obj: cast5.c + $(CC) $(CFLAGS) cast5.c + +demos/test.obj: demos/test.c + $(CC) $(CFLAGS) demos/test.c + +demos/hashsum.obj: demos/hashsum.c + $(CC) $(CFLAGS) demos/hashsum.c + +tomcrypt.lib: keyring.obj gf.obj mem.obj sprng.obj ecc.obj base64.obj dh.obj rsa.obj bits.obj hmac.obj \ +yarrow.obj cfb.obj ofb.obj ecb.obj ctr.obj cbc.obj hash.obj tiger.obj sha1.obj md2.obj md5.obj md4.obj sha256.obj sha512.obj xtea.obj \ +aes.obj serpent.obj safer_tab.obj safer.obj safer+.obj cast5.obj rc2.obj rc6.obj rc5.obj des.obj blowfish.obj crypt.obj ampi.obj \ +strings.obj mpi.obj prime.obj twofish.obj packet.obj + $(AR) /out:tomcrypt.lib keyring.obj gf.obj mem.obj sprng.obj ecc.obj base64.obj dh.obj rsa.obj hmac.obj \ +bits.obj yarrow.obj cfb.obj ofb.obj ecb.obj ctr.obj cbc.obj hash.obj tiger.obj sha1.obj md2.obj md5.obj md4.obj sha256.obj \ +strings.obj sha512.obj xtea.obj aes.obj serpent.obj safer_tab.obj safer.obj safer+.obj cast5.obj rc2.obj rc6.obj rc5.obj des.obj \ +blowfish.obj crypt.obj ampi.obj mpi.obj prime.obj twofish.obj packet.obj + + +test.exe: tomcrypt.lib demos/test.obj + link /OUT:test.exe test.obj tomcrypt.lib advapi32.lib + +hashsum.exe: tomcrypt.lib demos/hashsum.obj + link /OUT:hashsum.exe hashsum.obj tomcrypt.lib advapi32.lib + +clean: + rm -f demos/*.obj *.obj *.exe *.lib diff --git a/md2.c b/md2.c new file mode 100644 index 0000000..e29db7a --- /dev/null +++ b/md2.c @@ -0,0 +1,203 @@ +/* MD2 (RFC 1319) hash function implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef MD2 + +const struct _hash_descriptor md2_desc = +{ + "md2", + 7, + 16, + 16, + &md2_init, + &md2_process, + &md2_done, + &md2_test +}; + +static const unsigned char PI_SUBST[256] = { + 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, + 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, + 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, + 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, + 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, + 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, + 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, + 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, + 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, + 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, + 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, + 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, + 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, + 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, + 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, + 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, + 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, + 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 +}; + +/* adds 16 bytes to the checksum */ +static void md2_update_chksum(hash_state *md) +{ + int j; + unsigned char L; + L = md->md2.chksum[15]; + for (j = 0; j < 16; j++) { + +/* caution, the RFC says its "C[j] = S[M[i*16+j] xor L]" but the reference source code [and test vectors] say + otherwise. +*/ + L = (md->md2.chksum[j] ^= PI_SUBST[md->md2.buf[j] ^ L]); + } +} + +static void md2_compress(hash_state *md) +{ + int j, k; + unsigned char t; + + /* copy block */ + for (j = 0; j < 16; j++) { + md->md2.X[16+j] = md->md2.buf[j]; + md->md2.X[32+j] = md->md2.X[j] ^ md->md2.X[16+j]; + } + + t = 0; + + /* do 18 rounds */ + for (j = 0; j < 18; j++) { + for (k = 0; k < 48; k++) { + t = (md->md2.X[k] ^= PI_SUBST[t]); + } + t = (t + j) & 255; + } +} + +void md2_init(hash_state *md) +{ + _ARGCHK(md != NULL); + + /* MD2 uses a zero'ed state... */ + zeromem(md->md2.X, sizeof(md->md2.X)); + zeromem(md->md2.chksum, sizeof(md->md2.chksum)); + zeromem(md->md2.buf, sizeof(md->md2.buf)); + md->md2.curlen = 0; +} + +void md2_process(hash_state *md, const unsigned char *buf, unsigned long len) +{ + unsigned long n; + _ARGCHK(md != NULL); + _ARGCHK(buf != NULL); + while (len) { + n = MIN(len, (16 - md->md2.curlen)); + memcpy(md->md2.buf + md->md2.curlen, buf, n); + md->md2.curlen += n; + buf += n; + len -= n; + + /* is 16 bytes full? */ + if (md->md2.curlen == 16) { + md2_compress(md); + md2_update_chksum(md); + md->md2.curlen = 0; + } + } +} + +void md2_done(hash_state * md, unsigned char *hash) +{ + int i, k; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + /* pad the message */ + k = 16 - md->md2.curlen; + for (i = md->md2.curlen; i < 16; i++) { + md->md2.buf[i] = k; + } + + /* hash and update */ + md2_compress(md); + md2_update_chksum(md); + + /* hash checksum */ + memcpy(md->md2.buf, md->md2.chksum, 16); + md2_compress(md); + + /* output is lower 16 bytes of X */ + memcpy(hash, md->md2.X, 16); + +#ifdef CLEAN_STACK + zeromem(md, sizeof(hash_state)); +#endif +} + +int md2_test(void) +{ + static const struct { + unsigned char *msg; + unsigned char md[16]; + } tests[] = { + { "", + {0x83,0x50,0xe5,0xa3,0xe2,0x4c,0x15,0x3d, + 0xf2,0x27,0x5c,0x9f,0x80,0x69,0x27,0x73 + } + }, + { "a", + {0x32,0xec,0x01,0xec,0x4a,0x6d,0xac,0x72, + 0xc0,0xab,0x96,0xfb,0x34,0xc0,0xb5,0xd1 + } + }, + { "message digest", + {0xab,0x4f,0x49,0x6b,0xfb,0x2a,0x53,0x0b, + 0x21,0x9f,0xf3,0x30,0x31,0xfe,0x06,0xb0 + } + }, + { "abcdefghijklmnopqrstuvwxyz", + {0x4e,0x8d,0xdf,0xf3,0x65,0x02,0x92,0xab, + 0x5a,0x41,0x08,0xc3,0xaa,0x47,0x94,0x0b + } + }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + {0xda,0x33,0xde,0xf2,0xa4,0x2d,0xf1,0x39, + 0x75,0x35,0x28,0x46,0xc3,0x03,0x38,0xcd + } + }, + { "12345678901234567890123456789012345678901234567890123456789012345678901234567890", + {0xd5,0x97,0x6f,0x79,0xd8,0x3d,0x3a,0x0d, + 0xc9,0x80,0x6c,0x3c,0x66,0xf3,0xef,0xd8 + } + } + }; + int i; + hash_state md; + unsigned char buf[16]; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + md2_init(&md); + md2_process(&md, tests[i].msg, strlen(tests[i].msg)); + md2_done(&md, buf); + if (memcmp(buf, tests[i].md, 16)) { +#if 0 + int j; + printf("\n\nFailed test %d\n\n", i); + for (j = 0; j < 16; j++) { + printf("%02x ", buf[j]); + } + printf("\n"); + printf("Should have been\n"); + for (j = 0; j < 16; j++) { + printf("%02x ", tests[i].md[j]); + } + printf("\n"); +#endif + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; +} + +#endif + diff --git a/md4.c b/md4.c new file mode 100644 index 0000000..bbf2700 --- /dev/null +++ b/md4.c @@ -0,0 +1,290 @@ +/* Submitted by Dobes Vandermeer (dobes@smartt.com) */ +#include "mycrypt.h" + +#ifdef MD4 + +const struct _hash_descriptor md4_desc = +{ + "md4", + 6, + 16, + 64, + &md4_init, + &md4_process, + &md4_done, + &md4_test +}; + +#define S11 3 +#define S12 7 +#define S13 11 +#define S14 19 +#define S21 3 +#define S22 5 +#define S23 9 +#define S24 13 +#define S31 3 +#define S32 9 +#define S33 11 +#define S34 15 + +/* F, G and H are basic MD4 functions. */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +/* ROTATE_LEFT rotates x left n bits. */ +#define ROTATE_LEFT(x, n) ROL(x, n) + +/* FF, GG and HH are transformations for rounds 1, 2 and 3 */ +/* Rotation is separate from addition to prevent recomputation */ + +#define FF(a, b, c, d, x, s) { \ + (a) += F ((b), (c), (d)) + (x); \ + (a) = ROTATE_LEFT ((a), (s)); \ + } +#define GG(a, b, c, d, x, s) { \ + (a) += G ((b), (c), (d)) + (x) + 0x5a827999UL; \ + (a) = ROTATE_LEFT ((a), (s)); \ + } +#define HH(a, b, c, d, x, s) { \ + (a) += H ((b), (c), (d)) + (x) + 0x6ed9eba1UL; \ + (a) = ROTATE_LEFT ((a), (s)); \ + } + +#ifdef CLEAN_STACK +static void _md4_compress(hash_state *md) +#else +static void md4_compress(hash_state *md) +#endif +{ + unsigned long x[16], a, b, c, d; + int i; + + _ARGCHK(md != NULL); + + /* copy state */ + a = md->md4.state[0]; + b = md->md4.state[1]; + c = md->md4.state[2]; + d = md->md4.state[3]; + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD32L(x[i], md->md4.buf + (4*i)); + } + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11); /* 1 */ + FF (d, a, b, c, x[ 1], S12); /* 2 */ + FF (c, d, a, b, x[ 2], S13); /* 3 */ + FF (b, c, d, a, x[ 3], S14); /* 4 */ + FF (a, b, c, d, x[ 4], S11); /* 5 */ + FF (d, a, b, c, x[ 5], S12); /* 6 */ + FF (c, d, a, b, x[ 6], S13); /* 7 */ + FF (b, c, d, a, x[ 7], S14); /* 8 */ + FF (a, b, c, d, x[ 8], S11); /* 9 */ + FF (d, a, b, c, x[ 9], S12); /* 10 */ + FF (c, d, a, b, x[10], S13); /* 11 */ + FF (b, c, d, a, x[11], S14); /* 12 */ + FF (a, b, c, d, x[12], S11); /* 13 */ + FF (d, a, b, c, x[13], S12); /* 14 */ + FF (c, d, a, b, x[14], S13); /* 15 */ + FF (b, c, d, a, x[15], S14); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 0], S21); /* 17 */ + GG (d, a, b, c, x[ 4], S22); /* 18 */ + GG (c, d, a, b, x[ 8], S23); /* 19 */ + GG (b, c, d, a, x[12], S24); /* 20 */ + GG (a, b, c, d, x[ 1], S21); /* 21 */ + GG (d, a, b, c, x[ 5], S22); /* 22 */ + GG (c, d, a, b, x[ 9], S23); /* 23 */ + GG (b, c, d, a, x[13], S24); /* 24 */ + GG (a, b, c, d, x[ 2], S21); /* 25 */ + GG (d, a, b, c, x[ 6], S22); /* 26 */ + GG (c, d, a, b, x[10], S23); /* 27 */ + GG (b, c, d, a, x[14], S24); /* 28 */ + GG (a, b, c, d, x[ 3], S21); /* 29 */ + GG (d, a, b, c, x[ 7], S22); /* 30 */ + GG (c, d, a, b, x[11], S23); /* 31 */ + GG (b, c, d, a, x[15], S24); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 0], S31); /* 33 */ + HH (d, a, b, c, x[ 8], S32); /* 34 */ + HH (c, d, a, b, x[ 4], S33); /* 35 */ + HH (b, c, d, a, x[12], S34); /* 36 */ + HH (a, b, c, d, x[ 2], S31); /* 37 */ + HH (d, a, b, c, x[10], S32); /* 38 */ + HH (c, d, a, b, x[ 6], S33); /* 39 */ + HH (b, c, d, a, x[14], S34); /* 40 */ + HH (a, b, c, d, x[ 1], S31); /* 41 */ + HH (d, a, b, c, x[ 9], S32); /* 42 */ + HH (c, d, a, b, x[ 5], S33); /* 43 */ + HH (b, c, d, a, x[13], S34); /* 44 */ + HH (a, b, c, d, x[ 3], S31); /* 45 */ + HH (d, a, b, c, x[11], S32); /* 46 */ + HH (c, d, a, b, x[ 7], S33); /* 47 */ + HH (b, c, d, a, x[15], S34); /* 48 */ + + + /* Update our state */ + md->md4.state[0] = md->md4.state[0] + a; + md->md4.state[1] = md->md4.state[1] + b; + md->md4.state[2] = md->md4.state[2] + c; + md->md4.state[3] = md->md4.state[3] + d; +} + +#ifdef CLEAN_STACK +static void md4_compress(hash_state *md) +{ + _md4_compress(md); + burn_stack(sizeof(unsigned long) * 20 + sizeof(int)); +} +#endif + +void md4_init(hash_state * md) +{ + _ARGCHK(md != NULL); + md->md4.state[0] = 0x67452301UL; + md->md4.state[1] = 0xefcdab89UL; + md->md4.state[2] = 0x98badcfeUL; + md->md4.state[3] = 0x10325476UL; + md->md4.length = 0; + md->md4.curlen = 0; +} + +void md4_process(hash_state * md, const unsigned char *buf, unsigned long len) +{ + unsigned long n; + _ARGCHK(md != NULL); + _ARGCHK(buf != NULL); + while (len) { + n = MIN(len, (64 - md->md4.curlen)); + memcpy(md->md4.buf + md->md4.curlen, buf, n); + md->md4.curlen += n; + buf += n; + len -= n; + + /* is 64 bytes full? */ + if (md->md4.curlen == 64) { + md4_compress(md); + md->md4.length += 512; + md->md4.curlen = 0; + } + } +} + +void md4_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + /* increase the length of the message */ + md->md4.length += md->md4.curlen * 8; + + /* append the '1' bit */ + md->md4.buf[md->md4.curlen++] = 0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->md4.curlen > 56) { + while (md->md4.curlen < 64) { + md->md4.buf[md->md4.curlen++] = 0; + } + md4_compress(md); + md->md4.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->md4.curlen < 56) { + md->md4.buf[md->md4.curlen++] = 0; + } + + /* store length */ + STORE64L(md->md4.length, md->md4.buf+56); + md4_compress(md); + + /* copy output */ + for (i = 0; i < 4; i++) { + STORE32L(md->md4.state[i], hash+(4*i)); + } +#ifdef CLEAN_STACK + zeromem(md, sizeof(hash_state)); +#endif +} + +int md4_test(void) +{ + static const struct md4_test_case { + int num; + unsigned char input[128]; + int inputlen; + unsigned char digest[16]; + } cases[] = { + { 1, "", 0, + {0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31, + 0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0} }, + { 2, "a", 1, + {0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46, + 0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24} }, + { 3, "abc", 3, + {0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52, + 0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d} }, + { 4, "message digest", 14, + {0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8, + 0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b} }, + { 5, "abcdefghijklmnopqrstuvwxyz", 26, + {0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd, + 0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9} }, + { 6, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 62, + {0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35, + 0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4} }, + { 7, "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 80, + {0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19, + 0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36} }, + }; + int i, failed; + hash_state md; + unsigned char digest[16]; + + failed = 0; + for(i = 0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) { + md4_init(&md); + md4_process(&md, cases[i].input, cases[i].inputlen); + md4_done(&md, digest); + if(memcmp(digest, cases[i].digest, 16) != 0) { +#if 0 + int j; + printf("\nMD4 test #%d failed\n", cases[i].num); + printf( "Result: 0x"); + for(j=0; j < 16; j++) { + printf("%2x", digest[j]); + } + printf("\nCorrect: 0x"); + for(j=0; j < 16; j++) { + printf("%2x", cases[i].digest[j]); + } + printf("\n"); +#endif + failed++; + } else { +/* printf("MD4 test #%d succeeded.\n", cases[i].num); */ + } + } + + if (failed) { + return CRYPT_FAIL_TESTVECTOR; + } + + return CRYPT_OK; +} + +#endif + + diff --git a/md5.c b/md5.c new file mode 100644 index 0000000..2baf1b6 --- /dev/null +++ b/md5.c @@ -0,0 +1,268 @@ +#include "mycrypt.h" + +#ifdef MD5 + +const struct _hash_descriptor md5_desc = +{ + "md5", + 3, + 16, + 64, + &md5_init, + &md5_process, + &md5_done, + &md5_test +}; + +#define F(x,y,z) ( (x&y)|((~x)&z) ) +#define G(x,y,z) ( (x&z)|(y&(~z)) ) +#define H(x,y,z) (x^y^z) +#define I(x,y,z) (y ^ (x | (~z))) + +#define FF(a,b,c,d,M,s,t) \ + a = (a + F(b,c,d) + M + t); a = ROL(a, s); a = (b + a); + +#define GG(a,b,c,d,M,s,t) \ + a = (a + G(b,c,d) + M + t); a = ROL(a, s); a = (b + a); + +#define HH(a,b,c,d,M,s,t) \ + a = (a + H(b,c,d) + M + t); a = ROL(a, s); a = (b + a); + +#define II(a,b,c,d,M,s,t) \ + a = (a + I(b,c,d) + M + t); a = ROL(a, s); a = (b + a); + +#ifdef CLEAN_STACK +static void _md5_compress(hash_state *md) +#else +static void md5_compress(hash_state *md) +#endif +{ + unsigned long i, W[16], a, b, c, d; + + _ARGCHK(md != NULL); + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD32L(W[i], md->md5.buf + (4*i)); + } + + /* copy state */ + a = md->md5.state[0]; + b = md->md5.state[1]; + c = md->md5.state[2]; + d = md->md5.state[3]; + + FF(a,b,c,d,W[0],7,0xd76aa478UL) + FF(d,a,b,c,W[1],12,0xe8c7b756UL) + FF(c,d,a,b,W[2],17,0x242070dbUL) + FF(b,c,d,a,W[3],22,0xc1bdceeeUL) + FF(a,b,c,d,W[4],7,0xf57c0fafUL) + FF(d,a,b,c,W[5],12,0x4787c62aUL) + FF(c,d,a,b,W[6],17,0xa8304613UL) + FF(b,c,d,a,W[7],22,0xfd469501UL) + FF(a,b,c,d,W[8],7,0x698098d8UL) + FF(d,a,b,c,W[9],12,0x8b44f7afUL) + FF(c,d,a,b,W[10],17,0xffff5bb1UL) + FF(b,c,d,a,W[11],22,0x895cd7beUL) + FF(a,b,c,d,W[12],7,0x6b901122UL) + FF(d,a,b,c,W[13],12,0xfd987193UL) + FF(c,d,a,b,W[14],17,0xa679438eUL) + FF(b,c,d,a,W[15],22,0x49b40821UL) + GG(a,b,c,d,W[1],5,0xf61e2562UL) + GG(d,a,b,c,W[6],9,0xc040b340UL) + GG(c,d,a,b,W[11],14,0x265e5a51UL) + GG(b,c,d,a,W[0],20,0xe9b6c7aaUL) + GG(a,b,c,d,W[5],5,0xd62f105dUL) + GG(d,a,b,c,W[10],9,0x02441453UL) + GG(c,d,a,b,W[15],14,0xd8a1e681UL) + GG(b,c,d,a,W[4],20,0xe7d3fbc8UL) + GG(a,b,c,d,W[9],5,0x21e1cde6UL) + GG(d,a,b,c,W[14],9,0xc33707d6UL) + GG(c,d,a,b,W[3],14,0xf4d50d87UL) + GG(b,c,d,a,W[8],20,0x455a14edUL) + GG(a,b,c,d,W[13],5,0xa9e3e905UL) + GG(d,a,b,c,W[2],9,0xfcefa3f8UL) + GG(c,d,a,b,W[7],14,0x676f02d9UL) + GG(b,c,d,a,W[12],20,0x8d2a4c8aUL) + HH(a,b,c,d,W[5],4,0xfffa3942UL) + HH(d,a,b,c,W[8],11,0x8771f681UL) + HH(c,d,a,b,W[11],16,0x6d9d6122UL) + HH(b,c,d,a,W[14],23,0xfde5380cUL) + HH(a,b,c,d,W[1],4,0xa4beea44UL) + HH(d,a,b,c,W[4],11,0x4bdecfa9UL) + HH(c,d,a,b,W[7],16,0xf6bb4b60UL) + HH(b,c,d,a,W[10],23,0xbebfbc70UL) + HH(a,b,c,d,W[13],4,0x289b7ec6UL) + HH(d,a,b,c,W[0],11,0xeaa127faUL) + HH(c,d,a,b,W[3],16,0xd4ef3085UL) + HH(b,c,d,a,W[6],23,0x04881d05UL) + HH(a,b,c,d,W[9],4,0xd9d4d039UL) + HH(d,a,b,c,W[12],11,0xe6db99e5UL) + HH(c,d,a,b,W[15],16,0x1fa27cf8UL) + HH(b,c,d,a,W[2],23,0xc4ac5665UL) + II(a,b,c,d,W[0],6,0xf4292244UL) + II(d,a,b,c,W[7],10,0x432aff97UL) + II(c,d,a,b,W[14],15,0xab9423a7UL) + II(b,c,d,a,W[5],21,0xfc93a039UL) + II(a,b,c,d,W[12],6,0x655b59c3UL) + II(d,a,b,c,W[3],10,0x8f0ccc92UL) + II(c,d,a,b,W[10],15,0xffeff47dUL) + II(b,c,d,a,W[1],21,0x85845dd1UL) + II(a,b,c,d,W[8],6,0x6fa87e4fUL) + II(d,a,b,c,W[15],10,0xfe2ce6e0UL) + II(c,d,a,b,W[6],15,0xa3014314UL) + II(b,c,d,a,W[13],21,0x4e0811a1UL) + II(a,b,c,d,W[4],6,0xf7537e82UL) + II(d,a,b,c,W[11],10,0xbd3af235UL) + II(c,d,a,b,W[2],15,0x2ad7d2bbUL) + II(b,c,d,a,W[9],21,0xeb86d391UL) + + md->md5.state[0] = md->md5.state[0] + a; + md->md5.state[1] = md->md5.state[1] + b; + md->md5.state[2] = md->md5.state[2] + c; + md->md5.state[3] = md->md5.state[3] + d; +} + +#ifdef CLEAN_STACK +static void md5_compress(hash_state *md) +{ + _md5_compress(md); + burn_stack(sizeof(unsigned long) * 21); +} +#endif + +void md5_init(hash_state * md) +{ + _ARGCHK(md != NULL); + md->md5.state[0] = 0x67452301UL; + md->md5.state[1] = 0xefcdab89UL; + md->md5.state[2] = 0x98badcfeUL; + md->md5.state[3] = 0x10325476UL; + md->md5.curlen = 0; + md->md5.length = 0; +} + +void md5_process(hash_state * md, const unsigned char *buf, unsigned long len) +{ + unsigned long n; + _ARGCHK(md != NULL); + _ARGCHK(buf != NULL); + while (len) { + n = MIN(len, (64 - md->md5.curlen)); + memcpy(md->md5.buf + md->md5.curlen, buf, n); + md->md5.curlen += n; + buf += n; + len -= n; + + /* is 64 bytes full? */ + if (md->md5.curlen == 64) { + md5_compress(md); + md->md5.length += 512; + md->md5.curlen = 0; + } + } +} + +void md5_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + /* increase the length of the message */ + md->md5.length += md->md5.curlen * 8; + + /* append the '1' bit */ + md->md5.buf[md->md5.curlen++] = 0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->md5.curlen > 56) { + while (md->md5.curlen < 64) { + md->md5.buf[md->md5.curlen++] = 0; + } + md5_compress(md); + md->md5.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->md5.curlen < 56) { + md->md5.buf[md->md5.curlen++] = 0; + } + + /* store length */ + STORE64L(md->md5.length, md->md5.buf+56); + md5_compress(md); + + /* copy output */ + for (i = 0; i < 4; i++) { + STORE32L(md->md5.state[i], hash+(4*i)); + } +#ifdef CLEAN_STACK + zeromem(md, sizeof(hash_state)); +#endif +} + +int md5_test(void) +{ + static const struct { + unsigned char *msg; + unsigned char hash[16]; + } tests[] = { + { "", + { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, + 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } }, + { "a", + {0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, + 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } }, + { "abc", + { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, + 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } }, + { "message digest", + { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, + 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } }, + { "abcdefghijklmnopqrstuvwxyz", + { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, + 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, + 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } }, + { "12345678901234567890123456789012345678901234567890123456789012345678901234567890", + { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, + 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } }, + { NULL, { 0 } } + }; + + int failed, i; + unsigned char tmp[16]; + hash_state md; + + for (failed = i = 0; tests[i].msg != NULL; i++) { + md5_init(&md); + md5_process(&md, tests[i].msg, strlen(tests[i].msg)); + md5_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 16)) { +#if 0 + int j; + printf("MD5 Test %d (len == %d) failed\nGot (as a result): ", i, strlen(tests[i].msg)); + for (j = 0; j < 16; j++) { + printf("%02x ", tmp[j]); + } + printf("\n"); +#endif + failed = 1; + } + } + if (failed == 1) { + return CRYPT_FAIL_TESTVECTOR; + } else { + return CRYPT_OK; + } +} + +#endif + + diff --git a/mem.c b/mem.c new file mode 100644 index 0000000..7cbb791 --- /dev/null +++ b/mem.c @@ -0,0 +1,19 @@ +#include "mycrypt.h" + +void zeromem(void *dst, unsigned long len) +{ + unsigned char *mem = (unsigned char *)dst; + _ARGCHK(dst != NULL); + while (len--) + *mem++ = 0; +} + +void burn_stack(unsigned long len) +{ + unsigned char buf[32]; + zeromem(buf, sizeof(buf)); + if (len > sizeof(buf)) + burn_stack(len - sizeof(buf)); +} + + diff --git a/mpi-config.h b/mpi-config.h new file mode 100644 index 0000000..cb5bd40 --- /dev/null +++ b/mpi-config.h @@ -0,0 +1,87 @@ +/* Default configuration for MPI library */ +/* $ID$ */ + +#ifndef MPI_CONFIG_H_ +#define MPI_CONFIG_H_ + +/* + For boolean options, + 0 = no + 1 = yes + + Other options are documented individually. + + */ + +#ifndef MP_IOFUNC +#define MP_IOFUNC 1 /* include mp_print() ? */ +#endif + +#ifndef MP_MODARITH +#define MP_MODARITH 1 /* include modular arithmetic ? */ +#endif + +#ifndef MP_NUMTH +#define MP_NUMTH 1 /* include number theoretic functions? */ +#endif + +#ifndef MP_LOGTAB +#define MP_LOGTAB 1 /* use table of logs instead of log()? */ +#endif + +#ifndef MP_MEMSET +#define MP_MEMSET 1 /* use memset() to zero buffers? */ +#endif + +#ifndef MP_MEMCPY +#define MP_MEMCPY 1 /* use memcpy() to copy buffers? */ +#endif + +#ifndef MP_CRYPTO +#define MP_CRYPTO 1 /* erase memory on free? */ +#endif + +#ifndef MP_ARGCHK +/* + 0 = no parameter checks + 1 = runtime checks, continue execution and return an error to caller + 2 = assertions; dump core on parameter errors + */ +#define MP_ARGCHK 1 /* how to check input arguments */ +#endif + +#ifndef MP_DEBUG +#define MP_DEBUG 0 /* print diagnostic output? */ +#endif + +#ifndef MP_DEFPREC +#define MP_DEFPREC 8 /* default precision, in digits */ +#endif + +#ifndef MP_MACRO +#define MP_MACRO 1 /* use macros for frequent calls? */ +#endif + +#ifndef MP_SQUARE +#define MP_SQUARE 1 /* use separate squaring code? */ +#endif + +#ifndef MP_PTAB_SIZE +/* + When building mpprime.c, we build in a table of small prime + values to use for primality testing. The more you include, + the more space they take up. See primes.c for the possible + values (currently 16, 32, 64, 128, 256, and 6542) + */ +#define MP_PTAB_SIZE 128 /* how many built-in primes? */ +#endif + +#ifndef MP_COMPAT_MACROS +#define MP_COMPAT_MACROS 1 /* define compatibility macros? */ +#endif + +#endif /* ifndef MPI_CONFIG_H_ */ + + + + diff --git a/mpi-types.h b/mpi-types.h new file mode 100644 index 0000000..e097188 --- /dev/null +++ b/mpi-types.h @@ -0,0 +1,16 @@ +/* Type definitions generated by 'types.pl' */ +typedef char mp_sign; +typedef unsigned short mp_digit; /* 2 byte type */ +typedef unsigned int mp_word; /* 4 byte type */ +typedef unsigned int mp_size; +typedef int mp_err; + +#define MP_DIGIT_BIT (CHAR_BIT*sizeof(mp_digit)) +#define MP_DIGIT_MAX USHRT_MAX +#define MP_WORD_BIT (CHAR_BIT*sizeof(mp_word)) +#define MP_WORD_MAX UINT_MAX + +#define MP_DIGIT_SIZE 2 +#define DIGIT_FMT "%04X" +#define RADIX (MP_DIGIT_MAX+1) + diff --git a/mpi.c b/mpi.c new file mode 100644 index 0000000..fa8a777 --- /dev/null +++ b/mpi.c @@ -0,0 +1,4009 @@ + /* + mpi.c + + by Michael J. Fromberger + Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved + + Arbitrary precision integer arithmetic library + + $ID$ + */ + +#include +#include +#include +#include + +#include "mycrypt.h" + +#ifdef MPI + +#if MP_DEBUG +#include + +#define DIAG(T,V) {fprintf(stderr,T);mp_print(V,stderr);fputc('\n',stderr);} +#else +#define DIAG(T,V) +#endif + +/* + If MP_LOGTAB is not defined, use the math library to compute the + logarithms on the fly. Otherwise, use the static table below. + Pick which works best for your system. + */ +#if MP_LOGTAB + +/* {{{ s_logv_2[] - log table for 2 in various bases */ + +/* + A table of the logs of 2 for various bases (the 0 and 1 entries of + this table are meaningless and should not be referenced). + + This table is used to compute output lengths for the mp_toradix() + function. Since a number n in radix r takes up about log_r(n) + digits, we estimate the output size by taking the least integer + greater than log_r(n), where: + + log_r(n) = log_2(n) * log_r(2) + + This table, therefore, is a table of log_r(2) for 2 <= r <= 36, + which are the output bases supported. + */ +const float s_logv_2[] = { + 0.000000000, 0.000000000, 1.000000000, 0.630929754, /* 0 1 2 3 */ + 0.500000000, 0.430676558, 0.386852807, 0.356207187, /* 4 5 6 7 */ + 0.333333333, 0.315464877, 0.301029996, 0.289064826, /* 8 9 10 11 */ + 0.278942946, 0.270238154, 0.262649535, 0.255958025, /* 12 13 14 15 */ + 0.250000000, 0.244650542, 0.239812467, 0.235408913, /* 16 17 18 19 */ + 0.231378213, 0.227670249, 0.224243824, 0.221064729, /* 20 21 22 23 */ + 0.218104292, 0.215338279, 0.212746054, 0.210309918, /* 24 25 26 27 */ + 0.208014598, 0.205846832, 0.203795047, 0.201849087, /* 28 29 30 31 */ + 0.200000000, 0.198239863, 0.196561632, 0.194959022, /* 32 33 34 35 */ + 0.193426404, 0.191958720, 0.190551412, 0.189200360, /* 36 37 38 39 */ + 0.187901825, 0.186652411, 0.185449023, 0.184288833, /* 40 41 42 43 */ + 0.183169251, 0.182087900, 0.181042597, 0.180031327, /* 44 45 46 47 */ + 0.179052232, 0.178103594, 0.177183820, 0.176291434, /* 48 49 50 51 */ + 0.175425064, 0.174583430, 0.173765343, 0.172969690, /* 52 53 54 55 */ + 0.172195434, 0.171441601, 0.170707280, 0.169991616, /* 56 57 58 59 */ + 0.169293808, 0.168613099, 0.167948779, 0.167300179, /* 60 61 62 63 */ + 0.166666667 +}; +/* }}} */ +#define LOG_V_2(R) s_logv_2[(R)] + +#else + +#include +#define LOG_V_2(R) (log(2.0)/log(R)) + +#endif + +/* Default precision for newly created mp_int's */ +static unsigned int s_mp_defprec = MP_DEFPREC; + +/* {{{ Digit arithmetic macros */ + +/* + When adding and multiplying digits, the results can be larger than + can be contained in an mp_digit. Thus, an mp_word is used. These + macros mask off the upper and lower digits of the mp_word (the + mp_word may be more than 2 mp_digits wide, but we only concern + ourselves with the low-order 2 mp_digits) + + If your mp_word DOES have more than 2 mp_digits, you need to + uncomment the first line, and comment out the second. + */ + +/* #define CARRYOUT(W) (((W)>>DIGIT_BIT)&MP_DIGIT_MAX) */ +#define CARRYOUT(W) ((W)>>DIGIT_BIT) +#define ACCUM(W) ((W)&MP_DIGIT_MAX) + +/* }}} */ + +/* {{{ Comparison constants */ + + +/* }}} */ + +/* {{{ Constant strings */ + +/* Constant strings returned by mp_strerror() */ +static const char *mp_err_string[] = { + "unknown result code", /* say what? */ + "boolean true", /* MP_OKAY, MP_YES */ + "boolean false", /* MP_NO */ + "out of memory", /* MP_MEM */ + "argument out of range", /* MP_RANGE */ + "invalid input parameter", /* MP_BADARG */ + "result is undefined" /* MP_UNDEF */ +}; + +/* Value to digit maps for radix conversion */ + +/* s_dmap_1 - standard digits and letters */ +static const char *s_dmap_1 = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; + +#if 0 +/* s_dmap_2 - base64 ordering for digits */ +static const char *s_dmap_2 = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +#endif + +/* }}} */ + +/* {{{ Static function declarations */ + +/* + If MP_MACRO is false, these will be defined as actual functions; + otherwise, suitable macro definitions will be used. This works + around the fact that ANSI C89 doesn't support an 'inline' keyword + (although I hear C9x will ... about bloody time). At present, the + macro definitions are identical to the function bodies, but they'll + expand in place, instead of generating a function call. + + I chose these particular functions to be made into macros because + some profiling showed they are called a lot on a typical workload, + and yet they are primarily housekeeping. + */ +#if MP_MACRO == 0 + void s_mp_setz(mp_digit *dp, mp_size count); /* zero digits */ + void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count); /* copy */ + void *s_mp_alloc(size_t nb, size_t ni); /* general allocator */ + void s_mp_free(void *ptr); /* general free function */ +#else + + /* Even if these are defined as macros, we need to respect the settings + of the MP_MEMSET and MP_MEMCPY configuration options... + */ + #if MP_MEMSET == 0 + #define s_mp_setz(dp, count) \ + {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;} + #else + #define s_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mp_digit)) + #endif /* MP_MEMSET */ + + #if MP_MEMCPY == 0 + #define s_mp_copy(sp, dp, count) \ + {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];} + #else + #define s_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mp_digit)) + #endif /* MP_MEMCPY */ + + #define s_mp_alloc(nb, ni) XCALLOC(nb, ni) + #define s_mp_free(ptr) {if(ptr) XFREE(ptr);} +#endif /* MP_MACRO */ + +mp_err s_mp_grow(mp_int *mp, mp_size min); /* increase allocated size */ +mp_err s_mp_pad(mp_int *mp, mp_size min); /* left pad with zeroes */ + +void s_mp_clamp(mp_int *mp); /* clip leading zeroes */ + +void s_mp_exch(mp_int *a, mp_int *b); /* swap a and b in place */ + +mp_err s_mp_lshd(mp_int *mp, mp_size p); /* left-shift by p digits */ +void s_mp_rshd(mp_int *mp, mp_size p); /* right-shift by p digits */ +void s_mp_div_2d(mp_int *mp, mp_digit d); /* divide by 2^d in place */ +void s_mp_mod_2d(mp_int *mp, mp_digit d); /* modulo 2^d in place */ +mp_err s_mp_mul_2d(mp_int *mp, mp_digit d); /* multiply by 2^d in place*/ +void s_mp_div_2(mp_int *mp); /* divide by 2 in place */ +mp_err s_mp_mul_2(mp_int *mp); /* multiply by 2 in place */ +mp_digit s_mp_norm(mp_int *a, mp_int *b); /* normalize for division */ +mp_err s_mp_add_d(mp_int *mp, mp_digit d); /* unsigned digit addition */ +mp_err s_mp_sub_d(mp_int *mp, mp_digit d); /* unsigned digit subtract */ +mp_err s_mp_mul_d(mp_int *mp, mp_digit d); /* unsigned digit multiply */ +mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r); + /* unsigned digit divide */ +mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu); + /* Barrett reduction */ +mp_err s_mp_add(mp_int *a, mp_int *b); /* magnitude addition */ +mp_err s_mp_sub(mp_int *a, mp_int *b); /* magnitude subtract */ +mp_err s_mp_mul(mp_int *a, mp_int *b); /* magnitude multiply */ +#if 0 +void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len); + /* multiply buffers in place */ +#endif +#if MP_SQUARE +mp_err s_mp_sqr(mp_int *a); /* magnitude square */ +#else +#define s_mp_sqr(a) s_mp_mul(a, a) +#endif +mp_err s_mp_div(mp_int *a, mp_int *b); /* magnitude divide */ +mp_err s_mp_2expt(mp_int *a, mp_digit k); /* a = 2^k */ +int s_mp_cmp(mp_int *a, mp_int *b); /* magnitude comparison */ +int s_mp_cmp_d(mp_int *a, mp_digit d); /* magnitude digit compare */ +int s_mp_ispow2(mp_int *v); /* is v a power of 2? */ +int s_mp_ispow2d(mp_digit d); /* is d a power of 2? */ + +int s_mp_tovalue(char ch, int r); /* convert ch to value */ +char s_mp_todigit(int val, int r, int low); /* convert val to digit */ +int s_mp_outlen(int bits, int r); /* output length in bytes */ + +/* }}} */ + +/* {{{ Default precision manipulation */ + +unsigned int mp_get_prec(void) +{ + return s_mp_defprec; + +} /* end mp_get_prec() */ + +void mp_set_prec(unsigned int prec) +{ + if(prec == 0) + s_mp_defprec = MP_DEFPREC; + else + s_mp_defprec = prec; + +} /* end mp_set_prec() */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ mp_init(mp) */ + +/* + mp_init(mp) + + Initialize a new zero-valued mp_int. Returns MP_OKAY if successful, + MP_MEM if memory could not be allocated for the structure. + */ + +mp_err mp_init(mp_int *mp) +{ + return mp_init_size(mp, s_mp_defprec); + +} /* end mp_init() */ + +/* }}} */ + +/* {{{ mp_init_array(mp[], count) */ + +mp_err mp_init_array(mp_int mp[], int count) +{ + mp_err res; + int pos; + + ARGCHK(mp !=NULL && count > 0, MP_BADARG); + + for(pos = 0; pos < count; ++pos) { + if((res = mp_init(&mp[pos])) != MP_OKAY) + goto CLEANUP; + } + + return MP_OKAY; + + CLEANUP: + while(--pos >= 0) + mp_clear(&mp[pos]); + + return res; + +} /* end mp_init_array() */ + +/* }}} */ + +/* {{{ mp_init_size(mp, prec) */ + +/* + mp_init_size(mp, prec) + + Initialize a new zero-valued mp_int with at least the given + precision; returns MP_OKAY if successful, or MP_MEM if memory could + not be allocated for the structure. + */ + +mp_err mp_init_size(mp_int *mp, mp_size prec) +{ + ARGCHK(mp != NULL && prec > 0, MP_BADARG); + + if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit))) == NULL) + return MP_MEM; + + SIGN(mp) = MP_ZPOS; + USED(mp) = 1; + ALLOC(mp) = prec; + + return MP_OKAY; + +} /* end mp_init_size() */ + +/* }}} */ + +/* {{{ mp_init_copy(mp, from) */ + +/* + mp_init_copy(mp, from) + + Initialize mp as an exact copy of from. Returns MP_OKAY if + successful, MP_MEM if memory could not be allocated for the new + structure. + */ + +mp_err mp_init_copy(mp_int *mp, mp_int *from) +{ + ARGCHK(mp != NULL && from != NULL, MP_BADARG); + + if(mp == from) + return MP_OKAY; + + if((DIGITS(mp) = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) + return MP_MEM; + + s_mp_copy(DIGITS(from), DIGITS(mp), USED(from)); + USED(mp) = USED(from); + ALLOC(mp) = USED(from); + SIGN(mp) = SIGN(from); + + return MP_OKAY; + +} /* end mp_init_copy() */ + +/* }}} */ + +/* {{{ mp_copy(from, to) */ + +/* + mp_copy(from, to) + + Copies the mp_int 'from' to the mp_int 'to'. It is presumed that + 'to' has already been initialized (if not, use mp_init_copy() + instead). If 'from' and 'to' are identical, nothing happens. + */ + +mp_err mp_copy(mp_int *from, mp_int *to) +{ + ARGCHK(from != NULL && to != NULL, MP_BADARG); + + if(from == to) + return MP_OKAY; + + { /* copy */ + mp_digit *tmp; + + /* + If the allocated buffer in 'to' already has enough space to hold + all the used digits of 'from', we'll re-use it to avoid hitting + the memory allocater more than necessary; otherwise, we'd have + to grow anyway, so we just allocate a hunk and make the copy as + usual + */ + if(ALLOC(to) >= USED(from)) { + s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from)); + s_mp_copy(DIGITS(from), DIGITS(to), USED(from)); + + } else { + if((tmp = s_mp_alloc(USED(from), sizeof(mp_digit))) == NULL) + return MP_MEM; + + s_mp_copy(DIGITS(from), tmp, USED(from)); + + if(DIGITS(to) != NULL) { +#if MP_CRYPTO + s_mp_setz(DIGITS(to), ALLOC(to)); +#endif + s_mp_free(DIGITS(to)); + } + + DIGITS(to) = tmp; + ALLOC(to) = USED(from); + } + + /* Copy the precision and sign from the original */ + USED(to) = USED(from); + SIGN(to) = SIGN(from); + } /* end copy */ + + return MP_OKAY; + +} /* end mp_copy() */ + +/* }}} */ + +/* {{{ mp_exch(mp1, mp2) */ + +/* + mp_exch(mp1, mp2) + + Exchange mp1 and mp2 without allocating any intermediate memory + (well, unless you count the stack space needed for this call and the + locals it creates...). This cannot fail. + */ + +void mp_exch(mp_int *mp1, mp_int *mp2) +{ +#if MP_ARGCHK == 2 + assert(mp1 != NULL && mp2 != NULL); +#else + if(mp1 == NULL || mp2 == NULL) + return; +#endif + + s_mp_exch(mp1, mp2); + +} /* end mp_exch() */ + +/* }}} */ + +/* {{{ mp_clear(mp) */ + +/* + mp_clear(mp) + + Release the storage used by an mp_int, and void its fields so that + if someone calls mp_clear() again for the same int later, we won't + get tollchocked. + */ + +void mp_clear(mp_int *mp) +{ + if(mp == NULL) + return; + + if(DIGITS(mp) != NULL) { +#if MP_CRYPTO + s_mp_setz(DIGITS(mp), ALLOC(mp)); +#endif + s_mp_free(DIGITS(mp)); + DIGITS(mp) = NULL; + } + + USED(mp) = 0; + ALLOC(mp) = 0; + +} /* end mp_clear() */ + +/* }}} */ + +/* {{{ mp_clear_array(mp[], count) */ + +void mp_clear_array(mp_int mp[], int count) +{ +// ARGCHK(mp != NULL && count > 0, MP_BADARG); + + while(--count >= 0) + mp_clear(&mp[count]); + +} /* end mp_clear_array() */ + +/* }}} */ + +/* {{{ mp_zero(mp) */ + +/* + mp_zero(mp) + + Set mp to zero. Does not change the allocated size of the structure, + and therefore cannot fail (except on a bad argument, which we ignore) + */ +void mp_zero(mp_int *mp) +{ + if(mp == NULL) + return; + + s_mp_setz(DIGITS(mp), ALLOC(mp)); + USED(mp) = 1; + SIGN(mp) = MP_ZPOS; + +} /* end mp_zero() */ + +/* }}} */ + +/* {{{ mp_set(mp, d) */ + +void mp_set(mp_int *mp, mp_digit d) +{ + if(mp == NULL) + return; + + mp_zero(mp); + DIGIT(mp, 0) = d; + +} /* end mp_set() */ + +/* }}} */ + +/* {{{ mp_set_int(mp, z) */ + +mp_err mp_set_int(mp_int *mp, long z) +{ + int ix; + unsigned long v = abs(z); + mp_err res; + + ARGCHK(mp != NULL, MP_BADARG); + + mp_zero(mp); + if(z == 0) + return MP_OKAY; /* shortcut for zero */ + + for(ix = sizeof(long) - 1; ix >= 0; ix--) { + +/* --- bug in MSVC [first release] */ + if (ix == -1) break; +/* --- end of fix */ + + if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) + return res; + + res = s_mp_add_d(mp, + (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX)); + if(res != MP_OKAY) + return res; + } + + if(z < 0) + SIGN(mp) = MP_NEG; + + return MP_OKAY; + +} /* end mp_set_int() */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Digit arithmetic */ + +/* {{{ mp_add_d(a, d, b) */ + +/* + mp_add_d(a, d, b) + + Compute the sum b = a + d, for a single digit d. Respects the sign of + its primary addend (single digits are unsigned anyway). + */ + +mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b) +{ + mp_err res = MP_OKAY; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + if(SIGN(b) == MP_ZPOS) { + res = s_mp_add_d(b, d); + } else if(s_mp_cmp_d(b, d) >= 0) { + res = s_mp_sub_d(b, d); + } else { + SIGN(b) = MP_ZPOS; + + DIGIT(b, 0) = d - DIGIT(b, 0); + } + + return res; + +} /* end mp_add_d() */ + +/* }}} */ + +/* {{{ mp_sub_d(a, d, b) */ + +/* + mp_sub_d(a, d, b) + + Compute the difference b = a - d, for a single digit d. Respects the + sign of its subtrahend (single digits are unsigned anyway). + */ + +mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + if(SIGN(b) == MP_NEG) { + if((res = s_mp_add_d(b, d)) != MP_OKAY) + return res; + + } else if(s_mp_cmp_d(b, d) >= 0) { + if((res = s_mp_sub_d(b, d)) != MP_OKAY) + return res; + + } else { + mp_neg(b, b); + + DIGIT(b, 0) = d - DIGIT(b, 0); + SIGN(b) = MP_NEG; + } + + if(s_mp_cmp_d(b, 0) == 0) + SIGN(b) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_sub_d() */ + +/* }}} */ + +/* {{{ mp_mul_d(a, d, b) */ + +/* + mp_mul_d(a, d, b) + + Compute the product b = a * d, for a single digit d. Respects the sign + of its multiplicand (single digits are unsigned anyway) + */ + +mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if(d == 0) { + mp_zero(b); + return MP_OKAY; + } + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + res = s_mp_mul_d(b, d); + + return res; + +} /* end mp_mul_d() */ + +/* }}} */ + +/* {{{ mp_mul_2(a, c) */ + +mp_err mp_mul_2(mp_int *a, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + return s_mp_mul_2(c); + +} /* end mp_mul_2() */ + +/* }}} */ + +/* {{{ mp_div_d(a, d, q, r) */ + +/* + mp_div_d(a, d, q, r) + + Compute the quotient q = a / d and remainder r = a mod d, for a + single digit d. Respects the sign of its divisor (single digits are + unsigned anyway). + */ + +mp_err mp_div_d(mp_int *a, mp_digit d, mp_int *q, mp_digit *r) +{ + mp_err res; + mp_digit rem; + int pow; + + ARGCHK(a != NULL, MP_BADARG); + + if(d == 0) + return MP_RANGE; + + /* Shortcut for powers of two ... */ + if((pow = s_mp_ispow2d(d)) >= 0) { + mp_digit mask; + + mask = (1 << pow) - 1; + rem = DIGIT(a, 0) & mask; + + if(q) { + mp_copy(a, q); + s_mp_div_2d(q, (mp_digit)pow); + } + + if(r) + *r = rem; + + return MP_OKAY; + } + + /* + If the quotient is actually going to be returned, we'll try to + avoid hitting the memory allocator by copying the dividend into it + and doing the division there. This can't be any _worse_ than + always copying, and will sometimes be better (since it won't make + another copy) + + If it's not going to be returned, we need to allocate a temporary + to hold the quotient, which will just be discarded. + */ + if(q) { + if((res = mp_copy(a, q)) != MP_OKAY) + return res; + + res = s_mp_div_d(q, d, &rem); + if(s_mp_cmp_d(q, 0) == MP_EQ) + SIGN(q) = MP_ZPOS; + + } else { + mp_int qp; + + if((res = mp_init_copy(&qp, a)) != MP_OKAY) + return res; + + res = s_mp_div_d(&qp, d, &rem); + if(s_mp_cmp_d(&qp, 0) == 0) + SIGN(&qp) = MP_ZPOS; + + mp_clear(&qp); + } + + if(r) + *r = rem; + + return res; + +} /* end mp_div_d() */ + +/* }}} */ + +/* {{{ mp_div_2(a, c) */ + +/* + mp_div_2(a, c) + + Compute c = a / 2, disregarding the remainder. + */ + +mp_err mp_div_2(mp_int *a, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + s_mp_div_2(c); + + return MP_OKAY; + +} /* end mp_div_2() */ + +/* }}} */ + +/* {{{ mp_expt_d(a, d, b) */ + +mp_err mp_expt_d(mp_int *a, mp_digit d, mp_int *c) +{ + mp_int s, x; + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_init(&s)) != MP_OKAY) + return res; + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + + DIGIT(&s, 0) = 1; + + while(d != 0) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + } + + s_mp_exch(&s, c); + +CLEANUP: + mp_clear(&x); +X: + mp_clear(&s); + + return res; + +} /* end mp_expt_d() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Full arithmetic */ + +/* {{{ mp_abs(a, b) */ + +/* + mp_abs(a, b) + + Compute b = |a|. 'a' and 'b' may be identical. + */ + +mp_err mp_abs(mp_int *a, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + SIGN(b) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_abs() */ + +/* }}} */ + +/* {{{ mp_neg(a, b) */ + +/* + mp_neg(a, b) + + Compute b = -a. 'a' and 'b' may be identical. + */ + +mp_err mp_neg(mp_int *a, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + if(s_mp_cmp_d(b, 0) == MP_EQ) + SIGN(b) = MP_ZPOS; + else + SIGN(b) = (SIGN(b) == MP_NEG) ? MP_ZPOS : MP_NEG; + + return MP_OKAY; + +} /* end mp_neg() */ + +/* }}} */ + +/* {{{ mp_add(a, b, c) */ + +/* + mp_add(a, b, c) + + Compute c = a + b. All parameters may be identical. + */ + +mp_err mp_add(mp_int *a, mp_int *b, mp_int *c) +{ + mp_err res; + int cmp; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(SIGN(a) == SIGN(b)) { /* same sign: add values, keep sign */ + + /* Commutativity of addition lets us do this in either order, + so we avoid having to use a temporary even if the result + is supposed to replace the output + */ + if(c == b) { + if((res = s_mp_add(c, a)) != MP_OKAY) + return res; + } else { + if(c != a && (res = mp_copy(a, c)) != MP_OKAY) + return res; + + if((res = s_mp_add(c, b)) != MP_OKAY) + return res; + } + + } else if((cmp = s_mp_cmp(a, b)) > 0) { /* different sign: a > b */ + + /* If the output is going to be clobbered, we will use a temporary + variable; otherwise, we'll do it without touching the memory + allocator at all, if possible + */ + if(c == b) { + mp_int tmp; + + if((res = mp_init_copy(&tmp, a)) != MP_OKAY) + return res; + if((res = s_mp_sub(&tmp, b)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + s_mp_exch(&tmp, c); + mp_clear(&tmp); + + } else { + + if(c != a && (res = mp_copy(a, c)) != MP_OKAY) + return res; + if((res = s_mp_sub(c, b)) != MP_OKAY) + return res; + + } + + } else if(cmp == 0) { /* different sign, a == b */ + + mp_zero(c); + return MP_OKAY; + + } else { /* different sign: a < b */ + + /* See above... */ + if(c == a) { + mp_int tmp; + + if((res = mp_init_copy(&tmp, b)) != MP_OKAY) + return res; + if((res = s_mp_sub(&tmp, a)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + s_mp_exch(&tmp, c); + mp_clear(&tmp); + + } else { + + if(c != b && (res = mp_copy(b, c)) != MP_OKAY) + return res; + if((res = s_mp_sub(c, a)) != MP_OKAY) + return res; + + } + } + + if(USED(c) == 1 && DIGIT(c, 0) == 0) + SIGN(c) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_add() */ + +/* }}} */ + +/* {{{ mp_sub(a, b, c) */ + +/* + mp_sub(a, b, c) + + Compute c = a - b. All parameters may be identical. + */ + +mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c) +{ + mp_err res; + int cmp; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(SIGN(a) != SIGN(b)) { + if(c == a) { + if((res = s_mp_add(c, b)) != MP_OKAY) + return res; + } else { + if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) + return res; + if((res = s_mp_add(c, a)) != MP_OKAY) + return res; + SIGN(c) = SIGN(a); + } + + } else if((cmp = s_mp_cmp(a, b)) > 0) { /* Same sign, a > b */ + if(c == b) { + mp_int tmp; + + if((res = mp_init_copy(&tmp, a)) != MP_OKAY) + return res; + if((res = s_mp_sub(&tmp, b)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + s_mp_exch(&tmp, c); + mp_clear(&tmp); + + } else { + if(c != a && ((res = mp_copy(a, c)) != MP_OKAY)) + return res; + + if((res = s_mp_sub(c, b)) != MP_OKAY) + return res; + } + + } else if(cmp == 0) { /* Same sign, equal magnitude */ + mp_zero(c); + return MP_OKAY; + + } else { /* Same sign, b > a */ + if(c == a) { + mp_int tmp; + + if((res = mp_init_copy(&tmp, b)) != MP_OKAY) + return res; + + if((res = s_mp_sub(&tmp, a)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + s_mp_exch(&tmp, c); + mp_clear(&tmp); + + } else { + if(c != b && ((res = mp_copy(b, c)) != MP_OKAY)) + return res; + + if((res = s_mp_sub(c, a)) != MP_OKAY) + return res; + } + + SIGN(c) = !SIGN(b); + } + + if(USED(c) == 1 && DIGIT(c, 0) == 0) + SIGN(c) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_sub() */ + +/* }}} */ + +/* {{{ mp_mul(a, b, c) */ + +/* + mp_mul(a, b, c) + + Compute c = a * b. All parameters may be identical. + */ + +mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c) +{ + mp_err res; + mp_sign sgn; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + sgn = (SIGN(a) == SIGN(b)) ? MP_ZPOS : MP_NEG; + + if(c == b) { + if((res = s_mp_mul(c, a)) != MP_OKAY) + return res; + + } else { + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + if((res = s_mp_mul(c, b)) != MP_OKAY) + return res; + } + + if(sgn == MP_ZPOS || s_mp_cmp_d(c, 0) == MP_EQ) + SIGN(c) = MP_ZPOS; + else + SIGN(c) = sgn; + + return MP_OKAY; + +} /* end mp_mul() */ + +/* }}} */ + +/* {{{ mp_mul_2d(a, d, c) */ + +/* + mp_mul_2d(a, d, c) + + Compute c = a * 2^d. a may be the same as c. + */ + +mp_err mp_mul_2d(mp_int *a, mp_digit d, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + if(d == 0) + return MP_OKAY; + + return s_mp_mul_2d(c, d); + +} /* end mp_mul() */ + +/* }}} */ + +/* {{{ mp_sqr(a, b) */ + +#if MP_SQUARE +mp_err mp_sqr(mp_int *a, mp_int *b) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if((res = mp_copy(a, b)) != MP_OKAY) + return res; + + if((res = s_mp_sqr(b)) != MP_OKAY) + return res; + + SIGN(b) = MP_ZPOS; + + return MP_OKAY; + +} /* end mp_sqr() */ +#endif + +/* }}} */ + +/* {{{ mp_div(a, b, q, r) */ + +/* + mp_div(a, b, q, r) + + Compute q = a / b and r = a mod b. Input parameters may be re-used + as output parameters. If q or r is NULL, that portion of the + computation will be discarded (although it will still be computed) + + Pay no attention to the hacker behind the curtain. + */ + +mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r) +{ + mp_err res; + mp_int qtmp, rtmp; + int cmp; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + if(mp_cmp_z(b) == MP_EQ) + return MP_RANGE; + + /* If a <= b, we can compute the solution without division, and + avoid any memory allocation + */ + if((cmp = s_mp_cmp(a, b)) < 0) { + if(r) { + if((res = mp_copy(a, r)) != MP_OKAY) + return res; + } + + if(q) + mp_zero(q); + + return MP_OKAY; + + } else if(cmp == 0) { + + /* Set quotient to 1, with appropriate sign */ + if(q) { + int qneg = (SIGN(a) != SIGN(b)); + + mp_set(q, 1); + if(qneg) + SIGN(q) = MP_NEG; + } + + if(r) + mp_zero(r); + + return MP_OKAY; + } + + /* If we get here, it means we actually have to do some division */ + + /* Set up some temporaries... */ + if((res = mp_init_copy(&qtmp, a)) != MP_OKAY) + return res; + if((res = mp_init_copy(&rtmp, b)) != MP_OKAY) + goto CLEANUP; + + if((res = s_mp_div(&qtmp, &rtmp)) != MP_OKAY) + goto CLEANUP; + + /* Compute the signs for the output */ + SIGN(&rtmp) = SIGN(a); /* Sr = Sa */ + if(SIGN(a) == SIGN(b)) + SIGN(&qtmp) = MP_ZPOS; /* Sq = MP_ZPOS if Sa = Sb */ + else + SIGN(&qtmp) = MP_NEG; /* Sq = MP_NEG if Sa != Sb */ + + if(s_mp_cmp_d(&qtmp, 0) == MP_EQ) + SIGN(&qtmp) = MP_ZPOS; + if(s_mp_cmp_d(&rtmp, 0) == MP_EQ) + SIGN(&rtmp) = MP_ZPOS; + + /* Copy output, if it is needed */ + if(q) + s_mp_exch(&qtmp, q); + + if(r) + s_mp_exch(&rtmp, r); + +CLEANUP: + mp_clear(&rtmp); + mp_clear(&qtmp); + + return res; + +} /* end mp_div() */ + +/* }}} */ + +/* {{{ mp_div_2d(a, d, q, r) */ + +mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r) +{ + mp_err res; + + ARGCHK(a != NULL, MP_BADARG); + + if(q) { + if((res = mp_copy(a, q)) != MP_OKAY) + return res; + + s_mp_div_2d(q, d); + } + + if(r) { + if((res = mp_copy(a, r)) != MP_OKAY) + return res; + + s_mp_mod_2d(r, d); + } + + return MP_OKAY; + +} /* end mp_div_2d() */ + +/* }}} */ + +/* {{{ mp_expt(a, b, c) */ + +/* + mp_expt(a, b, c) + + Compute c = a ** b, that is, raise a to the b power. Uses a + standard iterative square-and-multiply technique. + */ + +mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c) +{ + mp_int s, x; + mp_err res; + mp_digit d; + int dig, bit; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(mp_cmp_z(b) < 0) + return MP_RANGE; + + if((res = mp_init(&s)) != MP_OKAY) + return res; + + mp_set(&s, 1); + + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + + /* Loop over low-order digits in ascending order */ + for(dig = 0; dig < (int)(USED(b) - 1); dig++) { + d = DIGIT(b, dig); + + /* Loop over bits of each non-maximal digit */ + for(bit = 0; bit < (int)DIGIT_BIT; bit++) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + } + } + + /* Consider now the last digit... */ + d = DIGIT(b, dig); + + while(d) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + } + + if(mp_iseven(b)) + SIGN(&s) = SIGN(a); + + res = mp_copy(&s, c); + +CLEANUP: + mp_clear(&x); +X: + mp_clear(&s); + + return res; + +} /* end mp_expt() */ + +/* }}} */ + +/* {{{ mp_2expt(a, k) */ + +/* Compute a = 2^k */ + +mp_err mp_2expt(mp_int *a, mp_digit k) +{ + ARGCHK(a != NULL, MP_BADARG); + + return s_mp_2expt(a, k); + +} /* end mp_2expt() */ + +/* }}} */ + +/* {{{ mp_mod(a, m, c) */ + +/* + mp_mod(a, m, c) + + Compute c = a (mod m). Result will always be 0 <= c < m. + */ + +mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c) +{ + mp_err res; + int mag; + + ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); + + if(SIGN(m) == MP_NEG) + return MP_RANGE; + + /* + If |a| > m, we need to divide to get the remainder and take the + absolute value. + + If |a| < m, we don't need to do any division, just copy and adjust + the sign (if a is negative). + + If |a| == m, we can simply set the result to zero. + + This order is intended to minimize the average path length of the + comparison chain on common workloads -- the most frequent cases are + that |a| != m, so we do those first. + */ + if((mag = s_mp_cmp(a, m)) > 0) { + if((res = mp_div(a, m, NULL, c)) != MP_OKAY) + return res; + + if(SIGN(c) == MP_NEG) { + if((res = mp_add(c, m, c)) != MP_OKAY) + return res; + } + + } else if(mag < 0) { + if((res = mp_copy(a, c)) != MP_OKAY) + return res; + + if(mp_cmp_z(a) < 0) { + if((res = mp_add(c, m, c)) != MP_OKAY) + return res; + + } + + } else { + mp_zero(c); + + } + + return MP_OKAY; + +} /* end mp_mod() */ + +/* }}} */ + +/* {{{ mp_mod_d(a, d, c) */ + +/* + mp_mod_d(a, d, c) + + Compute c = a (mod d). Result will always be 0 <= c < d + */ +mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c) +{ + mp_err res; + mp_digit rem; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if(s_mp_cmp_d(a, d) > 0) { + if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY) + return res; + + } else { + if(SIGN(a) == MP_NEG) + rem = d - DIGIT(a, 0); + else + rem = DIGIT(a, 0); + } + + if(c) + *c = rem; + + return MP_OKAY; + +} /* end mp_mod_d() */ + +/* }}} */ + +/* {{{ mp_sqrt(a, b) */ + +/* + mp_sqrt(a, b) + + Compute the integer square root of a, and store the result in b. + Uses an integer-arithmetic version of Newton's iterative linear + approximation technique to determine this value; the result has the + following two properties: + + b^2 <= a + (b+1)^2 >= a + + It is a range error to pass a negative value. + */ +mp_err mp_sqrt(mp_int *a, mp_int *b) +{ + mp_int x, t; + mp_err res; + + ARGCHK(a != NULL && b != NULL, MP_BADARG); + + /* Cannot take square root of a negative value */ + if(SIGN(a) == MP_NEG) + return MP_RANGE; + + /* Special cases for zero and one, trivial */ + if(mp_cmp_d(a, 0) == MP_EQ || mp_cmp_d(a, 1) == MP_EQ) + return mp_copy(a, b); + + /* Initialize the temporaries we'll use below */ + if((res = mp_init_size(&t, USED(a))) != MP_OKAY) + return res; + + /* Compute an initial guess for the iteration as a itself */ + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + + for(;;) { + /* t = (x * x) - a */ + mp_copy(&x, &t); /* can't fail, t is big enough for original x */ + if((res = mp_sqr(&t, &t)) != MP_OKAY || + (res = mp_sub(&t, a, &t)) != MP_OKAY) + goto CLEANUP; + + /* t = t / 2x */ + s_mp_mul_2(&x); + if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY) + goto CLEANUP; + s_mp_div_2(&x); + + /* Terminate the loop, if the quotient is zero */ + if(mp_cmp_z(&t) == MP_EQ) + break; + + /* x = x - t */ + if((res = mp_sub(&x, &t, &x)) != MP_OKAY) + goto CLEANUP; + + } + + /* Copy result to output parameter */ + mp_sub_d(&x, 1, &x); + s_mp_exch(&x, b); + + CLEANUP: + mp_clear(&x); + X: + mp_clear(&t); + + return res; + +} /* end mp_sqrt() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Modular arithmetic */ + +#if MP_MODARITH +/* {{{ mp_addmod(a, b, m, c) */ + +/* + mp_addmod(a, b, m, c) + + Compute c = (a + b) mod m + */ + +mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); + + if((res = mp_add(a, b, c)) != MP_OKAY) + return res; + if((res = mp_mod(c, m, c)) != MP_OKAY) + return res; + + return MP_OKAY; + +} + +/* }}} */ + +/* {{{ mp_submod(a, b, m, c) */ + +/* + mp_submod(a, b, m, c) + + Compute c = (a - b) mod m + */ + +mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); + + if((res = mp_sub(a, b, c)) != MP_OKAY) + return res; + if((res = mp_mod(c, m, c)) != MP_OKAY) + return res; + + return MP_OKAY; + +} + +/* }}} */ + +/* {{{ mp_mulmod(a, b, m, c) */ + +/* + mp_mulmod(a, b, m, c) + + Compute c = (a * b) mod m + */ + +mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG); + + if((res = mp_mul(a, b, c)) != MP_OKAY) + return res; + if((res = mp_mod(c, m, c)) != MP_OKAY) + return res; + + return MP_OKAY; + +} + +/* }}} */ + +/* {{{ mp_sqrmod(a, m, c) */ + +#if MP_SQUARE +mp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c) +{ + mp_err res; + + ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG); + + if((res = mp_sqr(a, c)) != MP_OKAY) + return res; + if((res = mp_mod(c, m, c)) != MP_OKAY) + return res; + + return MP_OKAY; + +} /* end mp_sqrmod() */ +#endif + +/* }}} */ + +/* {{{ mp_exptmod(a, b, m, c) */ + +/* + mp_exptmod(a, b, m, c) + + Compute c = (a ** b) mod m. Uses a standard square-and-multiply + method with modular reductions at each step. (This is basically the + same code as mp_expt(), except for the addition of the reductions) + + The modular reductions are done using Barrett's algorithm (see + s_mp_reduce() below for details) + */ + +mp_err mp_exptmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c) +{ + mp_int s, x, mu; + mp_err res; + mp_digit d, *db = DIGITS(b); + mp_size ub = USED(b); + int dig, bit; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(mp_cmp_z(b) < 0 || mp_cmp_z(m) <= 0) + return MP_RANGE; + + if((res = mp_init(&s)) != MP_OKAY) + return res; + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + if((res = mp_mod(&x, m, &x)) != MP_OKAY || + (res = mp_init(&mu)) != MP_OKAY) + goto MU; + + mp_set(&s, 1); + + /* mu = b^2k / m */ + s_mp_add_d(&mu, 1); + s_mp_lshd(&mu, 2 * USED(m)); + if((res = mp_div(&mu, m, &mu, NULL)) != MP_OKAY) + goto CLEANUP; + + /* Loop over digits of b in ascending order, except highest order */ + for(dig = 0; dig < (int)(ub - 1); dig++) { + d = *db++; + + /* Loop over the bits of the lower-order digits */ + for(bit = 0; bit < (int)DIGIT_BIT; bit++) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) + goto CLEANUP; + } + } + + /* Now do the last digit... */ + d = *db; + + while(d) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY) + goto CLEANUP; + if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY) + goto CLEANUP; + } + + d >>= 1; + + if((res = s_mp_sqr(&x)) != MP_OKAY) + goto CLEANUP; + if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY) + goto CLEANUP; + } + + s_mp_exch(&s, c); + + CLEANUP: + mp_clear(&mu); + MU: + mp_clear(&x); + X: + mp_clear(&s); + + return res; + +} /* end mp_exptmod() */ + +/* }}} */ + +/* {{{ mp_exptmod_d(a, d, m, c) */ + +mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c) +{ + mp_int s, x; + mp_err res; + + ARGCHK(a != NULL && c != NULL, MP_BADARG); + + if((res = mp_init(&s)) != MP_OKAY) + return res; + if((res = mp_init_copy(&x, a)) != MP_OKAY) + goto X; + + mp_set(&s, 1); + + while(d != 0) { + if(d & 1) { + if((res = s_mp_mul(&s, &x)) != MP_OKAY || + (res = mp_mod(&s, m, &s)) != MP_OKAY) + goto CLEANUP; + } + + d /= 2; + + if((res = s_mp_sqr(&x)) != MP_OKAY || + (res = mp_mod(&x, m, &x)) != MP_OKAY) + goto CLEANUP; + } + + s_mp_exch(&s, c); + +CLEANUP: + mp_clear(&x); +X: + mp_clear(&s); + + return res; + +} /* end mp_exptmod_d() */ + +/* }}} */ +#endif /* if MP_MODARITH */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Comparison functions */ + +/* {{{ mp_cmp_z(a) */ + +/* + mp_cmp_z(a) + + Compare a <=> 0. Returns <0 if a<0, 0 if a=0, >0 if a>0. + */ + +int mp_cmp_z(mp_int *a) +{ + if(SIGN(a) == MP_NEG) + return MP_LT; + else if(USED(a) == 1 && DIGIT(a, 0) == 0) + return MP_EQ; + else + return MP_GT; + +} /* end mp_cmp_z() */ + +/* }}} */ + +/* {{{ mp_cmp_d(a, d) */ + +/* + mp_cmp_d(a, d) + + Compare a <=> d. Returns <0 if a0 if a>d + */ + +int mp_cmp_d(mp_int *a, mp_digit d) +{ + ARGCHK(a != NULL, MP_EQ); + + if(SIGN(a) == MP_NEG) + return MP_LT; + + return s_mp_cmp_d(a, d); + +} /* end mp_cmp_d() */ + +/* }}} */ + +/* {{{ mp_cmp(a, b) */ + +int mp_cmp(mp_int *a, mp_int *b) +{ + ARGCHK(a != NULL && b != NULL, MP_EQ); + + if(SIGN(a) == SIGN(b)) { + int mag; + + if((mag = s_mp_cmp(a, b)) == MP_EQ) + return MP_EQ; + + if(SIGN(a) == MP_ZPOS) + return mag; + else + return -mag; + + } else if(SIGN(a) == MP_ZPOS) { + return MP_GT; + } else { + return MP_LT; + } + +} /* end mp_cmp() */ + +/* }}} */ + +/* {{{ mp_cmp_mag(a, b) */ + +/* + mp_cmp_mag(a, b) + + Compares |a| <=> |b|, and returns an appropriate comparison result + */ + +int mp_cmp_mag(mp_int *a, mp_int *b) +{ + ARGCHK(a != NULL && b != NULL, MP_EQ); + + return s_mp_cmp(a, b); + +} /* end mp_cmp_mag() */ + +/* }}} */ + +/* {{{ mp_cmp_int(a, z) */ + +/* + This just converts z to an mp_int, and uses the existing comparison + routines. This is sort of inefficient, but it's not clear to me how + frequently this wil get used anyway. For small positive constants, + you can always use mp_cmp_d(), and for zero, there is mp_cmp_z(). + */ +int mp_cmp_int(mp_int *a, long z) +{ + mp_int tmp; + int out; + + ARGCHK(a != NULL, MP_EQ); + + mp_init(&tmp); mp_set_int(&tmp, z); + out = mp_cmp(a, &tmp); + mp_clear(&tmp); + + return out; + +} /* end mp_cmp_int() */ + +/* }}} */ + +/* {{{ mp_isodd(a) */ + +/* + mp_isodd(a) + + Returns a true (non-zero) value if a is odd, false (zero) otherwise. + */ +int mp_isodd(mp_int *a) +{ + ARGCHK(a != NULL, 0); + + return (DIGIT(a, 0) & 1); + +} /* end mp_isodd() */ + +/* }}} */ + +/* {{{ mp_iseven(a) */ + +int mp_iseven(mp_int *a) +{ + return !mp_isodd(a); + +} /* end mp_iseven() */ + +/* }}} */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ Number theoretic functions */ + +#if MP_NUMTH +/* {{{ mp_gcd(a, b, c) */ + +/* + Like the old mp_gcd() function, except computes the GCD using the + binary algorithm due to Josef Stein in 1961 (via Knuth). + */ +mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c) +{ + mp_err res; + mp_int u, v, t; + mp_size k = 0; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ) + return MP_RANGE; + if(mp_cmp_z(a) == MP_EQ) { + return mp_copy(b, c); + } else if(mp_cmp_z(b) == MP_EQ) { + return mp_copy(a, c); + } + + if((res = mp_init(&t)) != MP_OKAY) + return res; + if((res = mp_init_copy(&u, a)) != MP_OKAY) + goto U; + if((res = mp_init_copy(&v, b)) != MP_OKAY) + goto V; + + SIGN(&u) = MP_ZPOS; + SIGN(&v) = MP_ZPOS; + + /* Divide out common factors of 2 until at least 1 of a, b is even */ + while(mp_iseven(&u) && mp_iseven(&v)) { + s_mp_div_2(&u); + s_mp_div_2(&v); + ++k; + } + + /* Initialize t */ + if(mp_isodd(&u)) { + if((res = mp_copy(&v, &t)) != MP_OKAY) + goto CLEANUP; + + /* t = -v */ + if(SIGN(&v) == MP_ZPOS) + SIGN(&t) = MP_NEG; + else + SIGN(&t) = MP_ZPOS; + + } else { + if((res = mp_copy(&u, &t)) != MP_OKAY) + goto CLEANUP; + + } + + for(;;) { + while(mp_iseven(&t)) { + s_mp_div_2(&t); + } + + if(mp_cmp_z(&t) == MP_GT) { + if((res = mp_copy(&t, &u)) != MP_OKAY) + goto CLEANUP; + + } else { + if((res = mp_copy(&t, &v)) != MP_OKAY) + goto CLEANUP; + + /* v = -t */ + if(SIGN(&t) == MP_ZPOS) + SIGN(&v) = MP_NEG; + else + SIGN(&v) = MP_ZPOS; + } + + if((res = mp_sub(&u, &v, &t)) != MP_OKAY) + goto CLEANUP; + + if(s_mp_cmp_d(&t, 0) == MP_EQ) + break; + } + + s_mp_2expt(&v, (mp_digit)k); /* v = 2^k */ + res = mp_mul(&u, &v, c); /* c = u * v */ + + CLEANUP: + mp_clear(&v); + V: + mp_clear(&u); + U: + mp_clear(&t); + + return res; + +} /* end mp_bgcd() */ + +/* }}} */ + +/* {{{ mp_lcm(a, b, c) */ + +/* We compute the least common multiple using the rule: + + ab = [a, b](a, b) + + ... by computing the product, and dividing out the gcd. + */ + +mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c) +{ + mp_int gcd, prod; + mp_err res; + + ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG); + + /* Set up temporaries */ + if((res = mp_init(&gcd)) != MP_OKAY) + return res; + if((res = mp_init(&prod)) != MP_OKAY) + goto GCD; + + if((res = mp_mul(a, b, &prod)) != MP_OKAY) + goto CLEANUP; + if((res = mp_gcd(a, b, &gcd)) != MP_OKAY) + goto CLEANUP; + + res = mp_div(&prod, &gcd, c, NULL); + + CLEANUP: + mp_clear(&prod); + GCD: + mp_clear(&gcd); + + return res; + +} /* end mp_lcm() */ + +/* }}} */ + +/* {{{ mp_xgcd(a, b, g, x, y) */ + +/* + mp_xgcd(a, b, g, x, y) + + Compute g = (a, b) and values x and y satisfying Bezout's identity + (that is, ax + by = g). This uses the extended binary GCD algorithm + based on the Stein algorithm used for mp_gcd() + */ + +mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y) +{ + mp_int gx, xc, yc, u, v, A, B, C, D; + mp_int *clean[9]; + mp_err res; + int last = -1; + + if(mp_cmp_z(b) == 0) + return MP_RANGE; + + /* Initialize all these variables we need */ + if((res = mp_init(&u)) != MP_OKAY) goto CLEANUP; + clean[++last] = &u; + if((res = mp_init(&v)) != MP_OKAY) goto CLEANUP; + clean[++last] = &v; + if((res = mp_init(&gx)) != MP_OKAY) goto CLEANUP; + clean[++last] = &gx; + if((res = mp_init(&A)) != MP_OKAY) goto CLEANUP; + clean[++last] = &A; + if((res = mp_init(&B)) != MP_OKAY) goto CLEANUP; + clean[++last] = &B; + if((res = mp_init(&C)) != MP_OKAY) goto CLEANUP; + clean[++last] = &C; + if((res = mp_init(&D)) != MP_OKAY) goto CLEANUP; + clean[++last] = &D; + if((res = mp_init_copy(&xc, a)) != MP_OKAY) goto CLEANUP; + clean[++last] = &xc; + mp_abs(&xc, &xc); + if((res = mp_init_copy(&yc, b)) != MP_OKAY) goto CLEANUP; + clean[++last] = &yc; + mp_abs(&yc, &yc); + + mp_set(&gx, 1); + + /* Divide by two until at least one of them is even */ + while(mp_iseven(&xc) && mp_iseven(&yc)) { + s_mp_div_2(&xc); + s_mp_div_2(&yc); + if((res = s_mp_mul_2(&gx)) != MP_OKAY) + goto CLEANUP; + } + + mp_copy(&xc, &u); + mp_copy(&yc, &v); + mp_set(&A, 1); mp_set(&D, 1); + + /* Loop through binary GCD algorithm */ + for(;;) { + while(mp_iseven(&u)) { + s_mp_div_2(&u); + + if(mp_iseven(&A) && mp_iseven(&B)) { + s_mp_div_2(&A); s_mp_div_2(&B); + } else { + if((res = mp_add(&A, &yc, &A)) != MP_OKAY) goto CLEANUP; + s_mp_div_2(&A); + if((res = mp_sub(&B, &xc, &B)) != MP_OKAY) goto CLEANUP; + s_mp_div_2(&B); + } + } + + while(mp_iseven(&v)) { + s_mp_div_2(&v); + + if(mp_iseven(&C) && mp_iseven(&D)) { + s_mp_div_2(&C); s_mp_div_2(&D); + } else { + if((res = mp_add(&C, &yc, &C)) != MP_OKAY) goto CLEANUP; + s_mp_div_2(&C); + if((res = mp_sub(&D, &xc, &D)) != MP_OKAY) goto CLEANUP; + s_mp_div_2(&D); + } + } + + if(mp_cmp(&u, &v) >= 0) { + if((res = mp_sub(&u, &v, &u)) != MP_OKAY) goto CLEANUP; + if((res = mp_sub(&A, &C, &A)) != MP_OKAY) goto CLEANUP; + if((res = mp_sub(&B, &D, &B)) != MP_OKAY) goto CLEANUP; + + } else { + if((res = mp_sub(&v, &u, &v)) != MP_OKAY) goto CLEANUP; + if((res = mp_sub(&C, &A, &C)) != MP_OKAY) goto CLEANUP; + if((res = mp_sub(&D, &B, &D)) != MP_OKAY) goto CLEANUP; + + } + + /* If we're done, copy results to output */ + if(mp_cmp_z(&u) == 0) { + if(x) + if((res = mp_copy(&C, x)) != MP_OKAY) goto CLEANUP; + + if(y) + if((res = mp_copy(&D, y)) != MP_OKAY) goto CLEANUP; + + if(g) + if((res = mp_mul(&gx, &v, g)) != MP_OKAY) goto CLEANUP; + + break; + } + } + + CLEANUP: + while(last >= 0) + mp_clear(clean[last--]); + + return res; + +} /* end mp_xgcd() */ + +/* }}} */ + +/* {{{ mp_invmod(a, m, c) */ + +/* + mp_invmod(a, m, c) + + Compute c = a^-1 (mod m), if there is an inverse for a (mod m). + This is equivalent to the question of whether (a, m) = 1. If not, + MP_UNDEF is returned, and there is no inverse. + */ + +mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c) +{ + mp_int g, x; + mp_err res; + + ARGCHK(a && m && c, MP_BADARG); + + if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0) + return MP_RANGE; + + if((res = mp_init(&g)) != MP_OKAY) + return res; + if((res = mp_init(&x)) != MP_OKAY) + goto X; + + if((res = mp_xgcd(a, m, &g, &x, NULL)) != MP_OKAY) + goto CLEANUP; + + if(mp_cmp_d(&g, 1) != MP_EQ) { + res = MP_UNDEF; + goto CLEANUP; + } + + res = mp_mod(&x, m, c); + SIGN(c) = SIGN(a); + +CLEANUP: + mp_clear(&x); +X: + mp_clear(&g); + + return res; + +} /* end mp_invmod() */ + +/* }}} */ +#endif /* if MP_NUMTH */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ mp_print(mp, ofp) */ + +#if MP_IOFUNC +/* + mp_print(mp, ofp) + + Print a textual representation of the given mp_int on the output + stream 'ofp'. Output is generated using the internal radix. + */ + +void mp_print(mp_int *mp, FILE *ofp) +{ + int ix; + + if(mp == NULL || ofp == NULL) + return; + + fputc((SIGN(mp) == MP_NEG) ? '-' : '+', ofp); + + for(ix = USED(mp) - 1; ix >= 0; ix--) { + fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix)); + } + +} /* end mp_print() */ + +#endif /* if MP_IOFUNC */ + +/* }}} */ + +/*------------------------------------------------------------------------*/ +/* {{{ More I/O Functions */ + +/* {{{ mp_read_signed_bin(mp, str, len) */ + +/* + mp_read_signed_bin(mp, str, len) + + Read in a raw value (base 256) into the given mp_int + */ + +mp_err mp_read_signed_bin(mp_int *mp, unsigned char *str, int len) +{ + mp_err res; + + ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); + + if((res = mp_read_unsigned_bin(mp, str + 1, len - 1)) == MP_OKAY) { + /* Get sign from first byte */ + if(str[0]) + SIGN(mp) = MP_NEG; + else + SIGN(mp) = MP_ZPOS; + } + + return res; + +} /* end mp_read_signed_bin() */ + +/* }}} */ + +/* {{{ mp_signed_bin_size(mp) */ + +int mp_signed_bin_size(mp_int *mp) +{ + ARGCHK(mp != NULL, 0); + + return mp_unsigned_bin_size(mp) + 1; + +} /* end mp_signed_bin_size() */ + +/* }}} */ + +/* {{{ mp_to_signed_bin(mp, str) */ + +mp_err mp_to_signed_bin(mp_int *mp, unsigned char *str) +{ + ARGCHK(mp != NULL && str != NULL, MP_BADARG); + + /* Caller responsible for allocating enough memory (use mp_raw_size(mp)) */ + str[0] = (char)SIGN(mp); + + return mp_to_unsigned_bin(mp, str + 1); + +} /* end mp_to_signed_bin() */ + +/* }}} */ + +/* {{{ mp_read_unsigned_bin(mp, str, len) */ + +/* + mp_read_unsigned_bin(mp, str, len) + + Read in an unsigned value (base 256) into the given mp_int + */ + +mp_err mp_read_unsigned_bin(mp_int *mp, unsigned char *str, int len) +{ + int ix; + mp_err res; + + ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG); + + mp_zero(mp); + + for(ix = 0; ix < len; ix++) { + if((res = s_mp_mul_2d(mp, CHAR_BIT)) != MP_OKAY) + return res; + + if((res = mp_add_d(mp, str[ix], mp)) != MP_OKAY) + return res; + } + + return MP_OKAY; + +} /* end mp_read_unsigned_bin() */ + +/* }}} */ + +/* {{{ mp_unsigned_bin_size(mp) */ + +int mp_unsigned_bin_size(mp_int *mp) +{ + mp_digit topdig; + int count; + + ARGCHK(mp != NULL, 0); + + /* Special case for the value zero */ + if(USED(mp) == 1 && DIGIT(mp, 0) == 0) + return 1; + + count = (USED(mp) - 1) * sizeof(mp_digit); + topdig = DIGIT(mp, USED(mp) - 1); + + while(topdig != 0) { + ++count; + topdig >>= CHAR_BIT; + } + + return count; + +} /* end mp_unsigned_bin_size() */ + +/* }}} */ + +/* {{{ mp_to_unsigned_bin(mp, str) */ + +mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str) +{ + mp_digit *dp, *end, d; + unsigned char *spos; + + ARGCHK(mp != NULL && str != NULL, MP_BADARG); + + dp = DIGITS(mp); + end = dp + USED(mp) - 1; + spos = str; + + /* Special case for zero, quick test */ + if(dp == end && *dp == 0) { + *str = '\0'; + return MP_OKAY; + } + + /* Generate digits in reverse order */ + while(dp < end) { + int ix; + + d = *dp; + for(ix = 0; ix < (int)sizeof(mp_digit); ++ix) { + *spos = d & UCHAR_MAX; + d >>= CHAR_BIT; + ++spos; + } + + ++dp; + } + + /* Now handle last digit specially, high order zeroes are not written */ + d = *end; + while(d != 0) { + *spos = d & UCHAR_MAX; + d >>= CHAR_BIT; + ++spos; + } + + /* Reverse everything to get digits in the correct order */ + while(--spos > str) { + unsigned char t = *str; + *str = *spos; + *spos = t; + + ++str; + } + + return MP_OKAY; + +} /* end mp_to_unsigned_bin() */ + +/* }}} */ + +/* {{{ mp_count_bits(mp) */ + +int mp_count_bits(mp_int *mp) +{ + int len; + mp_digit d; + + ARGCHK(mp != NULL, MP_BADARG); + + len = DIGIT_BIT * (USED(mp) - 1); + d = DIGIT(mp, USED(mp) - 1); + + while(d != 0) { + ++len; + d >>= 1; + } + + return len; + +} /* end mp_count_bits() */ + +/* }}} */ + +/* {{{ mp_read_radix(mp, str, radix) */ + +/* + mp_read_radix(mp, str, radix) + + Read an integer from the given string, and set mp to the resulting + value. The input is presumed to be in base 10. Leading non-digit + characters are ignored, and the function reads until a non-digit + character or the end of the string. + */ + +mp_err mp_read_radix(mp_int *mp, unsigned char *str, int radix) +{ + int ix = 0, val = 0; + mp_err res; + mp_sign sig = MP_ZPOS; + + ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX, + MP_BADARG); + + mp_zero(mp); + + /* Skip leading non-digit characters until a digit or '-' or '+' */ + while(str[ix] && + (s_mp_tovalue(str[ix], radix) < 0) && + str[ix] != '-' && + str[ix] != '+') { + ++ix; + } + + if(str[ix] == '-') { + sig = MP_NEG; + ++ix; + } else if(str[ix] == '+') { + sig = MP_ZPOS; /* this is the default anyway... */ + ++ix; + } + + while((val = s_mp_tovalue(str[ix], radix)) >= 0) { + if((res = s_mp_mul_d(mp, (mp_digit)radix)) != MP_OKAY) + return res; + if((res = s_mp_add_d(mp, (mp_digit)val)) != MP_OKAY) + return res; + ++ix; + } + + if(s_mp_cmp_d(mp, 0) == MP_EQ) + SIGN(mp) = MP_ZPOS; + else + SIGN(mp) = sig; + + return MP_OKAY; + +} /* end mp_read_radix() */ + +/* }}} */ + +/* {{{ mp_radix_size(mp, radix) */ + +int mp_radix_size(mp_int *mp, int radix) +{ + int len; + ARGCHK(mp != NULL, 0); + + len = s_mp_outlen(mp_count_bits(mp), radix) + 1; /* for NUL terminator */ + + if(mp_cmp_z(mp) < 0) + ++len; /* for sign */ + + return len; + +} /* end mp_radix_size() */ + +/* }}} */ + +/* {{{ mp_value_radix_size(num, qty, radix) */ + +/* num = number of digits + qty = number of bits per digit + radix = target base + + Return the number of digits in the specified radix that would be + needed to express 'num' digits of 'qty' bits each. + */ +int mp_value_radix_size(int num, int qty, int radix) +{ + ARGCHK(num >= 0 && qty > 0 && radix >= 2 && radix <= MAX_RADIX, 0); + + return s_mp_outlen(num * qty, radix); + +} /* end mp_value_radix_size() */ + +/* }}} */ + +/* {{{ mp_toradix(mp, str, radix) */ + +mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix) +{ + int ix, pos = 0; + + ARGCHK(mp != NULL && str != NULL, MP_BADARG); + ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE); + + if(mp_cmp_z(mp) == MP_EQ) { + str[0] = '0'; + str[1] = '\0'; + } else { + mp_err res; + mp_int tmp; + mp_sign sgn; + mp_digit rem, rdx = (mp_digit)radix; + char ch; + + if((res = mp_init_copy(&tmp, mp)) != MP_OKAY) + return res; + + /* Save sign for later, and take absolute value */ + sgn = SIGN(&tmp); SIGN(&tmp) = MP_ZPOS; + + /* Generate output digits in reverse order */ + while(mp_cmp_z(&tmp) != 0) { + if((res = s_mp_div_d(&tmp, rdx, &rem)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + /* Generate digits, use capital letters */ + ch = s_mp_todigit(rem, radix, 0); + + str[pos++] = ch; + } + + /* Add - sign if original value was negative */ + if(sgn == MP_NEG) + str[pos++] = '-'; + + /* Add trailing NUL to end the string */ + str[pos--] = '\0'; + + /* Reverse the digits and sign indicator */ + ix = 0; + while(ix < pos) { + char tmp = str[ix]; + + str[ix] = str[pos]; + str[pos] = tmp; + ++ix; + --pos; + } + + mp_clear(&tmp); + } + + return MP_OKAY; + +} /* end mp_toradix() */ + +/* }}} */ + +/* {{{ mp_char2value(ch, r) */ + +int mp_char2value(char ch, int r) +{ + return s_mp_tovalue(ch, r); + +} /* end mp_tovalue() */ + +/* }}} */ + +/* }}} */ + +/* {{{ mp_strerror(ec) */ + +/* + mp_strerror(ec) + + Return a string describing the meaning of error code 'ec'. The + string returned is allocated in static memory, so the caller should + not attempt to modify or free the memory associated with this + string. + */ +const char *mp_strerror(mp_err ec) +{ + int aec = (ec < 0) ? -ec : ec; + + /* Code values are negative, so the senses of these comparisons + are accurate */ + if(ec < MP_LAST_CODE || ec > MP_OKAY) { + return mp_err_string[0]; /* unknown error code */ + } else { + return mp_err_string[aec + 1]; + } + +} /* end mp_strerror() */ + +/* }}} */ + +/*========================================================================*/ +/*------------------------------------------------------------------------*/ +/* Static function definitions (internal use only) */ + +/* {{{ Memory management */ + +/* {{{ s_mp_grow(mp, min) */ + +/* Make sure there are at least 'min' digits allocated to mp */ +mp_err s_mp_grow(mp_int *mp, mp_size min) +{ + if(min > ALLOC(mp)) { + mp_digit *tmp; + + /* Set min to next nearest default precision block size */ + min = ((min + (s_mp_defprec - 1)) / s_mp_defprec) * s_mp_defprec; + + if((tmp = s_mp_alloc(min, sizeof(mp_digit))) == NULL) + return MP_MEM; + + s_mp_copy(DIGITS(mp), tmp, USED(mp)); + +#if MP_CRYPTO + s_mp_setz(DIGITS(mp), ALLOC(mp)); +#endif + s_mp_free(DIGITS(mp)); + DIGITS(mp) = tmp; + ALLOC(mp) = min; + } + + return MP_OKAY; + +} /* end s_mp_grow() */ + +/* }}} */ + +/* {{{ s_mp_pad(mp, min) */ + +/* Make sure the used size of mp is at least 'min', growing if needed */ +mp_err s_mp_pad(mp_int *mp, mp_size min) +{ + if(min > USED(mp)) { + mp_err res; + + /* Make sure there is room to increase precision */ + if(min > ALLOC(mp) && (res = s_mp_grow(mp, min)) != MP_OKAY) + return res; + + /* Increase precision; should already be 0-filled */ + USED(mp) = min; + } + + return MP_OKAY; + +} /* end s_mp_pad() */ + +/* }}} */ + +/* {{{ s_mp_setz(dp, count) */ + +#if MP_MACRO == 0 +/* Set 'count' digits pointed to by dp to be zeroes */ +void s_mp_setz(mp_digit *dp, mp_size count) +{ +#if MP_MEMSET == 0 + int ix; + + for(ix = 0; ix < count; ix++) + dp[ix] = 0; +#else + memset(dp, 0, count * sizeof(mp_digit)); +#endif + +} /* end s_mp_setz() */ +#endif + +/* }}} */ + +/* {{{ s_mp_copy(sp, dp, count) */ + +#if MP_MACRO == 0 +/* Copy 'count' digits from sp to dp */ +void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count) +{ +#if MP_MEMCPY == 0 + int ix; + + for(ix = 0; ix < count; ix++) + dp[ix] = sp[ix]; +#else + memcpy(dp, sp, count * sizeof(mp_digit)); +#endif + +} /* end s_mp_copy() */ +#endif + +/* }}} */ + +/* {{{ s_mp_alloc(nb, ni) */ + +#if MP_MACRO == 0 +/* Allocate ni records of nb bytes each, and return a pointer to that */ +void *s_mp_alloc(size_t nb, size_t ni) +{ + return XCALLOC(nb, ni); + +} /* end s_mp_alloc() */ +#endif + +/* }}} */ + +/* {{{ s_mp_free(ptr) */ + +#if MP_MACRO == 0 +/* Free the memory pointed to by ptr */ +void s_mp_free(void *ptr) +{ + if(ptr) + XFREE(ptr); + +} /* end s_mp_free() */ +#endif + +/* }}} */ + +/* {{{ s_mp_clamp(mp) */ + +/* Remove leading zeroes from the given value */ +void s_mp_clamp(mp_int *mp) +{ + mp_size du = USED(mp); + mp_digit *zp = DIGITS(mp) + du - 1; + + while(du > 1 && !*zp--) + --du; + + USED(mp) = du; + +} /* end s_mp_clamp() */ + + +/* }}} */ + +/* {{{ s_mp_exch(a, b) */ + +/* Exchange the data for a and b; (b, a) = (a, b) */ +void s_mp_exch(mp_int *a, mp_int *b) +{ + mp_int tmp; + + tmp = *a; + *a = *b; + *b = tmp; + +} /* end s_mp_exch() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Arithmetic helpers */ + +/* {{{ s_mp_lshd(mp, p) */ + +/* + Shift mp leftward by p digits, growing if needed, and zero-filling + the in-shifted digits at the right end. This is a convenient + alternative to multiplication by powers of the radix + */ + +mp_err s_mp_lshd(mp_int *mp, mp_size p) +{ + mp_err res; + mp_size pos; + mp_digit *dp; + int ix; + + if(p == 0) + return MP_OKAY; + + if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY) + return res; + + pos = USED(mp) - 1; + dp = DIGITS(mp); + + /* Shift all the significant figures over as needed */ + for(ix = pos - p; ix >= 0; ix--) + dp[ix + p] = dp[ix]; + + /* Fill the bottom digits with zeroes */ + for(ix = 0; ix < (int)p; ix++) + dp[ix] = 0; + + return MP_OKAY; + +} /* end s_mp_lshd() */ + +/* }}} */ + +/* {{{ s_mp_rshd(mp, p) */ + +/* + Shift mp rightward by p digits. Maintains the invariant that + digits above the precision are all zero. Digits shifted off the + end are lost. Cannot fail. + */ + +void s_mp_rshd(mp_int *mp, mp_size p) +{ + mp_size ix; + mp_digit *dp; + + if(p == 0) + return; + + /* Shortcut when all digits are to be shifted off */ + if(p >= USED(mp)) { + s_mp_setz(DIGITS(mp), ALLOC(mp)); + USED(mp) = 1; + SIGN(mp) = MP_ZPOS; + return; + } + + /* Shift all the significant figures over as needed */ + dp = DIGITS(mp); + for(ix = p; ix < USED(mp); ix++) + dp[ix - p] = dp[ix]; + + /* Fill the top digits with zeroes */ + ix -= p; + while(ix < USED(mp)) + dp[ix++] = 0; + + /* Strip off any leading zeroes */ + s_mp_clamp(mp); + +} /* end s_mp_rshd() */ + +/* }}} */ + +/* {{{ s_mp_div_2(mp) */ + +/* Divide by two -- take advantage of radix properties to do it fast */ +void s_mp_div_2(mp_int *mp) +{ + s_mp_div_2d(mp, 1); + +} /* end s_mp_div_2() */ + +/* }}} */ + +/* {{{ s_mp_mul_2(mp) */ + +mp_err s_mp_mul_2(mp_int *mp) +{ + int ix; + mp_digit kin = 0, kout, *dp = DIGITS(mp); + mp_err res; + + /* Shift digits leftward by 1 bit */ + for(ix = 0; ix < (int)USED(mp); ix++) { + kout = (dp[ix] >> (DIGIT_BIT - 1)) & 1; + dp[ix] = (dp[ix] << 1) | kin; + + kin = kout; + } + + /* Deal with rollover from last digit */ + if(kin) { + if(ix >= (int)ALLOC(mp)) { + if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY) + return res; + dp = DIGITS(mp); + } + + dp[ix] = kin; + USED(mp) += 1; + } + + return MP_OKAY; + +} /* end s_mp_mul_2() */ + +/* }}} */ + +/* {{{ s_mp_mod_2d(mp, d) */ + +/* + Remainder the integer by 2^d, where d is a number of bits. This + amounts to a bitwise AND of the value, and does not require the full + division code + */ +void s_mp_mod_2d(mp_int *mp, mp_digit d) +{ + unsigned int ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT); + unsigned int ix; + mp_digit dmask, *dp = DIGITS(mp); + + if(ndig >= USED(mp)) + return; + + /* Flush all the bits above 2^d in its digit */ + dmask = (1 << nbit) - 1; + dp[ndig] &= dmask; + + /* Flush all digits above the one with 2^d in it */ + for(ix = ndig + 1; ix < USED(mp); ix++) + dp[ix] = 0; + + s_mp_clamp(mp); + +} /* end s_mp_mod_2d() */ + +/* }}} */ + +/* {{{ s_mp_mul_2d(mp, d) */ + +/* + Multiply by the integer 2^d, where d is a number of bits. This + amounts to a bitwise shift of the value, and does not require the + full multiplication code. + */ +mp_err s_mp_mul_2d(mp_int *mp, mp_digit d) +{ + mp_err res; + mp_digit save, next, mask, *dp; + mp_size used; + int ix; + + if((res = s_mp_lshd(mp, d / DIGIT_BIT)) != MP_OKAY) + return res; + + dp = DIGITS(mp); used = USED(mp); + d %= DIGIT_BIT; + + mask = (1 << d) - 1; + + /* If the shift requires another digit, make sure we've got one to + work with */ + if((dp[used - 1] >> (DIGIT_BIT - d)) & mask) { + if((res = s_mp_grow(mp, used + 1)) != MP_OKAY) + return res; + dp = DIGITS(mp); + } + + /* Do the shifting... */ + save = 0; + for(ix = 0; ix < (int)used; ix++) { + next = (dp[ix] >> (DIGIT_BIT - d)) & mask; + dp[ix] = (dp[ix] << d) | save; + save = next; + } + + /* If, at this point, we have a nonzero carryout into the next + digit, we'll increase the size by one digit, and store it... + */ + if(save) { + dp[used] = save; + USED(mp) += 1; + } + + s_mp_clamp(mp); + return MP_OKAY; + +} /* end s_mp_mul_2d() */ + +/* }}} */ + +/* {{{ s_mp_div_2d(mp, d) */ + +/* + Divide the integer by 2^d, where d is a number of bits. This + amounts to a bitwise shift of the value, and does not require the + full division code (used in Barrett reduction, see below) + */ +void s_mp_div_2d(mp_int *mp, mp_digit d) +{ + int ix; + mp_digit save, next, mask, *dp = DIGITS(mp); + + s_mp_rshd(mp, d / DIGIT_BIT); + d %= DIGIT_BIT; + + mask = (1 << d) - 1; + + save = 0; + for(ix = USED(mp) - 1; ix >= 0; ix--) { + next = dp[ix] & mask; + dp[ix] = (dp[ix] >> d) | (save << (DIGIT_BIT - d)); + save = next; + } + + s_mp_clamp(mp); + +} /* end s_mp_div_2d() */ + +/* }}} */ + +/* {{{ s_mp_norm(a, b) */ + +/* + s_mp_norm(a, b) + + Normalize a and b for division, where b is the divisor. In order + that we might make good guesses for quotient digits, we want the + leading digit of b to be at least half the radix, which we + accomplish by multiplying a and b by a constant. This constant is + returned (so that it can be divided back out of the remainder at the + end of the division process). + + We multiply by the smallest power of 2 that gives us a leading digit + at least half the radix. By choosing a power of 2, we simplify the + multiplication and division steps to simple shifts. + */ +mp_digit s_mp_norm(mp_int *a, mp_int *b) +{ + mp_digit t, d = 0; + + t = DIGIT(b, USED(b) - 1); + while(t < (RADIX / 2)) { + t <<= 1; + ++d; + } + + if(d != 0) { + s_mp_mul_2d(a, d); + s_mp_mul_2d(b, d); + } + + return d; + +} /* end s_mp_norm() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive digit arithmetic */ + +/* {{{ s_mp_add_d(mp, d) */ + +/* Add d to |mp| in place */ +mp_err s_mp_add_d(mp_int *mp, mp_digit d) /* unsigned digit addition */ +{ + mp_word w, k = 0; + mp_size ix = 1, used = USED(mp); + mp_digit *dp = DIGITS(mp); + + w = dp[0] + d; + dp[0] = ACCUM(w); + k = CARRYOUT(w); + + while(ix < used && k) { + w = dp[ix] + k; + dp[ix] = ACCUM(w); + k = CARRYOUT(w); + ++ix; + } + + if(k != 0) { + mp_err res; + + if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY) + return res; + + DIGIT(mp, ix) = k; + } + + return MP_OKAY; + +} /* end s_mp_add_d() */ + +/* }}} */ + +/* {{{ s_mp_sub_d(mp, d) */ + +/* Subtract d from |mp| in place, assumes |mp| > d */ +mp_err s_mp_sub_d(mp_int *mp, mp_digit d) /* unsigned digit subtract */ +{ + mp_word w, b = 0; + mp_size ix = 1, used = USED(mp); + mp_digit *dp = DIGITS(mp); + + /* Compute initial subtraction */ + w = (RADIX + dp[0]) - d; + b = CARRYOUT(w) ? 0 : 1; + dp[0] = ACCUM(w); + + /* Propagate borrows leftward */ + while(b && ix < used) { + w = (RADIX + dp[ix]) - b; + b = CARRYOUT(w) ? 0 : 1; + dp[ix] = ACCUM(w); + ++ix; + } + + /* Remove leading zeroes */ + s_mp_clamp(mp); + + /* If we have a borrow out, it's a violation of the input invariant */ + if(b) + return MP_RANGE; + else + return MP_OKAY; + +} /* end s_mp_sub_d() */ + +/* }}} */ + +/* {{{ s_mp_mul_d(a, d) */ + +/* Compute a = a * d, single digit multiplication */ +mp_err s_mp_mul_d(mp_int *a, mp_digit d) +{ + mp_word w, k = 0; + mp_size ix, max; + mp_err res; + mp_digit *dp = DIGITS(a); + + /* + Single-digit multiplication will increase the precision of the + output by at most one digit. However, we can detect when this + will happen -- if the high-order digit of a, times d, gives a + two-digit result, then the precision of the result will increase; + otherwise it won't. We use this fact to avoid calling s_mp_pad() + unless absolutely necessary. + */ + max = USED(a); + w = dp[max - 1] * d; + if(CARRYOUT(w) != 0) { + if((res = s_mp_pad(a, max + 1)) != MP_OKAY) + return res; + dp = DIGITS(a); + } + + for(ix = 0; ix < max; ix++) { + w = (dp[ix] * d) + k; + dp[ix] = ACCUM(w); + k = CARRYOUT(w); + } + + /* If there is a precision increase, take care of it here; the above + test guarantees we have enough storage to do this safely. + */ + if(k) { + dp[max] = k; + USED(a) = max + 1; + } + + s_mp_clamp(a); + + return MP_OKAY; + +} /* end s_mp_mul_d() */ + +/* }}} */ + +/* {{{ s_mp_div_d(mp, d, r) */ + +/* + s_mp_div_d(mp, d, r) + + Compute the quotient mp = mp / d and remainder r = mp mod d, for a + single digit d. If r is null, the remainder will be discarded. + */ + +mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r) +{ + mp_word w = 0, t; + mp_int quot; + mp_err res; + mp_digit *dp = DIGITS(mp), *qp; + int ix; + + if(d == 0) + return MP_RANGE; + + /* Make room for the quotient */ + if((res = mp_init_size(", USED(mp))) != MP_OKAY) + return res; + + USED(") = USED(mp); /* so clamping will work below */ + qp = DIGITS("); + + /* Divide without subtraction */ + for(ix = USED(mp) - 1; ix >= 0; ix--) { + w = (w << DIGIT_BIT) | dp[ix]; + + if(w >= d) { + t = w / d; + w = w % d; + } else { + t = 0; + } + + qp[ix] = t; + } + + /* Deliver the remainder, if desired */ + if(r) + *r = w; + + s_mp_clamp("); + mp_exch(", mp); + mp_clear("); + + return MP_OKAY; + +} /* end s_mp_div_d() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive full arithmetic */ + +/* {{{ s_mp_add(a, b) */ + +/* Compute a = |a| + |b| */ +mp_err s_mp_add(mp_int *a, mp_int *b) /* magnitude addition */ +{ + mp_word w = 0; + mp_digit *pa, *pb; + mp_size ix, used = USED(b); + mp_err res; + + /* Make sure a has enough precision for the output value */ + if((used > USED(a)) && (res = s_mp_pad(a, used)) != MP_OKAY) + return res; + + /* + Add up all digits up to the precision of b. If b had initially + the same precision as a, or greater, we took care of it by the + padding step above, so there is no problem. If b had initially + less precision, we'll have to make sure the carry out is duly + propagated upward among the higher-order digits of the sum. + */ + pa = DIGITS(a); + pb = DIGITS(b); + for(ix = 0; ix < used; ++ix) { + w += *pa + *pb++; + *pa++ = ACCUM(w); + w = CARRYOUT(w); + } + + /* If we run out of 'b' digits before we're actually done, make + sure the carries get propagated upward... + */ + used = USED(a); + while(w && ix < used) { + w += *pa; + *pa++ = ACCUM(w); + w = CARRYOUT(w); + ++ix; + } + + /* If there's an overall carry out, increase precision and include + it. We could have done this initially, but why touch the memory + allocator unless we're sure we have to? + */ + if(w) { + if((res = s_mp_pad(a, used + 1)) != MP_OKAY) + return res; + + DIGIT(a, ix) = w; /* pa may not be valid after s_mp_pad() call */ + } + + return MP_OKAY; + +} /* end s_mp_add() */ + +/* }}} */ + +/* {{{ s_mp_sub(a, b) */ + +/* Compute a = |a| - |b|, assumes |a| >= |b| */ +mp_err s_mp_sub(mp_int *a, mp_int *b) /* magnitude subtract */ +{ + mp_word w = 0; + mp_digit *pa, *pb; + mp_size ix, used = USED(b); + + /* + Subtract and propagate borrow. Up to the precision of b, this + accounts for the digits of b; after that, we just make sure the + carries get to the right place. This saves having to pad b out to + the precision of a just to make the loops work right... + */ + pa = DIGITS(a); + pb = DIGITS(b); + + for(ix = 0; ix < used; ++ix) { + w = (RADIX + *pa) - w - *pb++; + *pa++ = ACCUM(w); + w = CARRYOUT(w) ? 0 : 1; + } + + used = USED(a); + while(ix < used) { + w = RADIX + *pa - w; + *pa++ = ACCUM(w); + w = CARRYOUT(w) ? 0 : 1; + ++ix; + } + + /* Clobber any leading zeroes we created */ + s_mp_clamp(a); + + /* + If there was a borrow out, then |b| > |a| in violation + of our input invariant. We've already done the work, + but we'll at least complain about it... + */ + if(w) + return MP_RANGE; + else + return MP_OKAY; + +} /* end s_mp_sub() */ + +/* }}} */ + +/* {{{ s_mp_mul(a, b) */ + +/* Compute a = |a| * |b| */ +mp_err s_mp_mul(mp_int *a, mp_int *b) +{ + mp_word w, k = 0; + mp_int tmp; + mp_err res; + mp_size ix, jx, ua = USED(a), ub = USED(b); + mp_digit *pa, *pb, *pt, *pbt; + + if((res = mp_init_size(&tmp, ua + ub)) != MP_OKAY) + return res; + + /* This has the effect of left-padding with zeroes... */ + USED(&tmp) = ua + ub; + + /* We're going to need the base value each iteration */ + pbt = DIGITS(&tmp); + + /* Outer loop: Digits of b */ + + pb = DIGITS(b); + for(ix = 0; ix < ub; ++ix, ++pb) { + if(*pb == 0) + continue; + + /* Inner product: Digits of a */ + pa = DIGITS(a); + for(jx = 0; jx < ua; ++jx, ++pa) { + pt = pbt + ix + jx; + w = *pb * *pa + k + *pt; + *pt = ACCUM(w); + k = CARRYOUT(w); + } + + pbt[ix + jx] = k; + k = 0; + } + + s_mp_clamp(&tmp); + s_mp_exch(&tmp, a); + + mp_clear(&tmp); + + return MP_OKAY; + +} /* end s_mp_mul() */ + +/* }}} */ + +/* {{{ s_mp_kmul(a, b, out, len) */ + +#if 0 +void s_mp_kmul(mp_digit *a, mp_digit *b, mp_digit *out, mp_size len) +{ + mp_word w, k = 0; + mp_size ix, jx; + mp_digit *pa, *pt; + + for(ix = 0; ix < len; ++ix, ++b) { + if(*b == 0) + continue; + + pa = a; + for(jx = 0; jx < len; ++jx, ++pa) { + pt = out + ix + jx; + w = *b * *pa + k + *pt; + *pt = ACCUM(w); + k = CARRYOUT(w); + } + + out[ix + jx] = k; + k = 0; + } + +} /* end s_mp_kmul() */ +#endif + +/* }}} */ + +/* {{{ s_mp_sqr(a) */ + +/* + Computes the square of a, in place. This can be done more + efficiently than a general multiplication, because many of the + computation steps are redundant when squaring. The inner product + step is a bit more complicated, but we save a fair number of + iterations of the multiplication loop. + */ +#if MP_SQUARE +mp_err s_mp_sqr(mp_int *a) +{ + mp_word w, k = 0; + mp_int tmp; + mp_err res; + mp_size ix, jx, kx, used = USED(a); + mp_digit *pa1, *pa2, *pt, *pbt; + + if((res = mp_init_size(&tmp, 2 * used)) != MP_OKAY) + return res; + + /* Left-pad with zeroes */ + USED(&tmp) = 2 * used; + + /* We need the base value each time through the loop */ + pbt = DIGITS(&tmp); + + pa1 = DIGITS(a); + for(ix = 0; ix < used; ++ix, ++pa1) { + if(*pa1 == 0) + continue; + + w = DIGIT(&tmp, ix + ix) + (*pa1 * *pa1); + + pbt[ix + ix] = ACCUM(w); + k = CARRYOUT(w); + + /* + The inner product is computed as: + + (C, S) = t[i,j] + 2 a[i] a[j] + C + + This can overflow what can be represented in an mp_word, and + since C arithmetic does not provide any way to check for + overflow, we have to check explicitly for overflow conditions + before they happen. + */ + for(jx = ix + 1, pa2 = DIGITS(a) + jx; jx < used; ++jx, ++pa2) { + mp_word u = 0, v; + + /* Store this in a temporary to avoid indirections later */ + pt = pbt + ix + jx; + + /* Compute the multiplicative step */ + w = *pa1 * *pa2; + + /* If w is more than half MP_WORD_MAX, the doubling will + overflow, and we need to record a carry out into the next + word */ + u = (w >> (MP_WORD_BIT - 1)) & 1; + + /* Double what we've got, overflow will be ignored as defined + for C arithmetic (we've already noted if it is to occur) + */ + w *= 2; + + /* Compute the additive step */ + v = *pt + k; + + /* If we do not already have an overflow carry, check to see + if the addition will cause one, and set the carry out if so + */ + u |= ((MP_WORD_MAX - v) < w); + + /* Add in the rest, again ignoring overflow */ + w += v; + + /* Set the i,j digit of the output */ + *pt = ACCUM(w); + + /* Save carry information for the next iteration of the loop. + This is why k must be an mp_word, instead of an mp_digit */ + k = CARRYOUT(w) | (u << DIGIT_BIT); + + } /* for(jx ...) */ + + /* Set the last digit in the cycle and reset the carry */ + k = DIGIT(&tmp, ix + jx) + k; + pbt[ix + jx] = ACCUM(k); + k = CARRYOUT(k); + + /* If we are carrying out, propagate the carry to the next digit + in the output. This may cascade, so we have to be somewhat + circumspect -- but we will have enough precision in the output + that we won't overflow + */ + kx = 1; + while(k) { + k = pbt[ix + jx + kx] + 1; + pbt[ix + jx + kx] = ACCUM(k); + k = CARRYOUT(k); + ++kx; + } + } /* for(ix ...) */ + + s_mp_clamp(&tmp); + s_mp_exch(&tmp, a); + + mp_clear(&tmp); + + return MP_OKAY; + +} /* end s_mp_sqr() */ +#endif + +/* }}} */ + +/* {{{ s_mp_div(a, b) */ + +/* + s_mp_div(a, b) + + Compute a = a / b and b = a mod b. Assumes b > a. + */ + +mp_err s_mp_div(mp_int *a, mp_int *b) +{ + mp_int quot, rem, t; + mp_word q; + mp_err res; + mp_digit d; + int ix; + + if(mp_cmp_z(b) == 0) + return MP_RANGE; + + /* Shortcut if b is power of two */ + if((ix = s_mp_ispow2(b)) >= 0) { + mp_copy(a, b); /* need this for remainder */ + s_mp_div_2d(a, (mp_digit)ix); + s_mp_mod_2d(b, (mp_digit)ix); + + return MP_OKAY; + } + + /* Allocate space to store the quotient */ + if((res = mp_init_size(", USED(a))) != MP_OKAY) + return res; + + /* A working temporary for division */ + if((res = mp_init_size(&t, USED(a))) != MP_OKAY) + goto T; + + /* Allocate space for the remainder */ + if((res = mp_init_size(&rem, USED(a))) != MP_OKAY) + goto REM; + + /* Normalize to optimize guessing */ + d = s_mp_norm(a, b); + + /* Perform the division itself...woo! */ + ix = USED(a) - 1; + + while(ix >= 0) { + /* Find a partial substring of a which is at least b */ + while(s_mp_cmp(&rem, b) < 0 && ix >= 0) { + if((res = s_mp_lshd(&rem, 1)) != MP_OKAY) + goto CLEANUP; + + if((res = s_mp_lshd(", 1)) != MP_OKAY) + goto CLEANUP; + + DIGIT(&rem, 0) = DIGIT(a, ix); + s_mp_clamp(&rem); + --ix; + } + + /* If we didn't find one, we're finished dividing */ + if(s_mp_cmp(&rem, b) < 0) + break; + + /* Compute a guess for the next quotient digit */ + q = DIGIT(&rem, USED(&rem) - 1); + if(q <= DIGIT(b, USED(b) - 1) && USED(&rem) > 1) + q = (q << DIGIT_BIT) | DIGIT(&rem, USED(&rem) - 2); + + q /= DIGIT(b, USED(b) - 1); + + /* The guess can be as much as RADIX + 1 */ + if(q >= RADIX) + q = RADIX - 1; + + /* See what that multiplies out to */ + mp_copy(b, &t); + if((res = s_mp_mul_d(&t, (mp_digit)q)) != MP_OKAY) + goto CLEANUP; + + /* + If it's too big, back it off. We should not have to do this + more than once, or, in rare cases, twice. Knuth describes a + method by which this could be reduced to a maximum of once, but + I didn't implement that here. + */ + while(s_mp_cmp(&t, &rem) > 0) { + --q; + s_mp_sub(&t, b); + } + + /* At this point, q should be the right next digit */ + if((res = s_mp_sub(&rem, &t)) != MP_OKAY) + goto CLEANUP; + + /* + Include the digit in the quotient. We allocated enough memory + for any quotient we could ever possibly get, so we should not + have to check for failures here + */ + DIGIT(", 0) = q; + } + + /* Denormalize remainder */ + if(d != 0) + s_mp_div_2d(&rem, d); + + s_mp_clamp("); + s_mp_clamp(&rem); + + /* Copy quotient back to output */ + s_mp_exch(", a); + + /* Copy remainder back to output */ + s_mp_exch(&rem, b); + +CLEANUP: + mp_clear(&rem); +REM: + mp_clear(&t); +T: + mp_clear("); + + return res; + +} /* end s_mp_div() */ + +/* }}} */ + +/* {{{ s_mp_2expt(a, k) */ + +mp_err s_mp_2expt(mp_int *a, mp_digit k) +{ + mp_err res; + mp_size dig, bit; + + dig = k / DIGIT_BIT; + bit = k % DIGIT_BIT; + + mp_zero(a); + if((res = s_mp_pad(a, dig + 1)) != MP_OKAY) + return res; + + DIGIT(a, dig) |= (1 << bit); + + return MP_OKAY; + +} /* end s_mp_2expt() */ + +/* }}} */ + +/* {{{ s_mp_reduce(x, m, mu) */ + +/* + Compute Barrett reduction, x (mod m), given a precomputed value for + mu = b^2k / m, where b = RADIX and k = #digits(m). This should be + faster than straight division, when many reductions by the same + value of m are required (such as in modular exponentiation). This + can nearly halve the time required to do modular exponentiation, + as compared to using the full integer divide to reduce. + + This algorithm was derived from the _Handbook of Applied + Cryptography_ by Menezes, Oorschot and VanStone, Ch. 14, + pp. 603-604. + */ + +mp_err s_mp_reduce(mp_int *x, mp_int *m, mp_int *mu) +{ + mp_int q; + mp_err res; + mp_size um = USED(m); + + if((res = mp_init_copy(&q, x)) != MP_OKAY) + return res; + + s_mp_rshd(&q, um - 1); /* q1 = x / b^(k-1) */ + s_mp_mul(&q, mu); /* q2 = q1 * mu */ + s_mp_rshd(&q, um + 1); /* q3 = q2 / b^(k+1) */ + + /* x = x mod b^(k+1), quick (no division) */ + s_mp_mod_2d(x, (mp_digit)(DIGIT_BIT * (um + 1))); + + /* q = q * m mod b^(k+1), quick (no division) */ + s_mp_mul(&q, m); + s_mp_mod_2d(&q, (mp_digit)(DIGIT_BIT * (um + 1))); + + /* x = x - q */ + if((res = mp_sub(x, &q, x)) != MP_OKAY) + goto CLEANUP; + + /* If x < 0, add b^(k+1) to it */ + if(mp_cmp_z(x) < 0) { + mp_set(&q, 1); + if((res = s_mp_lshd(&q, um + 1)) != MP_OKAY) + goto CLEANUP; + if((res = mp_add(x, &q, x)) != MP_OKAY) + goto CLEANUP; + } + + /* Back off if it's too big */ + while(mp_cmp(x, m) >= 0) { + if((res = s_mp_sub(x, m)) != MP_OKAY) + break; + } + + CLEANUP: + mp_clear(&q); + + return res; + +} /* end s_mp_reduce() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive comparisons */ + +/* {{{ s_mp_cmp(a, b) */ + +/* Compare |a| <=> |b|, return 0 if equal, <0 if a0 if a>b */ +int s_mp_cmp(mp_int *a, mp_int *b) +{ + mp_size ua = USED(a), ub = USED(b); + + if(ua > ub) + return MP_GT; + else if(ua < ub) + return MP_LT; + else { + int ix = ua - 1; + mp_digit *ap = DIGITS(a) + ix, *bp = DIGITS(b) + ix; + + while(ix >= 0) { + if(*ap > *bp) + return MP_GT; + else if(*ap < *bp) + return MP_LT; + + --ap; --bp; --ix; + } + + return MP_EQ; + } + +} /* end s_mp_cmp() */ + +/* }}} */ + +/* {{{ s_mp_cmp_d(a, d) */ + +/* Compare |a| <=> d, return 0 if equal, <0 if a0 if a>d */ +int s_mp_cmp_d(mp_int *a, mp_digit d) +{ + mp_size ua = USED(a); + mp_digit *ap = DIGITS(a); + + if(ua > 1) + return MP_GT; + + if(*ap < d) + return MP_LT; + else if(*ap > d) + return MP_GT; + else + return MP_EQ; + +} /* end s_mp_cmp_d() */ + +/* }}} */ + +/* {{{ s_mp_ispow2(v) */ + +/* + Returns -1 if the value is not a power of two; otherwise, it returns + k such that v = 2^k, i.e. lg(v). + */ +int s_mp_ispow2(mp_int *v) +{ + mp_digit d, *dp; + mp_size uv = USED(v); + int extra = 0, ix; + + d = DIGIT(v, uv - 1); /* most significant digit of v */ + + while(d && ((d & 1) == 0)) { + d >>= 1; + ++extra; + } + + if(d == 1) { + ix = uv - 2; + dp = DIGITS(v) + ix; + + while(ix >= 0) { + if(*dp) + return -1; /* not a power of two */ + + --dp; --ix; + } + + return ((uv - 1) * DIGIT_BIT) + extra; + } + + return -1; + +} /* end s_mp_ispow2() */ + +/* }}} */ + +/* {{{ s_mp_ispow2d(d) */ + +int s_mp_ispow2d(mp_digit d) +{ + int pow = 0; + + while((d & 1) == 0) { + ++pow; d >>= 1; + } + + if(d == 1) + return pow; + + return -1; + +} /* end s_mp_ispow2d() */ + +/* }}} */ + +/* }}} */ + +/* {{{ Primitive I/O helpers */ + +/* {{{ s_mp_tovalue(ch, r) */ + +/* + Convert the given character to its digit value, in the given radix. + If the given character is not understood in the given radix, -1 is + returned. Otherwise the digit's numeric value is returned. + + The results will be odd if you use a radix < 2 or > 62, you are + expected to know what you're up to. + */ +int s_mp_tovalue(char ch, int r) +{ + int val, xch; + + if(r > 36) + xch = ch; + else + xch = toupper(ch); + + if(isdigit(xch)) + val = xch - '0'; + else if(isupper(xch)) + val = xch - 'A' + 10; + else if(islower(xch)) + val = xch - 'a' + 36; + else if(xch == '+') + val = 62; + else if(xch == '/') + val = 63; + else + return -1; + + if(val < 0 || val >= r) + return -1; + + return val; + +} /* end s_mp_tovalue() */ + +/* }}} */ + +/* {{{ s_mp_todigit(val, r, low) */ + +/* + Convert val to a radix-r digit, if possible. If val is out of range + for r, returns zero. Otherwise, returns an ASCII character denoting + the value in the given radix. + + The results may be odd if you use a radix < 2 or > 64, you are + expected to know what you're doing. + */ + +char s_mp_todigit(int val, int r, int low) +{ + char ch; + + if(val < 0 || val >= r) + return 0; + + ch = s_dmap_1[val]; + + if(r <= 36 && low) + ch = tolower(ch); + + return ch; + +} /* end s_mp_todigit() */ + +/* }}} */ + +/* {{{ s_mp_outlen(bits, radix) */ + +/* + Return an estimate for how long a string is needed to hold a radix + r representation of a number with 'bits' significant bits. + + Does not include space for a sign or a NUL terminator. + */ +int s_mp_outlen(int bits, int r) +{ + return (int)((double)bits * LOG_V_2(r)); + +} /* end s_mp_outlen() */ + +/* }}} */ + +/* }}} */ + +#endif /* MPI */ + +/*------------------------------------------------------------------------*/ +/* HERE THERE BE DRAGONS */ + + diff --git a/mpi.h b/mpi.h new file mode 100644 index 0000000..cbcdc4d --- /dev/null +++ b/mpi.h @@ -0,0 +1,225 @@ +/* + mpi.h + + by Michael J. Fromberger + Copyright (C) 1998 Michael J. Fromberger, All Rights Reserved + + Arbitrary precision integer arithmetic library + + $ID$ + */ + +#ifndef _H_MPI_ +#define _H_MPI_ + +#include "mpi-config.h" + +#define MP_LT -1 +#define MP_EQ 0 +#define MP_GT 1 + +#if MP_DEBUG +#undef MP_IOFUNC +#define MP_IOFUNC 1 +#endif + +#if MP_IOFUNC +#include +#include +#endif + +#include + +#define MP_NEG 1 +#define MP_ZPOS 0 + +/* Included for compatibility... */ +#define NEG MP_NEG +#define ZPOS MP_ZPOS + +#define MP_OKAY 0 /* no error, all is well */ +#define MP_YES 0 /* yes (boolean result) */ +#define MP_NO -1 /* no (boolean result) */ +#define MP_MEM -2 /* out of memory */ +#define MP_RANGE -3 /* argument out of range */ +#define MP_BADARG -4 /* invalid parameter */ +#define MP_UNDEF -5 /* answer is undefined */ +#define MP_LAST_CODE MP_UNDEF + +#include "mpi-types.h" + +/* Included for compatibility... */ +#define DIGIT_BIT MP_DIGIT_BIT +#define DIGIT_MAX MP_DIGIT_MAX + +/* Macros for accessing the mp_int internals */ +#define SIGN(MP) ((MP)->sign) +#define USED(MP) ((MP)->used) +#define ALLOC(MP) ((MP)->alloc) +#define DIGITS(MP) ((MP)->dp) +#define DIGIT(MP,N) (MP)->dp[(N)] + +#if MP_ARGCHK == 1 +#define ARGCHK(X,Y) {if(!(X)){return (Y);}} +#elif MP_ARGCHK == 2 +#include +#define ARGCHK(X,Y) assert(X) +#else +#define ARGCHK(X,Y) /* */ +#endif + +/* This defines the maximum I/O base (minimum is 2) */ +#define MAX_RADIX 64 + +typedef struct { + mp_sign sign; /* sign of this quantity */ + mp_size alloc; /* how many digits allocated */ + mp_size used; /* how many digits used */ + mp_digit *dp; /* the digits themselves */ +} mp_int; + +/*------------------------------------------------------------------------*/ +/* Default precision */ + +unsigned int mp_get_prec(void); +void mp_set_prec(unsigned int prec); + +/*------------------------------------------------------------------------*/ +/* Memory management */ + +mp_err mp_init(mp_int *mp); +mp_err mp_init_array(mp_int mp[], int count); +mp_err mp_init_size(mp_int *mp, mp_size prec); +mp_err mp_init_copy(mp_int *mp, mp_int *from); +mp_err mp_copy(mp_int *from, mp_int *to); +void mp_exch(mp_int *mp1, mp_int *mp2); +void mp_clear(mp_int *mp); +void mp_clear_array(mp_int mp[], int count); +void mp_zero(mp_int *mp); +void mp_set(mp_int *mp, mp_digit d); +mp_err mp_set_int(mp_int *mp, long z); + +/*------------------------------------------------------------------------*/ +/* Single digit arithmetic */ + +mp_err mp_add_d(mp_int *a, mp_digit d, mp_int *b); +mp_err mp_sub_d(mp_int *a, mp_digit d, mp_int *b); +mp_err mp_mul_d(mp_int *a, mp_digit d, mp_int *b); +mp_err mp_mul_2(mp_int *a, mp_int *c); +mp_err mp_div_d(mp_int *a, mp_digit d, mp_int *q, mp_digit *r); +mp_err mp_div_2(mp_int *a, mp_int *c); +mp_err mp_expt_d(mp_int *a, mp_digit d, mp_int *c); + +/*------------------------------------------------------------------------*/ +/* Sign manipulations */ + +mp_err mp_abs(mp_int *a, mp_int *b); +mp_err mp_neg(mp_int *a, mp_int *b); + +/*------------------------------------------------------------------------*/ +/* Full arithmetic */ + +mp_err mp_add(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_sub(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_mul(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_mul_2d(mp_int *a, mp_digit d, mp_int *c); +#if MP_SQUARE +mp_err mp_sqr(mp_int *a, mp_int *b); +#else +#define mp_sqr(a, b) mp_mul(a, a, b) +#endif +mp_err mp_div(mp_int *a, mp_int *b, mp_int *q, mp_int *r); +mp_err mp_div_2d(mp_int *a, mp_digit d, mp_int *q, mp_int *r); +mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_2expt(mp_int *a, mp_digit k); +mp_err mp_sqrt(mp_int *a, mp_int *b); + +/*------------------------------------------------------------------------*/ +/* Modular arithmetic */ + +#if MP_MODARITH +mp_err mp_mod(mp_int *a, mp_int *m, mp_int *c); +mp_err mp_mod_d(mp_int *a, mp_digit d, mp_digit *c); +mp_err mp_addmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); +mp_err mp_submod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); +mp_err mp_mulmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); +#if MP_SQUARE +mp_err mp_sqrmod(mp_int *a, mp_int *m, mp_int *c); +#else +#define mp_sqrmod(a, m, c) mp_mulmod(a, a, m, c) +#endif +mp_err mp_exptmod(mp_int *a, mp_int *b, mp_int *m, mp_int *c); +mp_err mp_exptmod_d(mp_int *a, mp_digit d, mp_int *m, mp_int *c); +#endif /* MP_MODARITH */ + +/*------------------------------------------------------------------------*/ +/* Comparisons */ + +int mp_cmp_z(mp_int *a); +int mp_cmp_d(mp_int *a, mp_digit d); +int mp_cmp(mp_int *a, mp_int *b); +int mp_cmp_mag(mp_int *a, mp_int *b); +int mp_cmp_int(mp_int *a, long z); +int mp_isodd(mp_int *a); +int mp_iseven(mp_int *a); + +/*------------------------------------------------------------------------*/ +/* Number theoretic */ + +#if MP_NUMTH +mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c); +mp_err mp_xgcd(mp_int *a, mp_int *b, mp_int *g, mp_int *x, mp_int *y); +mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c); +#endif /* end MP_NUMTH */ + +/*------------------------------------------------------------------------*/ +/* Input and output */ + +#if MP_IOFUNC +void mp_print(mp_int *mp, FILE *ofp); +#endif /* end MP_IOFUNC */ + +/*------------------------------------------------------------------------*/ +/* Base conversion */ + +#define BITS 1 +#define BYTES CHAR_BIT + +mp_err mp_read_signed_bin(mp_int *mp, unsigned char *str, int len); +int mp_signed_bin_size(mp_int *mp); +mp_err mp_to_signed_bin(mp_int *mp, unsigned char *str); + +mp_err mp_read_unsigned_bin(mp_int *mp, unsigned char *str, int len); +int mp_unsigned_bin_size(mp_int *mp); +mp_err mp_to_unsigned_bin(mp_int *mp, unsigned char *str); + +int mp_count_bits(mp_int *mp); + +#if MP_COMPAT_MACROS +#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len)) +#define mp_raw_size(mp) mp_signed_bin_size(mp) +#define mp_toraw(mp, str) mp_to_signed_bin((mp), (str)) +#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len)) +#define mp_mag_size(mp) mp_unsigned_bin_size(mp) +#define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str)) +#endif + +mp_err mp_read_radix(mp_int *mp, unsigned char *str, int radix); +int mp_radix_size(mp_int *mp, int radix); +int mp_value_radix_size(int num, int qty, int radix); +mp_err mp_toradix(mp_int *mp, unsigned char *str, int radix); + +int mp_char2value(char ch, int r); + +#define mp_tobinary(M, S) mp_toradix((M), (S), 2) +#define mp_tooctal(M, S) mp_toradix((M), (S), 8) +#define mp_todecimal(M, S) mp_toradix((M), (S), 10) +#define mp_tohex(M, S) mp_toradix((M), (S), 16) + +/*------------------------------------------------------------------------*/ +/* Error strings */ + +const char *mp_strerror(mp_err ec); + +#endif /* end _H_MPI_ */ diff --git a/mycrypt.h b/mycrypt.h new file mode 100644 index 0000000..1604854 --- /dev/null +++ b/mycrypt.h @@ -0,0 +1,75 @@ +#ifndef CRYPT_H_ +#define CRYPT_H_ +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* version */ +#define CRYPT 0x0075 +#define SCRYPT "0.75" + +/* max size of either a cipher/hash block or symmetric key [largest of the two] */ +#define MAXBLOCKSIZE 128 + +/* error codes [will be expanded in future releases] */ +enum { + CRYPT_OK=0, + CRYPT_ERROR, + + CRYPT_INVALID_KEYSIZE, + CRYPT_INVALID_ROUNDS, + CRYPT_FAIL_TESTVECTOR, + + CRYPT_BUFFER_OVERFLOW, + CRYPT_INVALID_PACKET, + + CRYPT_INVALID_PRNGSIZE, + CRYPT_ERROR_READPRNG, + + CRYPT_INVALID_CIPHER, + CRYPT_INVALID_HASH, + CRYPT_INVALID_PRNG, + + CRYPT_MEM, + + CRYPT_PK_TYPE_MISMATCH, + CRYPT_PK_NOT_PRIVATE, + + CRYPT_INVALID_ARG, + + CRYPT_PK_INVALID_TYPE, + CRYPT_PK_INVALID_SYSTEM, + CRYPT_PK_DUP, + CRYPT_PK_NOT_FOUND, + CRYPT_PK_INVALID_SIZE, + + CRYPT_INVALID_PRIME_SIZE +}; + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#ifdef __cplusplus + } +#endif + +#endif /* CRYPT_H_ */ + diff --git a/mycrypt_argchk.h b/mycrypt_argchk.h new file mode 100644 index 0000000..4ce83c8 --- /dev/null +++ b/mycrypt_argchk.h @@ -0,0 +1,41 @@ +/* Defines the _ARGCHK macro used within the library */ + +/* ARGTYPE is defined in mycrypt_cfg.h */ +#if ARGTYPE == 0 + +#include + +/* this is the default LibTomCrypt macro + * + * On embedded platforms you can change the fprintf() to be a routine that would display a message + * somehow + */ +#ifndef SONY_PS2 + +#define _ARGCHK(x) \ + if (!(x)) { \ + fprintf(stderr, "_ARGCHK '%s' failure on line %d of file %s\n", #x, __LINE__, __FILE__); \ + raise(SIGABRT); \ + } + +#else + +#define _ARGCHK(x) \ + if (!(x)) { \ + printf("_ARGCHK '%s' failure on line %d of file %s\n", #x, __LINE__, __FILE__); \ + raise(SIGABRT); \ + } + +#endif /* SONY_PS2 */ + +#elif ARGTYPE == 1 + +/* fatal type of error */ +#define _ARGCHK(x) assert((x)) + +#elif ARGTYPE == 2 + +#define _ARGCHK(x) + +#endif + diff --git a/mycrypt_cfg.h b/mycrypt_cfg.h new file mode 100644 index 0000000..8306f37 --- /dev/null +++ b/mycrypt_cfg.h @@ -0,0 +1,122 @@ +/* This is the build config file. + * + * With this you can setup what to inlcude/exclude automatically during any build. Just comment + * out the line that #define's the word for the thing you want to remove. phew! + */ + +#ifndef MYCRYPT_CFG_H +#define MYCRYPT_CFG_H + +/* you can change how memory allocation works ... */ +extern void *XMALLOC(size_t n); +extern void *XCALLOC(size_t n, size_t s); +extern void XFREE(void *p); + +/* change the clock function too */ +extern clock_t XCLOCK(void); + +/* type of argument checking, 0=default, 1=fatal and 2=none */ +#define ARGTYPE 0 + +/* Controls endianess and size of registers. Leave uncommented to get platform neutral [slower] code */ +/* detect x86-32 machines somewhat */ +#if (defined(_MSC_VER) && defined(WIN32)) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__))) + #define ENDIAN_LITTLE + #define ENDIAN_32BITWORD +#endif + +/* detects MIPS R5900 processors (PS2) */ +#if (defined(__R5900) || defined(R5900) || defined(__R5900__)) && (defined(_mips) || defined(__mips__) || defined(mips)) + #define ENDIAN_LITTLE + #define ENDIAN_64BITWORD +#endif + +/* #define ENDIAN_LITTLE */ +/* #define ENDIAN_BIG */ + +/* #define ENDIAN_32BITWORD */ +/* #define ENDIAN_64BITWORD */ + +#if (defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) && !(defined(ENDIAN_32BITWORD) || defined(ENDIAN_64BITWORD)) + #error You must specify a word size as well as endianess in mycrypt_cfg.h +#endif + +#if !(defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) + #define ENDIAN_NEUTRAL +#endif + +#ifdef SHA384 + #ifndef SHA512 + #error The SHA384 hash requires SHA512 to be defined! + #endif +#endif + +#ifdef YARROW + #ifndef CTR + #error YARROW Requires CTR mode + #endif +#endif + +/* packet code */ +#if defined(MRSA) || defined(MDH) || defined(MECC) + #define PACKET + + /* size of a packet header in bytes */ + #define PACKET_SIZE 8 + + /* Section tags */ + #define PACKET_SECT_RSA 0 + #define PACKET_SECT_DH 1 + #define PACKET_SECT_ECC 2 + + /* Subsection Tags for the first three sections */ + #define PACKET_SUB_KEY 0 + #define PACKET_SUB_ENCRYPTED 1 + #define PACKET_SUB_SIGNED 2 + #define PACKET_SUB_ENC_KEY 3 +#endif + +/* Diffie-Hellman key settings you can omit ones you don't want to save space */ +#ifdef MDH + +#define DH512 +#define DH768 +#define DH1024 +#define DH1280 +#define DH1536 +#define DH1792 +#define DH2048 +#define DH2560 +#define DH3072 +#define DH4096 + +#endif /* MDH */ + +/* ECC Key settings */ +#ifdef MECC + +#define ECC160 +#define ECC192 +#define ECC224 +#define ECC256 +#define ECC384 +#define ECC521 + +#endif /* MECC */ + +#ifdef MPI + #include "mpi.h" +#else + #ifdef MRSA + #error RSA requires the big int library + #endif + #ifdef MECC + #error ECC requires the big int library + #endif + #ifdef MDH + #error DH requires the big int library + #endif +#endif /* MPI */ + +#endif /* MYCRYPT_CFG_H */ + diff --git a/mycrypt_cipher.h b/mycrypt_cipher.h new file mode 100644 index 0000000..72db085 --- /dev/null +++ b/mycrypt_cipher.h @@ -0,0 +1,349 @@ +/* ---- SYMMETRIC KEY STUFF ----- + * + * We put each of the ciphers scheduled keys in their own structs then we put all of + * the key formats in one union. This makes the function prototypes easier to use. + */ +#ifdef BLOWFISH +struct blowfish_key { + unsigned long S[4][256]; + unsigned long K[18]; +}; +#endif + +#ifdef RC5 +struct rc5_key { + int rounds; + unsigned long K[50]; +}; +#endif + +#ifdef RC6 +struct rc6_key { + unsigned long K[44]; +}; +#endif + +#ifdef SAFERP +struct saferp_key { + unsigned char K[33][16]; + long rounds; +}; +#endif + +#ifdef SERPENT +struct serpent_key { + unsigned long K[132]; +}; +#endif + +#ifdef RIJNDAEL +struct rijndael_key { + unsigned long eK[64], dK[64], k_len; +}; +#endif + +#ifdef XTEA +struct xtea_key { + unsigned long K[4]; +}; +#endif + +#ifdef TWOFISH +#ifndef TWOFISH_SMALL + struct twofish_key { + unsigned long S[4][256], K[40]; + }; +#else + struct twofish_key { + unsigned long K[40]; + unsigned char S[32], start; + }; +#endif +#endif + +#ifdef SAFER +#define SAFER_K64_DEFAULT_NOF_ROUNDS 6 +#define SAFER_K128_DEFAULT_NOF_ROUNDS 10 +#define SAFER_SK64_DEFAULT_NOF_ROUNDS 8 +#define SAFER_SK128_DEFAULT_NOF_ROUNDS 10 +#define SAFER_MAX_NOF_ROUNDS 13 +#define SAFER_BLOCK_LEN 8 +#define SAFER_KEY_LEN (1 + SAFER_BLOCK_LEN * (1 + 2 * SAFER_MAX_NOF_ROUNDS)) +typedef unsigned char safer_block_t[SAFER_BLOCK_LEN]; +typedef unsigned char safer_key_t[SAFER_KEY_LEN]; +struct safer_key { safer_key_t key; }; +#endif + +#ifdef RC2 +struct rc2_key { unsigned xkey[64]; }; +#endif + +#ifdef DES +struct des_key { + unsigned long ek[32], dk[32]; +}; + +struct des3_key { + unsigned long ek[3][32], dk[3][32]; +}; +#endif + +#ifdef CAST5 +struct cast5_key { + unsigned long K[32], keylen; +}; +#endif + +typedef union Symmetric_key { +#ifdef DES + struct des_key des; + struct des3_key des3; +#endif +#ifdef RC2 + struct rc2_key rc2; +#endif +#ifdef SAFER + struct safer_key safer; +#endif +#ifdef TWOFISH + struct twofish_key twofish; +#endif +#ifdef BLOWFISH + struct blowfish_key blowfish; +#endif +#ifdef RC5 + struct rc5_key rc5; +#endif +#ifdef RC6 + struct rc6_key rc6; +#endif +#ifdef SAFERP + struct saferp_key saferp; +#endif +#ifdef SERPENT + struct serpent_key serpent; +#endif +#ifdef RIJNDAEL + struct rijndael_key rijndael; +#endif +#ifdef XTEA + struct xtea_key xtea; +#endif +#ifdef CAST5 + struct cast5_key cast5; +#endif +} symmetric_key; + +/* A block cipher ECB structure */ +typedef struct { + int cipher, blocklen; + symmetric_key key; +} symmetric_ECB; + +/* A block cipher CFB structure */ +typedef struct { + int cipher, blocklen, padlen; + unsigned char IV[MAXBLOCKSIZE], pad[MAXBLOCKSIZE]; + symmetric_key key; +} symmetric_CFB; + +/* A block cipher OFB structure */ +typedef struct { + int cipher, blocklen, padlen; + unsigned char IV[MAXBLOCKSIZE]; + symmetric_key key; +} symmetric_OFB; + +/* A block cipher CBC structure */ +typedef struct Symmetric_CBC { + int cipher, blocklen; + unsigned char IV[MAXBLOCKSIZE]; + symmetric_key key; +} symmetric_CBC; + +/* A block cipher CTR structure */ +typedef struct Symmetric_CTR { + int cipher, blocklen, padlen; + unsigned char ctr[MAXBLOCKSIZE], pad[MAXBLOCKSIZE]; + symmetric_key key; +} symmetric_CTR; + +/* cipher descriptor table, last entry has "name == NULL" to mark the end of table */ +extern struct _cipher_descriptor { + char *name; + unsigned char ID; + unsigned long min_key_length, max_key_length, block_length, default_rounds; + int (*setup)(const unsigned char *key, int keylength, int num_rounds, symmetric_key *skey); + void (*ecb_encrypt)(const unsigned char *pt, unsigned char *ct, symmetric_key *key); + void (*ecb_decrypt)(const unsigned char *ct, unsigned char *pt, symmetric_key *key); + int (*test)(void); + int (*keysize)(int *desired_keysize); +} cipher_descriptor[]; + +#ifdef BLOWFISH +extern int blowfish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int blowfish_test(void); +extern int blowfish_keysize(int *desired_keysize); +extern const struct _cipher_descriptor blowfish_desc; +#endif + +#ifdef RC5 +extern int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int rc5_test(void); +extern int rc5_keysize(int *desired_keysize); +extern const struct _cipher_descriptor rc5_desc; +#endif + +#ifdef RC6 +extern int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int rc6_test(void); +extern int rc6_keysize(int *desired_keysize); +extern const struct _cipher_descriptor rc6_desc; +#endif + +#ifdef RC2 +extern int rc2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void rc2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void rc2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int rc2_test(void); +extern int rc2_keysize(int *desired_keysize); +extern const struct _cipher_descriptor rc2_desc; +#endif + +#ifdef SAFERP +extern int saferp_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void saferp_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void saferp_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int saferp_test(void); +extern int saferp_keysize(int *desired_keysize); +extern const struct _cipher_descriptor saferp_desc; +#endif + +#ifdef SAFER +extern int safer_k64_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern int safer_sk64_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern int safer_k128_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern int safer_sk128_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void safer_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void safer_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); + +extern int safer_k64_test(void); +extern int safer_sk64_test(void); +extern int safer_sk128_test(void); + +extern int safer_64_keysize(int *desired_keysize); +extern int safer_128_keysize(int *desired_keysize); +extern const struct _cipher_descriptor safer_k64_desc, safer_k128_desc, safer_sk64_desc, safer_sk128_desc; +#endif + +#ifdef SERPENT +extern int serpent_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void serpent_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void serpent_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int serpent_test(void); +extern int serpent_keysize(int *desired_keysize); +extern const struct _cipher_descriptor serpent_desc; +#endif + +#ifdef RIJNDAEL +extern int rijndael_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int rijndael_test(void); +extern int rijndael_keysize(int *desired_keysize); +extern const struct _cipher_descriptor rijndael_desc; +#endif + +#ifdef XTEA +extern int xtea_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void xtea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void xtea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int xtea_test(void); +extern int xtea_keysize(int *desired_keysize); +extern const struct _cipher_descriptor xtea_desc; +#endif + +#ifdef TWOFISH +extern int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int twofish_test(void); +extern int twofish_keysize(int *desired_keysize); +extern const struct _cipher_descriptor twofish_desc; +#endif + +#ifdef DES +extern int des_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int des_test(void); +extern int des_keysize(int *desired_keysize); + +extern int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int des3_test(void); +extern int des3_keysize(int *desired_keysize); + +extern const struct _cipher_descriptor des_desc, des3_desc; +#endif + +#ifdef CAST5 +extern int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int cast5_test(void); +extern int cast5_keysize(int *desired_keysize); +extern const struct _cipher_descriptor cast5_desc; +#endif + +#ifdef ECB +extern int ecb_start(int cipher, const unsigned char *key, + int keylen, int num_rounds, symmetric_ECB *ecb); +extern int ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ECB *ecb); +extern int ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_ECB *ecb); +#endif + +#ifdef CFB +extern int cfb_start(int cipher, const unsigned char *IV, const unsigned char *key, + int keylen, int num_rounds, symmetric_CFB *cfb); +extern int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CFB *cfb); +extern int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CFB *cfb); +#endif + +#ifdef OFB +extern int ofb_start(int cipher, const unsigned char *IV, const unsigned char *key, + int keylen, int num_rounds, symmetric_OFB *ofb); +extern int ofb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_OFB *ofb); +extern int ofb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_OFB *ofb); +#endif + +#ifdef CBC +extern int cbc_start(int cipher, const unsigned char *IV, const unsigned char *key, + int keylen, int num_rounds, symmetric_CBC *cbc); +extern int cbc_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_CBC *cbc); +extern int cbc_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_CBC *cbc); +#endif + +#ifdef CTR +extern int ctr_start(int cipher, const unsigned char *IV, const unsigned char *key, + int keylen, int num_rounds, symmetric_CTR *ctr); +extern int ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CTR *ctr); +extern int ctr_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CTR *ctr); +#endif + +extern int find_cipher(const char *name); +extern int find_cipher_any(const char *name, int blocklen, int keylen); +extern int find_cipher_id(unsigned char ID); + +extern int register_cipher(const struct _cipher_descriptor *cipher); +extern int unregister_cipher(const struct _cipher_descriptor *cipher); + +extern int cipher_is_valid(int idx); + diff --git a/mycrypt_gf.h b/mycrypt_gf.h new file mode 100644 index 0000000..331065d --- /dev/null +++ b/mycrypt_gf.h @@ -0,0 +1,32 @@ + +/* ---- GF(2^w) polynomial basis ---- */ +#ifdef GF +#define LSIZE 32 /* handle upto 1024-bit GF numbers */ + +typedef unsigned long gf_int[LSIZE]; +typedef unsigned long *gf_intp; + +extern void gf_copy(gf_intp a, gf_intp b); +extern void gf_zero(gf_intp a); +extern int gf_iszero(gf_intp a); +extern int gf_isone(gf_intp a); +extern int gf_deg(gf_intp a); + +extern void gf_shl(gf_intp a, gf_intp b); +extern void gf_shr(gf_intp a, gf_intp b); +extern void gf_add(gf_intp a, gf_intp b, gf_intp c); +extern void gf_mul(gf_intp a, gf_intp b, gf_intp c); +extern void gf_div(gf_intp a, gf_intp b, gf_intp q, gf_intp r); + +extern void gf_mod(gf_intp a, gf_intp m, gf_intp b); +extern void gf_mulmod(gf_intp a, gf_intp b, gf_intp m, gf_intp c); +extern void gf_invmod(gf_intp A, gf_intp M, gf_intp B); +extern void gf_sqrt(gf_intp a, gf_intp M, gf_intp b); +extern void gf_gcd(gf_intp A, gf_intp B, gf_intp c); +extern int gf_is_prime(gf_intp a); + +extern int gf_size(gf_intp a); +extern void gf_toraw(gf_intp a, unsigned char *dst); +extern void gf_readraw(gf_intp a, unsigned char *str, int len); + +#endif diff --git a/mycrypt_hash.h b/mycrypt_hash.h new file mode 100644 index 0000000..c6d9771 --- /dev/null +++ b/mycrypt_hash.h @@ -0,0 +1,184 @@ +/* ---- HASH FUNCTIONS ---- */ +#ifdef SHA512 +struct sha512_state { + ulong64 length, state[8]; + unsigned long curlen; + unsigned char buf[128]; +}; +#endif + +#ifdef SHA256 +struct sha256_state { + ulong64 length; + unsigned long state[8], curlen; + unsigned char buf[64]; +}; +#endif + +#ifdef SHA1 +struct sha1_state { + ulong64 length; + unsigned long state[5], curlen; + unsigned char buf[64]; +}; +#endif + +#ifdef MD5 +struct md5_state { + ulong64 length; + unsigned long state[4], curlen; + unsigned char buf[64]; +}; +#endif + +#ifdef MD4 +struct md4_state { + ulong64 length; + unsigned long state[4], curlen; + unsigned char buf[64]; +}; +#endif + +#ifdef TIGER +struct tiger_state { + ulong64 state[3], length; + unsigned long curlen; + unsigned char buf[64]; +}; +#endif + +#ifdef MD2 +struct md2_state { + unsigned char chksum[16], X[48], buf[16]; + unsigned long curlen; +}; +#endif + +typedef union Hash_state { +#ifdef SHA512 + struct sha512_state sha512; +#endif +#ifdef SHA256 + struct sha256_state sha256; +#endif +#ifdef SHA1 + struct sha1_state sha1; +#endif +#ifdef MD5 + struct md5_state md5; +#endif +#ifdef MD4 + struct md4_state md4; +#endif +#ifdef MD2 + struct md2_state md2; +#endif +#ifdef TIGER + struct tiger_state tiger; +#endif +} hash_state; + +extern struct _hash_descriptor { + char *name; + unsigned char ID; + unsigned long hashsize; /* digest output size in bytes */ + unsigned long blocksize; /* the block size the hash uses */ + void (*init)(hash_state *); + void (*process)(hash_state *, const unsigned char *, unsigned long); + void (*done)(hash_state *, unsigned char *); + int (*test)(void); +} hash_descriptor[]; + +#ifdef SHA512 +extern void sha512_init(hash_state * md); +extern void sha512_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern void sha512_done(hash_state * md, unsigned char *hash); +extern int sha512_test(void); +extern const struct _hash_descriptor sha512_desc; +#endif + +#ifdef SHA384 +extern void sha384_init(hash_state * md); +extern void sha384_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern void sha384_done(hash_state * md, unsigned char *hash); +extern int sha384_test(void); +extern const struct _hash_descriptor sha384_desc; +#endif + +#ifdef SHA256 +extern void sha256_init(hash_state * md); +extern void sha256_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern void sha256_done(hash_state * md, unsigned char *hash); +extern int sha256_test(void); +extern const struct _hash_descriptor sha256_desc; +#endif + +#ifdef SHA1 +extern void sha1_init(hash_state * md); +extern void sha1_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern void sha1_done(hash_state * md, unsigned char *hash); +extern int sha1_test(void); +extern const struct _hash_descriptor sha1_desc; +#endif + +#ifdef MD5 +extern void md5_init(hash_state * md); +extern void md5_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern void md5_done(hash_state * md, unsigned char *hash); +extern int md5_test(void); +extern const struct _hash_descriptor md5_desc; +#endif + +#ifdef MD4 +extern void md4_init(hash_state * md); +extern void md4_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern void md4_done(hash_state * md, unsigned char *hash); +extern int md4_test(void); +extern const struct _hash_descriptor md4_desc; +#endif + +#ifdef MD2 +extern void md2_init(hash_state * md); +extern void md2_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern void md2_done(hash_state * md, unsigned char *hash); +extern int md2_test(void); +extern const struct _hash_descriptor md2_desc; +#endif + +#ifdef TIGER +extern void tiger_init(hash_state * md); +extern void tiger_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern void tiger_done(hash_state * md, unsigned char *hash); +extern int tiger_test(void); +extern const struct _hash_descriptor tiger_desc; +#endif + +extern int find_hash(const char *name); +extern int find_hash_id(unsigned char ID); +extern int register_hash(const struct _hash_descriptor *hash); +extern int unregister_hash(const struct _hash_descriptor *hash); +extern int hash_is_valid(int idx); + +extern int hash_memory(int hash, const unsigned char *data, unsigned long len, unsigned char *dst, unsigned long *outlen); +extern int hash_filehandle(int hash, FILE *in, unsigned char *dst, unsigned long *outlen); +extern int hash_file(int hash, const char *fname, unsigned char *dst, unsigned long *outlen); + +#ifdef HMAC +typedef struct Hmac_state { + hash_state md; + int hash; + unsigned long hashsize; /* here for your reference */ + hash_state hashstate; + unsigned char key[MAXBLOCKSIZE]; +} hmac_state; + +extern int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen); +extern int hmac_process(hmac_state *hmac, const unsigned char *buf, unsigned long len); +extern int hmac_done(hmac_state *hmac, unsigned char *hash); +extern int hmac_test(void); +extern int hmac_memory(int hash, const unsigned char *key, unsigned long keylen, + const unsigned char *data, unsigned long len, unsigned char *dst); +extern int hmac_file(int hash, const char *fname, const unsigned char *key, + unsigned long keylen, unsigned char *dst); +#endif + diff --git a/mycrypt_kr.h b/mycrypt_kr.h new file mode 100644 index 0000000..e097a64 --- /dev/null +++ b/mycrypt_kr.h @@ -0,0 +1,77 @@ +#ifdef KR + +#define MAXLEN 256 + +enum { + NON_KEY=0, + RSA_KEY, + DH_KEY, + ECC_KEY +}; + +typedef union { + rsa_key rsa; + dh_key dh; + ecc_key ecc; +} _pk_key; + +typedef struct Pk_key { + int key_type, /* PUBLIC, PRIVATE, PRIVATE_OPTIMIZED */ + system; /* RSA, ECC or DH ? */ + + unsigned char + name[MAXLEN], /* various info's about this key */ + email[MAXLEN], + description[MAXLEN]; + + unsigned long ID; /* CRC32 of the name/email/description together */ + + _pk_key key; + + struct Pk_key *next; /* linked list chain */ +} pk_key; + +extern int kr_init(pk_key **pk); + +extern unsigned long kr_crc(const unsigned char *name, const unsigned char *email, const unsigned char *description); + +extern pk_key *kr_find(pk_key *pk, unsigned long ID); +extern pk_key *kr_find_name(pk_key *pk, const char *name); + +extern int kr_add(pk_key *pk, int key_type, int system, const unsigned char *name, + const unsigned char *email, const unsigned char *description, const _pk_key *key); + +extern int kr_del(pk_key **_pk, unsigned long ID); +extern int kr_clear(pk_key **pk); +extern int kr_make_key(pk_key *pk, prng_state *prng, int wprng, + int system, int keysize, const unsigned char *name, + const unsigned char *email, const unsigned char *description); + +extern int kr_export(pk_key *pk, unsigned long ID, int key_type, unsigned char *out, unsigned long *outlen); +extern int kr_import(pk_key *pk, const unsigned char *in); + +extern int kr_load(pk_key **pk, FILE *in, symmetric_CTR *ctr); +extern int kr_save(pk_key *pk, FILE *out, symmetric_CTR *ctr); + +extern int kr_encrypt_key(pk_key *pk, unsigned long ID, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, int hash); + +extern int kr_decrypt_key(pk_key *pk, const unsigned char *in, + unsigned char *out, unsigned long *outlen); + +extern int kr_sign_hash(pk_key *pk, unsigned long ID, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng); + +extern int kr_verify_hash(pk_key *pk, const unsigned char *in, + const unsigned char *hash, unsigned long hashlen, + int *stat); + +extern int kr_fingerprint(pk_key *pk, unsigned long ID, int hash, + unsigned char *out, unsigned long *outlen); + +#endif + diff --git a/mycrypt_macros.h b/mycrypt_macros.h new file mode 100644 index 0000000..cda6b99 --- /dev/null +++ b/mycrypt_macros.h @@ -0,0 +1,200 @@ +/* fix for MSVC ...evil! */ +#ifdef _MSC_VER + #define CONST64(n) n ## ui64 + typedef unsigned __int64 ulong64; +#else + #define CONST64(n) n ## ULL + typedef unsigned long long ulong64; +#endif + +extern char *crypt_error; + +/* ---- HELPER MACROS ---- */ +#ifdef ENDIAN_NEUTRAL + +#define STORE32L(x, y) \ + { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \ + (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } + +#define LOAD32L(x, y) \ + { x = ((unsigned long)((y)[3] & 255)<<24) | \ + ((unsigned long)((y)[2] & 255)<<16) | \ + ((unsigned long)((y)[1] & 255)<<8) | \ + ((unsigned long)((y)[0] & 255)); } + +#define STORE64L(x, y) \ + { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \ + (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \ + (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \ + (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } + +#define LOAD64L(x, y) \ + { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \ + (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \ + (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \ + (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); } + +#define STORE32H(x, y) \ + { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ + (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } + +#define LOAD32H(x, y) \ + { x = ((unsigned long)((y)[0] & 255)<<24) | \ + ((unsigned long)((y)[1] & 255)<<16) | \ + ((unsigned long)((y)[2] & 255)<<8) | \ + ((unsigned long)((y)[3] & 255)); } + +#define STORE64H(x, y) \ + { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ + (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ + (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ + (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } + +#define LOAD64H(x, y) \ + { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \ + (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \ + (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \ + (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); } + +#endif /* ENDIAN_NEUTRAL */ + +#ifdef ENDIAN_LITTLE + +#define STORE32H(x, y) \ + { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ + (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } + +#define LOAD32H(x, y) \ + { x = ((unsigned long)((y)[0] & 255)<<24) | \ + ((unsigned long)((y)[1] & 255)<<16) | \ + ((unsigned long)((y)[2] & 255)<<8) | \ + ((unsigned long)((y)[3] & 255)); } + +#define STORE64H(x, y) \ + { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ + (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ + (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ + (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } + +#define LOAD64H(x, y) \ + { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \ + (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \ + (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \ + (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); } + +#ifdef ENDIAN_32BITWORD + +#define STORE32L(x, y) \ + { unsigned long t = (x); memcpy(y, &t, 4); } + +#define LOAD32L(x, y) \ + memcpy(&(x), y, 4); + +#define STORE64L(x, y) \ + { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \ + (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \ + (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \ + (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } + +#define LOAD64L(x, y) \ + { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \ + (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \ + (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \ + (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); } + +#else /* 64-bit words then */ + +#define STORE32L(x, y) \ + { unsigned long t = (x); memcpy(y, &t, 4); } + +#define LOAD32L(x, y) \ + { memcpy(&(x), y, 4); x &= 0xFFFFFFFF; } + +#define STORE64L(x, y) \ + { ulong64 t = (x); memcpy(y, &t, 8); } + +#define LOAD64L(x, y) \ + { memcpy(&(x), y, 8); } + +#endif /* ENDIAN_64BITWORD */ + +#endif /* ENDIAN_LITTLE */ + +#ifdef ENDIAN_BIG +#define STORE32L(x, y) \ + { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ + (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } + +#define LOAD32L(x, y) \ + { x = ((unsigned long)((y)[0] & 255)<<24) | \ + ((unsigned long)((y)[1] & 255)<<16) | \ + ((unsigned long)((y)[2] & 255)<<8) | \ + ((unsigned long)((y)[3] & 255)); } + +#define STORE64L(x, y) \ + { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ + (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ + (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ + (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } + +#define LOAD64L(x, y) \ + { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \ + (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \ + (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \ + (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); } + +#ifdef ENDIAN_32BITWORD + +#define STORE32H(x, y) \ + { unsigned long t = (x); memcpy(y, &t, 4); } + +#define LOAD32H(x, y) \ + memcpy(&(x), y, 4); + +#define STORE64H(x, y) \ + { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \ + (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \ + (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \ + (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } + +#define LOAD64H(x, y) \ + { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \ + (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \ + (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \ + (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); } + +#else /* 64-bit words then */ + +#define STORE32H(x, y) \ + { unsigned long t = (x); memcpy(y, &t, 4); } + +#define LOAD32H(x, y) \ + { memcpy(&(x), y, 4); x &= 0xFFFFFFFF; } + +#define STORE64H(x, y) \ + { ulong64 t = (x); memcpy(y, &t, 8); } + +#define LOAD64H(x, y) \ + { memcpy(&(x), y, 8); } + +#endif /* ENDIAN_64BITWORD */ +#endif /* ENDIAN_BIG */ + +#define BSWAP(x) ( ((x>>24)&0x000000FFUL) | ((x<<24)&0xFF000000UL) | \ + ((x>>8)&0x0000FF00UL) | ((x<<8)&0x00FF0000UL) ) + +#define ROL(x, y) ( (((x)<<((y)&31)) | (((x)&0xFFFFFFFFUL)>>(32-((y)&31)))) & 0xFFFFFFFFUL) +#define ROR(x, y) ( ((((x)&0xFFFFFFFFUL)>>((y)&31)) | ((x)<<(32-((y)&31)))) & 0xFFFFFFFFUL) + +#define ROL64(x, y) \ + ( (((x)<<((ulong64)(y)&63)) | \ + (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF)) + +#define ROR64(x, y) \ + ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \ + ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF)) + +#undef MAX +#undef MIN +#define MAX(x, y) ( ((x)>(y))?(x):(y) ) +#define MIN(x, y) ( ((x)<(y))?(x):(y) ) diff --git a/mycrypt_misc.h b/mycrypt_misc.h new file mode 100644 index 0000000..ac4ed07 --- /dev/null +++ b/mycrypt_misc.h @@ -0,0 +1,16 @@ +/* ---- BASE64 Routines ---- */ +#ifdef BASE64 +extern int base64_encode(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen); + +extern int base64_decode(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen); +#endif + +/* ---- MEM routines ---- */ +extern void zeromem(void *dst, unsigned long len); +extern void burn_stack(unsigned long len); + +extern const char *error_to_string(int errno); + +extern const char *crypt_build_settings; diff --git a/mycrypt_pk.h b/mycrypt_pk.h new file mode 100644 index 0000000..941c8bf --- /dev/null +++ b/mycrypt_pk.h @@ -0,0 +1,219 @@ +/* ---- NUMBER THEORY ---- */ +#ifdef MPI + +extern int is_prime(mp_int *, int *); +extern int rand_prime(mp_int *N, long len, prng_state *prng, int wprng); +extern mp_err mp_init_multi(mp_int* mp, ...); +extern void mp_clear_multi(mp_int* mp, ...); + +#endif + +/* ---- PUBLIC KEY CRYPTO ---- */ + +#define PK_PRIVATE 0 /* PK private keys */ +#define PK_PUBLIC 1 /* PK public keys */ +#define PK_PRIVATE_OPTIMIZED 2 /* PK private key [rsa optimized] */ + +/* ---- PACKET ---- */ +#ifdef PACKET + +extern void packet_store_header(unsigned char *dst, int section, int subsection, unsigned long length); +extern int packet_valid_header(unsigned char *src, int section, int subsection); + +#endif + + +/* ---- RSA ---- */ +#ifdef MRSA +typedef struct Rsa_key { + int type; + mp_int e, d, N, qP, pQ, dP, dQ, p, q; +} rsa_key; + +extern int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key); + +extern int rsa_exptmod(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, int which, + rsa_key *key); + +extern int rsa_pad(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + int wprng, prng_state *prng); + +extern int rsa_signpad(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen); + +extern int rsa_depad(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen); + +extern int rsa_signdepad(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen); + + +extern void rsa_free(rsa_key *key); + +#ifdef PK_PACKET + +extern int rsa_encrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, int cipher, + rsa_key *key); + +extern int rsa_decrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + rsa_key *key); + +extern int rsa_sign(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + int hash, rsa_key *key); + +extern int rsa_verify(const unsigned char *sig, const unsigned char *msg, + unsigned long inlen, int *stat, + rsa_key *key); + +#endif + +extern int rsa_encrypt_key(const unsigned char *inkey, unsigned long inlen, + unsigned char *outkey, unsigned long *outlen, + prng_state *prng, int wprng, rsa_key *key); + +extern int rsa_decrypt_key(const unsigned char *in, unsigned char *outkey, + unsigned long *keylen, rsa_key *key); + +extern int rsa_sign_hash(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + rsa_key *key); + +extern int rsa_verify_hash(const unsigned char *sig, const unsigned char *hash, + int *stat, rsa_key *key); + +extern int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key); +extern int rsa_import(const unsigned char *in, rsa_key *key); +#endif + +/* ---- DH Routines ---- */ +#ifdef MDH + +typedef struct Dh_key { + int idx, type; + mp_int x, y; +} dh_key; + +extern int dh_test(void); +extern void dh_sizes(int *low, int *high); +extern int dh_get_size(dh_key *key); + +extern int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key); +extern void dh_free(dh_key *key); + +extern int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key); +extern int dh_import(const unsigned char *in, dh_key *key); + +extern int dh_shared_secret(dh_key *private_key, dh_key *public_key, + unsigned char *out, unsigned long *outlen); + +#ifdef PK_PACKET + +extern int dh_encrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, int cipher, int hash, + dh_key *key); + +extern int dh_decrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + dh_key *key); + +extern int dh_sign(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, int hash, + prng_state *prng, int wprng, + dh_key *key); + +extern int dh_verify(const unsigned char *sig, const unsigned char *msg, + unsigned long inlen, int *stat, + dh_key *key); + +#endif + +extern int dh_encrypt_key(const unsigned char *inkey, unsigned long keylen, + unsigned char *out, unsigned long *len, + prng_state *prng, int wprng, int hash, + dh_key *key); + +extern int dh_decrypt_key(const unsigned char *in, unsigned char *outkey, + unsigned long *keylen, dh_key *key); + +extern int dh_sign_hash(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, dh_key *key); + +extern int dh_verify_hash(const unsigned char *sig, const unsigned char *hash, + unsigned long inlen, int *stat, + dh_key *key); + + +#endif + +/* ---- ECC Routines ---- */ +#ifdef MECC +typedef struct { + mp_int x, y; +} ecc_point; + +typedef struct { + int type, idx; + ecc_point pubkey; + mp_int k; +} ecc_key; + +extern int ecc_test(void); +extern void ecc_sizes(int *low, int *high); +extern int ecc_get_size(ecc_key *key); + +extern int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key); +extern void ecc_free(ecc_key *key); + +extern int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key); +extern int ecc_import(const unsigned char *in, ecc_key *key); + +extern int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, + unsigned char *out, unsigned long *outlen); + +#ifdef PK_PACKET + +extern int ecc_encrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, int cipher, int hash, + ecc_key *key); + +extern int ecc_decrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + ecc_key *key); + +extern int ecc_sign(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, int hash, + prng_state *prng, int wprng, + ecc_key *key); + +extern int ecc_verify(const unsigned char *sig, const unsigned char *msg, + unsigned long inlen, int *stat, + ecc_key *key); + +#endif + +extern int ecc_encrypt_key(const unsigned char *inkey, unsigned long keylen, + unsigned char *out, unsigned long *len, + prng_state *prng, int wprng, int hash, + ecc_key *key); + +extern int ecc_decrypt_key(const unsigned char *in, unsigned char *outkey, + unsigned long *keylen, ecc_key *key); + +extern int ecc_sign_hash(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, ecc_key *key); + +extern int ecc_verify_hash(const unsigned char *sig, const unsigned char *hash, + unsigned long inlen, int *stat, + ecc_key *key); +#endif + diff --git a/mycrypt_prng.h b/mycrypt_prng.h new file mode 100644 index 0000000..f489e16 --- /dev/null +++ b/mycrypt_prng.h @@ -0,0 +1,62 @@ +/* ---- PRNG Stuff ---- */ +struct yarrow_prng { + int cipher, hash; + unsigned char pool[MAXBLOCKSIZE]; + symmetric_CTR ctr; +}; + +struct rc4_prng { + int x, y; + unsigned char buf[256]; +}; + +typedef union Prng_state { + struct yarrow_prng yarrow; + struct rc4_prng rc4; +} prng_state; + +extern struct _prng_descriptor { + char *name; + int (*start)(prng_state *); + int (*add_entropy)(const unsigned char *, unsigned long, prng_state *); + int (*ready)(prng_state *); + unsigned long (*read)(unsigned char *, unsigned long len, prng_state *); +} prng_descriptor[]; + +#ifdef YARROW +extern int yarrow_start(prng_state *prng); +extern int yarrow_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng); +extern int yarrow_ready(prng_state *prng); +extern unsigned long yarrow_read(unsigned char *buf, unsigned long len, prng_state *prng); +extern const struct _prng_descriptor yarrow_desc; +#endif + +#ifdef RC4 +extern int rc4_start(prng_state *prng); +extern int rc4_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng); +extern int rc4_ready(prng_state *prng); +extern unsigned long rc4_read(unsigned char *buf, unsigned long len, prng_state *prng); +extern const struct _prng_descriptor rc4_desc; +#endif + +#ifdef SPRNG +extern int sprng_start(prng_state *prng); +extern int sprng_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng); +extern int sprng_ready(prng_state *prng); +extern unsigned long sprng_read(unsigned char *buf, unsigned long len, prng_state *prng); +extern const struct _prng_descriptor sprng_desc; +#endif + +extern int find_prng(const char *name); +extern int register_prng(const struct _prng_descriptor *prng); +extern int unregister_prng(const struct _prng_descriptor *prng); +extern int prng_is_valid(int idx); + + +/* Slow RNG you **might** be able to use to seed a PRNG with. Be careful as this + * might not work on all platforms as planned + */ +extern unsigned long rng_get_bytes(unsigned char *buf, unsigned long len, void (*callback)(void)); + +extern int rng_make_prng(int bits, int wprng, prng_state *prng, void (*callback)(void)); + diff --git a/notes/tech0001.txt b/notes/tech0001.txt new file mode 100644 index 0000000..980b5f3 --- /dev/null +++ b/notes/tech0001.txt @@ -0,0 +1,73 @@ +Tech Note 0001 +How to Gather Entropy on Embedded Systems +Tom St Denis + +Introduction +------------ + +This tech note explains a relatively simple way to gather entropy for a PRNG (Yarrow in this case) in embedded systems +where there are few sources of entropy or physical sources. + +When trying to setup a secure random number generator a fresh source of random data (entropy) is required to ensure the +deterministic state of the PRNG is not known or predetermined with respect to an attacker. + +At the very least the system requires one timer and one source of un-timed interrupts. by "un-timed" I mean interrupts +that do not occur at regular intervals [e.g. joypad/keypad input, network packets, etc...]. + +First we shall begin by taking an overview of how the Yarrow PRNG works within libtomcrypt. At the heart of all +PRNGs is the "prng_state" data type. This is a union of structures that hold the PRNG state for the various prngs. The +first thing we require is a state... + + prng_state myPrng; + +Next we must initialize the state once to get the ball rolling + + if (yarrow_start(&myPrng) != CRYPT_OK) { + // error should never happen! + } + +At this point the PRNG is ready to accept fresh entropy which is added with + + int yarrow_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng) + +This function is **NOT** thread safe which will come under consideration later. To add entropy to our PRNG we must +call this function with fresh data as its sampled. Lets say we have a timer counter called "uTimer" which is a 32-bit +long and say a 32-bit joyPad state called "uPad". An example interrupt handler would look like + + void joypad_interrupt(...) { + unsigned char buf[8]; + + STORE32L(uTimer, buf); + STORE32L(uPad, buf+4) + if (yarrow_add_entropy(buf, 8, &myPrng) != CRYPT_OK) { + // this should never occur either unless you didn't call yarrow_start + } + + // handle interrupt + } + +In this snippet the timer count and state of the joypad are added together into the entropy pool. The timer is important +because with respect to the joypad it is a good source of entropy (on its own its not). For example, the probability of +the user pushing the up arrow is fairly high, but at a specific time is not. + +This method doesn't gather alot of entropy and has to be used to for quite a while. One way to speed it up is to tap +multiple sources. If you have a network adapter and other sources of events (keyboard, mouse, etc...) trapping their +data is ideal as well. Its important to gather the timer along with the event data. + +As mentioned the "yarrow_add_entropy()" function is not thread safe. If your system allows interrupt handlers to be +interrupted themselves then you could have trouble. One simple way is to detect when an interrupt is in progress and +simply not add entropy during the call (jump over the yarrow_add_entropy() call) + +Once you feel that there has been enough entropy added to the pool then within a single thread you can call + + int yarrow_ready(prng_state *prng) + +Now the PRNG is ready to read via the + + unsigned long yarrow_read(unsigned char *buf, unsigned long len, prng_state *prng) + +It is a very good idea that once you call the yarrow_ready() function that you stop harvesting entropy in your interrupt +functions. This will free up alot of CPU time. Also one more final note. The yarrow_read() function is not thread +safe either. This means if you have multiple threads or processes that read from it you will have to add your own semaphores +around calls to it. + diff --git a/ofb.c b/ofb.c new file mode 100644 index 0000000..adef476 --- /dev/null +++ b/ofb.c @@ -0,0 +1,60 @@ +#include "mycrypt.h" + +#ifdef OFB + +int ofb_start(int cipher, const unsigned char *IV, const unsigned char *key, + int keylen, int num_rounds, symmetric_OFB *ofb) +{ + int x, errno; + + _ARGCHK(IV != NULL); + _ARGCHK(key != NULL); + _ARGCHK(ofb != NULL); + + if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) { + return errno; + } + + /* copy details */ + ofb->cipher = cipher; + ofb->blocklen = cipher_descriptor[cipher].block_length; + for (x = 0; x < ofb->blocklen; x++) { + ofb->IV[x] = IV[x]; + } + + /* init the cipher */ + ofb->padlen = ofb->blocklen; + return cipher_descriptor[cipher].setup(key, keylen, num_rounds, &ofb->key); +} + +int ofb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_OFB *ofb) +{ + int errno; + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(ofb != NULL); + if ((errno = cipher_is_valid(ofb->cipher)) != CRYPT_OK) { + return errno; + } + while (len--) { + if (ofb->padlen == ofb->blocklen) { + cipher_descriptor[ofb->cipher].ecb_encrypt(ofb->IV, ofb->IV, &ofb->key); + ofb->padlen = 0; + } + *ct++ = *pt++ ^ ofb->IV[ofb->padlen++]; + } + return CRYPT_OK; +} + +int ofb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_OFB *ofb) +{ + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(ofb != NULL); + return ofb_encrypt(ct, pt, len, ofb); +} + + +#endif + + diff --git a/packet.c b/packet.c new file mode 100644 index 0000000..5ff054e --- /dev/null +++ b/packet.c @@ -0,0 +1,43 @@ +#include "mycrypt.h" + +#ifdef PACKET + +void packet_store_header(unsigned char *dst, int section, int subsection, unsigned long length) +{ + _ARGCHK(dst != NULL); + + /* store version number */ + dst[0] = CRYPT&255; + dst[1] = (CRYPT>>8)&255; + + /* store section and subsection */ + dst[2] = section & 255; + dst[3] = subsection & 255; + + /* store length */ + STORE32L(length, &dst[4]); +} + +int packet_valid_header(unsigned char *src, int section, int subsection) +{ + unsigned long ver; + + _ARGCHK(src != NULL); + + /* check version */ + ver = ((unsigned long)src[0]) | ((unsigned long)src[1] << 8); + if (CRYPT < ver) { + return CRYPT_INVALID_PACKET; + } + + /* check section and subsection */ + if (section != src[2] || subsection != src[3]) { + return CRYPT_INVALID_PACKET; + } + + return CRYPT_OK; +} + +#endif + + diff --git a/prime.c b/prime.c new file mode 100644 index 0000000..e60a0cc --- /dev/null +++ b/prime.c @@ -0,0 +1,1008 @@ +#include "mycrypt.h" + +#ifdef MPI + +#ifdef SMALL_PRIME_TAB +static const mp_digit prime_tab[] = { + 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, + 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, + 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, + 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083, + 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, + 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, + 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, + 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137 }; +#else +static const mp_digit prime_tab[] = { + 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, + 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, + 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, + 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083, + 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, + 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, + 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, + 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, + + 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, + 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, + 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, + 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, + 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, + 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, + 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, + 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, + + 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, + 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, + 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, + 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, + 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, + 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, + 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, + 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, + 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, + 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, + 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, + 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, + 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, + 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, + 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, + 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653, + 0x0655, 0x065B, 0x0665, 0x0679, 0x067F, 0x0683, 0x0685, 0x069D, + 0x06A1, 0x06A3, 0x06AD, 0x06B9, 0x06BB, 0x06C5, 0x06CD, 0x06D3, + 0x06D9, 0x06DF, 0x06F1, 0x06F7, 0x06FB, 0x06FD, 0x0709, 0x0713, + 0x071F, 0x0727, 0x0737, 0x0745, 0x074B, 0x074F, 0x0751, 0x0755, + 0x0757, 0x0761, 0x076D, 0x0773, 0x0779, 0x078B, 0x078D, 0x079D, + 0x079F, 0x07B5, 0x07BB, 0x07C3, 0x07C9, 0x07CD, 0x07CF, 0x07D3, + 0x07DB, 0x07E1, 0x07EB, 0x07ED, 0x07F7, 0x0805, 0x080F, 0x0815, + 0x0821, 0x0823, 0x0827, 0x0829, 0x0833, 0x083F, 0x0841, 0x0851, + 0x0853, 0x0859, 0x085D, 0x085F, 0x0869, 0x0871, 0x0883, 0x089B, + 0x089F, 0x08A5, 0x08AD, 0x08BD, 0x08BF, 0x08C3, 0x08CB, 0x08DB, + 0x08DD, 0x08E1, 0x08E9, 0x08EF, 0x08F5, 0x08F9, 0x0905, 0x0907, + 0x091D, 0x0923, 0x0925, 0x092B, 0x092F, 0x0935, 0x0943, 0x0949, + 0x094D, 0x094F, 0x0955, 0x0959, 0x095F, 0x096B, 0x0971, 0x0977, + 0x0985, 0x0989, 0x098F, 0x099B, 0x09A3, 0x09A9, 0x09AD, 0x09C7, + 0x09D9, 0x09E3, 0x09EB, 0x09EF, 0x09F5, 0x09F7, 0x09FD, 0x0A13, + 0x0A1F, 0x0A21, 0x0A31, 0x0A39, 0x0A3D, 0x0A49, 0x0A57, 0x0A61, + 0x0A63, 0x0A67, 0x0A6F, 0x0A75, 0x0A7B, 0x0A7F, 0x0A81, 0x0A85, + 0x0A8B, 0x0A93, 0x0A97, 0x0A99, 0x0A9F, 0x0AA9, 0x0AAB, 0x0AB5, + 0x0ABD, 0x0AC1, 0x0ACF, 0x0AD9, 0x0AE5, 0x0AE7, 0x0AED, 0x0AF1, + 0x0AF3, 0x0B03, 0x0B11, 0x0B15, 0x0B1B, 0x0B23, 0x0B29, 0x0B2D, + 0x0B3F, 0x0B47, 0x0B51, 0x0B57, 0x0B5D, 0x0B65, 0x0B6F, 0x0B7B, + 0x0B89, 0x0B8D, 0x0B93, 0x0B99, 0x0B9B, 0x0BB7, 0x0BB9, 0x0BC3, + 0x0BCB, 0x0BCF, 0x0BDD, 0x0BE1, 0x0BE9, 0x0BF5, 0x0BFB, 0x0C07, + 0x0C0B, 0x0C11, 0x0C25, 0x0C2F, 0x0C31, 0x0C41, 0x0C5B, 0x0C5F, + 0x0C61, 0x0C6D, 0x0C73, 0x0C77, 0x0C83, 0x0C89, 0x0C91, 0x0C95, + 0x0C9D, 0x0CB3, 0x0CB5, 0x0CB9, 0x0CBB, 0x0CC7, 0x0CE3, 0x0CE5, + 0x0CEB, 0x0CF1, 0x0CF7, 0x0CFB, 0x0D01, 0x0D03, 0x0D0F, 0x0D13, + 0x0D1F, 0x0D21, 0x0D2B, 0x0D2D, 0x0D3D, 0x0D3F, 0x0D4F, 0x0D55, + 0x0D69, 0x0D79, 0x0D81, 0x0D85, 0x0D87, 0x0D8B, 0x0D8D, 0x0DA3, + 0x0DAB, 0x0DB7, 0x0DBD, 0x0DC7, 0x0DC9, 0x0DCD, 0x0DD3, 0x0DD5, + 0x0DDB, 0x0DE5, 0x0DE7, 0x0DF3, 0x0DFD, 0x0DFF, 0x0E09, 0x0E17, + 0x0E1D, 0x0E21, 0x0E27, 0x0E2F, 0x0E35, 0x0E3B, 0x0E4B, 0x0E57, + 0x0E59, 0x0E5D, 0x0E6B, 0x0E71, 0x0E75, 0x0E7D, 0x0E87, 0x0E8F, + 0x0E95, 0x0E9B, 0x0EB1, 0x0EB7, 0x0EB9, 0x0EC3, 0x0ED1, 0x0ED5, + 0x0EDB, 0x0EED, 0x0EEF, 0x0EF9, 0x0F07, 0x0F0B, 0x0F0D, 0x0F17, + 0x0F25, 0x0F29, 0x0F31, 0x0F43, 0x0F47, 0x0F4D, 0x0F4F, 0x0F53, + 0x0F59, 0x0F5B, 0x0F67, 0x0F6B, 0x0F7F, 0x0F95, 0x0FA1, 0x0FA3, + 0x0FA7, 0x0FAD, 0x0FB3, 0x0FB5, 0x0FBB, 0x0FD1, 0x0FD3, 0x0FD9, + 0x0FE9, 0x0FEF, 0x0FFB, 0x0FFD, 0x1003, 0x100F, 0x101F, 0x1021, + 0x1025, 0x102B, 0x1039, 0x103D, 0x103F, 0x1051, 0x1069, 0x1073, + 0x1079, 0x107B, 0x1085, 0x1087, 0x1091, 0x1093, 0x109D, 0x10A3, + 0x10A5, 0x10AF, 0x10B1, 0x10BB, 0x10C1, 0x10C9, 0x10E7, 0x10F1, + 0x10F3, 0x10FD, 0x1105, 0x110B, 0x1115, 0x1127, 0x112D, 0x1139, + 0x1145, 0x1147, 0x1159, 0x115F, 0x1163, 0x1169, 0x116F, 0x1181, + 0x1183, 0x118D, 0x119B, 0x11A1, 0x11A5, 0x11A7, 0x11AB, 0x11C3, + 0x11C5, 0x11D1, 0x11D7, 0x11E7, 0x11EF, 0x11F5, 0x11FB, 0x120D, + 0x121D, 0x121F, 0x1223, 0x1229, 0x122B, 0x1231, 0x1237, 0x1241, + 0x1247, 0x1253, 0x125F, 0x1271, 0x1273, 0x1279, 0x127D, 0x128F, + 0x1297, 0x12AF, 0x12B3, 0x12B5, 0x12B9, 0x12BF, 0x12C1, 0x12CD, + 0x12D1, 0x12DF, 0x12FD, 0x1307, 0x130D, 0x1319, 0x1327, 0x132D, + 0x1337, 0x1343, 0x1345, 0x1349, 0x134F, 0x1357, 0x135D, 0x1367, + 0x1369, 0x136D, 0x137B, 0x1381, 0x1387, 0x138B, 0x1391, 0x1393, + 0x139D, 0x139F, 0x13AF, 0x13BB, 0x13C3, 0x13D5, 0x13D9, 0x13DF, + 0x13EB, 0x13ED, 0x13F3, 0x13F9, 0x13FF, 0x141B, 0x1421, 0x142F, + 0x1433, 0x143B, 0x1445, 0x144D, 0x1459, 0x146B, 0x146F, 0x1471, + 0x1475, 0x148D, 0x1499, 0x149F, 0x14A1, 0x14B1, 0x14B7, 0x14BD, + 0x14CB, 0x14D5, 0x14E3, 0x14E7, 0x1505, 0x150B, 0x1511, 0x1517, + 0x151F, 0x1525, 0x1529, 0x152B, 0x1537, 0x153D, 0x1541, 0x1543, + 0x1549, 0x155F, 0x1565, 0x1567, 0x156B, 0x157D, 0x157F, 0x1583, + 0x158F, 0x1591, 0x1597, 0x159B, 0x15B5, 0x15BB, 0x15C1, 0x15C5, + 0x15CD, 0x15D7, 0x15F7, 0x1607, 0x1609, 0x160F, 0x1613, 0x1615, + 0x1619, 0x161B, 0x1625, 0x1633, 0x1639, 0x163D, 0x1645, 0x164F, + 0x1655, 0x1669, 0x166D, 0x166F, 0x1675, 0x1693, 0x1697, 0x169F, + 0x16A9, 0x16AF, 0x16B5, 0x16BD, 0x16C3, 0x16CF, 0x16D3, 0x16D9, + 0x16DB, 0x16E1, 0x16E5, 0x16EB, 0x16ED, 0x16F7, 0x16F9, 0x1709, + 0x170F, 0x1723, 0x1727, 0x1733, 0x1741, 0x175D, 0x1763, 0x1777, + 0x177B, 0x178D, 0x1795, 0x179B, 0x179F, 0x17A5, 0x17B3, 0x17B9, + 0x17BF, 0x17C9, 0x17CB, 0x17D5, 0x17E1, 0x17E9, 0x17F3, 0x17F5, + 0x17FF, 0x1807, 0x1813, 0x181D, 0x1835, 0x1837, 0x183B, 0x1843, + 0x1849, 0x184D, 0x1855, 0x1867, 0x1871, 0x1877, 0x187D, 0x187F, + 0x1885, 0x188F, 0x189B, 0x189D, 0x18A7, 0x18AD, 0x18B3, 0x18B9, + 0x18C1, 0x18C7, 0x18D1, 0x18D7, 0x18D9, 0x18DF, 0x18E5, 0x18EB, + 0x18F5, 0x18FD, 0x1915, 0x191B, 0x1931, 0x1933, 0x1945, 0x1949, + 0x1951, 0x195B, 0x1979, 0x1981, 0x1993, 0x1997, 0x1999, 0x19A3, + 0x19A9, 0x19AB, 0x19B1, 0x19B5, 0x19C7, 0x19CF, 0x19DB, 0x19ED, + 0x19FD, 0x1A03, 0x1A05, 0x1A11, 0x1A17, 0x1A21, 0x1A23, 0x1A2D, + 0x1A2F, 0x1A35, 0x1A3F, 0x1A4D, 0x1A51, 0x1A69, 0x1A6B, 0x1A7B, + 0x1A7D, 0x1A87, 0x1A89, 0x1A93, 0x1AA7, 0x1AAB, 0x1AAD, 0x1AB1, + 0x1AB9, 0x1AC9, 0x1ACF, 0x1AD5, 0x1AD7, 0x1AE3, 0x1AF3, 0x1AFB, + 0x1AFF, 0x1B05, 0x1B23, 0x1B25, 0x1B2F, 0x1B31, 0x1B37, 0x1B3B, + 0x1B41, 0x1B47, 0x1B4F, 0x1B55, 0x1B59, 0x1B65, 0x1B6B, 0x1B73, + 0x1B7F, 0x1B83, 0x1B91, 0x1B9D, 0x1BA7, 0x1BBF, 0x1BC5, 0x1BD1, + 0x1BD7, 0x1BD9, 0x1BEF, 0x1BF7, 0x1C09, 0x1C13, 0x1C19, 0x1C27, + 0x1C2B, 0x1C2D, 0x1C33, 0x1C3D, 0x1C45, 0x1C4B, 0x1C4F, 0x1C55, + 0x1C73, 0x1C81, 0x1C8B, 0x1C8D, 0x1C99, 0x1CA3, 0x1CA5, 0x1CB5, + 0x1CB7, 0x1CC9, 0x1CE1, 0x1CF3, 0x1CF9, 0x1D09, 0x1D1B, 0x1D21, + 0x1D23, 0x1D35, 0x1D39, 0x1D3F, 0x1D41, 0x1D4B, 0x1D53, 0x1D5D, + 0x1D63, 0x1D69, 0x1D71, 0x1D75, 0x1D7B, 0x1D7D, 0x1D87, 0x1D89, + 0x1D95, 0x1D99, 0x1D9F, 0x1DA5, 0x1DA7, 0x1DB3, 0x1DB7, 0x1DC5, + 0x1DD7, 0x1DDB, 0x1DE1, 0x1DF5, 0x1DF9, 0x1E01, 0x1E07, 0x1E0B, + 0x1E13, 0x1E17, 0x1E25, 0x1E2B, 0x1E2F, 0x1E3D, 0x1E49, 0x1E4D, + 0x1E4F, 0x1E6D, 0x1E71, 0x1E89, 0x1E8F, 0x1E95, 0x1EA1, 0x1EAD, + 0x1EBB, 0x1EC1, 0x1EC5, 0x1EC7, 0x1ECB, 0x1EDD, 0x1EE3, 0x1EEF, + 0x1EF7, 0x1EFD, 0x1F01, 0x1F0D, 0x1F0F, 0x1F1B, 0x1F39, 0x1F49, + 0x1F4B, 0x1F51, 0x1F67, 0x1F75, 0x1F7B, 0x1F85, 0x1F91, 0x1F97, + 0x1F99, 0x1F9D, 0x1FA5, 0x1FAF, 0x1FB5, 0x1FBB, 0x1FD3, 0x1FE1, + 0x1FE7, 0x1FEB, 0x1FF3, 0x1FFF, 0x2011, 0x201B, 0x201D, 0x2027, + 0x2029, 0x202D, 0x2033, 0x2047, 0x204D, 0x2051, 0x205F, 0x2063, + 0x2065, 0x2069, 0x2077, 0x207D, 0x2089, 0x20A1, 0x20AB, 0x20B1, + 0x20B9, 0x20C3, 0x20C5, 0x20E3, 0x20E7, 0x20ED, 0x20EF, 0x20FB, + 0x20FF, 0x210D, 0x2113, 0x2135, 0x2141, 0x2149, 0x214F, 0x2159, + 0x215B, 0x215F, 0x2173, 0x217D, 0x2185, 0x2195, 0x2197, 0x21A1, + 0x21AF, 0x21B3, 0x21B5, 0x21C1, 0x21C7, 0x21D7, 0x21DD, 0x21E5, + 0x21E9, 0x21F1, 0x21F5, 0x21FB, 0x2203, 0x2209, 0x220F, 0x221B, + 0x2221, 0x2225, 0x222B, 0x2231, 0x2239, 0x224B, 0x224F, 0x2263, + 0x2267, 0x2273, 0x2275, 0x227F, 0x2285, 0x2287, 0x2291, 0x229D, + 0x229F, 0x22A3, 0x22B7, 0x22BD, 0x22DB, 0x22E1, 0x22E5, 0x22ED, + 0x22F7, 0x2303, 0x2309, 0x230B, 0x2327, 0x2329, 0x232F, 0x2333, + 0x2335, 0x2345, 0x2351, 0x2353, 0x2359, 0x2363, 0x236B, 0x2383, + 0x238F, 0x2395, 0x23A7, 0x23AD, 0x23B1, 0x23BF, 0x23C5, 0x23C9, + 0x23D5, 0x23DD, 0x23E3, 0x23EF, 0x23F3, 0x23F9, 0x2405, 0x240B, + 0x2417, 0x2419, 0x2429, 0x243D, 0x2441, 0x2443, 0x244D, 0x245F, + 0x2467, 0x246B, 0x2479, 0x247D, 0x247F, 0x2485, 0x249B, 0x24A1, + 0x24AF, 0x24B5, 0x24BB, 0x24C5, 0x24CB, 0x24CD, 0x24D7, 0x24D9, + 0x24DD, 0x24DF, 0x24F5, 0x24F7, 0x24FB, 0x2501, 0x2507, 0x2513, + 0x2519, 0x2527, 0x2531, 0x253D, 0x2543, 0x254B, 0x254F, 0x2573, + 0x2581, 0x258D, 0x2593, 0x2597, 0x259D, 0x259F, 0x25AB, 0x25B1, + 0x25BD, 0x25CD, 0x25CF, 0x25D9, 0x25E1, 0x25F7, 0x25F9, 0x2605, + 0x260B, 0x260F, 0x2615, 0x2627, 0x2629, 0x2635, 0x263B, 0x263F, + 0x264B, 0x2653, 0x2659, 0x2665, 0x2669, 0x266F, 0x267B, 0x2681, + 0x2683, 0x268F, 0x269B, 0x269F, 0x26AD, 0x26B3, 0x26C3, 0x26C9, + 0x26CB, 0x26D5, 0x26DD, 0x26EF, 0x26F5, 0x2717, 0x2719, 0x2735, + 0x2737, 0x274D, 0x2753, 0x2755, 0x275F, 0x276B, 0x276D, 0x2773, + 0x2777, 0x277F, 0x2795, 0x279B, 0x279D, 0x27A7, 0x27AF, 0x27B3, + 0x27B9, 0x27C1, 0x27C5, 0x27D1, 0x27E3, 0x27EF, 0x2803, 0x2807, + 0x280D, 0x2813, 0x281B, 0x281F, 0x2821, 0x2831, 0x283D, 0x283F, + 0x2849, 0x2851, 0x285B, 0x285D, 0x2861, 0x2867, 0x2875, 0x2881, + 0x2897, 0x289F, 0x28BB, 0x28BD, 0x28C1, 0x28D5, 0x28D9, 0x28DB, + 0x28DF, 0x28ED, 0x28F7, 0x2903, 0x2905, 0x2911, 0x2921, 0x2923, + 0x293F, 0x2947, 0x295D, 0x2965, 0x2969, 0x296F, 0x2975, 0x2983, + 0x2987, 0x298F, 0x299B, 0x29A1, 0x29A7, 0x29AB, 0x29BF, 0x29C3, + 0x29D5, 0x29D7, 0x29E3, 0x29E9, 0x29ED, 0x29F3, 0x2A01, 0x2A13, + 0x2A1D, 0x2A25, 0x2A2F, 0x2A4F, 0x2A55, 0x2A5F, 0x2A65, 0x2A6B, + 0x2A6D, 0x2A73, 0x2A83, 0x2A89, 0x2A8B, 0x2A97, 0x2A9D, 0x2AB9, + 0x2ABB, 0x2AC5, 0x2ACD, 0x2ADD, 0x2AE3, 0x2AEB, 0x2AF1, 0x2AFB, + 0x2B13, 0x2B27, 0x2B31, 0x2B33, 0x2B3D, 0x2B3F, 0x2B4B, 0x2B4F, + 0x2B55, 0x2B69, 0x2B6D, 0x2B6F, 0x2B7B, 0x2B8D, 0x2B97, 0x2B99, + 0x2BA3, 0x2BA5, 0x2BA9, 0x2BBD, 0x2BCD, 0x2BE7, 0x2BEB, 0x2BF3, + 0x2BF9, 0x2BFD, 0x2C09, 0x2C0F, 0x2C17, 0x2C23, 0x2C2F, 0x2C35, + 0x2C39, 0x2C41, 0x2C57, 0x2C59, 0x2C69, 0x2C77, 0x2C81, 0x2C87, + 0x2C93, 0x2C9F, 0x2CAD, 0x2CB3, 0x2CB7, 0x2CCB, 0x2CCF, 0x2CDB, + 0x2CE1, 0x2CE3, 0x2CE9, 0x2CEF, 0x2CFF, 0x2D07, 0x2D1D, 0x2D1F, + 0x2D3B, 0x2D43, 0x2D49, 0x2D4D, 0x2D61, 0x2D65, 0x2D71, 0x2D89, + 0x2D9D, 0x2DA1, 0x2DA9, 0x2DB3, 0x2DB5, 0x2DC5, 0x2DC7, 0x2DD3, + 0x2DDF, 0x2E01, 0x2E03, 0x2E07, 0x2E0D, 0x2E19, 0x2E1F, 0x2E25, + 0x2E2D, 0x2E33, 0x2E37, 0x2E39, 0x2E3F, 0x2E57, 0x2E5B, 0x2E6F, + 0x2E79, 0x2E7F, 0x2E85, 0x2E93, 0x2E97, 0x2E9D, 0x2EA3, 0x2EA5, + 0x2EB1, 0x2EB7, 0x2EC1, 0x2EC3, 0x2ECD, 0x2ED3, 0x2EE7, 0x2EEB, + 0x2F05, 0x2F09, 0x2F0B, 0x2F11, 0x2F27, 0x2F29, 0x2F41, 0x2F45, + 0x2F4B, 0x2F4D, 0x2F51, 0x2F57, 0x2F6F, 0x2F75, 0x2F7D, 0x2F81, + 0x2F83, 0x2FA5, 0x2FAB, 0x2FB3, 0x2FC3, 0x2FCF, 0x2FD1, 0x2FDB, + 0x2FDD, 0x2FE7, 0x2FED, 0x2FF5, 0x2FF9, 0x3001, 0x300D, 0x3023, + 0x3029, 0x3037, 0x303B, 0x3055, 0x3059, 0x305B, 0x3067, 0x3071, + 0x3079, 0x307D, 0x3085, 0x3091, 0x3095, 0x30A3, 0x30A9, 0x30B9, + 0x30BF, 0x30C7, 0x30CB, 0x30D1, 0x30D7, 0x30DF, 0x30E5, 0x30EF, + 0x30FB, 0x30FD, 0x3103, 0x3109, 0x3119, 0x3121, 0x3127, 0x312D, + 0x3139, 0x3143, 0x3145, 0x314B, 0x315D, 0x3161, 0x3167, 0x316D, + 0x3173, 0x317F, 0x3191, 0x3199, 0x319F, 0x31A9, 0x31B1, 0x31C3, + 0x31C7, 0x31D5, 0x31DB, 0x31ED, 0x31F7, 0x31FF, 0x3209, 0x3215, + 0x3217, 0x321D, 0x3229, 0x3235, 0x3259, 0x325D, 0x3263, 0x326B, + 0x326F, 0x3275, 0x3277, 0x327B, 0x328D, 0x3299, 0x329F, 0x32A7, + 0x32AD, 0x32B3, 0x32B7, 0x32C9, 0x32CB, 0x32CF, 0x32D1, 0x32E9, + 0x32ED, 0x32F3, 0x32F9, 0x3307, 0x3325, 0x332B, 0x332F, 0x3335, + 0x3341, 0x3347, 0x335B, 0x335F, 0x3367, 0x336B, 0x3373, 0x3379, + 0x337F, 0x3383, 0x33A1, 0x33A3, 0x33AD, 0x33B9, 0x33C1, 0x33CB, + 0x33D3, 0x33EB, 0x33F1, 0x33FD, 0x3401, 0x340F, 0x3413, 0x3419, + 0x341B, 0x3437, 0x3445, 0x3455, 0x3457, 0x3463, 0x3469, 0x346D, + 0x3481, 0x348B, 0x3491, 0x3497, 0x349D, 0x34A5, 0x34AF, 0x34BB, + 0x34C9, 0x34D3, 0x34E1, 0x34F1, 0x34FF, 0x3509, 0x3517, 0x351D, + 0x352D, 0x3533, 0x353B, 0x3541, 0x3551, 0x3565, 0x356F, 0x3571, + 0x3577, 0x357B, 0x357D, 0x3581, 0x358D, 0x358F, 0x3599, 0x359B, + 0x35A1, 0x35B7, 0x35BD, 0x35BF, 0x35C3, 0x35D5, 0x35DD, 0x35E7, + 0x35EF, 0x3605, 0x3607, 0x3611, 0x3623, 0x3631, 0x3635, 0x3637, + 0x363B, 0x364D, 0x364F, 0x3653, 0x3659, 0x3661, 0x366B, 0x366D, + 0x368B, 0x368F, 0x36AD, 0x36AF, 0x36B9, 0x36BB, 0x36CD, 0x36D1, + 0x36E3, 0x36E9, 0x36F7, 0x3701, 0x3703, 0x3707, 0x371B, 0x373F, + 0x3745, 0x3749, 0x374F, 0x375D, 0x3761, 0x3775, 0x377F, 0x378D, + 0x37A3, 0x37A9, 0x37AB, 0x37C9, 0x37D5, 0x37DF, 0x37F1, 0x37F3, + 0x37F7, 0x3805, 0x380B, 0x3821, 0x3833, 0x3835, 0x3841, 0x3847, + 0x384B, 0x3853, 0x3857, 0x385F, 0x3865, 0x386F, 0x3871, 0x387D, + 0x388F, 0x3899, 0x38A7, 0x38B7, 0x38C5, 0x38C9, 0x38CF, 0x38D5, + 0x38D7, 0x38DD, 0x38E1, 0x38E3, 0x38FF, 0x3901, 0x391D, 0x3923, + 0x3925, 0x3929, 0x392F, 0x393D, 0x3941, 0x394D, 0x395B, 0x396B, + 0x3979, 0x397D, 0x3983, 0x398B, 0x3991, 0x3995, 0x399B, 0x39A1, + 0x39A7, 0x39AF, 0x39B3, 0x39BB, 0x39BF, 0x39CD, 0x39DD, 0x39E5, + 0x39EB, 0x39EF, 0x39FB, 0x3A03, 0x3A13, 0x3A15, 0x3A1F, 0x3A27, + 0x3A2B, 0x3A31, 0x3A4B, 0x3A51, 0x3A5B, 0x3A63, 0x3A67, 0x3A6D, + 0x3A79, 0x3A87, 0x3AA5, 0x3AA9, 0x3AB7, 0x3ACD, 0x3AD5, 0x3AE1, + 0x3AE5, 0x3AEB, 0x3AF3, 0x3AFD, 0x3B03, 0x3B11, 0x3B1B, 0x3B21, + 0x3B23, 0x3B2D, 0x3B39, 0x3B45, 0x3B53, 0x3B59, 0x3B5F, 0x3B71, + 0x3B7B, 0x3B81, 0x3B89, 0x3B9B, 0x3B9F, 0x3BA5, 0x3BA7, 0x3BAD, + 0x3BB7, 0x3BB9, 0x3BC3, 0x3BCB, 0x3BD1, 0x3BD7, 0x3BE1, 0x3BE3, + 0x3BF5, 0x3BFF, 0x3C01, 0x3C0D, 0x3C11, 0x3C17, 0x3C1F, 0x3C29, + 0x3C35, 0x3C43, 0x3C4F, 0x3C53, 0x3C5B, 0x3C65, 0x3C6B, 0x3C71, + 0x3C85, 0x3C89, 0x3C97, 0x3CA7, 0x3CB5, 0x3CBF, 0x3CC7, 0x3CD1, + 0x3CDD, 0x3CDF, 0x3CF1, 0x3CF7, 0x3D03, 0x3D0D, 0x3D19, 0x3D1B, + 0x3D1F, 0x3D21, 0x3D2D, 0x3D33, 0x3D37, 0x3D3F, 0x3D43, 0x3D6F, + 0x3D73, 0x3D75, 0x3D79, 0x3D7B, 0x3D85, 0x3D91, 0x3D97, 0x3D9D, + 0x3DAB, 0x3DAF, 0x3DB5, 0x3DBB, 0x3DC1, 0x3DC9, 0x3DCF, 0x3DF3, + 0x3E05, 0x3E09, 0x3E0F, 0x3E11, 0x3E1D, 0x3E23, 0x3E29, 0x3E2F, + 0x3E33, 0x3E41, 0x3E57, 0x3E63, 0x3E65, 0x3E77, 0x3E81, 0x3E87, + 0x3EA1, 0x3EB9, 0x3EBD, 0x3EBF, 0x3EC3, 0x3EC5, 0x3EC9, 0x3ED7, + 0x3EDB, 0x3EE1, 0x3EE7, 0x3EEF, 0x3EFF, 0x3F0B, 0x3F0D, 0x3F37, + 0x3F3B, 0x3F3D, 0x3F41, 0x3F59, 0x3F5F, 0x3F65, 0x3F67, 0x3F79, + 0x3F7D, 0x3F8B, 0x3F91, 0x3FAD, 0x3FBF, 0x3FCD, 0x3FD3, 0x3FDD, + 0x3FE9, 0x3FEB, 0x3FF1, 0x3FFD, 0x401B, 0x4021, 0x4025, 0x402B, + 0x4031, 0x403F, 0x4043, 0x4045, 0x405D, 0x4061, 0x4067, 0x406D, + 0x4087, 0x4091, 0x40A3, 0x40A9, 0x40B1, 0x40B7, 0x40BD, 0x40DB, + 0x40DF, 0x40EB, 0x40F7, 0x40F9, 0x4109, 0x410B, 0x4111, 0x4115, + 0x4121, 0x4133, 0x4135, 0x413B, 0x413F, 0x4159, 0x4165, 0x416B, + 0x4177, 0x417B, 0x4193, 0x41AB, 0x41B7, 0x41BD, 0x41BF, 0x41CB, + 0x41E7, 0x41EF, 0x41F3, 0x41F9, 0x4205, 0x4207, 0x4219, 0x421F, + 0x4223, 0x4229, 0x422F, 0x4243, 0x4253, 0x4255, 0x425B, 0x4261, + 0x4273, 0x427D, 0x4283, 0x4285, 0x4289, 0x4291, 0x4297, 0x429D, + 0x42B5, 0x42C5, 0x42CB, 0x42D3, 0x42DD, 0x42E3, 0x42F1, 0x4307, + 0x430F, 0x431F, 0x4325, 0x4327, 0x4333, 0x4337, 0x4339, 0x434F, + 0x4357, 0x4369, 0x438B, 0x438D, 0x4393, 0x43A5, 0x43A9, 0x43AF, + 0x43B5, 0x43BD, 0x43C7, 0x43CF, 0x43E1, 0x43E7, 0x43EB, 0x43ED, + 0x43F1, 0x43F9, 0x4409, 0x440B, 0x4417, 0x4423, 0x4429, 0x443B, + 0x443F, 0x4445, 0x444B, 0x4451, 0x4453, 0x4459, 0x4465, 0x446F, + 0x4483, 0x448F, 0x44A1, 0x44A5, 0x44AB, 0x44AD, 0x44BD, 0x44BF, + 0x44C9, 0x44D7, 0x44DB, 0x44F9, 0x44FB, 0x4505, 0x4511, 0x4513, + 0x452B, 0x4531, 0x4541, 0x4549, 0x4553, 0x4555, 0x4561, 0x4577, + 0x457D, 0x457F, 0x458F, 0x45A3, 0x45AD, 0x45AF, 0x45BB, 0x45C7, + 0x45D9, 0x45E3, 0x45EF, 0x45F5, 0x45F7, 0x4601, 0x4603, 0x4609, + 0x4613, 0x4625, 0x4627, 0x4633, 0x4639, 0x463D, 0x4643, 0x4645, + 0x465D, 0x4679, 0x467B, 0x467F, 0x4681, 0x468B, 0x468D, 0x469D, + 0x46A9, 0x46B1, 0x46C7, 0x46C9, 0x46CF, 0x46D3, 0x46D5, 0x46DF, + 0x46E5, 0x46F9, 0x4705, 0x470F, 0x4717, 0x4723, 0x4729, 0x472F, + 0x4735, 0x4739, 0x474B, 0x474D, 0x4751, 0x475D, 0x476F, 0x4771, + 0x477D, 0x4783, 0x4787, 0x4789, 0x4799, 0x47A5, 0x47B1, 0x47BF, + 0x47C3, 0x47CB, 0x47DD, 0x47E1, 0x47ED, 0x47FB, 0x4801, 0x4807, + 0x480B, 0x4813, 0x4819, 0x481D, 0x4831, 0x483D, 0x4847, 0x4855, + 0x4859, 0x485B, 0x486B, 0x486D, 0x4879, 0x4897, 0x489B, 0x48A1, + 0x48B9, 0x48CD, 0x48E5, 0x48EF, 0x48F7, 0x4903, 0x490D, 0x4919, + 0x491F, 0x492B, 0x4937, 0x493D, 0x4945, 0x4955, 0x4963, 0x4969, + 0x496D, 0x4973, 0x4997, 0x49AB, 0x49B5, 0x49D3, 0x49DF, 0x49E1, + 0x49E5, 0x49E7, 0x4A03, 0x4A0F, 0x4A1D, 0x4A23, 0x4A39, 0x4A41, + 0x4A45, 0x4A57, 0x4A5D, 0x4A6B, 0x4A7D, 0x4A81, 0x4A87, 0x4A89, + 0x4A8F, 0x4AB1, 0x4AC3, 0x4AC5, 0x4AD5, 0x4ADB, 0x4AED, 0x4AEF, + 0x4B07, 0x4B0B, 0x4B0D, 0x4B13, 0x4B1F, 0x4B25, 0x4B31, 0x4B3B, + 0x4B43, 0x4B49, 0x4B59, 0x4B65, 0x4B6D, 0x4B77, 0x4B85, 0x4BAD, + 0x4BB3, 0x4BB5, 0x4BBB, 0x4BBF, 0x4BCB, 0x4BD9, 0x4BDD, 0x4BDF, + 0x4BE3, 0x4BE5, 0x4BE9, 0x4BF1, 0x4BF7, 0x4C01, 0x4C07, 0x4C0D, + 0x4C0F, 0x4C15, 0x4C1B, 0x4C21, 0x4C2D, 0x4C33, 0x4C4B, 0x4C55, + 0x4C57, 0x4C61, 0x4C67, 0x4C73, 0x4C79, 0x4C7F, 0x4C8D, 0x4C93, + 0x4C99, 0x4CCD, 0x4CE1, 0x4CE7, 0x4CF1, 0x4CF3, 0x4CFD, 0x4D05, + 0x4D0F, 0x4D1B, 0x4D27, 0x4D29, 0x4D2F, 0x4D33, 0x4D41, 0x4D51, + 0x4D59, 0x4D65, 0x4D6B, 0x4D81, 0x4D83, 0x4D8D, 0x4D95, 0x4D9B, + 0x4DB1, 0x4DB3, 0x4DC9, 0x4DCF, 0x4DD7, 0x4DE1, 0x4DED, 0x4DF9, + 0x4DFB, 0x4E05, 0x4E0B, 0x4E17, 0x4E19, 0x4E1D, 0x4E2B, 0x4E35, + 0x4E37, 0x4E3D, 0x4E4F, 0x4E53, 0x4E5F, 0x4E67, 0x4E79, 0x4E85, + 0x4E8B, 0x4E91, 0x4E95, 0x4E9B, 0x4EA1, 0x4EAF, 0x4EB3, 0x4EB5, + 0x4EC1, 0x4ECD, 0x4ED1, 0x4ED7, 0x4EE9, 0x4EFB, 0x4F07, 0x4F09, + 0x4F19, 0x4F25, 0x4F2D, 0x4F3F, 0x4F49, 0x4F63, 0x4F67, 0x4F6D, + 0x4F75, 0x4F7B, 0x4F81, 0x4F85, 0x4F87, 0x4F91, 0x4FA5, 0x4FA9, + 0x4FAF, 0x4FB7, 0x4FBB, 0x4FCF, 0x4FD9, 0x4FDB, 0x4FFD, 0x4FFF, + 0x5003, 0x501B, 0x501D, 0x5029, 0x5035, 0x503F, 0x5045, 0x5047, + 0x5053, 0x5071, 0x5077, 0x5083, 0x5093, 0x509F, 0x50A1, 0x50B7, + 0x50C9, 0x50D5, 0x50E3, 0x50ED, 0x50EF, 0x50FB, 0x5107, 0x510B, + 0x510D, 0x5111, 0x5117, 0x5123, 0x5125, 0x5135, 0x5147, 0x5149, + 0x5171, 0x5179, 0x5189, 0x518F, 0x5197, 0x51A1, 0x51A3, 0x51A7, + 0x51B9, 0x51C1, 0x51CB, 0x51D3, 0x51DF, 0x51E3, 0x51F5, 0x51F7, + 0x5209, 0x5213, 0x5215, 0x5219, 0x521B, 0x521F, 0x5227, 0x5243, + 0x5245, 0x524B, 0x5261, 0x526D, 0x5273, 0x5281, 0x5293, 0x5297, + 0x529D, 0x52A5, 0x52AB, 0x52B1, 0x52BB, 0x52C3, 0x52C7, 0x52C9, + 0x52DB, 0x52E5, 0x52EB, 0x52FF, 0x5315, 0x531D, 0x5323, 0x5341, + 0x5345, 0x5347, 0x534B, 0x535D, 0x5363, 0x5381, 0x5383, 0x5387, + 0x538F, 0x5395, 0x5399, 0x539F, 0x53AB, 0x53B9, 0x53DB, 0x53E9, + 0x53EF, 0x53F3, 0x53F5, 0x53FB, 0x53FF, 0x540D, 0x5411, 0x5413, + 0x5419, 0x5435, 0x5437, 0x543B, 0x5441, 0x5449, 0x5453, 0x5455, + 0x545F, 0x5461, 0x546B, 0x546D, 0x5471, 0x548F, 0x5491, 0x549D, + 0x54A9, 0x54B3, 0x54C5, 0x54D1, 0x54DF, 0x54E9, 0x54EB, 0x54F7, + 0x54FD, 0x5507, 0x550D, 0x551B, 0x5527, 0x552B, 0x5539, 0x553D, + 0x554F, 0x5551, 0x555B, 0x5563, 0x5567, 0x556F, 0x5579, 0x5585, + 0x5597, 0x55A9, 0x55B1, 0x55B7, 0x55C9, 0x55D9, 0x55E7, 0x55ED, + 0x55F3, 0x55FD, 0x560B, 0x560F, 0x5615, 0x5617, 0x5623, 0x562F, + 0x5633, 0x5639, 0x563F, 0x564B, 0x564D, 0x565D, 0x565F, 0x566B, + 0x5671, 0x5675, 0x5683, 0x5689, 0x568D, 0x568F, 0x569B, 0x56AD, + 0x56B1, 0x56D5, 0x56E7, 0x56F3, 0x56FF, 0x5701, 0x5705, 0x5707, + 0x570B, 0x5713, 0x571F, 0x5723, 0x5747, 0x574D, 0x575F, 0x5761, + 0x576D, 0x5777, 0x577D, 0x5789, 0x57A1, 0x57A9, 0x57AF, 0x57B5, + 0x57C5, 0x57D1, 0x57D3, 0x57E5, 0x57EF, 0x5803, 0x580D, 0x580F, + 0x5815, 0x5827, 0x582B, 0x582D, 0x5855, 0x585B, 0x585D, 0x586D, + 0x586F, 0x5873, 0x587B, 0x588D, 0x5897, 0x58A3, 0x58A9, 0x58AB, + 0x58B5, 0x58BD, 0x58C1, 0x58C7, 0x58D3, 0x58D5, 0x58DF, 0x58F1, + 0x58F9, 0x58FF, 0x5903, 0x5917, 0x591B, 0x5921, 0x5945, 0x594B, + 0x594D, 0x5957, 0x595D, 0x5975, 0x597B, 0x5989, 0x5999, 0x599F, + 0x59B1, 0x59B3, 0x59BD, 0x59D1, 0x59DB, 0x59E3, 0x59E9, 0x59ED, + 0x59F3, 0x59F5, 0x59FF, 0x5A01, 0x5A0D, 0x5A11, 0x5A13, 0x5A17, + 0x5A1F, 0x5A29, 0x5A2F, 0x5A3B, 0x5A4D, 0x5A5B, 0x5A67, 0x5A77, + 0x5A7F, 0x5A85, 0x5A95, 0x5A9D, 0x5AA1, 0x5AA3, 0x5AA9, 0x5ABB, + 0x5AD3, 0x5AE5, 0x5AEF, 0x5AFB, 0x5AFD, 0x5B01, 0x5B0F, 0x5B19, + 0x5B1F, 0x5B25, 0x5B2B, 0x5B3D, 0x5B49, 0x5B4B, 0x5B67, 0x5B79, + 0x5B87, 0x5B97, 0x5BA3, 0x5BB1, 0x5BC9, 0x5BD5, 0x5BEB, 0x5BF1, + 0x5BF3, 0x5BFD, 0x5C05, 0x5C09, 0x5C0B, 0x5C0F, 0x5C1D, 0x5C29, + 0x5C2F, 0x5C33, 0x5C39, 0x5C47, 0x5C4B, 0x5C4D, 0x5C51, 0x5C6F, + 0x5C75, 0x5C77, 0x5C7D, 0x5C87, 0x5C89, 0x5CA7, 0x5CBD, 0x5CBF, + 0x5CC3, 0x5CC9, 0x5CD1, 0x5CD7, 0x5CDD, 0x5CED, 0x5CF9, 0x5D05, + 0x5D0B, 0x5D13, 0x5D17, 0x5D19, 0x5D31, 0x5D3D, 0x5D41, 0x5D47, + 0x5D4F, 0x5D55, 0x5D5B, 0x5D65, 0x5D67, 0x5D6D, 0x5D79, 0x5D95, + 0x5DA3, 0x5DA9, 0x5DAD, 0x5DB9, 0x5DC1, 0x5DC7, 0x5DD3, 0x5DD7, + 0x5DDD, 0x5DEB, 0x5DF1, 0x5DFD, 0x5E07, 0x5E0D, 0x5E13, 0x5E1B, + 0x5E21, 0x5E27, 0x5E2B, 0x5E2D, 0x5E31, 0x5E39, 0x5E45, 0x5E49, + 0x5E57, 0x5E69, 0x5E73, 0x5E75, 0x5E85, 0x5E8B, 0x5E9F, 0x5EA5, + 0x5EAF, 0x5EB7, 0x5EBB, 0x5ED9, 0x5EFD, 0x5F09, 0x5F11, 0x5F27, + 0x5F33, 0x5F35, 0x5F3B, 0x5F47, 0x5F57, 0x5F5D, 0x5F63, 0x5F65, + 0x5F77, 0x5F7B, 0x5F95, 0x5F99, 0x5FA1, 0x5FB3, 0x5FBD, 0x5FC5, + 0x5FCF, 0x5FD5, 0x5FE3, 0x5FE7, 0x5FFB, 0x6011, 0x6023, 0x602F, + 0x6037, 0x6053, 0x605F, 0x6065, 0x606B, 0x6073, 0x6079, 0x6085, + 0x609D, 0x60AD, 0x60BB, 0x60BF, 0x60CD, 0x60D9, 0x60DF, 0x60E9, + 0x60F5, 0x6109, 0x610F, 0x6113, 0x611B, 0x612D, 0x6139, 0x614B, + 0x6155, 0x6157, 0x615B, 0x616F, 0x6179, 0x6187, 0x618B, 0x6191, + 0x6193, 0x619D, 0x61B5, 0x61C7, 0x61C9, 0x61CD, 0x61E1, 0x61F1, + 0x61FF, 0x6209, 0x6217, 0x621D, 0x6221, 0x6227, 0x623B, 0x6241, + 0x624B, 0x6251, 0x6253, 0x625F, 0x6265, 0x6283, 0x628D, 0x6295, + 0x629B, 0x629F, 0x62A5, 0x62AD, 0x62D5, 0x62D7, 0x62DB, 0x62DD, + 0x62E9, 0x62FB, 0x62FF, 0x6305, 0x630D, 0x6317, 0x631D, 0x632F, + 0x6341, 0x6343, 0x634F, 0x635F, 0x6367, 0x636D, 0x6371, 0x6377, + 0x637D, 0x637F, 0x63B3, 0x63C1, 0x63C5, 0x63D9, 0x63E9, 0x63EB, + 0x63EF, 0x63F5, 0x6401, 0x6403, 0x6409, 0x6415, 0x6421, 0x6427, + 0x642B, 0x6439, 0x6443, 0x6449, 0x644F, 0x645D, 0x6467, 0x6475, + 0x6485, 0x648D, 0x6493, 0x649F, 0x64A3, 0x64AB, 0x64C1, 0x64C7, + 0x64C9, 0x64DB, 0x64F1, 0x64F7, 0x64F9, 0x650B, 0x6511, 0x6521, + 0x652F, 0x6539, 0x653F, 0x654B, 0x654D, 0x6553, 0x6557, 0x655F, + 0x6571, 0x657D, 0x658D, 0x658F, 0x6593, 0x65A1, 0x65A5, 0x65AD, + 0x65B9, 0x65C5, 0x65E3, 0x65F3, 0x65FB, 0x65FF, 0x6601, 0x6607, + 0x661D, 0x6629, 0x6631, 0x663B, 0x6641, 0x6647, 0x664D, 0x665B, + 0x6661, 0x6673, 0x667D, 0x6689, 0x668B, 0x6695, 0x6697, 0x669B, + 0x66B5, 0x66B9, 0x66C5, 0x66CD, 0x66D1, 0x66E3, 0x66EB, 0x66F5, + 0x6703, 0x6713, 0x6719, 0x671F, 0x6727, 0x6731, 0x6737, 0x673F, + 0x6745, 0x6751, 0x675B, 0x676F, 0x6779, 0x6781, 0x6785, 0x6791, + 0x67AB, 0x67BD, 0x67C1, 0x67CD, 0x67DF, 0x67E5, 0x6803, 0x6809, + 0x6811, 0x6817, 0x682D, 0x6839, 0x683B, 0x683F, 0x6845, 0x684B, + 0x684D, 0x6857, 0x6859, 0x685D, 0x6863, 0x6869, 0x686B, 0x6871, + 0x6887, 0x6899, 0x689F, 0x68B1, 0x68BD, 0x68C5, 0x68D1, 0x68D7, + 0x68E1, 0x68ED, 0x68EF, 0x68FF, 0x6901, 0x690B, 0x690D, 0x6917, + 0x6929, 0x692F, 0x6943, 0x6947, 0x6949, 0x694F, 0x6965, 0x696B, + 0x6971, 0x6983, 0x6989, 0x6997, 0x69A3, 0x69B3, 0x69B5, 0x69BB, + 0x69C1, 0x69C5, 0x69D3, 0x69DF, 0x69E3, 0x69E5, 0x69F7, 0x6A07, + 0x6A2B, 0x6A37, 0x6A3D, 0x6A4B, 0x6A67, 0x6A69, 0x6A75, 0x6A7B, + 0x6A87, 0x6A8D, 0x6A91, 0x6A93, 0x6AA3, 0x6AC1, 0x6AC9, 0x6AE1, + 0x6AE7, 0x6B05, 0x6B0F, 0x6B11, 0x6B23, 0x6B27, 0x6B2D, 0x6B39, + 0x6B41, 0x6B57, 0x6B59, 0x6B5F, 0x6B75, 0x6B87, 0x6B89, 0x6B93, + 0x6B95, 0x6B9F, 0x6BBD, 0x6BBF, 0x6BDB, 0x6BE1, 0x6BEF, 0x6BFF, + 0x6C05, 0x6C19, 0x6C29, 0x6C2B, 0x6C31, 0x6C35, 0x6C55, 0x6C59, + 0x6C5B, 0x6C5F, 0x6C65, 0x6C67, 0x6C73, 0x6C77, 0x6C7D, 0x6C83, + 0x6C8F, 0x6C91, 0x6C97, 0x6C9B, 0x6CA1, 0x6CA9, 0x6CAF, 0x6CB3, + 0x6CC7, 0x6CCB, 0x6CEB, 0x6CF5, 0x6CFD, 0x6D0D, 0x6D0F, 0x6D25, + 0x6D27, 0x6D2B, 0x6D31, 0x6D39, 0x6D3F, 0x6D4F, 0x6D5D, 0x6D61, + 0x6D73, 0x6D7B, 0x6D7F, 0x6D93, 0x6D99, 0x6DA5, 0x6DB1, 0x6DB7, + 0x6DC1, 0x6DC3, 0x6DCD, 0x6DCF, 0x6DDB, 0x6DF7, 0x6E03, 0x6E15, + 0x6E17, 0x6E29, 0x6E33, 0x6E3B, 0x6E45, 0x6E75, 0x6E77, 0x6E7B, + 0x6E81, 0x6E89, 0x6E93, 0x6E95, 0x6E9F, 0x6EBD, 0x6EBF, 0x6EE3, + 0x6EE9, 0x6EF3, 0x6EF9, 0x6EFB, 0x6F0D, 0x6F11, 0x6F17, 0x6F1F, + 0x6F2F, 0x6F3D, 0x6F4D, 0x6F53, 0x6F61, 0x6F65, 0x6F79, 0x6F7D, + 0x6F83, 0x6F85, 0x6F8F, 0x6F9B, 0x6F9D, 0x6FA3, 0x6FAF, 0x6FB5, + 0x6FBB, 0x6FBF, 0x6FCB, 0x6FCD, 0x6FD3, 0x6FD7, 0x6FE3, 0x6FE9, + 0x6FF1, 0x6FF5, 0x6FF7, 0x6FFD, 0x700F, 0x7019, 0x701F, 0x7027, + 0x7033, 0x7039, 0x704F, 0x7051, 0x7057, 0x7063, 0x7075, 0x7079, + 0x7087, 0x708D, 0x7091, 0x70A5, 0x70AB, 0x70BB, 0x70C3, 0x70C7, + 0x70CF, 0x70E5, 0x70ED, 0x70F9, 0x70FF, 0x7105, 0x7115, 0x7121, + 0x7133, 0x7151, 0x7159, 0x715D, 0x715F, 0x7163, 0x7169, 0x7183, + 0x7187, 0x7195, 0x71AD, 0x71C3, 0x71C9, 0x71CB, 0x71D1, 0x71DB, + 0x71E1, 0x71EF, 0x71F5, 0x71FB, 0x7207, 0x7211, 0x7217, 0x7219, + 0x7225, 0x722F, 0x723B, 0x7243, 0x7255, 0x7267, 0x7271, 0x7277, + 0x727F, 0x728F, 0x7295, 0x729B, 0x72A3, 0x72B3, 0x72C7, 0x72CB, + 0x72CD, 0x72D7, 0x72D9, 0x72E3, 0x72EF, 0x72F5, 0x72FD, 0x7303, + 0x730D, 0x7321, 0x732B, 0x733D, 0x7357, 0x735B, 0x7361, 0x737F, + 0x7381, 0x7385, 0x738D, 0x7393, 0x739F, 0x73AB, 0x73BD, 0x73C1, + 0x73C9, 0x73DF, 0x73E5, 0x73E7, 0x73F3, 0x7415, 0x741B, 0x742D, + 0x7439, 0x743F, 0x7441, 0x745D, 0x746B, 0x747B, 0x7489, 0x748D, + 0x749B, 0x74A7, 0x74AB, 0x74B1, 0x74B7, 0x74B9, 0x74DD, 0x74E1, + 0x74E7, 0x74FB, 0x7507, 0x751F, 0x7525, 0x753B, 0x753D, 0x754D, + 0x755F, 0x756B, 0x7577, 0x7589, 0x758B, 0x7591, 0x7597, 0x759D, + 0x75A1, 0x75A7, 0x75B5, 0x75B9, 0x75BB, 0x75D1, 0x75D9, 0x75E5, + 0x75EB, 0x75F5, 0x75FB, 0x7603, 0x760F, 0x7621, 0x762D, 0x7633, + 0x763D, 0x763F, 0x7655, 0x7663, 0x7669, 0x766F, 0x7673, 0x7685, + 0x768B, 0x769F, 0x76B5, 0x76B7, 0x76C3, 0x76DB, 0x76DF, 0x76F1, + 0x7703, 0x7705, 0x771B, 0x771D, 0x7721, 0x772D, 0x7735, 0x7741, + 0x774B, 0x7759, 0x775D, 0x775F, 0x7771, 0x7781, 0x77A7, 0x77AD, + 0x77B3, 0x77B9, 0x77C5, 0x77CF, 0x77D5, 0x77E1, 0x77E9, 0x77EF, + 0x77F3, 0x77F9, 0x7807, 0x7825, 0x782B, 0x7835, 0x783D, 0x7853, + 0x7859, 0x7861, 0x786D, 0x7877, 0x7879, 0x7883, 0x7885, 0x788B, + 0x7895, 0x7897, 0x78A1, 0x78AD, 0x78BF, 0x78D3, 0x78D9, 0x78DD, + 0x78E5, 0x78FB, 0x7901, 0x7907, 0x7925, 0x792B, 0x7939, 0x793F, + 0x794B, 0x7957, 0x795D, 0x7967, 0x7969, 0x7973, 0x7991, 0x7993, + 0x79A3, 0x79AB, 0x79AF, 0x79B1, 0x79B7, 0x79C9, 0x79CD, 0x79CF, + 0x79D5, 0x79D9, 0x79F3, 0x79F7, 0x79FF, 0x7A05, 0x7A0F, 0x7A11, + 0x7A15, 0x7A1B, 0x7A23, 0x7A27, 0x7A2D, 0x7A4B, 0x7A57, 0x7A59, + 0x7A5F, 0x7A65, 0x7A69, 0x7A7D, 0x7A93, 0x7A9B, 0x7A9F, 0x7AA1, + 0x7AA5, 0x7AED, 0x7AF5, 0x7AF9, 0x7B01, 0x7B17, 0x7B19, 0x7B1D, + 0x7B2B, 0x7B35, 0x7B37, 0x7B3B, 0x7B4F, 0x7B55, 0x7B5F, 0x7B71, + 0x7B77, 0x7B8B, 0x7B9B, 0x7BA1, 0x7BA9, 0x7BAF, 0x7BB3, 0x7BC7, + 0x7BD3, 0x7BE9, 0x7BEB, 0x7BEF, 0x7BF1, 0x7BFD, 0x7C07, 0x7C19, + 0x7C1B, 0x7C31, 0x7C37, 0x7C49, 0x7C67, 0x7C69, 0x7C73, 0x7C81, + 0x7C8B, 0x7C93, 0x7CA3, 0x7CD5, 0x7CDB, 0x7CE5, 0x7CED, 0x7CF7, + 0x7D03, 0x7D09, 0x7D1B, 0x7D1D, 0x7D33, 0x7D39, 0x7D3B, 0x7D3F, + 0x7D45, 0x7D4D, 0x7D53, 0x7D59, 0x7D63, 0x7D75, 0x7D77, 0x7D8D, + 0x7D8F, 0x7D9F, 0x7DAD, 0x7DB7, 0x7DBD, 0x7DBF, 0x7DCB, 0x7DD5, + 0x7DE9, 0x7DED, 0x7DFB, 0x7E01, 0x7E05, 0x7E29, 0x7E2B, 0x7E2F, + 0x7E35, 0x7E41, 0x7E43, 0x7E47, 0x7E55, 0x7E61, 0x7E67, 0x7E6B, + 0x7E71, 0x7E73, 0x7E79, 0x7E7D, 0x7E91, 0x7E9B, 0x7E9D, 0x7EA7, + 0x7EAD, 0x7EB9, 0x7EBB, 0x7ED3, 0x7EDF, 0x7EEB, 0x7EF1, 0x7EF7, + 0x7EFB, 0x7F13, 0x7F15, 0x7F19, 0x7F31, 0x7F33, 0x7F39, 0x7F3D, + 0x7F43, 0x7F4B, 0x7F5B, 0x7F61, 0x7F63, 0x7F6D, 0x7F79, 0x7F87, + 0x7F8D, 0x7FAF, 0x7FB5, 0x7FC3, 0x7FC9, 0x7FCD, 0x7FCF, 0x7FED, + 0x8003, 0x800B, 0x800F, 0x8015, 0x801D, 0x8021, 0x8023, 0x803F, + 0x8041, 0x8047, 0x804B, 0x8065, 0x8077, 0x808D, 0x808F, 0x8095, + 0x80A5, 0x80AB, 0x80AD, 0x80BD, 0x80C9, 0x80CB, 0x80D7, 0x80DB, + 0x80E1, 0x80E7, 0x80F5, 0x80FF, 0x8105, 0x810D, 0x8119, 0x811D, + 0x812F, 0x8131, 0x813B, 0x8143, 0x8153, 0x8159, 0x815F, 0x817D, + 0x817F, 0x8189, 0x819B, 0x819D, 0x81A7, 0x81AF, 0x81B3, 0x81BB, + 0x81C7, 0x81DF, 0x8207, 0x8209, 0x8215, 0x821F, 0x8225, 0x8231, + 0x8233, 0x823F, 0x8243, 0x8245, 0x8249, 0x824F, 0x8261, 0x826F, + 0x827B, 0x8281, 0x8285, 0x8293, 0x82B1, 0x82B5, 0x82BD, 0x82C7, + 0x82CF, 0x82D5, 0x82DF, 0x82F1, 0x82F9, 0x82FD, 0x830B, 0x831B, + 0x8321, 0x8329, 0x832D, 0x8333, 0x8335, 0x833F, 0x8341, 0x834D, + 0x8351, 0x8353, 0x8357, 0x835D, 0x8365, 0x8369, 0x836F, 0x838F, + 0x83A7, 0x83B1, 0x83B9, 0x83CB, 0x83D5, 0x83D7, 0x83DD, 0x83E7, + 0x83E9, 0x83ED, 0x83FF, 0x8405, 0x8411, 0x8413, 0x8423, 0x8425, + 0x843B, 0x8441, 0x8447, 0x844F, 0x8461, 0x8465, 0x8477, 0x8483, + 0x848B, 0x8491, 0x8495, 0x84A9, 0x84AF, 0x84CD, 0x84E3, 0x84EF, + 0x84F1, 0x84F7, 0x8509, 0x850D, 0x854B, 0x854F, 0x8551, 0x855D, + 0x8563, 0x856D, 0x856F, 0x857B, 0x8587, 0x85A3, 0x85A5, 0x85A9, + 0x85B7, 0x85CD, 0x85D3, 0x85D5, 0x85DB, 0x85E1, 0x85EB, 0x85F9, + 0x85FD, 0x85FF, 0x8609, 0x860F, 0x8617, 0x8621, 0x862F, 0x8639, + 0x863F, 0x8641, 0x864D, 0x8663, 0x8675, 0x867D, 0x8687, 0x8699, + 0x86A5, 0x86A7, 0x86B3, 0x86B7, 0x86C3, 0x86C5, 0x86CF, 0x86D1, + 0x86D7, 0x86E9, 0x86EF, 0x86F5, 0x8717, 0x871D, 0x871F, 0x872B, + 0x872F, 0x8735, 0x8747, 0x8759, 0x875B, 0x876B, 0x8771, 0x8777, + 0x877F, 0x8785, 0x878F, 0x87A1, 0x87A9, 0x87B3, 0x87BB, 0x87C5, + 0x87C7, 0x87CB, 0x87DD, 0x87F7, 0x8803, 0x8819, 0x881B, 0x881F, + 0x8821, 0x8837, 0x883D, 0x8843, 0x8851, 0x8861, 0x8867, 0x887B, + 0x8885, 0x8891, 0x8893, 0x88A5, 0x88CF, 0x88D3, 0x88EB, 0x88ED, + 0x88F3, 0x88FD, 0x8909, 0x890B, 0x8911, 0x891B, 0x8923, 0x8927, + 0x892D, 0x8939, 0x8945, 0x894D, 0x8951, 0x8957, 0x8963, 0x8981, + 0x8995, 0x899B, 0x89B3, 0x89B9, 0x89C3, 0x89CF, 0x89D1, 0x89DB, + 0x89EF, 0x89F5, 0x89FB, 0x89FF, 0x8A0B, 0x8A19, 0x8A23, 0x8A35, + 0x8A41, 0x8A49, 0x8A4F, 0x8A5B, 0x8A5F, 0x8A6D, 0x8A77, 0x8A79, + 0x8A85, 0x8AA3, 0x8AB3, 0x8AB5, 0x8AC1, 0x8AC7, 0x8ACB, 0x8ACD, + 0x8AD1, 0x8AD7, 0x8AF1, 0x8AF5, 0x8B07, 0x8B09, 0x8B0D, 0x8B13, + 0x8B21, 0x8B57, 0x8B5D, 0x8B91, 0x8B93, 0x8BA3, 0x8BA9, 0x8BAF, + 0x8BBB, 0x8BD5, 0x8BD9, 0x8BDB, 0x8BE1, 0x8BF7, 0x8BFD, 0x8BFF, + 0x8C0B, 0x8C17, 0x8C1D, 0x8C27, 0x8C39, 0x8C3B, 0x8C47, 0x8C53, + 0x8C5D, 0x8C6F, 0x8C7B, 0x8C81, 0x8C89, 0x8C8F, 0x8C99, 0x8C9F, + 0x8CA7, 0x8CAB, 0x8CAD, 0x8CB1, 0x8CC5, 0x8CDD, 0x8CE3, 0x8CE9, + 0x8CF3, 0x8D01, 0x8D0B, 0x8D0D, 0x8D23, 0x8D29, 0x8D37, 0x8D41, + 0x8D5B, 0x8D5F, 0x8D71, 0x8D79, 0x8D85, 0x8D91, 0x8D9B, 0x8DA7, + 0x8DAD, 0x8DB5, 0x8DC5, 0x8DCB, 0x8DD3, 0x8DD9, 0x8DDF, 0x8DF5, + 0x8DF7, 0x8E01, 0x8E15, 0x8E1F, 0x8E25, 0x8E51, 0x8E63, 0x8E69, + 0x8E73, 0x8E75, 0x8E79, 0x8E7F, 0x8E8D, 0x8E91, 0x8EAB, 0x8EAF, + 0x8EB1, 0x8EBD, 0x8EC7, 0x8ECF, 0x8ED3, 0x8EDB, 0x8EE7, 0x8EEB, + 0x8EF7, 0x8EFF, 0x8F15, 0x8F1D, 0x8F23, 0x8F2D, 0x8F3F, 0x8F45, + 0x8F4B, 0x8F53, 0x8F59, 0x8F65, 0x8F69, 0x8F71, 0x8F83, 0x8F8D, + 0x8F99, 0x8F9F, 0x8FAB, 0x8FAD, 0x8FB3, 0x8FB7, 0x8FB9, 0x8FC9, + 0x8FD5, 0x8FE1, 0x8FEF, 0x8FF9, 0x9007, 0x900D, 0x9017, 0x9023, + 0x9025, 0x9031, 0x9037, 0x903B, 0x9041, 0x9043, 0x904F, 0x9053, + 0x906D, 0x9073, 0x9085, 0x908B, 0x9095, 0x909B, 0x909D, 0x90AF, + 0x90B9, 0x90C1, 0x90C5, 0x90DF, 0x90E9, 0x90FD, 0x9103, 0x9113, + 0x9127, 0x9133, 0x913D, 0x9145, 0x914F, 0x9151, 0x9161, 0x9167, + 0x917B, 0x9185, 0x9199, 0x919D, 0x91BB, 0x91BD, 0x91C1, 0x91C9, + 0x91D9, 0x91DB, 0x91ED, 0x91F1, 0x91F3, 0x91F9, 0x9203, 0x9215, + 0x9221, 0x922F, 0x9241, 0x9247, 0x9257, 0x926B, 0x9271, 0x9275, + 0x927D, 0x9283, 0x9287, 0x928D, 0x9299, 0x92A1, 0x92AB, 0x92AD, + 0x92B9, 0x92BF, 0x92C3, 0x92C5, 0x92CB, 0x92D5, 0x92D7, 0x92E7, + 0x92F3, 0x9301, 0x930B, 0x9311, 0x9319, 0x931F, 0x933B, 0x933D, + 0x9343, 0x9355, 0x9373, 0x9395, 0x9397, 0x93A7, 0x93B3, 0x93B5, + 0x93C7, 0x93D7, 0x93DD, 0x93E5, 0x93EF, 0x93F7, 0x9401, 0x9409, + 0x9413, 0x943F, 0x9445, 0x944B, 0x944F, 0x9463, 0x9467, 0x9469, + 0x946D, 0x947B, 0x9497, 0x949F, 0x94A5, 0x94B5, 0x94C3, 0x94E1, + 0x94E7, 0x9505, 0x9509, 0x9517, 0x9521, 0x9527, 0x952D, 0x9535, + 0x9539, 0x954B, 0x9557, 0x955D, 0x955F, 0x9575, 0x9581, 0x9589, + 0x958F, 0x959B, 0x959F, 0x95AD, 0x95B1, 0x95B7, 0x95B9, 0x95BD, + 0x95CF, 0x95E3, 0x95E9, 0x95F9, 0x961F, 0x962F, 0x9631, 0x9635, + 0x963B, 0x963D, 0x9665, 0x968F, 0x969D, 0x96A1, 0x96A7, 0x96A9, + 0x96C1, 0x96CB, 0x96D1, 0x96D3, 0x96E5, 0x96EF, 0x96FB, 0x96FD, + 0x970D, 0x970F, 0x9715, 0x9725, 0x972B, 0x9733, 0x9737, 0x9739, + 0x9743, 0x9749, 0x9751, 0x975B, 0x975D, 0x976F, 0x977F, 0x9787, + 0x9793, 0x97A5, 0x97B1, 0x97B7, 0x97C3, 0x97CD, 0x97D3, 0x97D9, + 0x97EB, 0x97F7, 0x9805, 0x9809, 0x980B, 0x9815, 0x9829, 0x982F, + 0x983B, 0x9841, 0x9851, 0x986B, 0x986F, 0x9881, 0x9883, 0x9887, + 0x98A7, 0x98B1, 0x98B9, 0x98BF, 0x98C3, 0x98C9, 0x98CF, 0x98DD, + 0x98E3, 0x98F5, 0x98F9, 0x98FB, 0x990D, 0x9917, 0x991F, 0x9929, + 0x9931, 0x993B, 0x993D, 0x9941, 0x9947, 0x9949, 0x9953, 0x997D, + 0x9985, 0x9991, 0x9995, 0x999B, 0x99AD, 0x99AF, 0x99BF, 0x99C7, + 0x99CB, 0x99CD, 0x99D7, 0x99E5, 0x99F1, 0x99FB, 0x9A0F, 0x9A13, + 0x9A1B, 0x9A25, 0x9A4B, 0x9A4F, 0x9A55, 0x9A57, 0x9A61, 0x9A75, + 0x9A7F, 0x9A8B, 0x9A91, 0x9A9D, 0x9AB7, 0x9AC3, 0x9AC7, 0x9ACF, + 0x9AEB, 0x9AF3, 0x9AF7, 0x9AFF, 0x9B17, 0x9B1D, 0x9B27, 0x9B2F, + 0x9B35, 0x9B45, 0x9B51, 0x9B59, 0x9B63, 0x9B6F, 0x9B77, 0x9B8D, + 0x9B93, 0x9B95, 0x9B9F, 0x9BA1, 0x9BA7, 0x9BB1, 0x9BB7, 0x9BBD, + 0x9BC5, 0x9BCB, 0x9BCF, 0x9BDD, 0x9BF9, 0x9C01, 0x9C11, 0x9C23, + 0x9C2B, 0x9C2F, 0x9C35, 0x9C49, 0x9C4D, 0x9C5F, 0x9C65, 0x9C67, + 0x9C7F, 0x9C97, 0x9C9D, 0x9CA3, 0x9CAF, 0x9CBB, 0x9CBF, 0x9CC1, + 0x9CD7, 0x9CD9, 0x9CE3, 0x9CE9, 0x9CF1, 0x9CFD, 0x9D01, 0x9D15, + 0x9D27, 0x9D2D, 0x9D31, 0x9D3D, 0x9D55, 0x9D5B, 0x9D61, 0x9D97, + 0x9D9F, 0x9DA5, 0x9DA9, 0x9DC3, 0x9DE7, 0x9DEB, 0x9DED, 0x9DF1, + 0x9E0B, 0x9E17, 0x9E23, 0x9E27, 0x9E2D, 0x9E33, 0x9E3B, 0x9E47, + 0x9E51, 0x9E53, 0x9E5F, 0x9E6F, 0x9E81, 0x9E87, 0x9E8F, 0x9E95, + 0x9EA1, 0x9EB3, 0x9EBD, 0x9EBF, 0x9EF5, 0x9EF9, 0x9EFB, 0x9F05, + 0x9F23, 0x9F2F, 0x9F37, 0x9F3B, 0x9F43, 0x9F53, 0x9F61, 0x9F6D, + 0x9F73, 0x9F77, 0x9F7D, 0x9F89, 0x9F8F, 0x9F91, 0x9F95, 0x9FA3, + 0x9FAF, 0x9FB3, 0x9FC1, 0x9FC7, 0x9FDF, 0x9FE5, 0x9FEB, 0x9FF5, + 0xA001, 0xA00D, 0xA021, 0xA033, 0xA039, 0xA03F, 0xA04F, 0xA057, + 0xA05B, 0xA061, 0xA075, 0xA079, 0xA099, 0xA09D, 0xA0AB, 0xA0B5, + 0xA0B7, 0xA0BD, 0xA0C9, 0xA0D9, 0xA0DB, 0xA0DF, 0xA0E5, 0xA0F1, + 0xA0F3, 0xA0FD, 0xA105, 0xA10B, 0xA10F, 0xA111, 0xA11B, 0xA129, + 0xA12F, 0xA135, 0xA141, 0xA153, 0xA175, 0xA17D, 0xA187, 0xA18D, + 0xA1A5, 0xA1AB, 0xA1AD, 0xA1B7, 0xA1C3, 0xA1C5, 0xA1E3, 0xA1ED, + 0xA1FB, 0xA207, 0xA213, 0xA223, 0xA229, 0xA22F, 0xA231, 0xA243, + 0xA247, 0xA24D, 0xA26B, 0xA279, 0xA27D, 0xA283, 0xA289, 0xA28B, + 0xA291, 0xA295, 0xA29B, 0xA2A9, 0xA2AF, 0xA2B3, 0xA2BB, 0xA2C5, + 0xA2D1, 0xA2D7, 0xA2F7, 0xA301, 0xA309, 0xA31F, 0xA321, 0xA32B, + 0xA331, 0xA349, 0xA351, 0xA355, 0xA373, 0xA379, 0xA37B, 0xA387, + 0xA397, 0xA39F, 0xA3A5, 0xA3A9, 0xA3AF, 0xA3B7, 0xA3C7, 0xA3D5, + 0xA3DB, 0xA3E1, 0xA3E5, 0xA3E7, 0xA3F1, 0xA3FD, 0xA3FF, 0xA40F, + 0xA41D, 0xA421, 0xA423, 0xA427, 0xA43B, 0xA44D, 0xA457, 0xA459, + 0xA463, 0xA469, 0xA475, 0xA493, 0xA49B, 0xA4AD, 0xA4B9, 0xA4C3, + 0xA4C5, 0xA4CB, 0xA4D1, 0xA4D5, 0xA4E1, 0xA4ED, 0xA4EF, 0xA4F3, + 0xA4FF, 0xA511, 0xA529, 0xA52B, 0xA535, 0xA53B, 0xA543, 0xA553, + 0xA55B, 0xA561, 0xA56D, 0xA577, 0xA585, 0xA58B, 0xA597, 0xA59D, + 0xA5A3, 0xA5A7, 0xA5A9, 0xA5C1, 0xA5C5, 0xA5CB, 0xA5D3, 0xA5D9, + 0xA5DD, 0xA5DF, 0xA5E3, 0xA5E9, 0xA5F7, 0xA5FB, 0xA603, 0xA60D, + 0xA625, 0xA63D, 0xA649, 0xA64B, 0xA651, 0xA65D, 0xA673, 0xA691, + 0xA693, 0xA699, 0xA6AB, 0xA6B5, 0xA6BB, 0xA6C1, 0xA6C9, 0xA6CD, + 0xA6CF, 0xA6D5, 0xA6DF, 0xA6E7, 0xA6F1, 0xA6F7, 0xA6FF, 0xA70F, + 0xA715, 0xA723, 0xA729, 0xA72D, 0xA745, 0xA74D, 0xA757, 0xA759, + 0xA765, 0xA76B, 0xA76F, 0xA793, 0xA795, 0xA7AB, 0xA7B1, 0xA7B9, + 0xA7BF, 0xA7C9, 0xA7D1, 0xA7D7, 0xA7E3, 0xA7ED, 0xA7FB, 0xA805, + 0xA80B, 0xA81D, 0xA829, 0xA82B, 0xA837, 0xA83B, 0xA855, 0xA85F, + 0xA86D, 0xA87D, 0xA88F, 0xA897, 0xA8A9, 0xA8B5, 0xA8C1, 0xA8C7, + 0xA8D7, 0xA8E5, 0xA8FD, 0xA907, 0xA913, 0xA91B, 0xA931, 0xA937, + 0xA939, 0xA943, 0xA97F, 0xA985, 0xA987, 0xA98B, 0xA993, 0xA9A3, + 0xA9B1, 0xA9BB, 0xA9C1, 0xA9D9, 0xA9DF, 0xA9EB, 0xA9FD, 0xAA15, + 0xAA17, 0xAA35, 0xAA39, 0xAA3B, 0xAA47, 0xAA4D, 0xAA57, 0xAA59, + 0xAA5D, 0xAA6B, 0xAA71, 0xAA81, 0xAA83, 0xAA8D, 0xAA95, 0xAAAB, + 0xAABF, 0xAAC5, 0xAAC9, 0xAAE9, 0xAAEF, 0xAB01, 0xAB05, 0xAB07, + 0xAB0B, 0xAB0D, 0xAB11, 0xAB19, 0xAB4D, 0xAB5B, 0xAB71, 0xAB73, + 0xAB89, 0xAB9D, 0xABA7, 0xABAF, 0xABB9, 0xABBB, 0xABC1, 0xABC5, + 0xABD3, 0xABD7, 0xABDD, 0xABF1, 0xABF5, 0xABFB, 0xABFD, 0xAC09, + 0xAC15, 0xAC1B, 0xAC27, 0xAC37, 0xAC39, 0xAC45, 0xAC4F, 0xAC57, + 0xAC5B, 0xAC61, 0xAC63, 0xAC7F, 0xAC8B, 0xAC93, 0xAC9D, 0xACA9, + 0xACAB, 0xACAF, 0xACBD, 0xACD9, 0xACE1, 0xACE7, 0xACEB, 0xACED, + 0xACF1, 0xACF7, 0xACF9, 0xAD05, 0xAD3F, 0xAD45, 0xAD53, 0xAD5D, + 0xAD5F, 0xAD65, 0xAD81, 0xADA1, 0xADA5, 0xADC3, 0xADCB, 0xADD1, + 0xADD5, 0xADDB, 0xADE7, 0xADF3, 0xADF5, 0xADF9, 0xADFF, 0xAE05, + 0xAE13, 0xAE23, 0xAE2B, 0xAE49, 0xAE4D, 0xAE4F, 0xAE59, 0xAE61, + 0xAE67, 0xAE6B, 0xAE71, 0xAE8B, 0xAE8F, 0xAE9B, 0xAE9D, 0xAEA7, + 0xAEB9, 0xAEC5, 0xAED1, 0xAEE3, 0xAEE5, 0xAEE9, 0xAEF5, 0xAEFD, + 0xAF09, 0xAF13, 0xAF27, 0xAF2B, 0xAF33, 0xAF43, 0xAF4F, 0xAF57, + 0xAF5D, 0xAF6D, 0xAF75, 0xAF7F, 0xAF8B, 0xAF99, 0xAF9F, 0xAFA3, + 0xAFAB, 0xAFB7, 0xAFBB, 0xAFCF, 0xAFD5, 0xAFFD, 0xB005, 0xB015, + 0xB01B, 0xB03F, 0xB041, 0xB047, 0xB04B, 0xB051, 0xB053, 0xB069, + 0xB07B, 0xB07D, 0xB087, 0xB08D, 0xB0B1, 0xB0BF, 0xB0CB, 0xB0CF, + 0xB0E1, 0xB0E9, 0xB0ED, 0xB0FB, 0xB105, 0xB107, 0xB111, 0xB119, + 0xB11D, 0xB11F, 0xB131, 0xB141, 0xB14D, 0xB15B, 0xB165, 0xB173, + 0xB179, 0xB17F, 0xB1A9, 0xB1B3, 0xB1B9, 0xB1BF, 0xB1D3, 0xB1DD, + 0xB1E5, 0xB1F1, 0xB1F5, 0xB201, 0xB213, 0xB215, 0xB21F, 0xB22D, + 0xB23F, 0xB249, 0xB25B, 0xB263, 0xB269, 0xB26D, 0xB27B, 0xB281, + 0xB28B, 0xB2A9, 0xB2B7, 0xB2BD, 0xB2C3, 0xB2C7, 0xB2D3, 0xB2F9, + 0xB2FD, 0xB2FF, 0xB303, 0xB309, 0xB311, 0xB31D, 0xB327, 0xB32D, + 0xB33F, 0xB345, 0xB377, 0xB37D, 0xB381, 0xB387, 0xB393, 0xB39B, + 0xB3A5, 0xB3C5, 0xB3CB, 0xB3E1, 0xB3E3, 0xB3ED, 0xB3F9, 0xB40B, + 0xB40D, 0xB413, 0xB417, 0xB435, 0xB43D, 0xB443, 0xB449, 0xB45B, + 0xB465, 0xB467, 0xB46B, 0xB477, 0xB48B, 0xB495, 0xB49D, 0xB4B5, + 0xB4BF, 0xB4C1, 0xB4C7, 0xB4DD, 0xB4E3, 0xB4E5, 0xB4F7, 0xB501, + 0xB50D, 0xB50F, 0xB52D, 0xB53F, 0xB54B, 0xB567, 0xB569, 0xB56F, + 0xB573, 0xB579, 0xB587, 0xB58D, 0xB599, 0xB5A3, 0xB5AB, 0xB5AF, + 0xB5BB, 0xB5D5, 0xB5DF, 0xB5E7, 0xB5ED, 0xB5FD, 0xB5FF, 0xB609, + 0xB61B, 0xB629, 0xB62F, 0xB633, 0xB639, 0xB647, 0xB657, 0xB659, + 0xB65F, 0xB663, 0xB66F, 0xB683, 0xB687, 0xB69B, 0xB69F, 0xB6A5, + 0xB6B1, 0xB6B3, 0xB6D7, 0xB6DB, 0xB6E1, 0xB6E3, 0xB6ED, 0xB6EF, + 0xB705, 0xB70D, 0xB713, 0xB71D, 0xB729, 0xB735, 0xB747, 0xB755, + 0xB76D, 0xB791, 0xB795, 0xB7A9, 0xB7C1, 0xB7CB, 0xB7D1, 0xB7D3, + 0xB7EF, 0xB7F5, 0xB807, 0xB80F, 0xB813, 0xB819, 0xB821, 0xB827, + 0xB82B, 0xB82D, 0xB839, 0xB855, 0xB867, 0xB875, 0xB885, 0xB893, + 0xB8A5, 0xB8AF, 0xB8B7, 0xB8BD, 0xB8C1, 0xB8C7, 0xB8CD, 0xB8D5, + 0xB8EB, 0xB8F7, 0xB8F9, 0xB903, 0xB915, 0xB91B, 0xB91D, 0xB92F, + 0xB939, 0xB93B, 0xB947, 0xB951, 0xB963, 0xB983, 0xB989, 0xB98D, + 0xB993, 0xB999, 0xB9A1, 0xB9A7, 0xB9AD, 0xB9B7, 0xB9CB, 0xB9D1, + 0xB9DD, 0xB9E7, 0xB9EF, 0xB9F9, 0xBA07, 0xBA0D, 0xBA17, 0xBA25, + 0xBA29, 0xBA2B, 0xBA41, 0xBA53, 0xBA55, 0xBA5F, 0xBA61, 0xBA65, + 0xBA79, 0xBA7D, 0xBA7F, 0xBAA1, 0xBAA3, 0xBAAF, 0xBAB5, 0xBABF, + 0xBAC1, 0xBACB, 0xBADD, 0xBAE3, 0xBAF1, 0xBAFD, 0xBB09, 0xBB1F, + 0xBB27, 0xBB2D, 0xBB3D, 0xBB43, 0xBB4B, 0xBB4F, 0xBB5B, 0xBB61, + 0xBB69, 0xBB6D, 0xBB91, 0xBB97, 0xBB9D, 0xBBB1, 0xBBC9, 0xBBCF, + 0xBBDB, 0xBBED, 0xBBF7, 0xBBF9, 0xBC03, 0xBC1D, 0xBC23, 0xBC33, + 0xBC3B, 0xBC41, 0xBC45, 0xBC5D, 0xBC6F, 0xBC77, 0xBC83, 0xBC8F, + 0xBC99, 0xBCAB, 0xBCB7, 0xBCB9, 0xBCD1, 0xBCD5, 0xBCE1, 0xBCF3, + 0xBCFF, 0xBD0D, 0xBD17, 0xBD19, 0xBD1D, 0xBD35, 0xBD41, 0xBD4F, + 0xBD59, 0xBD5F, 0xBD61, 0xBD67, 0xBD6B, 0xBD71, 0xBD8B, 0xBD8F, + 0xBD95, 0xBD9B, 0xBD9D, 0xBDB3, 0xBDBB, 0xBDCD, 0xBDD1, 0xBDE3, + 0xBDEB, 0xBDEF, 0xBE07, 0xBE09, 0xBE15, 0xBE21, 0xBE25, 0xBE27, + 0xBE5B, 0xBE5D, 0xBE6F, 0xBE75, 0xBE79, 0xBE7F, 0xBE8B, 0xBE8D, + 0xBE93, 0xBE9F, 0xBEA9, 0xBEB1, 0xBEB5, 0xBEB7, 0xBECF, 0xBED9, + 0xBEDB, 0xBEE5, 0xBEE7, 0xBEF3, 0xBEF9, 0xBF0B, 0xBF33, 0xBF39, + 0xBF4D, 0xBF5D, 0xBF5F, 0xBF6B, 0xBF71, 0xBF7B, 0xBF87, 0xBF89, + 0xBF8D, 0xBF93, 0xBFA1, 0xBFAD, 0xBFB9, 0xBFCF, 0xBFD5, 0xBFDD, + 0xBFE1, 0xBFE3, 0xBFF3, 0xC005, 0xC011, 0xC013, 0xC019, 0xC029, + 0xC02F, 0xC031, 0xC037, 0xC03B, 0xC047, 0xC065, 0xC06D, 0xC07D, + 0xC07F, 0xC091, 0xC09B, 0xC0B3, 0xC0B5, 0xC0BB, 0xC0D3, 0xC0D7, + 0xC0D9, 0xC0EF, 0xC0F1, 0xC101, 0xC103, 0xC109, 0xC115, 0xC119, + 0xC12B, 0xC133, 0xC137, 0xC145, 0xC149, 0xC15B, 0xC173, 0xC179, + 0xC17B, 0xC181, 0xC18B, 0xC18D, 0xC197, 0xC1BD, 0xC1C3, 0xC1CD, + 0xC1DB, 0xC1E1, 0xC1E7, 0xC1FF, 0xC203, 0xC205, 0xC211, 0xC221, + 0xC22F, 0xC23F, 0xC24B, 0xC24D, 0xC253, 0xC25D, 0xC277, 0xC27B, + 0xC27D, 0xC289, 0xC28F, 0xC293, 0xC29F, 0xC2A7, 0xC2B3, 0xC2BD, + 0xC2CF, 0xC2D5, 0xC2E3, 0xC2FF, 0xC301, 0xC307, 0xC311, 0xC313, + 0xC317, 0xC325, 0xC347, 0xC349, 0xC34F, 0xC365, 0xC367, 0xC371, + 0xC37F, 0xC383, 0xC385, 0xC395, 0xC39D, 0xC3A7, 0xC3AD, 0xC3B5, + 0xC3BF, 0xC3C7, 0xC3CB, 0xC3D1, 0xC3D3, 0xC3E3, 0xC3E9, 0xC3EF, + 0xC401, 0xC41F, 0xC42D, 0xC433, 0xC437, 0xC455, 0xC457, 0xC461, + 0xC46F, 0xC473, 0xC487, 0xC491, 0xC499, 0xC49D, 0xC4A5, 0xC4B7, + 0xC4BB, 0xC4C9, 0xC4CF, 0xC4D3, 0xC4EB, 0xC4F1, 0xC4F7, 0xC509, + 0xC51B, 0xC51D, 0xC541, 0xC547, 0xC551, 0xC55F, 0xC56B, 0xC56F, + 0xC575, 0xC577, 0xC595, 0xC59B, 0xC59F, 0xC5A1, 0xC5A7, 0xC5C3, + 0xC5D7, 0xC5DB, 0xC5EF, 0xC5FB, 0xC613, 0xC623, 0xC635, 0xC641, + 0xC64F, 0xC655, 0xC659, 0xC665, 0xC685, 0xC691, 0xC697, 0xC6A1, + 0xC6A9, 0xC6B3, 0xC6B9, 0xC6CB, 0xC6CD, 0xC6DD, 0xC6EB, 0xC6F1, + 0xC707, 0xC70D, 0xC719, 0xC71B, 0xC72D, 0xC731, 0xC739, 0xC757, + 0xC763, 0xC767, 0xC773, 0xC775, 0xC77F, 0xC7A5, 0xC7BB, 0xC7BD, + 0xC7C1, 0xC7CF, 0xC7D5, 0xC7E1, 0xC7F9, 0xC7FD, 0xC7FF, 0xC803, + 0xC811, 0xC81D, 0xC827, 0xC829, 0xC839, 0xC83F, 0xC853, 0xC857, + 0xC86B, 0xC881, 0xC88D, 0xC88F, 0xC893, 0xC895, 0xC8A1, 0xC8B7, + 0xC8CF, 0xC8D5, 0xC8DB, 0xC8DD, 0xC8E3, 0xC8E7, 0xC8ED, 0xC8EF, + 0xC8F9, 0xC905, 0xC911, 0xC917, 0xC919, 0xC91F, 0xC92F, 0xC937, + 0xC93D, 0xC941, 0xC953, 0xC95F, 0xC96B, 0xC979, 0xC97D, 0xC989, + 0xC98F, 0xC997, 0xC99D, 0xC9AF, 0xC9B5, 0xC9BF, 0xC9CB, 0xC9D9, + 0xC9DF, 0xC9E3, 0xC9EB, 0xCA01, 0xCA07, 0xCA09, 0xCA25, 0xCA37, + 0xCA39, 0xCA4B, 0xCA55, 0xCA5B, 0xCA69, 0xCA73, 0xCA75, 0xCA7F, + 0xCA8D, 0xCA93, 0xCA9D, 0xCA9F, 0xCAB5, 0xCABB, 0xCAC3, 0xCAC9, + 0xCAD9, 0xCAE5, 0xCAED, 0xCB03, 0xCB05, 0xCB09, 0xCB17, 0xCB29, + 0xCB35, 0xCB3B, 0xCB53, 0xCB59, 0xCB63, 0xCB65, 0xCB71, 0xCB87, + 0xCB99, 0xCB9F, 0xCBB3, 0xCBB9, 0xCBC3, 0xCBD1, 0xCBD5, 0xCBD7, + 0xCBDD, 0xCBE9, 0xCBFF, 0xCC0D, 0xCC19, 0xCC1D, 0xCC23, 0xCC2B, + 0xCC41, 0xCC43, 0xCC4D, 0xCC59, 0xCC61, 0xCC89, 0xCC8B, 0xCC91, + 0xCC9B, 0xCCA3, 0xCCA7, 0xCCD1, 0xCCE5, 0xCCE9, 0xCD09, 0xCD15, + 0xCD1F, 0xCD25, 0xCD31, 0xCD3D, 0xCD3F, 0xCD49, 0xCD51, 0xCD57, + 0xCD5B, 0xCD63, 0xCD67, 0xCD81, 0xCD93, 0xCD97, 0xCD9F, 0xCDBB, + 0xCDC1, 0xCDD3, 0xCDD9, 0xCDE5, 0xCDE7, 0xCDF1, 0xCDF7, 0xCDFD, + 0xCE0B, 0xCE15, 0xCE21, 0xCE2F, 0xCE47, 0xCE4D, 0xCE51, 0xCE65, + 0xCE7B, 0xCE7D, 0xCE8F, 0xCE93, 0xCE99, 0xCEA5, 0xCEA7, 0xCEB7, + 0xCEC9, 0xCED7, 0xCEDD, 0xCEE3, 0xCEE7, 0xCEED, 0xCEF5, 0xCF07, + 0xCF0B, 0xCF19, 0xCF37, 0xCF3B, 0xCF4D, 0xCF55, 0xCF5F, 0xCF61, + 0xCF65, 0xCF6D, 0xCF79, 0xCF7D, 0xCF89, 0xCF9B, 0xCF9D, 0xCFA9, + 0xCFB3, 0xCFB5, 0xCFC5, 0xCFCD, 0xCFD1, 0xCFEF, 0xCFF1, 0xCFF7, + 0xD013, 0xD015, 0xD01F, 0xD021, 0xD033, 0xD03D, 0xD04B, 0xD04F, + 0xD069, 0xD06F, 0xD081, 0xD085, 0xD099, 0xD09F, 0xD0A3, 0xD0AB, + 0xD0BD, 0xD0C1, 0xD0CD, 0xD0E7, 0xD0FF, 0xD103, 0xD117, 0xD12D, + 0xD12F, 0xD141, 0xD157, 0xD159, 0xD15D, 0xD169, 0xD16B, 0xD171, + 0xD177, 0xD17D, 0xD181, 0xD187, 0xD195, 0xD199, 0xD1B1, 0xD1BD, + 0xD1C3, 0xD1D5, 0xD1D7, 0xD1E3, 0xD1FF, 0xD20D, 0xD211, 0xD217, + 0xD21F, 0xD235, 0xD23B, 0xD247, 0xD259, 0xD261, 0xD265, 0xD279, + 0xD27F, 0xD283, 0xD289, 0xD28B, 0xD29D, 0xD2A3, 0xD2A7, 0xD2B3, + 0xD2BF, 0xD2C7, 0xD2E3, 0xD2E9, 0xD2F1, 0xD2FB, 0xD2FD, 0xD315, + 0xD321, 0xD32B, 0xD343, 0xD34B, 0xD355, 0xD369, 0xD375, 0xD37B, + 0xD387, 0xD393, 0xD397, 0xD3A5, 0xD3B1, 0xD3C9, 0xD3EB, 0xD3FD, + 0xD405, 0xD40F, 0xD415, 0xD427, 0xD42F, 0xD433, 0xD43B, 0xD44B, + 0xD459, 0xD45F, 0xD463, 0xD469, 0xD481, 0xD483, 0xD489, 0xD48D, + 0xD493, 0xD495, 0xD4A5, 0xD4AB, 0xD4B1, 0xD4C5, 0xD4DD, 0xD4E1, + 0xD4E3, 0xD4E7, 0xD4F5, 0xD4F9, 0xD50B, 0xD50D, 0xD513, 0xD51F, + 0xD523, 0xD531, 0xD535, 0xD537, 0xD549, 0xD559, 0xD55F, 0xD565, + 0xD567, 0xD577, 0xD58B, 0xD591, 0xD597, 0xD5B5, 0xD5B9, 0xD5C1, + 0xD5C7, 0xD5DF, 0xD5EF, 0xD5F5, 0xD5FB, 0xD603, 0xD60F, 0xD62D, + 0xD631, 0xD643, 0xD655, 0xD65D, 0xD661, 0xD67B, 0xD685, 0xD687, + 0xD69D, 0xD6A5, 0xD6AF, 0xD6BD, 0xD6C3, 0xD6C7, 0xD6D9, 0xD6E1, + 0xD6ED, 0xD709, 0xD70B, 0xD711, 0xD715, 0xD721, 0xD727, 0xD73F, + 0xD745, 0xD74D, 0xD757, 0xD76B, 0xD77B, 0xD783, 0xD7A1, 0xD7A7, + 0xD7AD, 0xD7B1, 0xD7B3, 0xD7BD, 0xD7CB, 0xD7D1, 0xD7DB, 0xD7FB, + 0xD811, 0xD823, 0xD825, 0xD829, 0xD82B, 0xD82F, 0xD837, 0xD84D, + 0xD855, 0xD867, 0xD873, 0xD88F, 0xD891, 0xD8A1, 0xD8AD, 0xD8BF, + 0xD8CD, 0xD8D7, 0xD8E9, 0xD8F5, 0xD8FB, 0xD91B, 0xD925, 0xD933, + 0xD939, 0xD943, 0xD945, 0xD94F, 0xD951, 0xD957, 0xD96D, 0xD96F, + 0xD973, 0xD979, 0xD981, 0xD98B, 0xD991, 0xD99F, 0xD9A5, 0xD9A9, + 0xD9B5, 0xD9D3, 0xD9EB, 0xD9F1, 0xD9F7, 0xD9FF, 0xDA05, 0xDA09, + 0xDA0B, 0xDA0F, 0xDA15, 0xDA1D, 0xDA23, 0xDA29, 0xDA3F, 0xDA51, + 0xDA59, 0xDA5D, 0xDA5F, 0xDA71, 0xDA77, 0xDA7B, 0xDA7D, 0xDA8D, + 0xDA9F, 0xDAB3, 0xDABD, 0xDAC3, 0xDAC9, 0xDAE7, 0xDAE9, 0xDAF5, + 0xDB11, 0xDB17, 0xDB1D, 0xDB23, 0xDB25, 0xDB31, 0xDB3B, 0xDB43, + 0xDB55, 0xDB67, 0xDB6B, 0xDB73, 0xDB85, 0xDB8F, 0xDB91, 0xDBAD, + 0xDBAF, 0xDBB9, 0xDBC7, 0xDBCB, 0xDBCD, 0xDBEB, 0xDBF7, 0xDC0D, + 0xDC27, 0xDC31, 0xDC39, 0xDC3F, 0xDC49, 0xDC51, 0xDC61, 0xDC6F, + 0xDC75, 0xDC7B, 0xDC85, 0xDC93, 0xDC99, 0xDC9D, 0xDC9F, 0xDCA9, + 0xDCB5, 0xDCB7, 0xDCBD, 0xDCC7, 0xDCCF, 0xDCD3, 0xDCD5, 0xDCDF, + 0xDCF9, 0xDD0F, 0xDD15, 0xDD17, 0xDD23, 0xDD35, 0xDD39, 0xDD53, + 0xDD57, 0xDD5F, 0xDD69, 0xDD6F, 0xDD7D, 0xDD87, 0xDD89, 0xDD9B, + 0xDDA1, 0xDDAB, 0xDDBF, 0xDDC5, 0xDDCB, 0xDDCF, 0xDDE7, 0xDDE9, + 0xDDED, 0xDDF5, 0xDDFB, 0xDE0B, 0xDE19, 0xDE29, 0xDE3B, 0xDE3D, + 0xDE41, 0xDE4D, 0xDE4F, 0xDE59, 0xDE5B, 0xDE61, 0xDE6D, 0xDE77, + 0xDE7D, 0xDE83, 0xDE97, 0xDE9D, 0xDEA1, 0xDEA7, 0xDECD, 0xDED1, + 0xDED7, 0xDEE3, 0xDEF1, 0xDEF5, 0xDF01, 0xDF09, 0xDF13, 0xDF1F, + 0xDF2B, 0xDF33, 0xDF37, 0xDF3D, 0xDF4B, 0xDF55, 0xDF5B, 0xDF67, + 0xDF69, 0xDF73, 0xDF85, 0xDF87, 0xDF99, 0xDFA3, 0xDFAB, 0xDFB5, + 0xDFB7, 0xDFC3, 0xDFC7, 0xDFD5, 0xDFF1, 0xDFF3, 0xE003, 0xE005, + 0xE017, 0xE01D, 0xE027, 0xE02D, 0xE035, 0xE045, 0xE053, 0xE071, + 0xE07B, 0xE08F, 0xE095, 0xE09F, 0xE0B7, 0xE0B9, 0xE0D5, 0xE0D7, + 0xE0E3, 0xE0F3, 0xE0F9, 0xE101, 0xE125, 0xE129, 0xE131, 0xE135, + 0xE143, 0xE14F, 0xE159, 0xE161, 0xE16D, 0xE171, 0xE177, 0xE17F, + 0xE183, 0xE189, 0xE197, 0xE1AD, 0xE1B5, 0xE1BB, 0xE1BF, 0xE1C1, + 0xE1CB, 0xE1D1, 0xE1E5, 0xE1EF, 0xE1F7, 0xE1FD, 0xE203, 0xE219, + 0xE22B, 0xE22D, 0xE23D, 0xE243, 0xE257, 0xE25B, 0xE275, 0xE279, + 0xE287, 0xE29D, 0xE2AB, 0xE2AF, 0xE2BB, 0xE2C1, 0xE2C9, 0xE2CD, + 0xE2D3, 0xE2D9, 0xE2F3, 0xE2FD, 0xE2FF, 0xE311, 0xE323, 0xE327, + 0xE329, 0xE339, 0xE33B, 0xE34D, 0xE351, 0xE357, 0xE35F, 0xE363, + 0xE369, 0xE375, 0xE377, 0xE37D, 0xE383, 0xE39F, 0xE3C5, 0xE3C9, + 0xE3D1, 0xE3E1, 0xE3FB, 0xE3FF, 0xE401, 0xE40B, 0xE417, 0xE419, + 0xE423, 0xE42B, 0xE431, 0xE43B, 0xE447, 0xE449, 0xE453, 0xE455, + 0xE46D, 0xE471, 0xE48F, 0xE4A9, 0xE4AF, 0xE4B5, 0xE4C7, 0xE4CD, + 0xE4D3, 0xE4E9, 0xE4EB, 0xE4F5, 0xE507, 0xE521, 0xE525, 0xE537, + 0xE53F, 0xE545, 0xE54B, 0xE557, 0xE567, 0xE56D, 0xE575, 0xE585, + 0xE58B, 0xE593, 0xE5A3, 0xE5A5, 0xE5CF, 0xE609, 0xE611, 0xE615, + 0xE61B, 0xE61D, 0xE621, 0xE629, 0xE639, 0xE63F, 0xE653, 0xE657, + 0xE663, 0xE66F, 0xE675, 0xE681, 0xE683, 0xE68D, 0xE68F, 0xE695, + 0xE6AB, 0xE6AD, 0xE6B7, 0xE6BD, 0xE6C5, 0xE6CB, 0xE6D5, 0xE6E3, + 0xE6E9, 0xE6EF, 0xE6F3, 0xE705, 0xE70D, 0xE717, 0xE71F, 0xE72F, + 0xE73D, 0xE747, 0xE749, 0xE753, 0xE755, 0xE761, 0xE767, 0xE76B, + 0xE77F, 0xE789, 0xE791, 0xE7C5, 0xE7CD, 0xE7D7, 0xE7DD, 0xE7DF, + 0xE7E9, 0xE7F1, 0xE7FB, 0xE801, 0xE807, 0xE80F, 0xE819, 0xE81B, + 0xE831, 0xE833, 0xE837, 0xE83D, 0xE84B, 0xE84F, 0xE851, 0xE869, + 0xE875, 0xE879, 0xE893, 0xE8A5, 0xE8A9, 0xE8AF, 0xE8BD, 0xE8DB, + 0xE8E1, 0xE8E5, 0xE8EB, 0xE8ED, 0xE903, 0xE90B, 0xE90F, 0xE915, + 0xE917, 0xE92D, 0xE933, 0xE93B, 0xE94B, 0xE951, 0xE95F, 0xE963, + 0xE969, 0xE97B, 0xE983, 0xE98F, 0xE995, 0xE9A1, 0xE9B9, 0xE9D7, + 0xE9E7, 0xE9EF, 0xEA11, 0xEA19, 0xEA2F, 0xEA35, 0xEA43, 0xEA4D, + 0xEA5F, 0xEA6D, 0xEA71, 0xEA7D, 0xEA85, 0xEA89, 0xEAAD, 0xEAB3, + 0xEAB9, 0xEABB, 0xEAC5, 0xEAC7, 0xEACB, 0xEADF, 0xEAE5, 0xEAEB, + 0xEAF5, 0xEB01, 0xEB07, 0xEB09, 0xEB31, 0xEB39, 0xEB3F, 0xEB5B, + 0xEB61, 0xEB63, 0xEB6F, 0xEB81, 0xEB85, 0xEB9D, 0xEBAB, 0xEBB1, + 0xEBB7, 0xEBC1, 0xEBD5, 0xEBDF, 0xEBED, 0xEBFD, 0xEC0B, 0xEC1B, + 0xEC21, 0xEC29, 0xEC4D, 0xEC51, 0xEC5D, 0xEC69, 0xEC6F, 0xEC7B, + 0xECAD, 0xECB9, 0xECBF, 0xECC3, 0xECC9, 0xECCF, 0xECD7, 0xECDD, + 0xECE7, 0xECE9, 0xECF3, 0xECF5, 0xED07, 0xED11, 0xED1F, 0xED2F, + 0xED37, 0xED3D, 0xED41, 0xED55, 0xED59, 0xED5B, 0xED65, 0xED6B, + 0xED79, 0xED8B, 0xED95, 0xEDBB, 0xEDC5, 0xEDD7, 0xEDD9, 0xEDE3, + 0xEDE5, 0xEDF1, 0xEDF5, 0xEDF7, 0xEDFB, 0xEE09, 0xEE0F, 0xEE19, + 0xEE21, 0xEE49, 0xEE4F, 0xEE63, 0xEE67, 0xEE73, 0xEE7B, 0xEE81, + 0xEEA3, 0xEEAB, 0xEEC1, 0xEEC9, 0xEED5, 0xEEDF, 0xEEE1, 0xEEF1, + 0xEF1B, 0xEF27, 0xEF2F, 0xEF45, 0xEF4D, 0xEF63, 0xEF6B, 0xEF71, + 0xEF93, 0xEF95, 0xEF9B, 0xEF9F, 0xEFAD, 0xEFB3, 0xEFC3, 0xEFC5, + 0xEFDB, 0xEFE1, 0xEFE9, 0xF001, 0xF017, 0xF01D, 0xF01F, 0xF02B, + 0xF02F, 0xF035, 0xF043, 0xF047, 0xF04F, 0xF067, 0xF06B, 0xF071, + 0xF077, 0xF079, 0xF08F, 0xF0A3, 0xF0A9, 0xF0AD, 0xF0BB, 0xF0BF, + 0xF0C5, 0xF0CB, 0xF0D3, 0xF0D9, 0xF0E3, 0xF0E9, 0xF0F1, 0xF0F7, + 0xF107, 0xF115, 0xF11B, 0xF121, 0xF137, 0xF13D, 0xF155, 0xF175, + 0xF17B, 0xF18D, 0xF193, 0xF1A5, 0xF1AF, 0xF1B7, 0xF1D5, 0xF1E7, + 0xF1ED, 0xF1FD, 0xF209, 0xF20F, 0xF21B, 0xF21D, 0xF223, 0xF227, + 0xF233, 0xF23B, 0xF241, 0xF257, 0xF25F, 0xF265, 0xF269, 0xF277, + 0xF281, 0xF293, 0xF2A7, 0xF2B1, 0xF2B3, 0xF2B9, 0xF2BD, 0xF2BF, + 0xF2DB, 0xF2ED, 0xF2EF, 0xF2F9, 0xF2FF, 0xF305, 0xF30B, 0xF319, + 0xF341, 0xF359, 0xF35B, 0xF35F, 0xF367, 0xF373, 0xF377, 0xF38B, + 0xF38F, 0xF3AF, 0xF3C1, 0xF3D1, 0xF3D7, 0xF3FB, 0xF403, 0xF409, + 0xF40D, 0xF413, 0xF421, 0xF425, 0xF42B, 0xF445, 0xF44B, 0xF455, + 0xF463, 0xF475, 0xF47F, 0xF485, 0xF48B, 0xF499, 0xF4A3, 0xF4A9, + 0xF4AF, 0xF4BD, 0xF4C3, 0xF4DB, 0xF4DF, 0xF4ED, 0xF503, 0xF50B, + 0xF517, 0xF521, 0xF529, 0xF535, 0xF547, 0xF551, 0xF563, 0xF56B, + 0xF583, 0xF58D, 0xF595, 0xF599, 0xF5B1, 0xF5B7, 0xF5C9, 0xF5CF, + 0xF5D1, 0xF5DB, 0xF5F9, 0xF5FB, 0xF605, 0xF607, 0xF60B, 0xF60D, + 0xF635, 0xF637, 0xF653, 0xF65B, 0xF661, 0xF667, 0xF679, 0xF67F, + 0xF689, 0xF697, 0xF69B, 0xF6AD, 0xF6CB, 0xF6DD, 0xF6DF, 0xF6EB, + 0xF709, 0xF70F, 0xF72D, 0xF731, 0xF743, 0xF74F, 0xF751, 0xF755, + 0xF763, 0xF769, 0xF773, 0xF779, 0xF781, 0xF787, 0xF791, 0xF79D, + 0xF79F, 0xF7A5, 0xF7B1, 0xF7BB, 0xF7BD, 0xF7CF, 0xF7D3, 0xF7E7, + 0xF7EB, 0xF7F1, 0xF7FF, 0xF805, 0xF80B, 0xF821, 0xF827, 0xF82D, + 0xF835, 0xF847, 0xF859, 0xF863, 0xF865, 0xF86F, 0xF871, 0xF877, + 0xF87B, 0xF881, 0xF88D, 0xF89F, 0xF8A1, 0xF8AB, 0xF8B3, 0xF8B7, + 0xF8C9, 0xF8CB, 0xF8D1, 0xF8D7, 0xF8DD, 0xF8E7, 0xF8EF, 0xF8F9, + 0xF8FF, 0xF911, 0xF91D, 0xF925, 0xF931, 0xF937, 0xF93B, 0xF941, + 0xF94F, 0xF95F, 0xF961, 0xF96D, 0xF971, 0xF977, 0xF99D, 0xF9A3, + 0xF9A9, 0xF9B9, 0xF9CD, 0xF9E9, 0xF9FD, 0xFA07, 0xFA0D, 0xFA13, + 0xFA21, 0xFA25, 0xFA3F, 0xFA43, 0xFA51, 0xFA5B, 0xFA6D, 0xFA7B, + 0xFA97, 0xFA99, 0xFA9D, 0xFAAB, 0xFABB, 0xFABD, 0xFAD9, 0xFADF, + 0xFAE7, 0xFAED, 0xFB0F, 0xFB17, 0xFB1B, 0xFB2D, 0xFB2F, 0xFB3F, + 0xFB47, 0xFB4D, 0xFB75, 0xFB7D, 0xFB8F, 0xFB93, 0xFBB1, 0xFBB7, + 0xFBC3, 0xFBC5, 0xFBE3, 0xFBE9, 0xFBF3, 0xFC01, 0xFC29, 0xFC37, + 0xFC41, 0xFC43, 0xFC4F, 0xFC59, 0xFC61, 0xFC65, 0xFC6D, 0xFC73, + 0xFC79, 0xFC95, 0xFC97, 0xFC9B, 0xFCA7, 0xFCB5, 0xFCC5, 0xFCCD, + 0xFCEB, 0xFCFB, 0xFD0D, 0xFD0F, 0xFD19, 0xFD2B, 0xFD31, 0xFD51, + 0xFD55, 0xFD67, 0xFD6D, 0xFD6F, 0xFD7B, 0xFD85, 0xFD97, 0xFD99, + 0xFD9F, 0xFDA9, 0xFDB7, 0xFDC9, 0xFDE5, 0xFDEB, 0xFDF3, 0xFE03, + 0xFE05, 0xFE09, 0xFE1D, 0xFE27, 0xFE2F, 0xFE41, 0xFE4B, 0xFE4D, + 0xFE57, 0xFE5F, 0xFE63, 0xFE69, 0xFE75, 0xFE7B, 0xFE8F, 0xFE93, + 0xFE95, 0xFE9B, 0xFE9F, 0xFEB3, 0xFEBD, 0xFED7, 0xFEE9, 0xFEF3, + 0xFEF5, 0xFF07, 0xFF0D, 0xFF1D, 0xFF2B, 0xFF2F, 0xFF49, 0xFF4D, + 0xFF5B, 0xFF65, 0xFF71, 0xFF7F, 0xFF85, 0xFF8B, 0xFF8F, 0xFF9D, + 0xFFA7, 0xFFA9, 0xFFC7, 0xFFD9, 0xFFEF, 0xFFF1 }; +#endif + +#define UPPER_LIMIT (sizeof(prime_tab) / sizeof(prime_tab[0])) + +/* figures out if a number is prime (MR test) */ +#ifdef CLEAN_STACK +static int _is_prime(mp_int *N, int *result) +#else +int is_prime(mp_int *N, int *result) +#endif +{ + long x, s, j; + int res; + mp_int n1, a, y, r; + mp_digit d; + + _ARGCHK(N != NULL); + _ARGCHK(result != NULL); + + /* default to answer of no */ + *result = 0; + + /* divisible by any of the first primes? */ + for (x = 0; x < (long)UPPER_LIMIT; x++) { + /* is N equal to a small prime? */ + if (mp_cmp_d(N, prime_tab[x]) == 0) { + *result = 1; + return CRYPT_OK; + } + + /* is N mod prime_tab[x] == 0, then its divisible by it */ + if (mp_mod_d(N, prime_tab[x], &d) != MP_OKAY) { + return CRYPT_MEM; + } + + if (d == 0) { + return CRYPT_OK; + } + } + + /* init variables */ + if (mp_init_multi(&r, &n1, &a, &y, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + /* n1 = N - 1 */ + if (mp_sub_d(N, 1, &n1) != MP_OKAY) { goto error; } + + /* r = N - 1 */ + if (mp_copy(&n1, &r) != MP_OKAY) { goto error; } + + /* find s such that N = (2^s)r */ + s = 0; + while (mp_iseven(&r) && mp_cmp_d(&r, 0)) { + ++s; + if (mp_div_2(&r, &r) != MP_OKAY) { + goto error; + } + } + + for (x = 0; x < 16; x++) { + /* choose a */ + mp_set(&a, prime_tab[x]); + + /* compute y = a^r mod n */ + if (mp_exptmod(&a, &r, N, &y) != MP_OKAY) { goto error; } + + /* (y != 1) AND (y != N-1) */ + if ((mp_cmp_d(&y, 1) != 0) && (mp_cmp(&y, &n1) != 0)) { + /* while j <= s-1 and y != n-1 */ + for (j = 1; (j <= (s-1)) && (mp_cmp(&y, &n1) != 0); j++) { + /* y = y^2 mod N */ + if (mp_sqrmod(&y, N, &y) != MP_OKAY) { goto error; } + + /* if y == 1 return false */ + if (mp_cmp_d(&y, 1) == 0) { goto ok; } + } + + /* if y != n-1 return false */ + if (mp_cmp(&y, &n1) != 0) { goto ok; } + } + } + *result = 1; +ok: + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +done: + mp_clear_multi(&a, &y, &n1, &r, NULL); + return res; +} + +#ifdef CLEAN_STACK +int is_prime(mp_int *N, int *result) +{ + int x; + x = _is_prime(N, result); + burn_stack(sizeof(long) * 3 + sizeof(int) + sizeof(mp_int) * 4 + sizeof(mp_digit)); + return x; +} +#endif + +int rand_prime(mp_int *N, long len, prng_state *prng, int wprng) +{ + unsigned char buf[260]; + int errno, step, ormask, res; + + _ARGCHK(N != NULL); + + /* pass a negative size if you want a prime congruent to 3 mod 4 */ + if (len < 0) { + step = 4; + ormask = 3; + len = -len; + } else { + step = 2; + ormask = 1; + } + + /* allow sizes between 2 and 256 bytes for a prime size */ + if (len < 2 || len > 256) { + return CRYPT_INVALID_PRIME_SIZE; + } + + /* valid PRNG? */ + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + /* read the prng */ + if (prng_descriptor[wprng].read(buf+2, len, prng) != (unsigned long)len) { + return CRYPT_ERROR_READPRNG; + } + + /* set sign byte to zero */ + buf[0] = 0; + + /* Set the top byte to 0x01 which makes the number a len*8 bit number */ + buf[1] = 0x01; + + /* set the LSB to the desired settings + * (1 for any prime, 3 for primes congruent to 3 mod 4) + */ + buf[len+1] |= ormask; + + /* read the number in */ + if (mp_read_raw(N, buf, 2+len) != MP_OKAY) { + return CRYPT_MEM; + } + + /* add the step size to it while N is not prime */ + do { + if (mp_add_d(N, (mp_digit)step, N) != MP_OKAY) { + return CRYPT_MEM; + } + if ((errno = is_prime(N, &res)) != CRYPT_OK) { + return errno; + } + } while (res == 0); + +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + + return CRYPT_OK; +} + +#endif + + + diff --git a/rc2.c b/rc2.c new file mode 100644 index 0000000..c4a8b81 --- /dev/null +++ b/rc2.c @@ -0,0 +1,321 @@ +/**********************************************************************\ +* To commemorate the 1996 RSA Data Security Conference, the following * +* code is released into the public domain by its author. Prost! * +* * +* This cipher uses 16-bit words and little-endian byte ordering. * +* I wonder which processor it was optimized for? * +* * +* Thanks to CodeView, SoftIce, and D86 for helping bring this code to * +* the public. * +\**********************************************************************/ + +#include + +#ifdef RC2 + +const struct _cipher_descriptor rc2_desc = { + "rc2", + 12, 8, 128, 8, 16, + &rc2_setup, + &rc2_ecb_encrypt, + &rc2_ecb_decrypt, + &rc2_test, + &rc2_keysize +}; + + +/**********************************************************************\ +* Expand a variable-length user key (between 1 and 128 bytes) to a * +* 64-short working rc2 key, of at most "bits" effective key bits. * +* The effective key bits parameter looks like an export control hack. * +* For normal use, it should always be set to 1024. For convenience, * +* zero is accepted as an alias for 1024. * +\**********************************************************************/ + + /* 256-entry permutation table, probably derived somehow from pi */ + static const unsigned char permute[256] = { + 217,120,249,196, 25,221,181,237, 40,233,253,121, 74,160,216,157, + 198,126, 55,131, 43,118, 83,142, 98, 76,100,136, 68,139,251,162, + 23,154, 89,245,135,179, 79, 19, 97, 69,109,141, 9,129,125, 50, + 189,143, 64,235,134,183,123, 11,240,149, 33, 34, 92,107, 78,130, + 84,214,101,147,206, 96,178, 28,115, 86,192, 20,167,140,241,220, + 18,117,202, 31, 59,190,228,209, 66, 61,212, 48,163, 60,182, 38, + 111,191, 14,218, 70,105, 7, 87, 39,242, 29,155,188,148, 67, 3, + 248, 17,199,246,144,239, 62,231, 6,195,213, 47,200,102, 30,215, + 8,232,234,222,128, 82,238,247,132,170,114,172, 53, 77,106, 42, + 150, 26,210,113, 90, 21, 73,116, 75,159,208, 94, 4, 24,164,236, + 194,224, 65,110, 15, 81,203,204, 36,145,175, 80,161,244,112, 57, + 153,124, 58,133, 35,184,180,122,252, 2, 54, 91, 37, 85,151, 49, + 45, 93,250,152,227,138,146,174, 5,223, 41, 16,103,108,186,201, + 211, 0,230,207,225,158,168, 44, 99, 22, 1, 63, 88,226,137,169, + 13, 56, 52, 27,171, 51,255,176,187, 72, 12, 95,185,177,205, 46, + 197,243,219, 71,229,165,156,119, 10,166, 32,104,254,127,193,173 + }; + +int rc2_setup(const unsigned char *key, int keylen, int rounds, symmetric_key *skey) +{ + unsigned *xkey = skey->rc2.xkey; + unsigned char tmp[128]; + unsigned T8, TM; + int i, bits; + + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + if (keylen < 8 || keylen > 128) { + return CRYPT_INVALID_KEYSIZE; + } + + if (rounds && rounds != 16) { + return CRYPT_INVALID_ROUNDS; + } + + for (i = 0; i < keylen; i++) { + tmp[i] = key[i]; + } + + /* Phase 1: Expand input key to 128 bytes */ + if (keylen < 128) { + for (i = keylen; i < 128; i++) { + tmp[i] = permute[(tmp[i - 1] + tmp[i - keylen]) & 255]; + } + } + + /* Phase 2 - reduce effective key size to "bits" */ + bits = keylen*8; + T8 = (bits+7)>>3; + TM = (255 >> (7 & -bits)); + tmp[128 - T8] = permute[tmp[128 - T8] & TM]; + for (i = 127 - T8; i >= 0; i--) { + tmp[i] = permute[tmp[i + 1] ^ tmp[i + T8]]; + } + + /* Phase 3 - copy to xkey in little-endian order */ + i = 63; + do { + xkey[i] = (unsigned)tmp[2*i] + ((unsigned)tmp[2*i+1] << 8); + } while (i--); + +#ifdef CLEAN_STACK + zeromem(tmp, sizeof(tmp)); +#endif + + return CRYPT_OK; +} + +/**********************************************************************\ +* Encrypt an 8-byte block of plaintext using the given key. * +\**********************************************************************/ +#ifdef CLEAN_STACK +static void _rc2_ecb_encrypt( const unsigned char *plain, + unsigned char *cipher, + symmetric_key *skey) +#else +void rc2_ecb_encrypt( const unsigned char *plain, + unsigned char *cipher, + symmetric_key *skey) +#endif +{ + unsigned *xkey = skey->rc2.xkey; + unsigned x76, x54, x32, x10, i; + + _ARGCHK(plain != NULL); + _ARGCHK(cipher != NULL); + _ARGCHK(skey != NULL); + + x76 = ((unsigned)plain[7] << 8) + (unsigned)plain[6]; + x54 = ((unsigned)plain[5] << 8) + (unsigned)plain[4]; + x32 = ((unsigned)plain[3] << 8) + (unsigned)plain[2]; + x10 = ((unsigned)plain[1] << 8) + (unsigned)plain[0]; + + for (i = 0; i < 16; i++) { + x10 = (x10 + (x32 & ~x76) + (x54 & x76) + xkey[4*i+0]) & 0xFFFF; + x10 = ((x10 << 1) | (x10 >> 15)) & 0xFFFF; + + x32 = (x32 + (x54 & ~x10) + (x76 & x10) + xkey[4*i+1]) & 0xFFFF; + x32 = ((x32 << 2) | (x32 >> 14)) & 0xFFFF; + + x54 = (x54 + (x76 & ~x32) + (x10 & x32) + xkey[4*i+2]) & 0xFFFF; + x54 = ((x54 << 3) | (x54 >> 13)) & 0xFFFF; + + x76 = (x76 + (x10 & ~x54) + (x32 & x54) + xkey[4*i+3]) & 0xFFFF; + x76 = ((x76 << 5) | (x76 >> 11)) & 0xFFFF; + + if (i == 4 || i == 10) { + x10 = (x10 + xkey[x76 & 63]) & 0xFFFF; + x32 = (x32 + xkey[x10 & 63]) & 0xFFFF; + x54 = (x54 + xkey[x32 & 63]) & 0xFFFF; + x76 = (x76 + xkey[x54 & 63]) & 0xFFFF; + } + } + + cipher[0] = (unsigned char)x10; + cipher[1] = (unsigned char)(x10 >> 8); + cipher[2] = (unsigned char)x32; + cipher[3] = (unsigned char)(x32 >> 8); + cipher[4] = (unsigned char)x54; + cipher[5] = (unsigned char)(x54 >> 8); + cipher[6] = (unsigned char)x76; + cipher[7] = (unsigned char)(x76 >> 8); +} + +#ifdef CLEAN_STACK +void rc2_ecb_encrypt( const unsigned char *plain, + unsigned char *cipher, + symmetric_key *skey) +{ + _rc2_ecb_encrypt(plain, cipher, skey); + burn_stack(sizeof(unsigned *) + sizeof(unsigned) * 5); +} +#endif + +/**********************************************************************\ +* Decrypt an 8-byte block of ciphertext using the given key. * +\**********************************************************************/ + +#ifdef CLEAN_STACK +static void _rc2_ecb_decrypt( const unsigned char *cipher, + unsigned char *plain, + symmetric_key *skey) +#else +void rc2_ecb_decrypt( const unsigned char *cipher, + unsigned char *plain, + symmetric_key *skey) +#endif +{ + unsigned x76, x54, x32, x10; + unsigned *xkey = skey->rc2.xkey; + int i; + + _ARGCHK(plain != NULL); + _ARGCHK(cipher != NULL); + _ARGCHK(skey != NULL); + + x76 = ((unsigned)cipher[7] << 8) + (unsigned)cipher[6]; + x54 = ((unsigned)cipher[5] << 8) + (unsigned)cipher[4]; + x32 = ((unsigned)cipher[3] << 8) + (unsigned)cipher[2]; + x10 = ((unsigned)cipher[1] << 8) + (unsigned)cipher[0]; + + for (i = 15; i >= 0; i--) { + if (i == 4 || i == 10) { + x76 = (x76 - xkey[x54 & 63]) & 0xFFFF; + x54 = (x54 - xkey[x32 & 63]) & 0xFFFF; + x32 = (x32 - xkey[x10 & 63]) & 0xFFFF; + x10 = (x10 - xkey[x76 & 63]) & 0xFFFF; + } + + x76 = ((x76 << 11) | (x76 >> 5)) & 0xFFFF; + x76 = (x76 - ((x10 & ~x54) + (x32 & x54) + xkey[4*i+3])) & 0xFFFF; + + x54 = ((x54 << 13) | (x54 >> 3)) & 0xFFFF; + x54 = (x54 - ((x76 & ~x32) + (x10 & x32) + xkey[4*i+2])) & 0xFFFF; + + x32 = ((x32 << 14) | (x32 >> 2)) & 0xFFFF; + x32 = (x32 - ((x54 & ~x10) + (x76 & x10) + xkey[4*i+1])) & 0xFFFF; + + x10 = ((x10 << 15) | (x10 >> 1)) & 0xFFFF; + x10 = (x10 - ((x32 & ~x76) + (x54 & x76) + xkey[4*i+0])) & 0xFFFF; + } + + plain[0] = (unsigned char)x10; + plain[1] = (unsigned char)(x10 >> 8); + plain[2] = (unsigned char)x32; + plain[3] = (unsigned char)(x32 >> 8); + plain[4] = (unsigned char)x54; + plain[5] = (unsigned char)(x54 >> 8); + plain[6] = (unsigned char)x76; + plain[7] = (unsigned char)(x76 >> 8); +} + +#ifdef CLEAN_STACK +void rc2_ecb_decrypt( const unsigned char *cipher, + unsigned char *plain, + symmetric_key *skey) +{ + _rc2_ecb_decrypt(cipher, plain, skey); + burn_stack(sizeof(unsigned *) + sizeof(unsigned) * 4 + sizeof(int)); +} +#endif + +int rc2_test(void) +{ + static const struct { + int keylen; + unsigned char key[16], pt[8], ct[8]; + } tests[] = { + + { 8, + { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x30, 0x64, 0x9e, 0xdf, 0x9b, 0xe7, 0xd2, 0xc2 } + + }, + { 16, + { 0x88, 0xbc, 0xa9, 0x0e, 0x90, 0x87, 0x5a, 0x7f, + 0x0f, 0x79, 0xc3, 0x84, 0x62, 0x7b, 0xaf, 0xb2 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x22, 0x69, 0x55, 0x2a, 0xb0, 0xf8, 0x5c, 0xa6 } + } + }; + int x, failed, errno; + symmetric_key skey; + unsigned char buf[2][8]; + + failed = 0; + for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) { + zeromem(buf, sizeof(buf)); + if ((errno = rc2_setup(tests[x].key, tests[x].keylen, 0, &skey)) != CRYPT_OK) { + return errno; + } + + rc2_ecb_encrypt(tests[x].pt, buf[0], &skey); + rc2_ecb_decrypt(buf[0], buf[1], &skey); + + if (memcmp(buf[0], tests[x].ct, 8)) { +#if 0 + int y; + printf("\nTest %d failed to encrypt\n", x); + for (y = 0; y < 8; y++) { + printf("%02x ", buf[0][y]); + } + printf("\n"); +#endif + failed = 1; + } + + if (memcmp(buf[1], tests[x].pt, 8)) { +#if 0 + int y; + printf("\nTest %d failed to decrypt\n", x); + for (y = 0; y < 8; y++) { + printf("%02x ", buf[1][y]); + } + printf("\n"); +#endif + failed = 1; + } + } + + if (failed == 1) { + return CRYPT_FAIL_TESTVECTOR; + } else { + return CRYPT_OK; + } +} + +int rc2_keysize(int *keysize) +{ + _ARGCHK(keysize != NULL); + if (*keysize < 8) { + return CRYPT_INVALID_KEYSIZE; + } else if (*keysize > 128) { + *keysize = 128; + } + return CRYPT_OK; +} + +#endif + + + diff --git a/rc4.c b/rc4.c new file mode 100644 index 0000000..e60cada --- /dev/null +++ b/rc4.c @@ -0,0 +1,97 @@ +#include "mycrypt.h" + +#ifdef RC4 + +const struct _prng_descriptor rc4_desc = +{ + "rc4", + &rc4_start, + &rc4_add_entropy, + &rc4_ready, + &rc4_read +}; + +int rc4_start(prng_state *prng) +{ + _ARGCHK(prng != NULL); + + /* set keysize to zero */ + prng->rc4.x = 0; + + return CRYPT_OK; +} + +int rc4_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng) +{ + _ARGCHK(buf != NULL); + _ARGCHK(prng != NULL); + + if (prng->rc4.x + len > 256) { + return CRYPT_INVALID_KEYSIZE; + } + + while (len--) { + prng->rc4.buf[prng->rc4.x++] = *buf++; + } + + return CRYPT_OK; + +} + +int rc4_ready(prng_state *prng) +{ + unsigned char key[256], tmp; + int keylen, x, y; + + _ARGCHK(prng != NULL); + + /* extract the key */ + memcpy(key, prng->rc4.buf, 256); + keylen = prng->rc4.x; + + /* make RC4 perm and shuffle */ + for (x = 0; x < 256; x++) { + prng->rc4.buf[x] = x; + } + + for (x = y = 0; x < 256; x++) { + y = (y + prng->rc4.buf[x] + key[x % keylen]) & 255; + tmp = prng->rc4.buf[x]; prng->rc4.buf[x] = prng->rc4.buf[y]; prng->rc4.buf[y] = tmp; + } + prng->rc4.x = x; + prng->rc4.y = y; + +#ifdef CLEAN_STACK + zeromem(key, sizeof(key)); +#endif + + return CRYPT_OK; +} + +unsigned long rc4_read(unsigned char *buf, unsigned long len, prng_state *prng) +{ + int x, y; + unsigned char *s, tmp; + unsigned long n; + + _ARGCHK(buf != NULL); + _ARGCHK(prng != NULL); + + n = len; + x = prng->rc4.x; + y = prng->rc4.y; + s = prng->rc4.buf; + while (len--) { + x = (x + 1) & 255; + y = (y + s[x]) & 255; + tmp = s[x]; s[x] = s[y]; s[y] = tmp; + tmp = (s[x] + s[y]) & 255; + *buf++ ^= s[tmp]; + } + prng->rc4.x = x; + prng->rc4.y = y; + return n; +} + +#endif + diff --git a/rc5.c b/rc5.c new file mode 100644 index 0000000..d699ba6 --- /dev/null +++ b/rc5.c @@ -0,0 +1,234 @@ +#include "mycrypt.h" + +#ifdef RC5 + +const struct _cipher_descriptor rc5_desc = +{ + "rc5", + 2, + 8, 128, 8, 12, + &rc5_setup, + &rc5_ecb_encrypt, + &rc5_ecb_decrypt, + &rc5_test, + &rc5_keysize +}; + +#ifdef CLEAN_STACK +static int _rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +#else +int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +#endif +{ + unsigned long L[64], S[50], A, B, i, j, v, s, t, l; + + _ARGCHK(skey != NULL); + _ARGCHK(key != NULL); + + /* test parameters */ + if (num_rounds == 0) { + num_rounds = rc5_desc.default_rounds; + } + + if (num_rounds < 12 || num_rounds > 24) { + return CRYPT_INVALID_ROUNDS; + } + + /* key must be between 64 and 1024 bits */ + if (keylen < 8 || keylen > 128) { + return CRYPT_INVALID_KEYSIZE; + } + + /* copy the key into the L array */ + for (A = i = j = 0; i < (unsigned long)keylen; ) { + A = (A << 8) | ((unsigned long)(key[i++] & 255)); + if (!(i & 3)) { + L[j++] = BSWAP(A); + A = 0; + } + } + + if (keylen & 3) { + A <<= (8 * (4 - (keylen&3))); + L[j++] = BSWAP(A); + } + + /* setup the S array */ + t = 2 * (num_rounds + 1); + S[0] = 0xB7E15163UL; + for (i = 1; i < t; i++) S[i] = S[i - 1] + 0x9E3779B9UL; + + /* mix buffer */ + s = 3 * MAX(t, j); + l = j; + for (A = B = i = j = v = 0; v < s; v++) { + A = S[i] = ROL(S[i] + A + B, 3); + B = L[j] = ROL(L[j] + A + B, (A+B)); + i = (i + 1) % t; + j = (j + 1) % l; + } + + /* copy to key */ + for (i = 0; i < t; i++) { + skey->rc5.K[i] = S[i]; + } + skey->rc5.rounds = num_rounds; + return CRYPT_OK; +} + +#ifdef CLEAN_STACK +int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + int x; + x = _rc5_setup(key, keylen, num_rounds, skey); + burn_stack(sizeof(unsigned long) * 122 + sizeof(int)); + return x; +} +#endif + +#ifdef CLEAN_STACK +static void _rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#else +void rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#endif +{ + unsigned long A, B; + int r; + _ARGCHK(key != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + + LOAD32L(A, &pt[0]); + LOAD32L(B, &pt[4]); + A += key->rc5.K[0]; + B += key->rc5.K[1]; + for (r = 0; r < key->rc5.rounds; r++) { + A = ROL(A ^ B, B) + key->rc5.K[r+r+2]; + B = ROL(B ^ A, A) + key->rc5.K[r+r+3]; + } + STORE32L(A, &ct[0]); + STORE32L(B, &ct[4]); +} + +#ifdef CLEAN_STACK +void rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + _rc5_ecb_encrypt(pt, ct, key); + burn_stack(sizeof(unsigned long) * 2 + sizeof(int)); +} +#endif + +#ifdef CLEAN_STACK +static void _rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#else +void rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#endif +{ + unsigned long A, B; + int r; + _ARGCHK(key != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + + LOAD32L(A, &ct[0]); + LOAD32L(B, &ct[4]); + for (r = key->rc5.rounds - 1; r >= 0; r--) { + B = ROR(B - key->rc5.K[r+r+3], A) ^ A; + A = ROR(A - key->rc5.K[r+r+2], B) ^ B; + } + A -= key->rc5.K[0]; + B -= key->rc5.K[1]; + STORE32L(A, &pt[0]); + STORE32L(B, &pt[4]); +} + +#ifdef CLEAN_STACK +void rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +{ + _rc5_ecb_decrypt(ct, pt, key); + burn_stack(sizeof(unsigned long) * 2 + sizeof(int)); +} +#endif + +int rc5_test(void) +{ + static const struct { + unsigned char key[16], pt[8], ct[8]; + } tests[] = { + { + { 0x91, 0x5f, 0x46, 0x19, 0xbe, 0x41, 0xb2, 0x51, + 0x63, 0x55, 0xa5, 0x01, 0x10, 0xa9, 0xce, 0x91 }, + { 0x21, 0xa5, 0xdb, 0xee, 0x15, 0x4b, 0x8f, 0x6d }, + { 0xf7, 0xc0, 0x13, 0xac, 0x5b, 0x2b, 0x89, 0x52 } + }, + { + { 0x78, 0x33, 0x48, 0xe7, 0x5a, 0xeb, 0x0f, 0x2f, + 0xd7, 0xb1, 0x69, 0xbb, 0x8d, 0xc1, 0x67, 0x87 }, + { 0xF7, 0xC0, 0x13, 0xAC, 0x5B, 0x2B, 0x89, 0x52 }, + { 0x2F, 0x42, 0xB3, 0xB7, 0x03, 0x69, 0xFC, 0x92 } + }, + { + { 0xDC, 0x49, 0xdb, 0x13, 0x75, 0xa5, 0x58, 0x4f, + 0x64, 0x85, 0xb4, 0x13, 0xb5, 0xf1, 0x2b, 0xaf }, + { 0x2F, 0x42, 0xB3, 0xB7, 0x03, 0x69, 0xFC, 0x92 }, + { 0x65, 0xc1, 0x78, 0xb2, 0x84, 0xd1, 0x97, 0xcc } + } + }; + unsigned char buf[2][8]; + int x, failed, errno; + symmetric_key key; + + for (x = failed = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) { + /* setup key */ + if ((errno = rc5_setup(tests[x].key, 16, 12, &key)) != CRYPT_OK) { + return errno; + } + + /* encrypt and decrypt */ + rc5_ecb_encrypt(tests[x].pt, buf[0], &key); + rc5_ecb_decrypt(buf[0], buf[1], &key); + + /* compare */ + if (memcmp(buf[0], tests[x].ct, 8)) { +#if 0 + int y; + printf("\nEncrypt test %d failed\n", x); + for (y = 0; y < 8; y++) printf("%02x ", buf[0][y]); + printf("\n"); +#endif + failed = 1; + } + + if (memcmp(buf[1], tests[x].pt, 8)) { +#if 0 + int y; + printf("\nDecrypt test %d failed\n", x); + for (y = 0; y < 8; y++) printf("%02x ", buf[1][y]); + printf("\n"); +#endif + failed = 1; + } + } + + if (failed == 1) { + return CRYPT_FAIL_TESTVECTOR; + } else { + return CRYPT_OK; + } +} + +int rc5_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize != NULL); + if (*desired_keysize < 8) { + return CRYPT_INVALID_KEYSIZE; + } else if (*desired_keysize > 128) { + *desired_keysize = 128; + } + return CRYPT_OK; +} + +#endif + + + diff --git a/rc6.c b/rc6.c new file mode 100644 index 0000000..fc7aacd --- /dev/null +++ b/rc6.c @@ -0,0 +1,253 @@ +#include "mycrypt.h" + +#ifdef RC6 + +const struct _cipher_descriptor rc6_desc = +{ + "rc6", + 3, + 8, 128, 16, 20, + &rc6_setup, + &rc6_ecb_encrypt, + &rc6_ecb_decrypt, + &rc6_test, + &rc6_keysize +}; + +#ifdef CLEAN_STACK +static int _rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +#else +int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +#endif +{ + unsigned long L[64], S[50], A, B, i, j, v, s, t, l; + + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + /* test parameters */ + if (num_rounds != 0 && num_rounds != 20) { + return CRYPT_INVALID_ROUNDS; + } + + /* key must be between 64 and 1024 bits */ + if (keylen < 8 || keylen > 128) { + return CRYPT_INVALID_KEYSIZE; + } + + /* copy the key into the L array */ + for (A = i = j = 0; i < (unsigned long)keylen; ) { + A = (A << 8) | ((unsigned long)(key[i++] & 255)); + if (!(i & 3)) { + L[j++] = BSWAP(A); + A = 0; + } + } + + /* handle odd sized keys */ + if (keylen & 3) { + A <<= (8 * (4 - (keylen&3))); + L[j++] = BSWAP(A); + } + + /* setup the S array */ + t = 44; /* fixed at 20 rounds */ + S[0] = 0xB7E15163UL; + for (i = 1; i < t; i++) + S[i] = S[i - 1] + 0x9E3779B9UL; + + /* mix buffer */ + s = 3 * MAX(t, j); + l = j; + for (A = B = i = j = v = 0; v < s; v++) { + A = S[i] = ROL(S[i] + A + B, 3); + B = L[j] = ROL(L[j] + A + B, (A+B)); + i = (i + 1) % t; + j = (j + 1) % l; + } + + /* copy to key */ + for (i = 0; i < t; i++) { + skey->rc6.K[i] = S[i]; + } + return CRYPT_OK; +} + +#ifdef CLEAN_STACK +int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + int x; + x = _rc6_setup(key, keylen, num_rounds, skey); + burn_stack(sizeof(unsigned long) * 122); + return x; +} +#endif + +#ifdef CLEAN_STACK +static void _rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#else +void rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#endif +{ + unsigned long a,b,c,d,t,u; + int r; + + _ARGCHK(key != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + LOAD32L(a,&pt[0]);LOAD32L(b,&pt[4]);LOAD32L(c,&pt[8]);LOAD32L(d,&pt[12]); + b += key->rc6.K[0]; + d += key->rc6.K[1]; + for (r = 0; r < 20; r++) { + t = (b * (b + b + 1)); t = ROL(t, 5); + u = (d * (d + d + 1)); u = ROL(u, 5); + a = ROL(a^t,u) + key->rc6.K[r+r+2]; + c = ROL(c^u,t) + key->rc6.K[r+r+3]; + t = a; a = b; b = c; c = d; d = t; + } + a += key->rc6.K[42]; + c += key->rc6.K[43]; + STORE32L(a,&ct[0]);STORE32L(b,&ct[4]);STORE32L(c,&ct[8]);STORE32L(d,&ct[12]); +} + +#ifdef CLEAN_STACK +void rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + _rc6_ecb_encrypt(pt, ct, key); + burn_stack(sizeof(unsigned long) * 6 + sizeof(int)); +} +#endif + +#ifdef CLEAN_STACK +static void _rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#else +void rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#endif +{ + unsigned long a,b,c,d,t,u; + int r; + + _ARGCHK(key != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + + LOAD32L(a,&ct[0]);LOAD32L(b,&ct[4]);LOAD32L(c,&ct[8]);LOAD32L(d,&ct[12]); + a -= key->rc6.K[42]; + c -= key->rc6.K[43]; + for (r = 19; r >= 0; r--) { + t = d; d = c; c = b; b = a; a = t; + t = (b * (b + b + 1)); t = ROL(t, 5); + u = (d * (d + d + 1)); u = ROL(u, 5); + c = ROR(c - key->rc6.K[r+r+3], t) ^ u; + a = ROR(a - key->rc6.K[r+r+2], u) ^ t; + } + b -= key->rc6.K[0]; + d -= key->rc6.K[1]; + STORE32L(a,&pt[0]);STORE32L(b,&pt[4]);STORE32L(c,&pt[8]);STORE32L(d,&pt[12]); +} + +#ifdef CLEAN_STACK +void rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +{ + _rc6_ecb_decrypt(ct, pt, key); + burn_stack(sizeof(unsigned long) * 6 + sizeof(int)); +} +#endif + +int rc6_test(void) +{ + static const struct { + int keylen; + unsigned char key[32], pt[16], ct[16]; + } tests[] = { + { + 16, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79, + 0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1 }, + { 0x52, 0x4e, 0x19, 0x2f, 0x47, 0x15, 0xc6, 0x23, + 0x1f, 0x51, 0xf6, 0x36, 0x7e, 0xa4, 0x3f, 0x18 } + }, + { + 24, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, + 0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79, + 0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1 }, + { 0x68, 0x83, 0x29, 0xd0, 0x19, 0xe5, 0x05, 0x04, + 0x1e, 0x52, 0xe9, 0x2a, 0xf9, 0x52, 0x91, 0xd4 } + }, + { + 32, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, + 0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, 0xf0, + 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }, + { 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79, + 0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1 }, + { 0xc8, 0x24, 0x18, 0x16, 0xf0, 0xd7, 0xe4, 0x89, + 0x20, 0xad, 0x16, 0xa1, 0x67, 0x4e, 0x5d, 0x48 } + } + }; + unsigned char buf[2][16]; + int x, failed, errno; + symmetric_key key; + + for (x = failed = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) { + /* setup key */ + if ((errno = rc6_setup(tests[x].key, tests[x].keylen, 0, &key)) != CRYPT_OK) { + return errno; + } + + /* encrypt and decrypt */ + rc6_ecb_encrypt(tests[x].pt, buf[0], &key); + rc6_ecb_decrypt(buf[0], buf[1], &key); + + /* compare */ + if (memcmp(buf[0], tests[x].ct, 16)) { +#if 0 + int y; + printf("\nEncrypt test %d failed\n", x); + for (y = 0; y < 16; y++) printf("%02x ", buf[0][y]); + printf("\n"); +#endif + failed = 1; + } + + if (memcmp(buf[1], tests[x].pt, 16)) { +#if 0 + int y; + printf("\nDecrypt test %d failed\n", x); + for (y = 0; y < 16; y++) printf("%02x ", buf[1][y]); + printf("\n"); +#endif + failed = 1; + } + } + + if (failed == 1) { + return CRYPT_FAIL_TESTVECTOR; + } else { + return CRYPT_OK; + } +} + +int rc6_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize != NULL); + if (*desired_keysize < 8) { + return CRYPT_INVALID_KEYSIZE; + } else if (*desired_keysize > 128) { + *desired_keysize = 128; + } + return CRYPT_OK; +} + +#endif /*RC6*/ + + diff --git a/rsa.c b/rsa.c new file mode 100644 index 0000000..f5d988b --- /dev/null +++ b/rsa.c @@ -0,0 +1,436 @@ +#include "mycrypt.h" + +#ifdef MRSA + +int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key) +{ + mp_int p, q, tmp1, tmp2, tmp3; + int res, errno; + + _ARGCHK(key != NULL); + + if ((size < (1024/8)) || (size > (4096/8))) { + return CRYPT_INVALID_KEYSIZE; + } + + if ((e < 3) || (!(e & 1))) { + return CRYPT_INVALID_ARG; + } + + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + if (mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + /* make primes p and q (optimization provided by Wayne Scott) */ + if (mp_set_int(&tmp3, e) != MP_OKAY) { goto error; } /* tmp3 = e */ + + /* make prime "p" */ + do { + if (rand_prime(&p, size/2, prng, wprng) != CRYPT_OK) { res = CRYPT_ERROR; goto done; } + if (mp_sub_d(&p, 1, &tmp1) != MP_OKAY) { goto error; } /* tmp1 = p-1 */ + if (mp_gcd(&tmp1, &tmp3, &tmp2) != MP_OKAY) { goto error; } /* tmp2 = gcd(p-1, e) */ + } while (mp_cmp_d(&tmp2, 1) != 0); + + /* make prime "q" */ + do { + if (rand_prime(&q, size/2, prng, wprng) != CRYPT_OK) { res = CRYPT_ERROR; goto done; } + if (mp_sub_d(&q, 1, &tmp1) != MP_OKAY) { goto error; } /* tmp1 = q-1 */ + if (mp_gcd(&tmp1, &tmp3, &tmp2) != MP_OKAY) { goto error; } /* tmp2 = gcd(q-1, e) */ + } while (mp_cmp_d(&tmp2, 1) != 0); + + /* tmp1 = lcm(p-1, q-1) */ + if (mp_sub_d(&p, 1, &tmp2) != MP_OKAY) { goto error; } /* tmp2 = p-1 */ + /* tmp1 = q-1 (previous do/while loop) */ + if (mp_lcm(&tmp1, &tmp2, &tmp1) != MP_OKAY) { goto error; } /* tmp1 = lcm(p-1, q-1) */ + + /* make key */ + if (mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, + &key->qP, &key->pQ, &key->p, &key->q, NULL) != MP_OKAY) { + goto error; + } + + mp_set_int(&key->e, e); /* key->e = e */ + if (mp_invmod(&key->e, &tmp1, &key->d) != MP_OKAY) goto error2; /* key->d = 1/e mod lcm(p-1,q-1) */ + if (mp_mul(&p, &q, &key->N) != MP_OKAY) goto error2; /* key->N = pq */ + +/* optimize for CRT now */ + /* find d mod q-1 and d mod p-1 */ + if (mp_sub_d(&p, 1, &tmp1) != MP_OKAY) { goto error2; } /* tmp1 = q-1 */ + if (mp_sub_d(&q, 1, &tmp2) != MP_OKAY) { goto error2; } /* tmp2 = p-1 */ + + if (mp_mod(&key->d, &tmp1, &key->dP) != MP_OKAY) { goto error2; } /* dP = d mod p-1 */ + if (mp_mod(&key->d, &tmp2, &key->dQ) != MP_OKAY) { goto error2; } /* dQ = d mod q-1 */ + + if (mp_invmod(&q, &p, &key->qP) != MP_OKAY) { goto error2; } /* qP = 1/q mod p */ + if (mp_mulmod(&key->qP, &q, &key->N, &key->qP)) { goto error2; } /* qP = q * (1/q mod p) mod N */ + + if (mp_invmod(&p, &q, &key->pQ) != MP_OKAY) { goto error2; } /* pQ = 1/p mod q */ + if (mp_mulmod(&key->pQ, &p, &key->N, &key->pQ)) { goto error2; } /* pQ = p * (1/p mod q) mod N */ + + if (mp_copy(&p, &key->p) != MP_OKAY) { goto error2; } + if (mp_copy(&q, &key->q) != MP_OKAY) { goto error2; } + + res = CRYPT_OK; + key->type = PK_PRIVATE_OPTIMIZED; + goto done; +error2: + mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, + &key->qP, &key->pQ, &key->p, &key->q, NULL); +error: + res = CRYPT_MEM; +done: + mp_clear_multi(&tmp3, &tmp2, &tmp1, &p, &q, NULL); + return res; +} + +void rsa_free(rsa_key *key) +{ + _ARGCHK(key != NULL); + mp_clear_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, + &key->qP, &key->pQ, &key->p, &key->q, NULL); +} + +int rsa_exptmod(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, int which, + rsa_key *key) +{ + mp_int tmp, tmpa, tmpb; + unsigned long x; + int res; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + if (which == PK_PRIVATE && (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED)) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* init and copy into tmp */ + if (mp_init_multi(&tmp, &tmpa, &tmpb, NULL) != MP_OKAY) { goto error; } + if (mp_read_unsigned_bin(&tmp, (unsigned char *)in, inlen) != MP_OKAY) { goto error; } + + /* sanity check on the input */ + if (mp_cmp(&key->N, &tmp) == MP_LT) { + res = CRYPT_PK_INVALID_SIZE; + goto done; + } + + /* are we using the private exponent and is the key optimized? */ + if (which == PK_PRIVATE && key->type == PK_PRIVATE_OPTIMIZED) { + /* tmpa = tmp^dP mod p */ + if (mp_exptmod(&tmp, &key->dP, &key->p, &tmpa) != MP_OKAY) { goto error; } + + /* tmpb = tmp^dQ mod q */ + if (mp_exptmod(&tmp, &key->dQ, &key->q, &tmpb) != MP_OKAY) { goto error; } + + /* tmp = tmpa*qP + tmpb*pQ mod N */ + if (mp_mul(&tmpa, &key->qP, &tmpa) != MP_OKAY) { goto error; } + if (mp_mul(&tmpb, &key->pQ, &tmpb) != MP_OKAY) { goto error; } + if (mp_addmod(&tmpa, &tmpb, &key->N, &tmp) != MP_OKAY) { goto error; } + } else { + /* exptmod it */ + if (mp_exptmod(&tmp, which==PK_PRIVATE?&key->d:&key->e, &key->N, &tmp) != MP_OKAY) { goto error; } + } + + /* read it back */ + x = mp_raw_size(&tmp)-1; + if (x > *outlen) { + res = CRYPT_BUFFER_OVERFLOW; + goto done; + } + *outlen = x; + + /* convert it */ + mp_to_unsigned_bin(&tmp, out); + + /* clean up and return */ + res = CRYPT_OK; + goto done; +error: + res = CRYPT_MEM; +done: + mp_clear_multi(&tmp, &tmpa, &tmpb, NULL); + return res; +} + +int rsa_signpad(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen) +{ + unsigned long x, y; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + if (*outlen < (3 * inlen)) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* check inlen */ + if ((inlen <= 0) || inlen > 512) { + return CRYPT_PK_INVALID_SIZE; + } + + for (y = x = 0; x < inlen; x++) + out[y++] = 0xFF; + for (x = 0; x < inlen; x++) + out[y++] = in[x]; + for (x = 0; x < inlen; x++) + out[y++] = 0xFF; + *outlen = 3 * inlen; + return CRYPT_OK; +} + +int rsa_pad(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + int wprng, prng_state *prng) +{ + unsigned char buf[2048]; + unsigned long x; + int errno; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* is output big enough? */ + if (*outlen < (3 * inlen)) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* get random padding required */ + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + /* check inlen */ + if ((inlen <= 0) || inlen > 512) { + return CRYPT_PK_INVALID_SIZE; + } + + if (prng_descriptor[wprng].read(buf, inlen*2-2, prng) != (inlen*2 - 2)) { + return CRYPT_ERROR_READPRNG; + } + + /* pad it like a sandwitch (sp?) + * + * Looks like 0xFF R1 M R2 0xFF + * + * Where R1/R2 are random and exactly equal to the length of M minus one byte. + */ + for (x = 0; x < inlen-1; x++) { + out[x+1] = buf[x]; + } + + for (x = 0; x < inlen; x++) { + out[x+inlen] = in[x]; + } + + for (x = 0; x < inlen-1; x++) { + out[x+inlen+inlen] = buf[x+inlen-1]; + } + + /* last and first bytes are 0xFF */ + out[0] = 0xFF; + out[inlen+inlen+inlen-1] = 0xFF; + + /* clear up and return */ +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + *outlen = inlen*3; + return CRYPT_OK; +} + +int rsa_signdepad(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen) +{ + unsigned long x; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + if (*outlen < inlen/3) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* check padding bytes */ + for (x = 0; x < inlen/3; x++) { + if (in[x] != 0xFF || in[x+(inlen/3)+(inlen/3)] != 0xFF) { + return CRYPT_INVALID_PACKET; + } + } + for (x = 0; x < inlen/3; x++) + out[x] = in[x+(inlen/3)]; + *outlen = inlen/3; + return CRYPT_OK; +} + +int rsa_depad(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen) +{ + unsigned long x; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + if (*outlen < inlen/3) { + return CRYPT_BUFFER_OVERFLOW; + } + for (x = 0; x < inlen/3; x++) + out[x] = in[x+(inlen/3)]; + *outlen = inlen/3; + return CRYPT_OK; +} + +#define OUTPUT_BIGNUM(num, buf2, y, z) \ +{ \ + z = mp_raw_size(num); \ + STORE32L(z, buf2+y); \ + y += 4; \ + mp_toraw(num, buf2+y); \ + y += z; \ +} + + +#define INPUT_BIGNUM(num, in, x, y) \ +{ \ + /* load value */ \ + LOAD32L(x, in+y); \ + y += 4; \ + \ + /* sanity check... */ \ + if (x > 1024) { \ + goto error2; \ + } \ + \ + /* load it */ \ + if (mp_read_raw(num, (unsigned char *)in+y, x) != MP_OKAY) {\ + goto error2; \ + } \ + y += x; \ +} + +int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key) +{ + unsigned char buf2[5120]; + unsigned long y, z; + + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* type valid? */ + if (!(key->type == PK_PRIVATE || key->type == PK_PRIVATE_OPTIMIZED) && + (type == PK_PRIVATE || type == PK_PRIVATE_OPTIMIZED)) { + return CRYPT_PK_INVALID_TYPE; + } + + /* start at offset y=PACKET_SIZE */ + y = PACKET_SIZE; + + /* output key type */ + buf2[y++] = type; + + /* output modulus */ + OUTPUT_BIGNUM(&key->N, buf2, y, z); + + /* output public key */ + OUTPUT_BIGNUM(&key->e, buf2, y, z); + + if (type == PK_PRIVATE || type == PK_PRIVATE_OPTIMIZED) { + OUTPUT_BIGNUM(&key->d, buf2, y, z); + } + + if (type == PK_PRIVATE_OPTIMIZED) { + OUTPUT_BIGNUM(&key->dQ, buf2, y, z); + OUTPUT_BIGNUM(&key->dP, buf2, y, z); + OUTPUT_BIGNUM(&key->pQ, buf2, y, z); + OUTPUT_BIGNUM(&key->qP, buf2, y, z); + OUTPUT_BIGNUM(&key->p, buf2, y, z); + OUTPUT_BIGNUM(&key->q, buf2, y, z); + } + + /* check size */ + if (*outlen < y) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* store packet header */ + packet_store_header(buf2, PACKET_SECT_RSA, PACKET_SUB_KEY, y); + + /* copy to the user buffer */ + memcpy(out, buf2, y); + *outlen = y; + + /* clear stack and return */ +#ifdef CLEAN_STACK + zeromem(buf2, sizeof(buf2)); +#endif + return CRYPT_OK; +} + +int rsa_import(const unsigned char *in, rsa_key *key) +{ + unsigned long x, y; + int errno; + + _ARGCHK(in != NULL); + _ARGCHK(key != NULL); + + /* test packet header */ + if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_KEY)) != CRYPT_OK) { + return errno; + } + + /* init key */ + if (mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, + &key->pQ, &key->p, &key->q, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + /* get key type */ + y = PACKET_SIZE; + key->type = in[y++]; + + /* load the modulus */ + INPUT_BIGNUM(&key->N, in, x, y); + + /* load public exponent */ + INPUT_BIGNUM(&key->e, in, x, y); + + /* get private exponent */ + if (key->type == PK_PRIVATE || key->type == PK_PRIVATE_OPTIMIZED) { + INPUT_BIGNUM(&key->d, in, x, y); + } + + /* get CRT private data if required */ + if (key->type == PK_PRIVATE_OPTIMIZED) { + INPUT_BIGNUM(&key->dQ, in, x, y); + INPUT_BIGNUM(&key->dP, in, x, y); + INPUT_BIGNUM(&key->pQ, in, x, y); + INPUT_BIGNUM(&key->qP, in, x, y); + INPUT_BIGNUM(&key->p, in, x, y); + INPUT_BIGNUM(&key->q, in, x, y); + } + + return CRYPT_OK; +error2: + mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, + &key->pQ, &key->qP, &key->p, &key->q, NULL); + return CRYPT_MEM; +} + +#include "rsa_sys.c" + +#endif /* RSA */ + + diff --git a/rsa_sys.c b/rsa_sys.c new file mode 100644 index 0000000..915e677 --- /dev/null +++ b/rsa_sys.c @@ -0,0 +1,584 @@ +#ifdef PK_PACKET + +int rsa_encrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, int cipher, + rsa_key *key) +{ + unsigned char sym_IV[MAXBLOCKSIZE], sym_key[MAXBLOCKSIZE], rsa_in[4096], rsa_out[4096]; + symmetric_CTR ctr; + unsigned long x, y, blklen, rsa_size; + int keylen, errno;; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* are the parameters valid? */ + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + if ((errno = cipher_is_valid(cipher)) != CRYPT_OK) { + return errno; + } + + /* setup the CTR key */ + keylen = 32; /* default to 256-bit keys */ + if ((errno = cipher_descriptor[cipher].keysize(&keylen)) != CRYPT_OK) { + return errno; + } + + blklen = cipher_descriptor[cipher].block_length; + if (prng_descriptor[wprng].read(sym_key, keylen, prng) != (unsigned long)keylen) { + return CRYPT_ERROR_READPRNG; + } + + if (prng_descriptor[wprng].read(sym_IV, blklen, prng) != blklen) { + return CRYPT_ERROR_READPRNG; + } + + /* setup CTR mode */ + if ((errno = ctr_start(cipher, sym_IV, sym_key, keylen, 0, &ctr)) != CRYPT_OK) { + return errno; + } + + /* rsa_pad the symmetric key */ + y = sizeof(rsa_in); + if ((errno = rsa_pad(sym_key, keylen, rsa_in, &y, wprng, prng)) != CRYPT_OK) { + return errno; + } + + /* rsa encrypt it */ + rsa_size = sizeof(rsa_out); + if ((errno = rsa_exptmod(rsa_in, y, rsa_out, &rsa_size, PK_PUBLIC, key)) != CRYPT_OK) { + return errno; + } + + /* check size */ + if (*outlen < (PACKET_SIZE+9+rsa_size+blklen+len)) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* now lets make the header */ + y = PACKET_SIZE; + out[y++] = cipher_descriptor[cipher].ID; + + /* store the size of the RSA value */ + STORE32L(rsa_size, (out+y)); + y += 4; + + /* store the rsa value */ + for (x = 0; x < rsa_size; x++, y++) { + out[y] = rsa_out[x]; + } + + /* store the IV used */ + for (x = 0; x < blklen; x++, y++) { + out[y] = sym_IV[x]; + } + + /* store the length */ + STORE32L(len, (out+y)); + y += 4; + + /* encrypt the message */ + if ((errno = ctr_encrypt(in, out+y, len, &ctr)) != CRYPT_OK) { + return errno; + } + + y += len; + + /* store the header */ + packet_store_header(out, PACKET_SECT_RSA, PACKET_SUB_ENCRYPTED, y); + +#ifdef CLEAN_STACK + /* clean up */ + zeromem(sym_key, sizeof(sym_key)); + zeromem(sym_IV, sizeof(sym_IV)); + zeromem(&ctr, sizeof(ctr)); + zeromem(rsa_in, sizeof(rsa_in)); + zeromem(rsa_out, sizeof(rsa_out)); +#endif + + *outlen = y; + return CRYPT_OK; +} + +int rsa_decrypt(const unsigned char *in, unsigned long len, + unsigned char *out, unsigned long *outlen, + rsa_key *key) +{ + unsigned char sym_IV[MAXBLOCKSIZE], sym_key[MAXBLOCKSIZE], rsa_in[4096], rsa_out[4096]; + symmetric_CTR ctr; + unsigned long x, y, z, keylen, blklen, rsa_size; + int cipher, errno; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* right key type? */ + if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* check the header */ + if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_ENCRYPTED)) != CRYPT_OK) { + return errno; + } + + /* grab cipher name */ + y = PACKET_SIZE; + cipher = find_cipher_id(in[y++]); + if (cipher == -1) { + return CRYPT_INVALID_CIPHER; + } + keylen = MIN(cipher_descriptor[cipher].max_key_length, 32); + blklen = cipher_descriptor[cipher].block_length; + + /* grab length of the rsa key */ + LOAD32L(rsa_size, (in+y)) + y += 4; + + /* read it in */ + for (x = 0; x < rsa_size; x++, y++) { + rsa_in[x] = in[y]; + } + + /* decrypt it */ + x = sizeof(rsa_out); + if ((errno = rsa_exptmod(rsa_in, rsa_size, rsa_out, &x, PK_PRIVATE, key)) != CRYPT_OK) { + return errno; + } + + /* depad it */ + z = sizeof(sym_key); + if ((errno = rsa_depad(rsa_out, x, sym_key, &z)) != CRYPT_OK) { + return errno; + } + + /* read the IV in */ + for (x = 0; x < blklen; x++, y++) { + sym_IV[x] = in[y]; + } + + /* setup CTR mode */ + if ((errno = ctr_start(cipher, sym_IV, sym_key, keylen, 0, &ctr)) != CRYPT_OK) { + return errno; + } + + /* get len */ + LOAD32L(len, (in+y)); + y += 4; + + /* check size */ + if (*outlen < len) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* decrypt the message */ + if ((errno = ctr_decrypt(in+y, out, len, &ctr)) != CRYPT_OK) { + return errno; + } + +#ifdef CLEAN_STACK + /* clean up */ + zeromem(sym_key, sizeof(sym_key)); + zeromem(sym_IV, sizeof(sym_IV)); + zeromem(&ctr, sizeof(ctr)); + zeromem(rsa_in, sizeof(rsa_in)); + zeromem(rsa_out, sizeof(rsa_out)); +#endif + *outlen = len; + return CRYPT_OK; +} + +/* Signature Message Format +offset | length | Contents +---------------------------------------------------------------------- +0 | 1 | hash ID +1 | 4 | length of rsa_pad'ed signature +5 | p | the rsa_pad'ed signature +*/ + +int rsa_sign(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + int hash, rsa_key *key) +{ + unsigned long hashlen, rsa_size, x, y, z; + unsigned char rsa_in[4096], rsa_out[4096]; + int errno; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* type of key? */ + if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* are the parameters valid? */ + if ((errno = hash_is_valid(hash)) != CRYPT_OK) { + return errno; + } + + /* hash it */ + hashlen = hash_descriptor[hash].hashsize; + z = sizeof(rsa_in); + if ((errno = hash_memory(hash, in, inlen, rsa_in, &z)) != CRYPT_OK) { + return errno; + } + + /* pad it */ + x = sizeof(rsa_in); + if ((errno = rsa_signpad(rsa_in, hashlen, rsa_out, &x)) != CRYPT_OK) { + return errno; + } + + /* sign it */ + rsa_size = sizeof(rsa_in); + if ((errno = rsa_exptmod(rsa_out, x, rsa_in, &rsa_size, PK_PRIVATE, key)) != CRYPT_OK) { + return errno; + } + + /* check size */ + if (*outlen < (PACKET_SIZE+4+rsa_size)) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* now lets output the message */ + y = PACKET_SIZE; + out[y++] = hash_descriptor[hash].ID; + + /* output the len */ + STORE32L(rsa_size, (out+y)); + y += 4; + + /* store the signature */ + for (x = 0; x < rsa_size; x++, y++) { + out[y] = rsa_in[x]; + } + + /* store header */ + packet_store_header(out, PACKET_SECT_RSA, PACKET_SUB_SIGNED, y); + +#ifdef CLEAN_STACK + /* clean up */ + zeromem(rsa_in, sizeof(rsa_in)); + zeromem(rsa_out, sizeof(rsa_out)); +#endif + *outlen = y; + return CRYPT_OK; +} + +int rsa_verify(const unsigned char *sig, const unsigned char *msg, + unsigned long inlen, int *stat, + rsa_key *key) +{ + unsigned long hashlen, rsa_size, x, y, z, w; + int hash, errno; + unsigned char rsa_in[4096], rsa_out[4096]; + + _ARGCHK(sig != NULL); + _ARGCHK(msg != NULL); + _ARGCHK(stat != NULL); + _ARGCHK(key != NULL); + + /* always be incorrect by default */ + *stat = 0; + + /* verify header */ + if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_RSA, PACKET_SUB_SIGNED)) != CRYPT_OK) { + return errno; + } + + /* grab hash name */ + y = PACKET_SIZE; + hash = find_hash_id(sig[y++]); + if (hash == -1) { + return CRYPT_INVALID_HASH; + } + hashlen = hash_descriptor[hash].hashsize; + + /* get the len */ + LOAD32L(rsa_size, (sig+y)); + y += 4; + + /* load the signature */ + for (x = 0; x < rsa_size; x++, y++) { + rsa_in[x] = sig[y]; + } + + /* exptmod it */ + x = sizeof(rsa_in); + if ((errno = rsa_exptmod(rsa_in, rsa_size, rsa_out, &x, PK_PUBLIC, key)) != CRYPT_OK) { + return errno; + } + + /* depad it */ + z = sizeof(rsa_in); + if ((errno = rsa_signdepad(rsa_out, x, rsa_in, &z)) != CRYPT_OK) { + return errno; + } + + /* check? */ + w = sizeof(rsa_out); + if ((errno = hash_memory(hash, msg, inlen, rsa_out, &w)) != CRYPT_OK) { + return errno; + } + + if ((z == hashlen) && (!memcmp(rsa_in, rsa_out, hashlen))) { + *stat = 1; + } + +#ifdef CLEAN_STACK + zeromem(rsa_in, sizeof(rsa_in)); + zeromem(rsa_out, sizeof(rsa_out)); +#endif + return CRYPT_OK; +} + +#endif + +/* these are smaller routines written by Clay Culver. They do the same function as the rsa_encrypt/decrypt + * except that they are used to RSA encrypt/decrypt a single value and not a packet. + */ +int rsa_encrypt_key(const unsigned char *inkey, unsigned long inlen, + unsigned char *outkey, unsigned long *outlen, + prng_state *prng, int wprng, rsa_key *key) +{ + unsigned char rsa_in[4096], rsa_out[4096]; + unsigned long x, y, rsa_size; + int errno; + + _ARGCHK(inkey != NULL); + _ARGCHK(outkey != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* are the parameters valid? */ + if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { + return errno; + } + + /* rsa_pad the symmetric key */ + y = sizeof(rsa_in); + if ((errno = rsa_pad(inkey, inlen, rsa_in, &y, wprng, prng)) != CRYPT_OK) { + return CRYPT_ERROR; + } + + /* rsa encrypt it */ + rsa_size = sizeof(rsa_out); + if ((errno = rsa_exptmod(rsa_in, y, rsa_out, &rsa_size, PK_PUBLIC, key)) != CRYPT_OK) { + return CRYPT_ERROR; + } + + /* check size */ + if (*outlen < (PACKET_SIZE+4+rsa_size)) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* now lets make the header */ + y = PACKET_SIZE; + + /* store the size of the RSA value */ + STORE32L(rsa_size, (outkey+y)); + y += 4; + + /* store the rsa value */ + for (x = 0; x < rsa_size; x++, y++) { + outkey[y] = rsa_out[x]; + } + + /* store header */ + packet_store_header(outkey, PACKET_SECT_RSA, PACKET_SUB_ENC_KEY, y); + +#ifdef CLEAN_STACK + /* clean up */ + zeromem(rsa_in, sizeof(rsa_in)); + zeromem(rsa_out, sizeof(rsa_out)); +#endif + *outlen = y; + return CRYPT_OK; +} + +int rsa_decrypt_key(const unsigned char *in, unsigned char *outkey, + unsigned long *keylen, rsa_key *key) +{ + unsigned char sym_key[MAXBLOCKSIZE], rsa_in[4096], rsa_out[4096]; + unsigned long x, y, z, i, rsa_size; + int errno; + + _ARGCHK(in != NULL); + _ARGCHK(outkey != NULL); + _ARGCHK(keylen != NULL); + _ARGCHK(key != NULL); + + /* right key type? */ + if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* check the header */ + if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_ENC_KEY)) != CRYPT_OK) { + return errno; + } + + /* grab length of the rsa key */ + y = PACKET_SIZE; + LOAD32L(rsa_size, (in+y)) + y += 4; + + /* read it in */ + for (x = 0; x < rsa_size; x++, y++) { + rsa_in[x] = in[y]; + } + + /* decrypt it */ + x = sizeof(rsa_out); + if ((errno = rsa_exptmod(rsa_in, rsa_size, rsa_out, &x, PK_PRIVATE, key)) != CRYPT_OK) + return errno; + + /* depad it */ + z = sizeof(sym_key); + if ((errno = rsa_depad(rsa_out, x, sym_key, &z)) != CRYPT_OK) { + return errno; + } + + /* check size */ + if (*keylen < z) { + return CRYPT_BUFFER_OVERFLOW; + } + + for (i = 0; i < z; i++) { + outkey[i] = sym_key[i]; + } + +#ifdef CLEAN_STACK + /* clean up */ + zeromem(sym_key, sizeof(sym_key)); + zeromem(rsa_in, sizeof(rsa_in)); + zeromem(rsa_out, sizeof(rsa_out)); +#endif + *keylen = z; + return CRYPT_OK; +} + +int rsa_sign_hash(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + rsa_key *key) +{ + unsigned long rsa_size, x, y; + unsigned char rsa_in[4096], rsa_out[4096]; + int errno; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* type of key? */ + if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* pad it */ + x = sizeof(rsa_out); + if ((errno = rsa_signpad(in, inlen, rsa_out, &x)) != CRYPT_OK) { + return errno; + } + + /* sign it */ + rsa_size = sizeof(rsa_in); + if ((errno = rsa_exptmod(rsa_out, x, rsa_in, &rsa_size, PK_PRIVATE, key)) != CRYPT_OK) { + return errno; + } + + /* check size */ + if (*outlen < (PACKET_SIZE+4+rsa_size)) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* now lets output the message */ + y = PACKET_SIZE; + + /* output the len */ + STORE32L(rsa_size, (out+y)); + y += 4; + + /* store the signature */ + for (x = 0; x < rsa_size; x++, y++) { + out[y] = rsa_in[x]; + } + + /* store header */ + packet_store_header(out, PACKET_SECT_RSA, PACKET_SUB_SIGNED, y); + +#ifdef CLEAN_STACK + /* clean up */ + zeromem(rsa_in, sizeof(rsa_in)); + zeromem(rsa_out, sizeof(rsa_out)); +#endif + *outlen = y; + return CRYPT_OK; +} + +int rsa_verify_hash(const unsigned char *sig, const unsigned char *md, + int *stat, rsa_key *key) +{ + unsigned long rsa_size, x, y, z; + unsigned char rsa_in[4096], rsa_out[4096]; + int errno; + + _ARGCHK(sig != NULL); + _ARGCHK(md != NULL); + _ARGCHK(stat != NULL); + _ARGCHK(key != NULL); + + /* always be incorrect by default */ + *stat = 0; + + /* verify header */ + if ((errno = packet_valid_header((unsigned char *)sig, PACKET_SECT_RSA, PACKET_SUB_SIGNED)) != CRYPT_OK) { + return errno; + } + + /* get the len */ + y = PACKET_SIZE; + LOAD32L(rsa_size, (sig+y)); + y += 4; + + /* load the signature */ + for (x = 0; x < rsa_size; x++, y++) { + rsa_in[x] = sig[y]; + } + + /* exptmod it */ + x = sizeof(rsa_in); + if ((errno = rsa_exptmod(rsa_in, rsa_size, rsa_out, &x, PK_PUBLIC, key)) != CRYPT_OK) { + return errno; + } + + /* depad it */ + z = sizeof(rsa_in); + if ((errno = rsa_signdepad(rsa_out, x, rsa_in, &z)) != CRYPT_OK) { + return errno; + } + + /* check? */ + if (!memcmp(rsa_in, md, z)) { + *stat = 1; + } + +#ifdef CLEAN_STACK + zeromem(rsa_in, sizeof(rsa_in)); + zeromem(rsa_out, sizeof(rsa_out)); +#endif + return CRYPT_OK; +} + diff --git a/safer+.c b/safer+.c new file mode 100644 index 0000000..13254b7 --- /dev/null +++ b/safer+.c @@ -0,0 +1,506 @@ +#include "mycrypt.h" + +#ifdef SAFERP + +const struct _cipher_descriptor saferp_desc = +{ + "safer+", + 4, + 16, 32, 16, 8, + &saferp_setup, + &saferp_ecb_encrypt, + &saferp_ecb_decrypt, + &saferp_test, + &saferp_keysize +}; + +/* ROUND(b,i) + * + * This is one forward key application. Note the basic form is + * key addition, substitution, key addition. The safer_ebox and safer_lbox + * are the exponentiation box and logarithm boxes respectively. + * The value of 'i' is the current round number which allows this + * function to be unrolled massively. Most of SAFER+'s speed + * comes from not having to compute indirect accesses into the + * array of 16 bytes b[0..15] which is the block of data +*/ + +extern const unsigned char safer_ebox[], safer_lbox[]; + +#define ROUND(b, i) \ + b[0] = (safer_ebox[(b[0] ^ skey->saferp.K[i][0]) & 255] + skey->saferp.K[i+1][0]) & 255; \ + b[1] = safer_lbox[(b[1] + skey->saferp.K[i][1]) & 255] ^ skey->saferp.K[i+1][1]; \ + b[2] = safer_lbox[(b[2] + skey->saferp.K[i][2]) & 255] ^ skey->saferp.K[i+1][2]; \ + b[3] = (safer_ebox[(b[3] ^ skey->saferp.K[i][3]) & 255] + skey->saferp.K[i+1][3]) & 255; \ + b[4] = (safer_ebox[(b[4] ^ skey->saferp.K[i][4]) & 255] + skey->saferp.K[i+1][4]) & 255; \ + b[5] = safer_lbox[(b[5] + skey->saferp.K[i][5]) & 255] ^ skey->saferp.K[i+1][5]; \ + b[6] = safer_lbox[(b[6] + skey->saferp.K[i][6]) & 255] ^ skey->saferp.K[i+1][6]; \ + b[7] = (safer_ebox[(b[7] ^ skey->saferp.K[i][7]) & 255] + skey->saferp.K[i+1][7]) & 255; \ + b[8] = (safer_ebox[(b[8] ^ skey->saferp.K[i][8]) & 255] + skey->saferp.K[i+1][8]) & 255; \ + b[9] = safer_lbox[(b[9] + skey->saferp.K[i][9]) & 255] ^ skey->saferp.K[i+1][9]; \ + b[10] = safer_lbox[(b[10] + skey->saferp.K[i][10]) & 255] ^ skey->saferp.K[i+1][10]; \ + b[11] = (safer_ebox[(b[11] ^ skey->saferp.K[i][11]) & 255] + skey->saferp.K[i+1][11]) & 255; \ + b[12] = (safer_ebox[(b[12] ^ skey->saferp.K[i][12]) & 255] + skey->saferp.K[i+1][12]) & 255; \ + b[13] = safer_lbox[(b[13] + skey->saferp.K[i][13]) & 255] ^ skey->saferp.K[i+1][13]; \ + b[14] = safer_lbox[(b[14] + skey->saferp.K[i][14]) & 255] ^ skey->saferp.K[i+1][14]; \ + b[15] = (safer_ebox[(b[15] ^ skey->saferp.K[i][15]) & 255] + skey->saferp.K[i+1][15]) & 255; + +/* This is one inverse key application */ +#define iROUND(b, i) \ + b[0] = safer_lbox[(b[0] - skey->saferp.K[i+1][0]) & 255] ^ skey->saferp.K[i][0]; \ + b[1] = (safer_ebox[(b[1] ^ skey->saferp.K[i+1][1]) & 255] - skey->saferp.K[i][1]) & 255; \ + b[2] = (safer_ebox[(b[2] ^ skey->saferp.K[i+1][2]) & 255] - skey->saferp.K[i][2]) & 255; \ + b[3] = safer_lbox[(b[3] - skey->saferp.K[i+1][3]) & 255] ^ skey->saferp.K[i][3]; \ + b[4] = safer_lbox[(b[4] - skey->saferp.K[i+1][4]) & 255] ^ skey->saferp.K[i][4]; \ + b[5] = (safer_ebox[(b[5] ^ skey->saferp.K[i+1][5]) & 255] - skey->saferp.K[i][5]) & 255; \ + b[6] = (safer_ebox[(b[6] ^ skey->saferp.K[i+1][6]) & 255] - skey->saferp.K[i][6]) & 255; \ + b[7] = safer_lbox[(b[7] - skey->saferp.K[i+1][7]) & 255] ^ skey->saferp.K[i][7]; \ + b[8] = safer_lbox[(b[8] - skey->saferp.K[i+1][8]) & 255] ^ skey->saferp.K[i][8]; \ + b[9] = (safer_ebox[(b[9] ^ skey->saferp.K[i+1][9]) & 255] - skey->saferp.K[i][9]) & 255; \ + b[10] = (safer_ebox[(b[10] ^ skey->saferp.K[i+1][10]) & 255] - skey->saferp.K[i][10]) & 255; \ + b[11] = safer_lbox[(b[11] - skey->saferp.K[i+1][11]) & 255] ^ skey->saferp.K[i][11]; \ + b[12] = safer_lbox[(b[12] - skey->saferp.K[i+1][12]) & 255] ^ skey->saferp.K[i][12]; \ + b[13] = (safer_ebox[(b[13] ^ skey->saferp.K[i+1][13]) & 255] - skey->saferp.K[i][13]) & 255; \ + b[14] = (safer_ebox[(b[14] ^ skey->saferp.K[i+1][14]) & 255] - skey->saferp.K[i][14]) & 255; \ + b[15] = safer_lbox[(b[15] - skey->saferp.K[i+1][15]) & 255] ^ skey->saferp.K[i][15]; + +/* This is a forward single layer PHT transform. */ +#define PHT(b) \ + b[0] = (b[0] + (b[1] = (b[0] + b[1]) & 255)) & 255; \ + b[2] = (b[2] + (b[3] = (b[3] + b[2]) & 255)) & 255; \ + b[4] = (b[4] + (b[5] = (b[5] + b[4]) & 255)) & 255; \ + b[6] = (b[6] + (b[7] = (b[7] + b[6]) & 255)) & 255; \ + b[8] = (b[8] + (b[9] = (b[9] + b[8]) & 255)) & 255; \ + b[10] = (b[10] + (b[11] = (b[11] + b[10]) & 255)) & 255; \ + b[12] = (b[12] + (b[13] = (b[13] + b[12]) & 255)) & 255; \ + b[14] = (b[14] + (b[15] = (b[15] + b[14]) & 255)) & 255; + +/* This is an inverse single layer PHT transform */ +#define iPHT(b) \ + b[15] = (b[15] - (b[14] = (b[14] - b[15]) & 255)) & 255; \ + b[13] = (b[13] - (b[12] = (b[12] - b[13]) & 255)) & 255; \ + b[11] = (b[11] - (b[10] = (b[10] - b[11]) & 255)) & 255; \ + b[9] = (b[9] - (b[8] = (b[8] - b[9]) & 255)) & 255; \ + b[7] = (b[7] - (b[6] = (b[6] - b[7]) & 255)) & 255; \ + b[5] = (b[5] - (b[4] = (b[4] - b[5]) & 255)) & 255; \ + b[3] = (b[3] - (b[2] = (b[2] - b[3]) & 255)) & 255; \ + b[1] = (b[1] - (b[0] = (b[0] - b[1]) & 255)) & 255; \ + +/* This is the "Armenian" Shuffle. It takes the input from b and stores it in b2 */ +#define SHUF(b, b2) \ + b2[0] = b[8]; b2[1] = b[11]; b2[2] = b[12]; b2[3] = b[15]; \ + b2[4] = b[2]; b2[5] = b[1]; b2[6] = b[6]; b2[7] = b[5]; \ + b2[8] = b[10]; b2[9] = b[9]; b2[10] = b[14]; b2[11] = b[13]; \ + b2[12] = b[0]; b2[13] = b[7]; b2[14] = b[4]; b2[15] = b[3]; + +/* This is the inverse shuffle. It takes from b and gives to b2 */ +#define iSHUF(b, b2) \ + b2[0] = b[12]; b2[1] = b[5]; b2[2] = b[4]; b2[3] = b[15]; \ + b2[4] = b[14]; b2[5] = b[7]; b2[6] = b[6]; b2[7] = b[13]; \ + b2[8] = b[0]; b2[9] = b[9]; b2[10] = b[8]; b2[11] = b[1]; \ + b2[12] = b[2]; b2[13] = b[11]; b2[14] = b[10]; b2[15] = b[3]; + +/* The complete forward Linear Transform layer. + * Note that alternating usage of b and b2. + * Each round of LT starts in 'b' and ends in 'b2'. + */ +#define LT(b, b2) \ + PHT(b); SHUF(b, b2); \ + PHT(b2); SHUF(b2, b); \ + PHT(b); SHUF(b, b2); \ + PHT(b2); + +/* This is the inverse linear transform layer. */ +#define iLT(b, b2) \ + iPHT(b); \ + iSHUF(b, b2); iPHT(b2); \ + iSHUF(b2, b); iPHT(b); \ + iSHUF(b, b2); iPHT(b2); + +#ifdef SAFERP_SMALL + +static void _round(unsigned char *b, int i, symmetric_key *skey) +{ + ROUND(b, i); +} + +static void _iround(unsigned char *b, int i, symmetric_key *skey) +{ + iROUND(b, i); +} + +static void _lt(unsigned char *b, unsigned char *b2) +{ + LT(b, b2); +} + +static void _ilt(unsigned char *b, unsigned char *b2) +{ + iLT(b, b2); +} + +#undef ROUND +#define ROUND(b, i) _round(b, i, skey) + +#undef iROUND +#define iROUND(b, i) _iround(b, i, skey) + +#undef LT +#define LT(b, b2) _lt(b, b2) + +#undef iLT +#define iLT(b, b2) _ilt(b, b2) + +#endif + +/* These are the 33, 128-bit bias words for the key schedule */ +const unsigned char safer_bias[33][16] = { +{ 70, 151, 177, 186, 163, 183, 16, 10, 197, 55, 179, 201, 90, 40, 172, 100}, +{ 236, 171, 170, 198, 103, 149, 88, 13, 248, 154, 246, 110, 102, 220, 5, 61}, +{ 138, 195, 216, 137, 106, 233, 54, 73, 67, 191, 235, 212, 150, 155, 104, 160}, +{ 93, 87, 146, 31, 213, 113, 92, 187, 34, 193, 190, 123, 188, 153, 99, 148}, +{ 42, 97, 184, 52, 50, 25, 253, 251, 23, 64, 230, 81, 29, 65, 68, 143}, +{ 221, 4, 128, 222, 231, 49, 214, 127, 1, 162, 247, 57, 218, 111, 35, 202}, +{ 58, 208, 28, 209, 48, 62, 18, 161, 205, 15, 224, 168, 175, 130, 89, 44}, +{ 125, 173, 178, 239, 194, 135, 206, 117, 6, 19, 2, 144, 79, 46, 114, 51}, +{ 192, 141, 207, 169, 129, 226, 196, 39, 47, 108, 122, 159, 82, 225, 21, 56}, +{ 252, 32, 66, 199, 8, 228, 9, 85, 94, 140, 20, 118, 96, 255, 223, 215}, +{ 250, 11, 33, 0, 26, 249, 166, 185, 232, 158, 98, 76, 217, 145, 80, 210}, +{ 24, 180, 7, 132, 234, 91, 164, 200, 14, 203, 72, 105, 75, 78, 156, 53}, +{ 69, 77, 84, 229, 37, 60, 12, 74, 139, 63, 204, 167, 219, 107, 174, 244}, +{ 45, 243, 124, 109, 157, 181, 38, 116, 242, 147, 83, 176, 240, 17, 237, 131}, +{ 182, 3, 22, 115, 59, 30, 142, 112, 189, 134, 27, 71, 126, 36, 86, 241}, +{ 136, 70, 151, 177, 186, 163, 183, 16, 10, 197, 55, 179, 201, 90, 40, 172}, +{ 220, 134, 119, 215, 166, 17, 251, 244, 186, 146, 145, 100, 131, 241, 51, 239}, +{ 44, 181, 178, 43, 136, 209, 153, 203, 140, 132, 29, 20, 129, 151, 113, 202}, +{ 163, 139, 87, 60, 130, 196, 82, 92, 28, 232, 160, 4, 180, 133, 74, 246}, +{ 84, 182, 223, 12, 26, 142, 222, 224, 57, 252, 32, 155, 36, 78, 169, 152}, +{ 171, 242, 96, 208, 108, 234, 250, 199, 217, 0, 212, 31, 110, 67, 188, 236}, +{ 137, 254, 122, 93, 73, 201, 50, 194, 249, 154, 248, 109, 22, 219, 89, 150}, +{ 233, 205, 230, 70, 66, 143, 10, 193, 204, 185, 101, 176, 210, 198, 172, 30}, +{ 98, 41, 46, 14, 116, 80, 2, 90, 195, 37, 123, 138, 42, 91, 240, 6}, +{ 71, 111, 112, 157, 126, 16, 206, 18, 39, 213, 76, 79, 214, 121, 48, 104}, +{ 117, 125, 228, 237, 128, 106, 144, 55, 162, 94, 118, 170, 197, 127, 61, 175}, +{ 229, 25, 97, 253, 77, 124, 183, 11, 238, 173, 75, 34, 245, 231, 115, 35}, +{ 200, 5, 225, 102, 221, 179, 88, 105, 99, 86, 15, 161, 49, 149, 23, 7}, +{ 40, 1, 45, 226, 147, 190, 69, 21, 174, 120, 3, 135, 164, 184, 56, 207}, +{ 8, 103, 9, 148, 235, 38, 168, 107, 189, 24, 52, 27, 187, 191, 114, 247}, +{ 53, 72, 156, 81, 47, 59, 85, 227, 192, 159, 216, 211, 243, 141, 177, 255}, +{ 62, 220, 134, 119, 215, 166, 17, 251, 244, 186, 146, 145, 100, 131, 241, 51}}; + +int saferp_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + unsigned x, y; + unsigned char t[33]; + static const int rounds[3] = { 8, 12, 16 }; + + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + /* check arguments */ + if (keylen != 16 && keylen != 24 && keylen != 32) { + return CRYPT_INVALID_KEYSIZE; + } + + /* Is the number of rounds valid? Either use zero for default or + * 8,12,16 rounds for 16,24,32 byte keys + */ + if (num_rounds != 0 && num_rounds != rounds[(keylen/8)-2]) { + return CRYPT_INVALID_ROUNDS; + } + + /* 128 bit key version */ + if (keylen == 16) { + /* copy key into t */ + for (x = y = 0; x < 16; x++) { + t[x] = key[x]; + y ^= key[x]; + } + t[16] = y; + + /* make round keys */ + for (x = 0; x < 16; x++) { + skey->saferp.K[0][x] = t[x]; + } + + /* make the 16 other keys as a transformation of the first key */ + for (x = 1; x < 17; x++) { + /* rotate 3 bits each */ + for (y = 0; y < 17; y++) { + t[y] = ((t[y]<<3)|(t[y]>>5)) & 255; + } + + /* select and add */ + for (y = 0; y < 16; y++) { + skey->saferp.K[x][y] = (t[(x+y)%17] + safer_bias[x-1][y]) & 255; + } + } + skey->saferp.rounds = 8; + } else if (keylen == 24) { + /* copy key into t */ + for (x = y = 0; x < 24; x++) { + t[x] = key[x]; + y ^= key[x]; + } + t[24] = y; + + /* make round keys */ + for (x = 0; x < 16; x++) { + skey->saferp.K[0][x] = t[x]; + } + + for (x = 1; x < 25; x++) { + /* rotate 3 bits each */ + for (y = 0; y < 25; y++) { + t[y] = ((t[y]<<3)|(t[y]>>5)) & 255; + } + + /* select and add */ + for (y = 0; y < 16; y++) { + skey->saferp.K[x][y] = (t[(x+y)%25] + safer_bias[x-1][y]) & 255; + } + } + skey->saferp.rounds = 12; + } else { + /* copy key into t */ + for (x = y = 0; x < 32; x++) { + t[x] = key[x]; + y ^= key[x]; + } + t[32] = y; + + /* make round keys */ + for (x = 0; x < 16; x++) { + skey->saferp.K[0][x] = t[x]; + } + + for (x = 1; x < 33; x++) { + /* rotate 3 bits each */ + for (y = 0; y < 33; y++) { + t[y] = ((t[y]<<3)|(t[y]>>5)) & 255; + } + + /* select and add */ + for (y = 0; y < 16; y++) { + skey->saferp.K[x][y] = (t[(x+y)%33] + safer_bias[x-1][y]) & 255; + } + } + skey->saferp.rounds = 16; + } +#ifdef CLEAN_STACK + zeromem(t, sizeof(t)); +#endif + return CRYPT_OK; +} + +void saferp_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) +{ + unsigned char b[16]; + int x; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(skey != NULL); + + /* do eight rounds */ + for (x = 0; x < 16; x++) { + b[x] = pt[x]; + } + ROUND(b, 0); LT(b, ct); + ROUND(ct, 2); LT(ct, b); + ROUND(b, 4); LT(b, ct); + ROUND(ct, 6); LT(ct, b); + ROUND(b, 8); LT(b, ct); + ROUND(ct, 10); LT(ct, b); + ROUND(b, 12); LT(b, ct); + ROUND(ct, 14); LT(ct, b); + /* 192-bit key? */ + if (skey->saferp.rounds > 8) { + ROUND(b, 16); LT(b, ct); + ROUND(ct, 18); LT(ct, b); + ROUND(b, 20); LT(b, ct); + ROUND(ct, 22); LT(ct, b); + } + /* 256-bit key? */ + if (skey->saferp.rounds > 12) { + ROUND(b, 24); LT(b, ct); + ROUND(ct, 26); LT(ct, b); + ROUND(b, 28); LT(b, ct); + ROUND(ct, 30); LT(ct, b); + } + ct[0] = b[0] ^ skey->saferp.K[skey->saferp.rounds*2][0]; + ct[1] = (b[1] + skey->saferp.K[skey->saferp.rounds*2][1]) & 255; + ct[2] = (b[2] + skey->saferp.K[skey->saferp.rounds*2][2]) & 255; + ct[3] = b[3] ^ skey->saferp.K[skey->saferp.rounds*2][3]; + ct[4] = b[4] ^ skey->saferp.K[skey->saferp.rounds*2][4]; + ct[5] = (b[5] + skey->saferp.K[skey->saferp.rounds*2][5]) & 255; + ct[6] = (b[6] + skey->saferp.K[skey->saferp.rounds*2][6]) & 255; + ct[7] = b[7] ^ skey->saferp.K[skey->saferp.rounds*2][7]; + ct[8] = b[8] ^ skey->saferp.K[skey->saferp.rounds*2][8]; + ct[9] = (b[9] + skey->saferp.K[skey->saferp.rounds*2][9]) & 255; + ct[10] = (b[10] + skey->saferp.K[skey->saferp.rounds*2][10]) & 255; + ct[11] = b[11] ^ skey->saferp.K[skey->saferp.rounds*2][11]; + ct[12] = b[12] ^ skey->saferp.K[skey->saferp.rounds*2][12]; + ct[13] = (b[13] + skey->saferp.K[skey->saferp.rounds*2][13]) & 255; + ct[14] = (b[14] + skey->saferp.K[skey->saferp.rounds*2][14]) & 255; + ct[15] = b[15] ^ skey->saferp.K[skey->saferp.rounds*2][15]; +#ifdef CLEAN_STACK + zeromem(b, sizeof(b)); +#endif +} + +void saferp_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) +{ + unsigned char b[16]; + int x; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(skey != NULL); + + /* do eight rounds */ + b[0] = ct[0] ^ skey->saferp.K[skey->saferp.rounds*2][0]; + b[1] = (ct[1] - skey->saferp.K[skey->saferp.rounds*2][1]) & 255; + b[2] = (ct[2] - skey->saferp.K[skey->saferp.rounds*2][2]) & 255; + b[3] = ct[3] ^ skey->saferp.K[skey->saferp.rounds*2][3]; + b[4] = ct[4] ^ skey->saferp.K[skey->saferp.rounds*2][4]; + b[5] = (ct[5] - skey->saferp.K[skey->saferp.rounds*2][5]) & 255; + b[6] = (ct[6] - skey->saferp.K[skey->saferp.rounds*2][6]) & 255; + b[7] = ct[7] ^ skey->saferp.K[skey->saferp.rounds*2][7]; + b[8] = ct[8] ^ skey->saferp.K[skey->saferp.rounds*2][8]; + b[9] = (ct[9] - skey->saferp.K[skey->saferp.rounds*2][9]) & 255; + b[10] = (ct[10] - skey->saferp.K[skey->saferp.rounds*2][10]) & 255; + b[11] = ct[11] ^ skey->saferp.K[skey->saferp.rounds*2][11]; + b[12] = ct[12] ^ skey->saferp.K[skey->saferp.rounds*2][12]; + b[13] = (ct[13] - skey->saferp.K[skey->saferp.rounds*2][13]) & 255; + b[14] = (ct[14] - skey->saferp.K[skey->saferp.rounds*2][14]) & 255; + b[15] = ct[15] ^ skey->saferp.K[skey->saferp.rounds*2][15]; + /* 256-bit key? */ + if (skey->saferp.rounds > 12) { + iLT(b, pt); iROUND(pt, 30); + iLT(pt, b); iROUND(b, 28); + iLT(b, pt); iROUND(pt, 26); + iLT(pt, b); iROUND(b, 24); + } + /* 192-bit key? */ + if (skey->saferp.rounds > 8) { + iLT(b, pt); iROUND(pt, 22); + iLT(pt, b); iROUND(b, 20); + iLT(b, pt); iROUND(pt, 18); + iLT(pt, b); iROUND(b, 16); + } + iLT(b, pt); iROUND(pt, 14); + iLT(pt, b); iROUND(b, 12); + iLT(b, pt); iROUND(pt,10); + iLT(pt, b); iROUND(b, 8); + iLT(b, pt); iROUND(pt,6); + iLT(pt, b); iROUND(b, 4); + iLT(b, pt); iROUND(pt,2); + iLT(pt, b); iROUND(b, 0); + for (x = 0; x < 16; x++) { + pt[x] = b[x]; + } +#ifdef CLEAN_STACK + zeromem(b, sizeof(b)); +#endif +} + +int saferp_test(void) +{ + static const unsigned char key128[16] = + { 41, 35, 190, 132, 225, 108, 214, 174, + 82, 144, 73, 241, 241, 187, 233, 235 }; + static const unsigned char pt128[16] = + { 179, 166, 219, 60, 135, 12, 62, 153, + 36, 94, 13, 28, 6, 183, 71, 222 }; + static const unsigned char ct128[16] = + { 224, 31, 182, 10, 12, 255, 84, 70, + 127, 13, 89, 249, 9, 57, 165, 220 }; + + static const unsigned char key192[24] = + { 72, 211, 143, 117, 230, 217, 29, 42, + 229, 192, 247, 43, 120, 129, 135, 68, + 14, 95, 80, 0, 212, 97, 141, 190 }; + static const unsigned char pt192[16] = + { 123, 5, 21, 7, 59, 51, 130, 31, + 24, 112, 146, 218, 100, 84, 206, 177 }; + static const unsigned char ct192[16] = + { 92, 136, 4, 63, 57, 95, 100, 0, + 150, 130, 130, 16, 193, 111, 219, 133 }; + + static const unsigned char key256[32] = + { 243, 168, 141, 254, 190, 242, 235, 113, + 255, 160, 208, 59, 117, 6, 140, 126, + 135, 120, 115, 77, 208, 190, 130, 190, + 219, 194, 70, 65, 43, 140, 250, 48 }; + static const unsigned char pt256[16] = + { 127, 112, 240, 167, 84, 134, 50, 149, + 170, 91, 104, 19, 11, 230, 252, 245 }; + static const unsigned char ct256[16] = + { 88, 11, 25, 36, 172, 229, 202, 213, + 170, 65, 105, 153, 220, 104, 153, 138 }; + + unsigned char buf[2][16]; + symmetric_key skey; + int errno; + + /* test 128-bit key */ + if ((errno = saferp_setup(key128, 16, 0, &skey)) != CRYPT_OK) { + return errno; + } + saferp_ecb_encrypt(pt128, buf[0], &skey); + saferp_ecb_decrypt(buf[0], buf[1], &skey); + + /* compare */ + if (memcmp(buf[0], &ct128, 16) || memcmp(buf[1], &pt128, 16)) { + return CRYPT_FAIL_TESTVECTOR; + } + + /* test 192-bit key */ + if ((errno = saferp_setup(key192, 24, 0, &skey)) != CRYPT_OK) { + return errno; + } + saferp_ecb_encrypt(pt192, buf[0], &skey); + saferp_ecb_decrypt(buf[0], buf[1], &skey); + + /* compare */ + if (memcmp(buf[0], &ct192, 16) || memcmp(buf[1], &pt192, 16)) { + return CRYPT_FAIL_TESTVECTOR; + } + + /* test 256-bit key */ + if ((errno = saferp_setup(key256, 32, 0, &skey)) != CRYPT_OK) { + return errno; + } + saferp_ecb_encrypt(pt256, buf[0], &skey); + saferp_ecb_decrypt(buf[0], buf[1], &skey); + + /* compare */ + if (memcmp(buf[0], &ct256, 16) || memcmp(buf[1], &pt256, 16)) { + return CRYPT_FAIL_TESTVECTOR; + } + + return CRYPT_OK; +} + +int saferp_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize != NULL); + + if (*desired_keysize < 16) + return CRYPT_INVALID_KEYSIZE; + if (*desired_keysize < 24) { + *desired_keysize = 16; + return CRYPT_OK; + } else if (*desired_keysize < 32) { + *desired_keysize = 24; + return CRYPT_OK; + } else { + *desired_keysize = 32; + return CRYPT_OK; + } +} + +#endif + + diff --git a/safer.c b/safer.c new file mode 100644 index 0000000..ef831f3 --- /dev/null +++ b/safer.c @@ -0,0 +1,421 @@ +/******************************************************************************* +* +* FILE: safer.c +* +* DESCRIPTION: block-cipher algorithm SAFER (Secure And Fast Encryption +* Routine) in its four versions: SAFER K-64, SAFER K-128, +* SAFER SK-64 and SAFER SK-128. +* +* AUTHOR: Richard De Moliner (demoliner@isi.ee.ethz.ch) +* Signal and Information Processing Laboratory +* Swiss Federal Institute of Technology +* CH-8092 Zuerich, Switzerland +* +* DATE: September 9, 1995 +* +* CHANGE HISTORY: +* +*******************************************************************************/ + +#include + +#ifdef SAFER + +const struct _cipher_descriptor + safer_k64_desc = { + "safer-k64", + 8, 8, 8, 8, SAFER_K64_DEFAULT_NOF_ROUNDS, + &safer_k64_setup, + &safer_ecb_encrypt, + &safer_ecb_decrypt, + &safer_k64_test, + &safer_64_keysize + }, + + safer_sk64_desc = { + "safer-sk64", + 9, 8, 8, 8, SAFER_SK64_DEFAULT_NOF_ROUNDS, + &safer_sk64_setup, + &safer_ecb_encrypt, + &safer_ecb_decrypt, + &safer_sk64_test, + &safer_64_keysize + }, + + safer_k128_desc = { + "safer-k128", + 10, 16, 16, 8, SAFER_K128_DEFAULT_NOF_ROUNDS, + &safer_k128_setup, + &safer_ecb_encrypt, + &safer_ecb_decrypt, + &safer_sk128_test, + &safer_128_keysize + }, + + safer_sk128_desc = { + "safer-sk128", + 11, 16, 16, 8, SAFER_SK128_DEFAULT_NOF_ROUNDS, + &safer_sk128_setup, + &safer_ecb_encrypt, + &safer_ecb_decrypt, + &safer_sk128_test, + &safer_128_keysize + }; + +/******************* Constants ************************************************/ +// #define TAB_LEN 256 + +/******************* Assertions ***********************************************/ + +/******************* Macros ***************************************************/ +#define ROL8(x, n) ((unsigned char)((unsigned int)(x) << (n)\ + |(unsigned int)((x) & 0xFF) >> (8 - (n)))) +#define EXP(x) safer_ebox[(x) & 0xFF] +#define LOG(x) safer_lbox[(x) & 0xFF] +#define PHT(x, y) { y += x; x += y; } +#define IPHT(x, y) { x -= y; y -= x; } + +/******************* Types ****************************************************/ +extern const unsigned char safer_ebox[], safer_lbox[]; + +#ifdef CLEAN_STACK +static void _Safer_Expand_Userkey(const unsigned char *userkey_1, + const unsigned char *userkey_2, + unsigned int nof_rounds, + int strengthened, + safer_key_t key) +#else +static void Safer_Expand_Userkey(const unsigned char *userkey_1, + const unsigned char *userkey_2, + unsigned int nof_rounds, + int strengthened, + safer_key_t key) +#endif +{ unsigned int i, j; + unsigned char ka[SAFER_BLOCK_LEN + 1]; + unsigned char kb[SAFER_BLOCK_LEN + 1]; + + if (SAFER_MAX_NOF_ROUNDS < nof_rounds) + nof_rounds = SAFER_MAX_NOF_ROUNDS; + *key++ = (unsigned char)nof_rounds; + ka[SAFER_BLOCK_LEN] = 0; + kb[SAFER_BLOCK_LEN] = 0; + for (j = 0; j < SAFER_BLOCK_LEN; j++) + { + ka[SAFER_BLOCK_LEN] ^= ka[j] = ROL8(userkey_1[j], 5); + kb[SAFER_BLOCK_LEN] ^= kb[j] = *key++ = userkey_2[j]; + } + for (i = 1; i <= nof_rounds; i++) + { + for (j = 0; j < SAFER_BLOCK_LEN + 1; j++) + { + ka[j] = ROL8(ka[j], 6); + kb[j] = ROL8(kb[j], 6); + } + for (j = 0; j < SAFER_BLOCK_LEN; j++) + if (strengthened) + *key++ = (ka[(j + 2 * i - 1) % (SAFER_BLOCK_LEN + 1)] + + safer_ebox[safer_ebox[18 * i + j + 1]]) & 0xFF; + else + *key++ = (ka[j] + safer_ebox[safer_ebox[18 * i + j + 1]]) & 0xFF; + for (j = 0; j < SAFER_BLOCK_LEN; j++) + if (strengthened) + *key++ = (kb[(j + 2 * i) % (SAFER_BLOCK_LEN + 1)] + + safer_ebox[safer_ebox[18 * i + j + 10]]) & 0xFF; + else + *key++ = (kb[j] + safer_ebox[safer_ebox[18 * i + j + 10]]) & 0xFF; + } + +#ifdef CLEAN_STACK + zeromem(ka, sizeof(ka)); + zeromem(kb, sizeof(kb)); +#endif +} + +#ifdef CLEAN_STACK +static void Safer_Expand_Userkey(const unsigned char *userkey_1, + const unsigned char *userkey_2, + unsigned int nof_rounds, + int strengthened, + safer_key_t key) +{ + _Safer_Expand_Userkey(userkey_1, userkey_2, nof_rounds, strengthened, key); + burn_stack(sizeof(unsigned char) * (2 * (SAFER_BLOCK_LEN + 1)) + sizeof(unsigned int)*2); +} +#endif + +int safer_k64_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey) +{ + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + if (numrounds && (numrounds < 6 || numrounds > SAFER_MAX_NOF_ROUNDS)) { + return CRYPT_INVALID_ROUNDS; + } + + if (keylen != 8) { + return CRYPT_INVALID_KEYSIZE; + } + + Safer_Expand_Userkey(key, key, numrounds?numrounds:SAFER_K64_DEFAULT_NOF_ROUNDS, 0, skey->safer.key); + return CRYPT_OK; +} + +int safer_sk64_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey) +{ + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + if (numrounds && (numrounds < 6 || numrounds > SAFER_MAX_NOF_ROUNDS)) { + return CRYPT_INVALID_ROUNDS; + } + + if (keylen != 8) { + return CRYPT_INVALID_KEYSIZE; + } + + Safer_Expand_Userkey(key, key, numrounds?numrounds:SAFER_SK64_DEFAULT_NOF_ROUNDS, 1, skey->safer.key); + return CRYPT_OK; +} + +int safer_k128_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey) +{ + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + if (numrounds && (numrounds < 6 || numrounds > SAFER_MAX_NOF_ROUNDS)) { + return CRYPT_INVALID_ROUNDS; + } + + if (keylen != 16) { + return CRYPT_INVALID_KEYSIZE; + } + + Safer_Expand_Userkey(key, key+8, numrounds?numrounds:SAFER_K128_DEFAULT_NOF_ROUNDS, 0, skey->safer.key); + return CRYPT_OK; +} + +int safer_sk128_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey) +{ + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + if (numrounds && (numrounds < 6 || numrounds > SAFER_MAX_NOF_ROUNDS)) { + return CRYPT_INVALID_ROUNDS; + } + + if (keylen != 16) { + return CRYPT_INVALID_KEYSIZE; + } + + Safer_Expand_Userkey(key, key+8, numrounds?numrounds:SAFER_SK128_DEFAULT_NOF_ROUNDS, 1, skey->safer.key); + return CRYPT_OK; +} + +#ifdef CLEAN_STACK +static void _safer_ecb_encrypt(const unsigned char *block_in, + unsigned char *block_out, + symmetric_key *skey) +#else +void safer_ecb_encrypt(const unsigned char *block_in, + unsigned char *block_out, + symmetric_key *skey) +#endif +{ unsigned char a, b, c, d, e, f, g, h, t; + unsigned int round; + unsigned char *key; + + _ARGCHK(block_in != NULL); + _ARGCHK(block_out != NULL); + _ARGCHK(skey != NULL); + + key = skey->safer.key; + a = block_in[0]; b = block_in[1]; c = block_in[2]; d = block_in[3]; + e = block_in[4]; f = block_in[5]; g = block_in[6]; h = block_in[7]; + if (SAFER_MAX_NOF_ROUNDS < (round = *key)) round = SAFER_MAX_NOF_ROUNDS; + while(round--) + { + a ^= *++key; b += *++key; c += *++key; d ^= *++key; + e ^= *++key; f += *++key; g += *++key; h ^= *++key; + a = EXP(a) + *++key; b = LOG(b) ^ *++key; + c = LOG(c) ^ *++key; d = EXP(d) + *++key; + e = EXP(e) + *++key; f = LOG(f) ^ *++key; + g = LOG(g) ^ *++key; h = EXP(h) + *++key; + PHT(a, b); PHT(c, d); PHT(e, f); PHT(g, h); + PHT(a, c); PHT(e, g); PHT(b, d); PHT(f, h); + PHT(a, e); PHT(b, f); PHT(c, g); PHT(d, h); + t = b; b = e; e = c; c = t; t = d; d = f; f = g; g = t; + } + a ^= *++key; b += *++key; c += *++key; d ^= *++key; + e ^= *++key; f += *++key; g += *++key; h ^= *++key; + block_out[0] = a & 0xFF; block_out[1] = b & 0xFF; + block_out[2] = c & 0xFF; block_out[3] = d & 0xFF; + block_out[4] = e & 0xFF; block_out[5] = f & 0xFF; + block_out[6] = g & 0xFF; block_out[7] = h & 0xFF; +} + +#ifdef CLEAN_STACK +void safer_ecb_encrypt(const unsigned char *block_in, + unsigned char *block_out, + symmetric_key *skey) +{ + _safer_ecb_encrypt(block_in, block_out, skey); + burn_stack(sizeof(unsigned char) * 9 + sizeof(unsigned int) + sizeof(unsigned char *)); +} +#endif + +#ifdef CLEAN_STACK +static void _safer_ecb_decrypt(const unsigned char *block_in, + unsigned char *block_out, + symmetric_key *skey) +#else +void safer_ecb_decrypt(const unsigned char *block_in, + unsigned char *block_out, + symmetric_key *skey) +#endif +{ unsigned char a, b, c, d, e, f, g, h, t; + unsigned int round; + unsigned char *key; + + _ARGCHK(block_in != NULL); + _ARGCHK(block_out != NULL); + _ARGCHK(skey != NULL); + + key = skey->safer.key; + a = block_in[0]; b = block_in[1]; c = block_in[2]; d = block_in[3]; + e = block_in[4]; f = block_in[5]; g = block_in[6]; h = block_in[7]; + if (SAFER_MAX_NOF_ROUNDS < (round = *key)) round = SAFER_MAX_NOF_ROUNDS; + key += SAFER_BLOCK_LEN * (1 + 2 * round); + h ^= *key; g -= *--key; f -= *--key; e ^= *--key; + d ^= *--key; c -= *--key; b -= *--key; a ^= *--key; + while (round--) + { + t = e; e = b; b = c; c = t; t = f; f = d; d = g; g = t; + IPHT(a, e); IPHT(b, f); IPHT(c, g); IPHT(d, h); + IPHT(a, c); IPHT(e, g); IPHT(b, d); IPHT(f, h); + IPHT(a, b); IPHT(c, d); IPHT(e, f); IPHT(g, h); + h -= *--key; g ^= *--key; f ^= *--key; e -= *--key; + d -= *--key; c ^= *--key; b ^= *--key; a -= *--key; + h = LOG(h) ^ *--key; g = EXP(g) - *--key; + f = EXP(f) - *--key; e = LOG(e) ^ *--key; + d = LOG(d) ^ *--key; c = EXP(c) - *--key; + b = EXP(b) - *--key; a = LOG(a) ^ *--key; + } + block_out[0] = a & 0xFF; block_out[1] = b & 0xFF; + block_out[2] = c & 0xFF; block_out[3] = d & 0xFF; + block_out[4] = e & 0xFF; block_out[5] = f & 0xFF; + block_out[6] = g & 0xFF; block_out[7] = h & 0xFF; +} + +#ifdef CLEAN_STACK +void safer_ecb_decrypt(const unsigned char *block_in, + unsigned char *block_out, + symmetric_key *skey) +{ + _safer_ecb_decrypt(block_in, block_out, skey); + burn_stack(sizeof(unsigned char) * 9 + sizeof(unsigned int) + sizeof(unsigned char *)); +} +#endif + +int safer_64_keysize(int *keysize) +{ + _ARGCHK(keysize != NULL); + if (*keysize < 8) { + return CRYPT_INVALID_KEYSIZE; + } else { + *keysize = 8; + return CRYPT_OK; + } +} + +int safer_128_keysize(int *keysize) +{ + _ARGCHK(keysize != NULL); + if (*keysize < 16) { + return CRYPT_INVALID_KEYSIZE; + } else { + *keysize = 16; + return CRYPT_OK; + } +} + +int safer_k64_test(void) +{ + static const unsigned char k64_pt[] = { 1, 2, 3, 4, 5, 6, 7, 8 }, + k64_key[] = { 8, 7, 6, 5, 4, 3, 2, 1 }, + k64_ct[] = { 200, 242, 156, 221, 135, 120, 62, 217 }; + + symmetric_key skey; + unsigned char buf[2][8]; + int errno; + + /* test K64 */ + if ((errno = safer_k64_setup(k64_key, 8, 6, &skey)) != CRYPT_OK) { + return errno; + } + safer_ecb_encrypt(k64_pt, buf[0], &skey); + safer_ecb_decrypt(buf[0], buf[1], &skey); + + if (memcmp(buf[0], k64_ct, 8) || memcmp(buf[1], k64_pt, 8)) { + return CRYPT_FAIL_TESTVECTOR; + } + + return CRYPT_OK; +} + + +int safer_sk64_test(void) +{ + static const unsigned char sk64_pt[] = { 1, 2, 3, 4, 5, 6, 7, 8 }, + sk64_key[] = { 1, 2, 3, 4, 5, 6, 7, 8 }, + sk64_ct[] = { 95, 206, 155, 162, 5, 132, 56, 199 }; + + symmetric_key skey; + unsigned char buf[2][8]; + int errno; + + /* test SK64 */ + if ((errno = safer_sk64_setup(sk64_key, 8, 6, &skey)) != CRYPT_OK) { + return errno; + } + + safer_ecb_encrypt(sk64_pt, buf[0], &skey); + safer_ecb_decrypt(buf[0], buf[1], &skey); + + if (memcmp(buf[0], sk64_ct, 8) || memcmp(buf[1], sk64_pt, 8)) { + return CRYPT_FAIL_TESTVECTOR; + } + + return CRYPT_OK; +} + +int safer_sk128_test(void) +{ + static const unsigned char sk128_pt[] = { 1, 2, 3, 4, 5, 6, 7, 8 }, + sk128_key[] = { 1, 2, 3, 4, 5, 6, 7, 8, + 0, 0, 0, 0, 0, 0, 0, 0 }, + sk128_ct[] = { 255, 120, 17, 228, 179, 167, 46, 113 }; + + symmetric_key skey; + unsigned char buf[2][8]; + int errno; + + /* test SK128 */ + if ((errno = safer_sk128_setup(sk128_key, 16, 0, &skey)) != CRYPT_OK) { + return errno; + } + safer_ecb_encrypt(sk128_pt, buf[0], &skey); + safer_ecb_decrypt(buf[0], buf[1], &skey); + + if (memcmp(buf[0], sk128_ct, 8) || memcmp(buf[1], sk128_pt, 8)) { + return CRYPT_FAIL_TESTVECTOR; + } + + + return CRYPT_OK; +} + +#endif + + + diff --git a/safer_tab.c b/safer_tab.c new file mode 100644 index 0000000..79242cd --- /dev/null +++ b/safer_tab.c @@ -0,0 +1,48 @@ +#include "mycrypt.h" + +#if defined(SAFERP) || defined(SAFER) + +/* This is the box defined by ebox[x] = 45^x mod 257. + * Its assumed that the value "256" corresponds to zero. */ +const unsigned char safer_ebox[256] = { + 1, 45, 226, 147, 190, 69, 21, 174, 120, 3, 135, 164, 184, 56, 207, 63, + 8, 103, 9, 148, 235, 38, 168, 107, 189, 24, 52, 27, 187, 191, 114, 247, + 64, 53, 72, 156, 81, 47, 59, 85, 227, 192, 159, 216, 211, 243, 141, 177, +255, 167, 62, 220, 134, 119, 215, 166, 17, 251, 244, 186, 146, 145, 100, 131, +241, 51, 239, 218, 44, 181, 178, 43, 136, 209, 153, 203, 140, 132, 29, 20, +129, 151, 113, 202, 95, 163, 139, 87, 60, 130, 196, 82, 92, 28, 232, 160, + 4, 180, 133, 74, 246, 19, 84, 182, 223, 12, 26, 142, 222, 224, 57, 252, + 32, 155, 36, 78, 169, 152, 158, 171, 242, 96, 208, 108, 234, 250, 199, 217, + 0, 212, 31, 110, 67, 188, 236, 83, 137, 254, 122, 93, 73, 201, 50, 194, +249, 154, 248, 109, 22, 219, 89, 150, 68, 233, 205, 230, 70, 66, 143, 10, +193, 204, 185, 101, 176, 210, 198, 172, 30, 65, 98, 41, 46, 14, 116, 80, + 2, 90, 195, 37, 123, 138, 42, 91, 240, 6, 13, 71, 111, 112, 157, 126, + 16, 206, 18, 39, 213, 76, 79, 214, 121, 48, 104, 54, 117, 125, 228, 237, +128, 106, 144, 55, 162, 94, 118, 170, 197, 127, 61, 175, 165, 229, 25, 97, +253, 77, 124, 183, 11, 238, 173, 75, 34, 245, 231, 115, 35, 33, 200, 5, +225, 102, 221, 179, 88, 105, 99, 86, 15, 161, 49, 149, 23, 7, 58, 40 +}; + +/* This is the inverse of ebox or the base 45 logarithm */ +const unsigned char safer_lbox[256] = { +128, 0, 176, 9, 96, 239, 185, 253, 16, 18, 159, 228, 105, 186, 173, 248, +192, 56, 194, 101, 79, 6, 148, 252, 25, 222, 106, 27, 93, 78, 168, 130, +112, 237, 232, 236, 114, 179, 21, 195, 255, 171, 182, 71, 68, 1, 172, 37, +201, 250, 142, 65, 26, 33, 203, 211, 13, 110, 254, 38, 88, 218, 50, 15, + 32, 169, 157, 132, 152, 5, 156, 187, 34, 140, 99, 231, 197, 225, 115, 198, +175, 36, 91, 135, 102, 39, 247, 87, 244, 150, 177, 183, 92, 139, 213, 84, +121, 223, 170, 246, 62, 163, 241, 17, 202, 245, 209, 23, 123, 147, 131, 188, +189, 82, 30, 235, 174, 204, 214, 53, 8, 200, 138, 180, 226, 205, 191, 217, +208, 80, 89, 63, 77, 98, 52, 10, 72, 136, 181, 86, 76, 46, 107, 158, +210, 61, 60, 3, 19, 251, 151, 81, 117, 74, 145, 113, 35, 190, 118, 42, + 95, 249, 212, 85, 11, 220, 55, 49, 22, 116, 215, 119, 167, 230, 7, 219, +164, 47, 70, 243, 97, 69, 103, 227, 12, 162, 59, 28, 133, 24, 4, 29, + 41, 160, 143, 178, 90, 216, 166, 126, 238, 141, 83, 75, 161, 154, 193, 14, +122, 73, 165, 44, 129, 196, 199, 54, 43, 127, 67, 149, 51, 242, 108, 104, +109, 240, 2, 40, 206, 221, 155, 234, 94, 153, 124, 20, 134, 207, 229, 66, +184, 64, 120, 45, 58, 233, 100, 31, 146, 144, 125, 57, 111, 224, 137, 48 +}; + +#endif + + diff --git a/serpent.c b/serpent.c new file mode 100644 index 0000000..05902e5 --- /dev/null +++ b/serpent.c @@ -0,0 +1,719 @@ +#include "mycrypt.h" + +#ifdef SERPENT + +const struct _cipher_descriptor serpent_desc = +{ + "serpent", + 5, + 16, 32, 16, 32, + &serpent_setup, + &serpent_ecb_encrypt, + &serpent_ecb_decrypt, + &serpent_test, + &serpent_keysize +}; + +/* These defines are derived from Brian Gladman's work. Contact him at gladman@seven77.demon.co.uk + * + * Available on the web at http://fp.gladman.plus.com/cryptography_technology/aes/index.htm + */ +#define sb0(a,b,c,d,e,f,g,h) \ + t1 = a ^ d; \ + t2 = a & d; \ + t3 = c ^ t1; \ + t6 = b & t1; \ + t4 = b ^ t3; \ + t10 = ~t3; \ + h = t2 ^ t4; \ + t7 = a ^ t6; \ + t14 = ~t7; \ + t8 = c | t7; \ + t11 = t3 ^ t7; \ + g = t4 ^ t8; \ + t12 = h & t11; \ + f = t10 ^ t12; \ + e = t12 ^ t14 + +/* 15 terms */ + +#define ib0(a,b,c,d,e,f,g,h) \ + t1 = ~a; \ + t2 = a ^ b; \ + t3 = t1 | t2; \ + t4 = d ^ t3; \ + t7 = d & t2; \ + t5 = c ^ t4; \ + t8 = t1 ^ t7; \ + g = t2 ^ t5; \ + t11 = a & t4; \ + t9 = g & t8; \ + t14 = t5 ^ t8; \ + f = t4 ^ t9; \ + t12 = t5 | f; \ + h = t11 ^ t12; \ + e = h ^ t14 + +/* 14 terms! */ + +#define sb1(a,b,c,d,e,f,g,h) \ + t1 = ~a; \ + t2 = b ^ t1; \ + t3 = a | t2; \ + t4 = d | t2; \ + t5 = c ^ t3; \ + g = d ^ t5; \ + t7 = b ^ t4; \ + t8 = t2 ^ g; \ + t9 = t5 & t7; \ + h = t8 ^ t9; \ + t11 = t5 ^ t7; \ + f = h ^ t11; \ + t13 = t8 & t11; \ + e = t5 ^ t13 + +/* 17 terms */ + +#define ib1(a,b,c,d,e,f,g,h) \ + t1 = a ^ d; \ + t2 = a & b; \ + t3 = b ^ c; \ + t4 = a ^ t3; \ + t5 = b | d; \ + t7 = c | t1; \ + h = t4 ^ t5; \ + t8 = b ^ t7; \ + t11 = ~t2; \ + t9 = t4 & t8; \ + f = t1 ^ t9; \ + t13 = t9 ^ t11; \ + t12 = h & f; \ + g = t12 ^ t13; \ + t15 = a & d; \ + t16 = c ^ t13; \ + e = t15 ^ t16 + +/* 16 terms */ + +#define sb2(a,b,c,d,e,f,g,h) \ + t1 = ~a; \ + t2 = b ^ d; \ + t3 = c & t1; \ + t13 = d | t1; \ + e = t2 ^ t3; \ + t5 = c ^ t1; \ + t6 = c ^ e; \ + t7 = b & t6; \ + t10 = e | t5; \ + h = t5 ^ t7; \ + t9 = d | t7; \ + t11 = t9 & t10; \ + t14 = t2 ^ h; \ + g = a ^ t11; \ + t15 = g ^ t13; \ + f = t14 ^ t15 + +/* 16 terms */ + +#define ib2(a,b,c,d,e,f,g,h) \ + t1 = b ^ d; \ + t2 = ~t1; \ + t3 = a ^ c; \ + t4 = c ^ t1; \ + t7 = a | t2; \ + t5 = b & t4; \ + t8 = d ^ t7; \ + t11 = ~t4; \ + e = t3 ^ t5; \ + t9 = t3 | t8; \ + t14 = d & t11; \ + h = t1 ^ t9; \ + t12 = e | h; \ + f = t11 ^ t12; \ + t15 = t3 ^ t12; \ + g = t14 ^ t15 + +/* 17 terms */ + +#define sb3(a,b,c,d,e,f,g,h) \ + t1 = a ^ c; \ + t2 = d ^ t1; \ + t3 = a & t2; \ + t4 = d ^ t3; \ + t5 = b & t4; \ + g = t2 ^ t5; \ + t7 = a | g; \ + t8 = b | d; \ + t11 = a | d; \ + t9 = t4 & t7; \ + f = t8 ^ t9; \ + t12 = b ^ t11; \ + t13 = g ^ t9; \ + t15 = t3 ^ t8; \ + h = t12 ^ t13; \ + t16 = c & t15; \ + e = t12 ^ t16 + +/* 16 term solution that performs less well than 17 term one + in my environment (PPro/PII) + +#define sb3(a,b,c,d,e,f,g,h) \ + t1 = a ^ b; \ + t2 = a & c; \ + t3 = a | d; \ + t4 = c ^ d; \ + t5 = t1 & t3; \ + t6 = t2 | t5; \ + g = t4 ^ t6; \ + t8 = b ^ t3; \ + t9 = t6 ^ t8; \ + t10 = t4 & t9; \ + e = t1 ^ t10; \ + t12 = g & e; \ + f = t9 ^ t12; \ + t14 = b | d; \ + t15 = t4 ^ t12; \ + h = t14 ^ t15 +*/ + +/* 17 terms */ + +#define ib3(a,b,c,d,e,f,g,h) \ + t1 = b ^ c; \ + t2 = b | c; \ + t3 = a ^ c; \ + t7 = a ^ d; \ + t4 = t2 ^ t3; \ + t5 = d | t4; \ + t9 = t2 ^ t7; \ + e = t1 ^ t5; \ + t8 = t1 | t5; \ + t11 = a & t4; \ + g = t8 ^ t9; \ + t12 = e | t9; \ + f = t11 ^ t12; \ + t14 = a & g; \ + t15 = t2 ^ t14; \ + t16 = e & t15; \ + h = t4 ^ t16 + +/* 15 terms */ + +#define sb4(a,b,c,d,e,f,g,h) \ + t1 = a ^ d; \ + t2 = d & t1; \ + t3 = c ^ t2; \ + t4 = b | t3; \ + h = t1 ^ t4; \ + t6 = ~b; \ + t7 = t1 | t6; \ + e = t3 ^ t7; \ + t9 = a & e; \ + t10 = t1 ^ t6; \ + t11 = t4 & t10; \ + g = t9 ^ t11; \ + t13 = a ^ t3; \ + t14 = t10 & g; \ + f = t13 ^ t14 + +/* 17 terms */ + +#define ib4(a,b,c,d,e,f,g,h) \ + t1 = c ^ d; \ + t2 = c | d; \ + t3 = b ^ t2; \ + t4 = a & t3; \ + f = t1 ^ t4; \ + t6 = a ^ d; \ + t7 = b | d; \ + t8 = t6 & t7; \ + h = t3 ^ t8; \ + t10 = ~a; \ + t11 = c ^ h; \ + t12 = t10 | t11;\ + e = t3 ^ t12; \ + t14 = c | t4; \ + t15 = t7 ^ t14; \ + t16 = h | t10; \ + g = t15 ^ t16 + +/* 16 terms */ + +#define sb5(a,b,c,d,e,f,g,h) \ + t1 = ~a; \ + t2 = a ^ b; \ + t3 = a ^ d; \ + t4 = c ^ t1; \ + t5 = t2 | t3; \ + e = t4 ^ t5; \ + t7 = d & e; \ + t8 = t2 ^ e; \ + t10 = t1 | e; \ + f = t7 ^ t8; \ + t11 = t2 | t7; \ + t12 = t3 ^ t10; \ + t14 = b ^ t7; \ + g = t11 ^ t12; \ + t15 = f & t12; \ + h = t14 ^ t15 + +/* 16 terms */ + +#define ib5(a,b,c,d,e,f,g,h) \ + t1 = ~c; \ + t2 = b & t1; \ + t3 = d ^ t2; \ + t4 = a & t3; \ + t5 = b ^ t1; \ + h = t4 ^ t5; \ + t7 = b | h; \ + t8 = a & t7; \ + f = t3 ^ t8; \ + t10 = a | d; \ + t11 = t1 ^ t7; \ + e = t10 ^ t11; \ + t13 = a ^ c; \ + t14 = b & t10; \ + t15 = t4 | t13; \ + g = t14 ^ t15 + +/* 15 terms */ + +#define sb6(a,b,c,d,e,f,g,h) \ + t1 = ~a; \ + t2 = a ^ d; \ + t3 = b ^ t2; \ + t4 = t1 | t2; \ + t5 = c ^ t4; \ + f = b ^ t5; \ + t13 = ~t5; \ + t7 = t2 | f; \ + t8 = d ^ t7; \ + t9 = t5 & t8; \ + g = t3 ^ t9; \ + t11 = t5 ^ t8; \ + e = g ^ t11; \ + t14 = t3 & t11; \ + h = t13 ^ t14 + +/* 15 terms */ + +#define ib6(a,b,c,d,e,f,g,h) \ + t1 = ~a; \ + t2 = a ^ b; \ + t3 = c ^ t2; \ + t4 = c | t1; \ + t5 = d ^ t4; \ + t13 = d & t1; \ + f = t3 ^ t5; \ + t7 = t3 & t5; \ + t8 = t2 ^ t7; \ + t9 = b | t8; \ + h = t5 ^ t9; \ + t11 = b | h; \ + e = t8 ^ t11; \ + t14 = t3 ^ t11; \ + g = t13 ^ t14 + +/* 17 terms */ + +#define sb7(a,b,c,d,e,f,g,h) \ + t1 = ~c; \ + t2 = b ^ c; \ + t3 = b | t1; \ + t4 = d ^ t3; \ + t5 = a & t4; \ + t7 = a ^ d; \ + h = t2 ^ t5; \ + t8 = b ^ t5; \ + t9 = t2 | t8; \ + t11 = d & t3; \ + f = t7 ^ t9; \ + t12 = t5 ^ f; \ + t15 = t1 | t4; \ + t13 = h & t12; \ + g = t11 ^ t13; \ + t16 = t12 ^ g; \ + e = t15 ^ t16 + +/* 17 terms */ + +#define ib7(a,b,c,d,e,f,g,h) \ + t1 = a & b; \ + t2 = a | b; \ + t3 = c | t1; \ + t4 = d & t2; \ + h = t3 ^ t4; \ + t6 = ~d; \ + t7 = b ^ t4; \ + t8 = h ^ t6; \ + t11 = c ^ t7; \ + t9 = t7 | t8; \ + f = a ^ t9; \ + t12 = d | f; \ + e = t11 ^ t12; \ + t14 = a & h; \ + t15 = t3 ^ f; \ + t16 = e ^ t14; \ + g = t15 ^ t16 + +#define k_xor(r,a,b,c,d) \ + a ^= skey->serpent.K[4 * (r) + 0]; \ + b ^= skey->serpent.K[4 * (r) + 1]; \ + c ^= skey->serpent.K[4 * (r) + 2]; \ + d ^= skey->serpent.K[4 * (r) + 3] + +#define k_set(r,a,b,c,d) \ + a = lkey[4 * (r) + 8]; \ + b = lkey[4 * (r) + 9]; \ + c = lkey[4 * (r) + 10]; \ + d = lkey[4 * (r) + 11] + +#define k_get(r,a,b,c,d) \ + skey->serpent.K[4 * (r) + 0] = a; \ + skey->serpent.K[4 * (r) + 1] = b; \ + skey->serpent.K[4 * (r) + 2] = c; \ + skey->serpent.K[4 * (r) + 3] = d + +/* the linear transformation and its inverse */ + +#define rot(a,b,c,d) \ + a = ROL(a, 13); \ + c = ROL(c, 3); \ + d ^= c ^ (a << 3); \ + b ^= a ^ c; \ + d = ROL(d, 7); \ + b = ROL(b, 1); \ + a ^= b ^ d; \ + c ^= d ^ (b << 7); \ + a = ROL(a, 5); \ + c = ROL(c, 22) + +#define irot(a,b,c,d) \ + c = ROR(c, 22); \ + a = ROR(a, 5); \ + c ^= d ^ (b << 7); \ + a ^= b ^ d; \ + d = ROR(d, 7); \ + b = ROR(b, 1); \ + d ^= c ^ (a << 3); \ + b ^= a ^ c; \ + c = ROR(c, 3); \ + a = ROR(a, 13) + +#ifdef CLEAN_STACK +static int _serpent_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +#else +int serpent_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +#endif +{ + unsigned long lkey[140], t, a, b, c, d, e, f, g, h, x; + unsigned long t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16; + unsigned char buf[32]; + + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + /* check rounds */ + if (num_rounds != 0 && num_rounds != 32) { + return CRYPT_INVALID_ROUNDS; + } + + /* check keylen */ + if (keylen < 16 || keylen > 32) { + return CRYPT_INVALID_KEYSIZE; + } + + /* copy key and expand to 32bytes as required */ + for (x = 0; x < (unsigned long)keylen; x++) { + buf[x] = key[x]; + } + + if (x < 32) { + buf[x++] = 0x01; + while (x < 32) { + buf[x++] = 0; + } + } + + /* copy key into 32-bit words */ + for (x = 0; x < 8; x++) { + LOAD32L(lkey[x], &buf[x*4]); + } + + /* expand using the LFSR to 140 words */ + for (x = 0; x < 132; x++) { + t = lkey[x] ^ lkey[x+3] ^ lkey[x+5] ^ lkey[x+7] ^ x ^ 0x9E3779B9UL; + lkey[x + 8] = ROL(t, 11); + } + + /* perform the substituions */ + for (x = 0; x < 32; ) { + k_set( x,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x; + k_set( x,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x; + k_set( x,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x; + k_set( x,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x; + k_set( x,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x; + k_set( x,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x; + k_set( x,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x; + k_set( x,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get( x,e,f,g,h); ++x; + } + k_set(32,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get(32,e,f,g,h); + return CRYPT_OK; +} + +#ifdef CLEAN_STACK +int serpent_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + int x; + x = _serpent_setup(key, keylen, num_rounds, skey); + burn_stack(sizeof(unsigned long)*166 + sizeof(unsigned char)*32); + return x; +} +#endif + +#ifdef CLEAN_STACK +static void _serpent_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) +#else +void serpent_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) +#endif +{ + unsigned long a,b,c,d,e,f,g,h; + unsigned long t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(skey != NULL); + + LOAD32L(a, &pt[0]);LOAD32L(b, &pt[4]);LOAD32L(c, &pt[8]);LOAD32L(d, &pt[12]); + k_xor( 0,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor( 1,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor( 2,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor( 3,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor( 4,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor( 5,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor( 6,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor( 7,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor( 8,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor( 9,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor(10,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor(11,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor(12,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor(13,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor(14,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor(15,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor(16,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor(17,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor(18,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor(19,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor(20,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor(21,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor(22,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor(23,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor(24,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor(25,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor(26,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor(27,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor(28,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor(29,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); + k_xor(30,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); + k_xor(31,e,f,g,h); sb7(e,f,g,h,a,b,c,d); k_xor(32,a,b,c,d); + STORE32L(a, &ct[0]);STORE32L(b, &ct[4]);STORE32L(c, &ct[8]);STORE32L(d, &ct[12]); +} + +#ifdef CLEAN_STACK +void serpent_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) +{ + _serpent_ecb_encrypt(pt, ct, skey); + burn_stack(sizeof(unsigned long)*24); +} +#endif + +#ifdef CLEAN_STACK +static void _serpent_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) +#else +void serpent_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) +#endif +{ + unsigned long a,b,c,d,e,f,g,h; + unsigned long t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(skey != NULL); + + LOAD32L(a, &ct[0]);LOAD32L(b, &ct[4]);LOAD32L(c, &ct[8]);LOAD32L(d, &ct[12]); + k_xor(32,a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(31,e,f,g,h); + irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(30,a,b,c,d); + irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(29,e,f,g,h); + irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(28,a,b,c,d); + irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(27,e,f,g,h); + irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(26,a,b,c,d); + irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor(25,e,f,g,h); + irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor(24,a,b,c,d); + irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(23,e,f,g,h); + irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(22,a,b,c,d); + irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(21,e,f,g,h); + irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(20,a,b,c,d); + irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(19,e,f,g,h); + irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(18,a,b,c,d); + irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor(17,e,f,g,h); + irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor(16,a,b,c,d); + irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(15,e,f,g,h); + irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(14,a,b,c,d); + irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(13,e,f,g,h); + irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(12,a,b,c,d); + irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(11,e,f,g,h); + irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(10,a,b,c,d); + irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor( 9,e,f,g,h); + irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor( 8,a,b,c,d); + irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor( 7,e,f,g,h); + irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor( 6,a,b,c,d); + irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor( 5,e,f,g,h); + irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor( 4,a,b,c,d); + irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor( 3,e,f,g,h); + irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor( 2,a,b,c,d); + irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor( 1,e,f,g,h); + irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor( 0,a,b,c,d); + STORE32L(a, &pt[0]);STORE32L(b, &pt[4]);STORE32L(c, &pt[8]);STORE32L(d, &pt[12]); +} + +#ifdef CLEAN_STACK +void serpent_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) +{ + _serpent_ecb_decrypt(ct, pt, skey); + burn_stack(sizeof(unsigned long)*24); +} +#endif + +int serpent_test(void) +{ + static const struct { + int keylen; + unsigned char key[32], pt[16], ct[16]; + } tests[] = { + { + 16, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xdd, 0xd2, 0x6b, 0x98, 0xa5, 0xff, 0xd8, 0x2c, + 0x05, 0x34, 0x5a, 0x9d, 0xad, 0xbf, 0xaf, 0x49 } + }, + { + 16, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, + { 0x4a, 0xe9, 0xa2, 0x0b, 0x2b, 0x14, 0xa1, 0x02, + 0x90, 0xcb, 0xb8, 0x20, 0xb7, 0xff, 0xb5, 0x10 } + }, + { + 24, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 }, + { 0xe1, 0x1b, 0x01, 0x52, 0x4e, 0xa1, 0xf4, 0x65, + 0xa2, 0xa2, 0x00, 0x43, 0xeb, 0x9f, 0x7e, 0x8a } + }, + { + 32, + { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xe0, 0x88, 0x5d, 0x44, 0x60, 0x37, 0x34, 0x69, + 0xd1, 0xfa, 0x6c, 0x36, 0xa6, 0xe1, 0xc5, 0x2f } + }, + { + 32, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x17, 0xc6, 0x25, 0x8e, 0x60, 0x09, 0xe2, 0x82, + 0x66, 0x18, 0x69, 0xd5, 0x25, 0xf7, 0xd2, 0x04 } + }, + { + 32, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x9f, 0xe1, 0x43, 0x25, 0x0d, 0x00, 0xe2, 0x56, + 0x96, 0xb0, 0x1e, 0x0a, 0x2e, 0xd0, 0x5d, 0xb3 } + } + }; + + unsigned char buf[2][16]; + int x, failed, errno; + symmetric_key key; + + for (x = failed = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) { + /* setup key */ + if ((errno = serpent_setup(tests[x].key, tests[x].keylen, 0, &key))!= CRYPT_OK) { + return errno; + } + + /* encrypt and decrypt */ + serpent_ecb_encrypt(tests[x].pt, buf[0], &key); + serpent_ecb_decrypt(buf[0], buf[1], &key); + + /* compare */ + if (memcmp(buf[0], tests[x].ct, 16)) { +#if 0 + int y; + printf("\nEncrypt test %d failed\n", x); + for (y = 0; y < 16; y++) printf("%02x ", buf[0][y]); + printf("\n"); +#endif + failed = 1; + } + + if (memcmp(buf[1], tests[x].pt, 16)) { +#if 0 + int y; + printf("\nDecrypt test %d failed\n", x); + for (y = 0; y < 16; y++) printf("%02x ", buf[1][y]); + printf("\n"); +#endif + failed = 1; + } + } + + if (failed == 1) { + return CRYPT_FAIL_TESTVECTOR; + } else { + return CRYPT_OK; + } +} + +int serpent_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize != NULL); + + if (*desired_keysize < 16) + return CRYPT_INVALID_KEYSIZE; + if (*desired_keysize > 32) + *desired_keysize = 32; + return CRYPT_OK; +} + +#endif + + diff --git a/sha1.c b/sha1.c new file mode 100644 index 0000000..4e5e07d --- /dev/null +++ b/sha1.c @@ -0,0 +1,232 @@ +#include "mycrypt.h" + +#ifdef SHA1 + +const struct _hash_descriptor sha1_desc = +{ + "sha1", + 2, + 20, + 64, + &sha1_init, + &sha1_process, + &sha1_done, + &sha1_test +}; + +#define F0(x,y,z) ( (x&y) | ((~x)&z) ) +#define F1(x,y,z) (x ^ y ^ z) +#define F2(x,y,z) ((x & y) | (z & (x | y))) +#define F3(x,y,z) (x ^ y ^ z) + +#ifdef CLEAN_STACK +static void _sha1_compress(hash_state *md) +#else +static void sha1_compress(hash_state *md) +#endif +{ + unsigned long a,b,c,d,e,W[80],i,j; + + _ARGCHK(md != NULL); + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD32H(W[i], md->sha1.buf + (4*i)); + } + + /* copy state */ + a = md->sha1.state[0]; + b = md->sha1.state[1]; + c = md->sha1.state[2]; + d = md->sha1.state[3]; + e = md->sha1.state[4]; + + /* expand it */ + for (i = 16; i < 80; i++) { + j = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]; + W[i] = ROL(j, 1); + } + + /* compress */ + /* round one */ + for (i = 0; i < 20; i++) { + j = (ROL(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); + e = d; + d = c; + c = ROL(b, 30); + b = a; + a = j; + } + + /* round two */ + for (i = 20; i < 40; i++) { + j = (ROL(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); + e = d; + d = c; + c = ROL(b, 30); + b = a; + a = j; + } + + /* round three */ + for (i = 40; i < 60; i++) { + j = (ROL(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); + e = d; + d = c; + c = ROL(b, 30); + b = a; + a = j; + } + + /* round four */ + for (i = 60; i < 80; i++) { + j = (ROL(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); + e = d; + d = c; + c = ROL(b, 30); + b = a; + a = j; + } + + /* store */ + md->sha1.state[0] = md->sha1.state[0] + a; + md->sha1.state[1] = md->sha1.state[1] + b; + md->sha1.state[2] = md->sha1.state[2] + c; + md->sha1.state[3] = md->sha1.state[3] + d; + md->sha1.state[4] = md->sha1.state[4] + e; +} + +#ifdef CLEAN_STACK +static void sha1_compress(hash_state *md) +{ + _sha1_compress(md); + burn_stack(sizeof(unsigned long) * 87); +} +#endif + +void sha1_init(hash_state * md) +{ + _ARGCHK(md != NULL); + md->sha1.state[0] = 0x67452301UL; + md->sha1.state[1] = 0xefcdab89UL; + md->sha1.state[2] = 0x98badcfeUL; + md->sha1.state[3] = 0x10325476UL; + md->sha1.state[4] = 0xc3d2e1f0UL; + md->sha1.curlen = 0; + md->sha1.length = 0; +} + +void sha1_process(hash_state * md, const unsigned char *buf, unsigned long len) +{ + unsigned long n; + _ARGCHK(md != NULL); + _ARGCHK(buf != NULL); + + while (len) { + n = MIN(len, (64 - md->sha1.curlen)); + memcpy(md->sha1.buf + md->sha1.curlen, buf, n); + md->sha1.curlen += n; + buf += n; + len -= n; + + /* is 64 bytes full? */ + if (md->sha1.curlen == 64) { + sha1_compress(md); + md->sha1.length += 512; + md->sha1.curlen = 0; + } + } +} + +void sha1_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + /* increase the length of the message */ + md->sha1.length += md->sha1.curlen * 8; + + /* append the '1' bit */ + md->sha1.buf[md->sha1.curlen++] = 0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->sha1.curlen > 56) { + while (md->sha1.curlen < 64) { + md->sha1.buf[md->sha1.curlen++] = 0; + } + sha1_compress(md); + md->sha1.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->sha1.curlen < 56) { + md->sha1.buf[md->sha1.curlen++] = 0; + } + + /* store length */ + STORE64H(md->sha1.length, md->sha1.buf+56); + sha1_compress(md); + + /* copy output */ + for (i = 0; i < 5; i++) { + STORE32H(md->sha1.state[i], hash+(4*i)); + } +#ifdef CLEAN_STACK + zeromem(md, sizeof(hash_state)); +#endif +} + +int sha1_test(void) +{ + static const struct { + unsigned char *msg; + unsigned char hash[20]; + } tests[] = { + { "abc", + { 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, + 0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, + 0x9c, 0xd0, 0xd8, 0x9d } + }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, + 0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, + 0xE5, 0x46, 0x70, 0xF1 } + }, + { NULL, { 0 }} + }; + + int failed, i; + unsigned char tmp[20]; + hash_state md; + + for (failed = i = 0; tests[i].msg != NULL; i++) { + sha1_init(&md); + sha1_process(&md, tests[i].msg, strlen(tests[i].msg)); + sha1_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 20)) { +#if 0 + int j; + printf("\nSHA-1 Test %d failed\nGot (as a result): ", i); + for (j = 0; j < 20; j++) { + printf("%02x ", tmp[j]); + } + printf("\n"); +#endif + failed = 1; + } + } + if (failed == 1) { + return CRYPT_FAIL_TESTVECTOR; + } else { + return CRYPT_OK; + } +} + +#endif + + diff --git a/sha256.c b/sha256.c new file mode 100644 index 0000000..b54421d --- /dev/null +++ b/sha256.c @@ -0,0 +1,229 @@ +#include "mycrypt.h" + +#ifdef SHA256 + +const struct _hash_descriptor sha256_desc = +{ + "sha256", + 0, + 32, + 64, + &sha256_init, + &sha256_process, + &sha256_done, + &sha256_test +}; + +/* the K array */ +static const unsigned long K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Various logical functions */ +#define Ch(x,y,z) ((x & y) ^ (~x & z)) +#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z)) +#define S(x, n) ROR((x),(n)) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) + +/* compress 512-bits */ +#ifdef CLEAN_STACK +static void _sha256_compress(hash_state * md) +#else +static void sha256_compress(hash_state * md) +#endif +{ + unsigned long S[8], W[64], t0, t1; + int i; + + _ARGCHK(md != NULL); + + /* copy state into S */ + for (i = 0; i < 8; i++) + S[i] = md->sha256.state[i]; + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD32H(W[i], md->sha256.buf + (4*i)); + } + + /* fill W[16..63] */ + for (i = 16; i < 64; i++) + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + + /* Compress */ + for (i = 0; i < 64; i++) { + t0 = S[7] + Sigma1(S[4]) + Ch(S[4], S[5], S[6]) + K[i] + W[i]; + t1 = Sigma0(S[0]) + Maj(S[0], S[1], S[2]); + S[7] = S[6]; + S[6] = S[5]; + S[5] = S[4]; + S[4] = S[3] + t0; + S[3] = S[2]; + S[2] = S[1]; + S[1] = S[0]; + S[0] = t0 + t1; + } + + /* feedback */ + for (i = 0; i < 8; i++) { + md->sha256.state[i] = md->sha256.state[i] + S[i]; + } +} + +#ifdef CLEAN_STACK +static void sha256_compress(hash_state * md) +{ + _sha256_compress(md); + burn_stack(sizeof(unsigned long) * 74); +} +#endif + +/* init the sha256 state */ +void sha256_init(hash_state * md) +{ + _ARGCHK(md != NULL); + + md->sha256.curlen = 0; + md->sha256.length = 0; + md->sha256.state[0] = 0x6A09E667UL; + md->sha256.state[1] = 0xBB67AE85UL; + md->sha256.state[2] = 0x3C6EF372UL; + md->sha256.state[3] = 0xA54FF53AUL; + md->sha256.state[4] = 0x510E527FUL; + md->sha256.state[5] = 0x9B05688CUL; + md->sha256.state[6] = 0x1F83D9ABUL; + md->sha256.state[7] = 0x5BE0CD19UL; +} + +void sha256_process(hash_state * md, const unsigned char *buf, unsigned long len) +{ + unsigned long n; + _ARGCHK(md != NULL); + _ARGCHK(buf != NULL); + + while (len) { + n = MIN(len, (64 - md->sha256.curlen)); + memcpy(md->sha256.buf + md->sha256.curlen, buf, n); + md->sha256.curlen += n; + buf += n; + len -= n; + + /* is 64 bytes full? */ + if (md->sha256.curlen == 64) { + sha256_compress(md); + md->sha256.length += 512; + md->sha256.curlen = 0; + } + } +} + +void sha256_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + /* increase the length of the message */ + md->sha256.length += md->sha256.curlen * 8; + + /* append the '1' bit */ + md->sha256.buf[md->sha256.curlen++] = 0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->sha256.curlen > 56) { + while (md->sha256.curlen < 64) { + md->sha256.buf[md->sha256.curlen++] = 0; + } + sha256_compress(md); + md->sha256.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->sha256.curlen < 56) { + md->sha256.buf[md->sha256.curlen++] = 0; + } + + /* store length */ + STORE64H(md->sha256.length, md->sha256.buf+56); + sha256_compress(md); + + /* copy output */ + for (i = 0; i < 8; i++) { + STORE32H(md->sha256.state[i], hash+(4*i)); + } +#ifdef CLEAN_STACK + zeromem(md, sizeof(hash_state)); +#endif +} + +int sha256_test(void) +{ + static const struct { + unsigned char *msg; + unsigned char hash[32]; + } tests[] = { + { "abc", + { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad } + }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, + 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, + 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 } + }, + { NULL, { 0 } } + }; + + int failed, i; + unsigned char tmp[32]; + hash_state md; + + for (failed = i = 0; tests[i].msg != NULL; i++) { + sha256_init(&md); + sha256_process(&md, tests[i].msg, strlen(tests[i].msg)); + sha256_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 32)) { +#if 0 + int j; + printf("\nSHA-256 Test %d failed\nGot (as a result): ", i); + for (j = 0; j < 32; j++) { + printf("%02x ", tmp[j]); + } + printf("\n"); +#endif + failed = 1; + } + } + if (failed == 1) { + return CRYPT_FAIL_TESTVECTOR; + } else { + return CRYPT_OK; + } +} + +#endif + + diff --git a/sha384.c b/sha384.c new file mode 100644 index 0000000..4c4f492 --- /dev/null +++ b/sha384.c @@ -0,0 +1,107 @@ +/* included in sha512.c */ + +const struct _hash_descriptor sha384_desc = +{ + "sha384", + 4, + 48, + 128, + &sha384_init, + &sha384_process, + &sha384_done, + &sha384_test +}; + +void sha384_init(hash_state * md) +{ + _ARGCHK(md != NULL); + + md->sha512.curlen = 0; + md->sha512.length = 0; + md->sha512.state[0] = CONST64(0xcbbb9d5dc1059ed8); + md->sha512.state[1] = CONST64(0x629a292a367cd507); + md->sha512.state[2] = CONST64(0x9159015a3070dd17); + md->sha512.state[3] = CONST64(0x152fecd8f70e5939); + md->sha512.state[4] = CONST64(0x67332667ffc00b31); + md->sha512.state[5] = CONST64(0x8eb44a8768581511); + md->sha512.state[6] = CONST64(0xdb0c2e0d64f98fa7); + md->sha512.state[7] = CONST64(0x47b5481dbefa4fa4); +} + +void sha384_process(hash_state * md, const unsigned char *buf, unsigned long len) +{ + _ARGCHK(md != NULL); + _ARGCHK(buf != NULL); + sha512_process(md, buf, len); +} + +void sha384_done(hash_state * md, unsigned char *hash) +{ + unsigned char buf[64]; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + sha512_done(md, buf); + memcpy(hash, buf, 48); +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif +} + +int sha384_test(void) +{ + static const struct { + unsigned char *msg; + unsigned char hash[48]; + } tests[] = { + { "abc", + { 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b, + 0xb5, 0xa0, 0x3d, 0x69, 0x9a, 0xc6, 0x50, 0x07, + 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63, + 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed, + 0x80, 0x86, 0x07, 0x2b, 0xa1, 0xe7, 0xcc, 0x23, + 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7 } + }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + { 0x09, 0x33, 0x0c, 0x33, 0xf7, 0x11, 0x47, 0xe8, + 0x3d, 0x19, 0x2f, 0xc7, 0x82, 0xcd, 0x1b, 0x47, + 0x53, 0x11, 0x1b, 0x17, 0x3b, 0x3b, 0x05, 0xd2, + 0x2f, 0xa0, 0x80, 0x86, 0xe3, 0xb0, 0xf7, 0x12, + 0xfc, 0xc7, 0xc7, 0x1a, 0x55, 0x7e, 0x2d, 0xb9, + 0x66, 0xc3, 0xe9, 0xfa, 0x91, 0x74, 0x60, 0x39 } + }, + { NULL, { 0 }} + }; + + int failed, i; + unsigned char tmp[48]; + hash_state md; + + for (failed = i = 0; tests[i].msg != NULL; i++) { + sha384_init(&md); + sha384_process(&md, tests[i].msg, strlen(tests[i].msg)); + sha384_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 48)) { +#if 0 + int j; + printf("\nSHA-384 Test %d failed\nGot (as a result): ", i); + for (j = 0; j < 48; j++) { + printf("%02x ", tmp[j]); + } + printf("\n"); +#endif + failed = 1; + } + } + if (failed == 1) { + return CRYPT_FAIL_TESTVECTOR; + } else { + return CRYPT_OK; + } +} + + + + + diff --git a/sha512.c b/sha512.c new file mode 100644 index 0000000..ecb3107 --- /dev/null +++ b/sha512.c @@ -0,0 +1,272 @@ +#include "mycrypt.h" + +#ifdef SHA512 + +const struct _hash_descriptor sha512_desc = +{ + "sha512", + 5, + 64, + 128, + &sha512_init, + &sha512_process, + &sha512_done, + &sha512_test +}; + +/* the K array */ +static const ulong64 K[80] = { +CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd), +CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc), +CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019), +CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118), +CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe), +CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2), +CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1), +CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694), +CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3), +CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65), +CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483), +CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5), +CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210), +CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4), +CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725), +CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70), +CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926), +CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df), +CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8), +CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b), +CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001), +CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30), +CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910), +CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8), +CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53), +CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8), +CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb), +CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3), +CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60), +CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec), +CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9), +CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b), +CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207), +CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178), +CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6), +CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b), +CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493), +CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c), +CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a), +CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817) +}; + +/* Various logical functions */ +#define Ch(x,y,z) ((x & y) ^ (~x & z)) +#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z)) +#define S(x, n) ROR64((x),(n)) +#define R(x, n) (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)n)) +#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) +#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) +#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) +#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) + +/* compress 1024-bits */ +#ifdef CLEAN_STACK +static void _sha512_compress(hash_state * md) +#else +static void sha512_compress(hash_state * md) +#endif +{ + ulong64 S[8], W[80], t0, t1; + int i; + + _ARGCHK(md != NULL); + + /* copy state into S */ + for (i = 0; i < 8; i++) + S[i] = md->sha512.state[i]; + + /* copy the state into 1024-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD64H(W[i], md->sha512.buf + (8*i)); + } + + /* fill W[16..79] */ + for (i = 16; i < 80; i++) + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + + /* Compress */ + for (i = 0; i < 80; i++) { + t0 = S[7] + Sigma1(S[4]) + Ch(S[4], S[5], S[6]) + K[i] + W[i]; + t1 = Sigma0(S[0]) + Maj(S[0], S[1], S[2]); + S[7] = S[6]; + S[6] = S[5]; + S[5] = S[4]; + S[4] = S[3] + t0; + S[3] = S[2]; + S[2] = S[1]; + S[1] = S[0]; + S[0] = t0 + t1; + } + + /* feedback */ + for (i = 0; i < 8; i++) { + md->sha512.state[i] = md->sha512.state[i] + S[i]; + } +} + +/* compress 1024-bits */ +#ifdef CLEAN_STACK +static void sha512_compress(hash_state * md) +{ + _sha512_compress(md); + burn_stack(sizeof(ulong64) * 90 + sizeof(int)); +} +#endif + +/* init the sha512 state */ +void sha512_init(hash_state * md) +{ + _ARGCHK(md != NULL); + + md->sha512.curlen = 0; + md->sha512.length = 0; + md->sha512.state[0] = CONST64(0x6a09e667f3bcc908); + md->sha512.state[1] = CONST64(0xbb67ae8584caa73b); + md->sha512.state[2] = CONST64(0x3c6ef372fe94f82b); + md->sha512.state[3] = CONST64(0xa54ff53a5f1d36f1); + md->sha512.state[4] = CONST64(0x510e527fade682d1); + md->sha512.state[5] = CONST64(0x9b05688c2b3e6c1f); + md->sha512.state[6] = CONST64(0x1f83d9abfb41bd6b); + md->sha512.state[7] = CONST64(0x5be0cd19137e2179); +} + +void sha512_process(hash_state * md, const unsigned char *buf, unsigned long len) +{ + unsigned long n; + _ARGCHK(md != NULL); + _ARGCHK(buf != NULL); + while (len) { + n = MIN(len, (128 - md->sha512.curlen)); + memcpy(md->sha512.buf + md->sha512.curlen, buf, n); + md->sha512.curlen += n; + buf += n; + len -= n; + + /* is 64 bytes full? */ + if (md->sha512.curlen == 128) { + sha512_compress(md); + md->sha512.length += 1024; + md->sha512.curlen = 0; + } + } +} + +void sha512_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + /* increase the length of the message */ + md->sha512.length += md->sha512.curlen * CONST64(8); + + /* append the '1' bit */ + md->sha512.buf[md->sha512.curlen++] = 0x80; + + /* if the length is currently above 112 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->sha512.curlen > 112) { + while (md->sha512.curlen < 128) { + md->sha512.buf[md->sha512.curlen++] = 0; + } + sha512_compress(md); + md->sha512.curlen = 0; + } + + /* pad upto 120 bytes of zeroes + * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash + * > 2^64 bits of data... :-) + */ + while (md->sha512.curlen < 120) { + md->sha512.buf[md->sha512.curlen++] = 0; + } + + /* store length */ + STORE64H(md->sha512.length, md->sha512.buf+120); + sha512_compress(md); + + /* copy output */ + for (i = 0; i < 8; i++) { + STORE64H(md->sha512.state[i], hash+(8*i)); + } +#ifdef CLEAN_STACK + zeromem(md, sizeof(hash_state)); +#endif +} + +int sha512_test(void) +{ + static const struct { + unsigned char *msg; + unsigned char hash[64]; + } tests[] = { + { "abc", + { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, + 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, + 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, + 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, + 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, + 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, + 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, + 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f } + }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + { 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, + 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f, + 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, + 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, + 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, + 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a, + 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, + 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09 } + }, + { NULL, { 0 }} + }; + + int failed, i; + unsigned char tmp[64]; + hash_state md; + + for (failed = i = 0; tests[i].msg != NULL; i++) { + sha512_init(&md); + sha512_process(&md, tests[i].msg, strlen(tests[i].msg)); + sha512_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 64)) { +#if 0 + int j; + printf("\nSHA-512 Test %d failed\nGot (as a result): ", i); + for (j = 0; j < 64; j++) { + printf("%02x ", tmp[j]); + } + printf("\n"); +#endif + failed = 1; + } + } + if (failed == 1) { + return CRYPT_FAIL_TESTVECTOR; + } else { + return CRYPT_OK; + } +} + +#ifdef SHA384 + #include "sha384.c" +#endif + +#endif + + + diff --git a/sprng.c b/sprng.c new file mode 100644 index 0000000..e3e4b2b --- /dev/null +++ b/sprng.c @@ -0,0 +1,42 @@ +/* A secure PRNG using the RNG functions. Basically this is a + * wrapper that allows you to use a secure RNG as a PRNG + * in the various other functions. + */ +#include "mycrypt.h" + +#ifdef SPRNG + +const struct _prng_descriptor sprng_desc = +{ + "sprng", + &sprng_start, + &sprng_add_entropy, + &sprng_ready, + &sprng_read +}; + +int sprng_start(prng_state *prng) +{ + return CRYPT_OK; +} + +int sprng_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng) +{ + return CRYPT_OK; +} + +int sprng_ready(prng_state *prng) +{ + return CRYPT_OK; +} + +unsigned long sprng_read(unsigned char *buf, unsigned long len, prng_state *prng) +{ + _ARGCHK(buf != NULL); + return rng_get_bytes(buf, len, NULL); +} + +#endif + + + diff --git a/strings.c b/strings.c new file mode 100644 index 0000000..6ca2749 --- /dev/null +++ b/strings.c @@ -0,0 +1,47 @@ +/* Future releases will make use of this */ +#include "mycrypt.h" + +static const char *err_2_str[] = +{ + "CRYPT_OK", + "CRYPT_ERROR", + + "Invalid keysize for block cipher.", + "Invalid number of rounds for block cipher.", + "Algorithm failed test vectors.", + + "Buffer overflow.", + "Invalid input packet.", + + "Invalid number of bits for a PRNG.", + "Error reading the PRNG.", + + "Invalid cipher specified.", + "Invalid hash specified.", + "Invalid PRNG specified.", + + "Out of memory.", + + "Invalid PK key or key type specified for function.", + "A private PK key is required.", + + "Invalid argument provided.", + + "Invalid PK type.", + "Invalid PK system.", + "Duplicate PK key found on keyring.", + "Key not found in keyring.", + "Invalid sized parameter.", + + "Invalid size for prime." +}; + +const char *error_to_string(int errno) +{ + if (errno < 0 || errno > (int)(sizeof(err_2_str)/sizeof(err_2_str[0]))) { + return "Invalid error code."; + } else { + return err_2_str[errno]; + } +} + diff --git a/tiger.c b/tiger.c new file mode 100644 index 0000000..07fb3ce --- /dev/null +++ b/tiger.c @@ -0,0 +1,775 @@ +#include "mycrypt.h" + +#ifdef TIGER + +const struct _hash_descriptor tiger_desc = +{ + "tiger", + 1, + 24, + 64, + &tiger_init, + &tiger_process, + &tiger_done, + &tiger_test +}; + +#define t1 (table) +#define t2 (table+256) +#define t3 (table+256*2) +#define t4 (table+256*3) + +#define save_abc aa = a; bb = b; cc = c; + +static const ulong64 table[4*256] = { + CONST64(0x02AAB17CF7E90C5E) /* 0 */, CONST64(0xAC424B03E243A8EC) /* 1 */, + CONST64(0x72CD5BE30DD5FCD3) /* 2 */, CONST64(0x6D019B93F6F97F3A) /* 3 */, + CONST64(0xCD9978FFD21F9193) /* 4 */, CONST64(0x7573A1C9708029E2) /* 5 */, + CONST64(0xB164326B922A83C3) /* 6 */, CONST64(0x46883EEE04915870) /* 7 */, + CONST64(0xEAACE3057103ECE6) /* 8 */, CONST64(0xC54169B808A3535C) /* 9 */, + CONST64(0x4CE754918DDEC47C) /* 10 */, CONST64(0x0AA2F4DFDC0DF40C) /* 11 */, + CONST64(0x10B76F18A74DBEFA) /* 12 */, CONST64(0xC6CCB6235AD1AB6A) /* 13 */, + CONST64(0x13726121572FE2FF) /* 14 */, CONST64(0x1A488C6F199D921E) /* 15 */, + CONST64(0x4BC9F9F4DA0007CA) /* 16 */, CONST64(0x26F5E6F6E85241C7) /* 17 */, + CONST64(0x859079DBEA5947B6) /* 18 */, CONST64(0x4F1885C5C99E8C92) /* 19 */, + CONST64(0xD78E761EA96F864B) /* 20 */, CONST64(0x8E36428C52B5C17D) /* 21 */, + CONST64(0x69CF6827373063C1) /* 22 */, CONST64(0xB607C93D9BB4C56E) /* 23 */, + CONST64(0x7D820E760E76B5EA) /* 24 */, CONST64(0x645C9CC6F07FDC42) /* 25 */, + CONST64(0xBF38A078243342E0) /* 26 */, CONST64(0x5F6B343C9D2E7D04) /* 27 */, + CONST64(0xF2C28AEB600B0EC6) /* 28 */, CONST64(0x6C0ED85F7254BCAC) /* 29 */, + CONST64(0x71592281A4DB4FE5) /* 30 */, CONST64(0x1967FA69CE0FED9F) /* 31 */, + CONST64(0xFD5293F8B96545DB) /* 32 */, CONST64(0xC879E9D7F2A7600B) /* 33 */, + CONST64(0x860248920193194E) /* 34 */, CONST64(0xA4F9533B2D9CC0B3) /* 35 */, + CONST64(0x9053836C15957613) /* 36 */, CONST64(0xDB6DCF8AFC357BF1) /* 37 */, + CONST64(0x18BEEA7A7A370F57) /* 38 */, CONST64(0x037117CA50B99066) /* 39 */, + CONST64(0x6AB30A9774424A35) /* 40 */, CONST64(0xF4E92F02E325249B) /* 41 */, + CONST64(0x7739DB07061CCAE1) /* 42 */, CONST64(0xD8F3B49CECA42A05) /* 43 */, + CONST64(0xBD56BE3F51382F73) /* 44 */, CONST64(0x45FAED5843B0BB28) /* 45 */, + CONST64(0x1C813D5C11BF1F83) /* 46 */, CONST64(0x8AF0E4B6D75FA169) /* 47 */, + CONST64(0x33EE18A487AD9999) /* 48 */, CONST64(0x3C26E8EAB1C94410) /* 49 */, + CONST64(0xB510102BC0A822F9) /* 50 */, CONST64(0x141EEF310CE6123B) /* 51 */, + CONST64(0xFC65B90059DDB154) /* 52 */, CONST64(0xE0158640C5E0E607) /* 53 */, + CONST64(0x884E079826C3A3CF) /* 54 */, CONST64(0x930D0D9523C535FD) /* 55 */, + CONST64(0x35638D754E9A2B00) /* 56 */, CONST64(0x4085FCCF40469DD5) /* 57 */, + CONST64(0xC4B17AD28BE23A4C) /* 58 */, CONST64(0xCAB2F0FC6A3E6A2E) /* 59 */, + CONST64(0x2860971A6B943FCD) /* 60 */, CONST64(0x3DDE6EE212E30446) /* 61 */, + CONST64(0x6222F32AE01765AE) /* 62 */, CONST64(0x5D550BB5478308FE) /* 63 */, + CONST64(0xA9EFA98DA0EDA22A) /* 64 */, CONST64(0xC351A71686C40DA7) /* 65 */, + CONST64(0x1105586D9C867C84) /* 66 */, CONST64(0xDCFFEE85FDA22853) /* 67 */, + CONST64(0xCCFBD0262C5EEF76) /* 68 */, CONST64(0xBAF294CB8990D201) /* 69 */, + CONST64(0xE69464F52AFAD975) /* 70 */, CONST64(0x94B013AFDF133E14) /* 71 */, + CONST64(0x06A7D1A32823C958) /* 72 */, CONST64(0x6F95FE5130F61119) /* 73 */, + CONST64(0xD92AB34E462C06C0) /* 74 */, CONST64(0xED7BDE33887C71D2) /* 75 */, + CONST64(0x79746D6E6518393E) /* 76 */, CONST64(0x5BA419385D713329) /* 77 */, + CONST64(0x7C1BA6B948A97564) /* 78 */, CONST64(0x31987C197BFDAC67) /* 79 */, + CONST64(0xDE6C23C44B053D02) /* 80 */, CONST64(0x581C49FED002D64D) /* 81 */, + CONST64(0xDD474D6338261571) /* 82 */, CONST64(0xAA4546C3E473D062) /* 83 */, + CONST64(0x928FCE349455F860) /* 84 */, CONST64(0x48161BBACAAB94D9) /* 85 */, + CONST64(0x63912430770E6F68) /* 86 */, CONST64(0x6EC8A5E602C6641C) /* 87 */, + CONST64(0x87282515337DDD2B) /* 88 */, CONST64(0x2CDA6B42034B701B) /* 89 */, + CONST64(0xB03D37C181CB096D) /* 90 */, CONST64(0xE108438266C71C6F) /* 91 */, + CONST64(0x2B3180C7EB51B255) /* 92 */, CONST64(0xDF92B82F96C08BBC) /* 93 */, + CONST64(0x5C68C8C0A632F3BA) /* 94 */, CONST64(0x5504CC861C3D0556) /* 95 */, + CONST64(0xABBFA4E55FB26B8F) /* 96 */, CONST64(0x41848B0AB3BACEB4) /* 97 */, + CONST64(0xB334A273AA445D32) /* 98 */, CONST64(0xBCA696F0A85AD881) /* 99 */, + CONST64(0x24F6EC65B528D56C) /* 100 */, CONST64(0x0CE1512E90F4524A) /* 101 */, + CONST64(0x4E9DD79D5506D35A) /* 102 */, CONST64(0x258905FAC6CE9779) /* 103 */, + CONST64(0x2019295B3E109B33) /* 104 */, CONST64(0xF8A9478B73A054CC) /* 105 */, + CONST64(0x2924F2F934417EB0) /* 106 */, CONST64(0x3993357D536D1BC4) /* 107 */, + CONST64(0x38A81AC21DB6FF8B) /* 108 */, CONST64(0x47C4FBF17D6016BF) /* 109 */, + CONST64(0x1E0FAADD7667E3F5) /* 110 */, CONST64(0x7ABCFF62938BEB96) /* 111 */, + CONST64(0xA78DAD948FC179C9) /* 112 */, CONST64(0x8F1F98B72911E50D) /* 113 */, + CONST64(0x61E48EAE27121A91) /* 114 */, CONST64(0x4D62F7AD31859808) /* 115 */, + CONST64(0xECEBA345EF5CEAEB) /* 116 */, CONST64(0xF5CEB25EBC9684CE) /* 117 */, + CONST64(0xF633E20CB7F76221) /* 118 */, CONST64(0xA32CDF06AB8293E4) /* 119 */, + CONST64(0x985A202CA5EE2CA4) /* 120 */, CONST64(0xCF0B8447CC8A8FB1) /* 121 */, + CONST64(0x9F765244979859A3) /* 122 */, CONST64(0xA8D516B1A1240017) /* 123 */, + CONST64(0x0BD7BA3EBB5DC726) /* 124 */, CONST64(0xE54BCA55B86ADB39) /* 125 */, + CONST64(0x1D7A3AFD6C478063) /* 126 */, CONST64(0x519EC608E7669EDD) /* 127 */, + CONST64(0x0E5715A2D149AA23) /* 128 */, CONST64(0x177D4571848FF194) /* 129 */, + CONST64(0xEEB55F3241014C22) /* 130 */, CONST64(0x0F5E5CA13A6E2EC2) /* 131 */, + CONST64(0x8029927B75F5C361) /* 132 */, CONST64(0xAD139FABC3D6E436) /* 133 */, + CONST64(0x0D5DF1A94CCF402F) /* 134 */, CONST64(0x3E8BD948BEA5DFC8) /* 135 */, + CONST64(0xA5A0D357BD3FF77E) /* 136 */, CONST64(0xA2D12E251F74F645) /* 137 */, + CONST64(0x66FD9E525E81A082) /* 138 */, CONST64(0x2E0C90CE7F687A49) /* 139 */, + CONST64(0xC2E8BCBEBA973BC5) /* 140 */, CONST64(0x000001BCE509745F) /* 141 */, + CONST64(0x423777BBE6DAB3D6) /* 142 */, CONST64(0xD1661C7EAEF06EB5) /* 143 */, + CONST64(0xA1781F354DAACFD8) /* 144 */, CONST64(0x2D11284A2B16AFFC) /* 145 */, + CONST64(0xF1FC4F67FA891D1F) /* 146 */, CONST64(0x73ECC25DCB920ADA) /* 147 */, + CONST64(0xAE610C22C2A12651) /* 148 */, CONST64(0x96E0A810D356B78A) /* 149 */, + CONST64(0x5A9A381F2FE7870F) /* 150 */, CONST64(0xD5AD62EDE94E5530) /* 151 */, + CONST64(0xD225E5E8368D1427) /* 152 */, CONST64(0x65977B70C7AF4631) /* 153 */, + CONST64(0x99F889B2DE39D74F) /* 154 */, CONST64(0x233F30BF54E1D143) /* 155 */, + CONST64(0x9A9675D3D9A63C97) /* 156 */, CONST64(0x5470554FF334F9A8) /* 157 */, + CONST64(0x166ACB744A4F5688) /* 158 */, CONST64(0x70C74CAAB2E4AEAD) /* 159 */, + CONST64(0xF0D091646F294D12) /* 160 */, CONST64(0x57B82A89684031D1) /* 161 */, + CONST64(0xEFD95A5A61BE0B6B) /* 162 */, CONST64(0x2FBD12E969F2F29A) /* 163 */, + CONST64(0x9BD37013FEFF9FE8) /* 164 */, CONST64(0x3F9B0404D6085A06) /* 165 */, + CONST64(0x4940C1F3166CFE15) /* 166 */, CONST64(0x09542C4DCDF3DEFB) /* 167 */, + CONST64(0xB4C5218385CD5CE3) /* 168 */, CONST64(0xC935B7DC4462A641) /* 169 */, + CONST64(0x3417F8A68ED3B63F) /* 170 */, CONST64(0xB80959295B215B40) /* 171 */, + CONST64(0xF99CDAEF3B8C8572) /* 172 */, CONST64(0x018C0614F8FCB95D) /* 173 */, + CONST64(0x1B14ACCD1A3ACDF3) /* 174 */, CONST64(0x84D471F200BB732D) /* 175 */, + CONST64(0xC1A3110E95E8DA16) /* 176 */, CONST64(0x430A7220BF1A82B8) /* 177 */, + CONST64(0xB77E090D39DF210E) /* 178 */, CONST64(0x5EF4BD9F3CD05E9D) /* 179 */, + CONST64(0x9D4FF6DA7E57A444) /* 180 */, CONST64(0xDA1D60E183D4A5F8) /* 181 */, + CONST64(0xB287C38417998E47) /* 182 */, CONST64(0xFE3EDC121BB31886) /* 183 */, + CONST64(0xC7FE3CCC980CCBEF) /* 184 */, CONST64(0xE46FB590189BFD03) /* 185 */, + CONST64(0x3732FD469A4C57DC) /* 186 */, CONST64(0x7EF700A07CF1AD65) /* 187 */, + CONST64(0x59C64468A31D8859) /* 188 */, CONST64(0x762FB0B4D45B61F6) /* 189 */, + CONST64(0x155BAED099047718) /* 190 */, CONST64(0x68755E4C3D50BAA6) /* 191 */, + CONST64(0xE9214E7F22D8B4DF) /* 192 */, CONST64(0x2ADDBF532EAC95F4) /* 193 */, + CONST64(0x32AE3909B4BD0109) /* 194 */, CONST64(0x834DF537B08E3450) /* 195 */, + CONST64(0xFA209DA84220728D) /* 196 */, CONST64(0x9E691D9B9EFE23F7) /* 197 */, + CONST64(0x0446D288C4AE8D7F) /* 198 */, CONST64(0x7B4CC524E169785B) /* 199 */, + CONST64(0x21D87F0135CA1385) /* 200 */, CONST64(0xCEBB400F137B8AA5) /* 201 */, + CONST64(0x272E2B66580796BE) /* 202 */, CONST64(0x3612264125C2B0DE) /* 203 */, + CONST64(0x057702BDAD1EFBB2) /* 204 */, CONST64(0xD4BABB8EACF84BE9) /* 205 */, + CONST64(0x91583139641BC67B) /* 206 */, CONST64(0x8BDC2DE08036E024) /* 207 */, + CONST64(0x603C8156F49F68ED) /* 208 */, CONST64(0xF7D236F7DBEF5111) /* 209 */, + CONST64(0x9727C4598AD21E80) /* 210 */, CONST64(0xA08A0896670A5FD7) /* 211 */, + CONST64(0xCB4A8F4309EBA9CB) /* 212 */, CONST64(0x81AF564B0F7036A1) /* 213 */, + CONST64(0xC0B99AA778199ABD) /* 214 */, CONST64(0x959F1EC83FC8E952) /* 215 */, + CONST64(0x8C505077794A81B9) /* 216 */, CONST64(0x3ACAAF8F056338F0) /* 217 */, + CONST64(0x07B43F50627A6778) /* 218 */, CONST64(0x4A44AB49F5ECCC77) /* 219 */, + CONST64(0x3BC3D6E4B679EE98) /* 220 */, CONST64(0x9CC0D4D1CF14108C) /* 221 */, + CONST64(0x4406C00B206BC8A0) /* 222 */, CONST64(0x82A18854C8D72D89) /* 223 */, + CONST64(0x67E366B35C3C432C) /* 224 */, CONST64(0xB923DD61102B37F2) /* 225 */, + CONST64(0x56AB2779D884271D) /* 226 */, CONST64(0xBE83E1B0FF1525AF) /* 227 */, + CONST64(0xFB7C65D4217E49A9) /* 228 */, CONST64(0x6BDBE0E76D48E7D4) /* 229 */, + CONST64(0x08DF828745D9179E) /* 230 */, CONST64(0x22EA6A9ADD53BD34) /* 231 */, + CONST64(0xE36E141C5622200A) /* 232 */, CONST64(0x7F805D1B8CB750EE) /* 233 */, + CONST64(0xAFE5C7A59F58E837) /* 234 */, CONST64(0xE27F996A4FB1C23C) /* 235 */, + CONST64(0xD3867DFB0775F0D0) /* 236 */, CONST64(0xD0E673DE6E88891A) /* 237 */, + CONST64(0x123AEB9EAFB86C25) /* 238 */, CONST64(0x30F1D5D5C145B895) /* 239 */, + CONST64(0xBB434A2DEE7269E7) /* 240 */, CONST64(0x78CB67ECF931FA38) /* 241 */, + CONST64(0xF33B0372323BBF9C) /* 242 */, CONST64(0x52D66336FB279C74) /* 243 */, + CONST64(0x505F33AC0AFB4EAA) /* 244 */, CONST64(0xE8A5CD99A2CCE187) /* 245 */, + CONST64(0x534974801E2D30BB) /* 246 */, CONST64(0x8D2D5711D5876D90) /* 247 */, + CONST64(0x1F1A412891BC038E) /* 248 */, CONST64(0xD6E2E71D82E56648) /* 249 */, + CONST64(0x74036C3A497732B7) /* 250 */, CONST64(0x89B67ED96361F5AB) /* 251 */, + CONST64(0xFFED95D8F1EA02A2) /* 252 */, CONST64(0xE72B3BD61464D43D) /* 253 */, + CONST64(0xA6300F170BDC4820) /* 254 */, CONST64(0xEBC18760ED78A77A) /* 255 */, + CONST64(0xE6A6BE5A05A12138) /* 256 */, CONST64(0xB5A122A5B4F87C98) /* 257 */, + CONST64(0x563C6089140B6990) /* 258 */, CONST64(0x4C46CB2E391F5DD5) /* 259 */, + CONST64(0xD932ADDBC9B79434) /* 260 */, CONST64(0x08EA70E42015AFF5) /* 261 */, + CONST64(0xD765A6673E478CF1) /* 262 */, CONST64(0xC4FB757EAB278D99) /* 263 */, + CONST64(0xDF11C6862D6E0692) /* 264 */, CONST64(0xDDEB84F10D7F3B16) /* 265 */, + CONST64(0x6F2EF604A665EA04) /* 266 */, CONST64(0x4A8E0F0FF0E0DFB3) /* 267 */, + CONST64(0xA5EDEEF83DBCBA51) /* 268 */, CONST64(0xFC4F0A2A0EA4371E) /* 269 */, + CONST64(0xE83E1DA85CB38429) /* 270 */, CONST64(0xDC8FF882BA1B1CE2) /* 271 */, + CONST64(0xCD45505E8353E80D) /* 272 */, CONST64(0x18D19A00D4DB0717) /* 273 */, + CONST64(0x34A0CFEDA5F38101) /* 274 */, CONST64(0x0BE77E518887CAF2) /* 275 */, + CONST64(0x1E341438B3C45136) /* 276 */, CONST64(0xE05797F49089CCF9) /* 277 */, + CONST64(0xFFD23F9DF2591D14) /* 278 */, CONST64(0x543DDA228595C5CD) /* 279 */, + CONST64(0x661F81FD99052A33) /* 280 */, CONST64(0x8736E641DB0F7B76) /* 281 */, + CONST64(0x15227725418E5307) /* 282 */, CONST64(0xE25F7F46162EB2FA) /* 283 */, + CONST64(0x48A8B2126C13D9FE) /* 284 */, CONST64(0xAFDC541792E76EEA) /* 285 */, + CONST64(0x03D912BFC6D1898F) /* 286 */, CONST64(0x31B1AAFA1B83F51B) /* 287 */, + CONST64(0xF1AC2796E42AB7D9) /* 288 */, CONST64(0x40A3A7D7FCD2EBAC) /* 289 */, + CONST64(0x1056136D0AFBBCC5) /* 290 */, CONST64(0x7889E1DD9A6D0C85) /* 291 */, + CONST64(0xD33525782A7974AA) /* 292 */, CONST64(0xA7E25D09078AC09B) /* 293 */, + CONST64(0xBD4138B3EAC6EDD0) /* 294 */, CONST64(0x920ABFBE71EB9E70) /* 295 */, + CONST64(0xA2A5D0F54FC2625C) /* 296 */, CONST64(0xC054E36B0B1290A3) /* 297 */, + CONST64(0xF6DD59FF62FE932B) /* 298 */, CONST64(0x3537354511A8AC7D) /* 299 */, + CONST64(0xCA845E9172FADCD4) /* 300 */, CONST64(0x84F82B60329D20DC) /* 301 */, + CONST64(0x79C62CE1CD672F18) /* 302 */, CONST64(0x8B09A2ADD124642C) /* 303 */, + CONST64(0xD0C1E96A19D9E726) /* 304 */, CONST64(0x5A786A9B4BA9500C) /* 305 */, + CONST64(0x0E020336634C43F3) /* 306 */, CONST64(0xC17B474AEB66D822) /* 307 */, + CONST64(0x6A731AE3EC9BAAC2) /* 308 */, CONST64(0x8226667AE0840258) /* 309 */, + CONST64(0x67D4567691CAECA5) /* 310 */, CONST64(0x1D94155C4875ADB5) /* 311 */, + CONST64(0x6D00FD985B813FDF) /* 312 */, CONST64(0x51286EFCB774CD06) /* 313 */, + CONST64(0x5E8834471FA744AF) /* 314 */, CONST64(0xF72CA0AEE761AE2E) /* 315 */, + CONST64(0xBE40E4CDAEE8E09A) /* 316 */, CONST64(0xE9970BBB5118F665) /* 317 */, + CONST64(0x726E4BEB33DF1964) /* 318 */, CONST64(0x703B000729199762) /* 319 */, + CONST64(0x4631D816F5EF30A7) /* 320 */, CONST64(0xB880B5B51504A6BE) /* 321 */, + CONST64(0x641793C37ED84B6C) /* 322 */, CONST64(0x7B21ED77F6E97D96) /* 323 */, + CONST64(0x776306312EF96B73) /* 324 */, CONST64(0xAE528948E86FF3F4) /* 325 */, + CONST64(0x53DBD7F286A3F8F8) /* 326 */, CONST64(0x16CADCE74CFC1063) /* 327 */, + CONST64(0x005C19BDFA52C6DD) /* 328 */, CONST64(0x68868F5D64D46AD3) /* 329 */, + CONST64(0x3A9D512CCF1E186A) /* 330 */, CONST64(0x367E62C2385660AE) /* 331 */, + CONST64(0xE359E7EA77DCB1D7) /* 332 */, CONST64(0x526C0773749ABE6E) /* 333 */, + CONST64(0x735AE5F9D09F734B) /* 334 */, CONST64(0x493FC7CC8A558BA8) /* 335 */, + CONST64(0xB0B9C1533041AB45) /* 336 */, CONST64(0x321958BA470A59BD) /* 337 */, + CONST64(0x852DB00B5F46C393) /* 338 */, CONST64(0x91209B2BD336B0E5) /* 339 */, + CONST64(0x6E604F7D659EF19F) /* 340 */, CONST64(0xB99A8AE2782CCB24) /* 341 */, + CONST64(0xCCF52AB6C814C4C7) /* 342 */, CONST64(0x4727D9AFBE11727B) /* 343 */, + CONST64(0x7E950D0C0121B34D) /* 344 */, CONST64(0x756F435670AD471F) /* 345 */, + CONST64(0xF5ADD442615A6849) /* 346 */, CONST64(0x4E87E09980B9957A) /* 347 */, + CONST64(0x2ACFA1DF50AEE355) /* 348 */, CONST64(0xD898263AFD2FD556) /* 349 */, + CONST64(0xC8F4924DD80C8FD6) /* 350 */, CONST64(0xCF99CA3D754A173A) /* 351 */, + CONST64(0xFE477BACAF91BF3C) /* 352 */, CONST64(0xED5371F6D690C12D) /* 353 */, + CONST64(0x831A5C285E687094) /* 354 */, CONST64(0xC5D3C90A3708A0A4) /* 355 */, + CONST64(0x0F7F903717D06580) /* 356 */, CONST64(0x19F9BB13B8FDF27F) /* 357 */, + CONST64(0xB1BD6F1B4D502843) /* 358 */, CONST64(0x1C761BA38FFF4012) /* 359 */, + CONST64(0x0D1530C4E2E21F3B) /* 360 */, CONST64(0x8943CE69A7372C8A) /* 361 */, + CONST64(0xE5184E11FEB5CE66) /* 362 */, CONST64(0x618BDB80BD736621) /* 363 */, + CONST64(0x7D29BAD68B574D0B) /* 364 */, CONST64(0x81BB613E25E6FE5B) /* 365 */, + CONST64(0x071C9C10BC07913F) /* 366 */, CONST64(0xC7BEEB7909AC2D97) /* 367 */, + CONST64(0xC3E58D353BC5D757) /* 368 */, CONST64(0xEB017892F38F61E8) /* 369 */, + CONST64(0xD4EFFB9C9B1CC21A) /* 370 */, CONST64(0x99727D26F494F7AB) /* 371 */, + CONST64(0xA3E063A2956B3E03) /* 372 */, CONST64(0x9D4A8B9A4AA09C30) /* 373 */, + CONST64(0x3F6AB7D500090FB4) /* 374 */, CONST64(0x9CC0F2A057268AC0) /* 375 */, + CONST64(0x3DEE9D2DEDBF42D1) /* 376 */, CONST64(0x330F49C87960A972) /* 377 */, + CONST64(0xC6B2720287421B41) /* 378 */, CONST64(0x0AC59EC07C00369C) /* 379 */, + CONST64(0xEF4EAC49CB353425) /* 380 */, CONST64(0xF450244EEF0129D8) /* 381 */, + CONST64(0x8ACC46E5CAF4DEB6) /* 382 */, CONST64(0x2FFEAB63989263F7) /* 383 */, + CONST64(0x8F7CB9FE5D7A4578) /* 384 */, CONST64(0x5BD8F7644E634635) /* 385 */, + CONST64(0x427A7315BF2DC900) /* 386 */, CONST64(0x17D0C4AA2125261C) /* 387 */, + CONST64(0x3992486C93518E50) /* 388 */, CONST64(0xB4CBFEE0A2D7D4C3) /* 389 */, + CONST64(0x7C75D6202C5DDD8D) /* 390 */, CONST64(0xDBC295D8E35B6C61) /* 391 */, + CONST64(0x60B369D302032B19) /* 392 */, CONST64(0xCE42685FDCE44132) /* 393 */, + CONST64(0x06F3DDB9DDF65610) /* 394 */, CONST64(0x8EA4D21DB5E148F0) /* 395 */, + CONST64(0x20B0FCE62FCD496F) /* 396 */, CONST64(0x2C1B912358B0EE31) /* 397 */, + CONST64(0xB28317B818F5A308) /* 398 */, CONST64(0xA89C1E189CA6D2CF) /* 399 */, + CONST64(0x0C6B18576AAADBC8) /* 400 */, CONST64(0xB65DEAA91299FAE3) /* 401 */, + CONST64(0xFB2B794B7F1027E7) /* 402 */, CONST64(0x04E4317F443B5BEB) /* 403 */, + CONST64(0x4B852D325939D0A6) /* 404 */, CONST64(0xD5AE6BEEFB207FFC) /* 405 */, + CONST64(0x309682B281C7D374) /* 406 */, CONST64(0xBAE309A194C3B475) /* 407 */, + CONST64(0x8CC3F97B13B49F05) /* 408 */, CONST64(0x98A9422FF8293967) /* 409 */, + CONST64(0x244B16B01076FF7C) /* 410 */, CONST64(0xF8BF571C663D67EE) /* 411 */, + CONST64(0x1F0D6758EEE30DA1) /* 412 */, CONST64(0xC9B611D97ADEB9B7) /* 413 */, + CONST64(0xB7AFD5887B6C57A2) /* 414 */, CONST64(0x6290AE846B984FE1) /* 415 */, + CONST64(0x94DF4CDEACC1A5FD) /* 416 */, CONST64(0x058A5BD1C5483AFF) /* 417 */, + CONST64(0x63166CC142BA3C37) /* 418 */, CONST64(0x8DB8526EB2F76F40) /* 419 */, + CONST64(0xE10880036F0D6D4E) /* 420 */, CONST64(0x9E0523C9971D311D) /* 421 */, + CONST64(0x45EC2824CC7CD691) /* 422 */, CONST64(0x575B8359E62382C9) /* 423 */, + CONST64(0xFA9E400DC4889995) /* 424 */, CONST64(0xD1823ECB45721568) /* 425 */, + CONST64(0xDAFD983B8206082F) /* 426 */, CONST64(0xAA7D29082386A8CB) /* 427 */, + CONST64(0x269FCD4403B87588) /* 428 */, CONST64(0x1B91F5F728BDD1E0) /* 429 */, + CONST64(0xE4669F39040201F6) /* 430 */, CONST64(0x7A1D7C218CF04ADE) /* 431 */, + CONST64(0x65623C29D79CE5CE) /* 432 */, CONST64(0x2368449096C00BB1) /* 433 */, + CONST64(0xAB9BF1879DA503BA) /* 434 */, CONST64(0xBC23ECB1A458058E) /* 435 */, + CONST64(0x9A58DF01BB401ECC) /* 436 */, CONST64(0xA070E868A85F143D) /* 437 */, + CONST64(0x4FF188307DF2239E) /* 438 */, CONST64(0x14D565B41A641183) /* 439 */, + CONST64(0xEE13337452701602) /* 440 */, CONST64(0x950E3DCF3F285E09) /* 441 */, + CONST64(0x59930254B9C80953) /* 442 */, CONST64(0x3BF299408930DA6D) /* 443 */, + CONST64(0xA955943F53691387) /* 444 */, CONST64(0xA15EDECAA9CB8784) /* 445 */, + CONST64(0x29142127352BE9A0) /* 446 */, CONST64(0x76F0371FFF4E7AFB) /* 447 */, + CONST64(0x0239F450274F2228) /* 448 */, CONST64(0xBB073AF01D5E868B) /* 449 */, + CONST64(0xBFC80571C10E96C1) /* 450 */, CONST64(0xD267088568222E23) /* 451 */, + CONST64(0x9671A3D48E80B5B0) /* 452 */, CONST64(0x55B5D38AE193BB81) /* 453 */, + CONST64(0x693AE2D0A18B04B8) /* 454 */, CONST64(0x5C48B4ECADD5335F) /* 455 */, + CONST64(0xFD743B194916A1CA) /* 456 */, CONST64(0x2577018134BE98C4) /* 457 */, + CONST64(0xE77987E83C54A4AD) /* 458 */, CONST64(0x28E11014DA33E1B9) /* 459 */, + CONST64(0x270CC59E226AA213) /* 460 */, CONST64(0x71495F756D1A5F60) /* 461 */, + CONST64(0x9BE853FB60AFEF77) /* 462 */, CONST64(0xADC786A7F7443DBF) /* 463 */, + CONST64(0x0904456173B29A82) /* 464 */, CONST64(0x58BC7A66C232BD5E) /* 465 */, + CONST64(0xF306558C673AC8B2) /* 466 */, CONST64(0x41F639C6B6C9772A) /* 467 */, + CONST64(0x216DEFE99FDA35DA) /* 468 */, CONST64(0x11640CC71C7BE615) /* 469 */, + CONST64(0x93C43694565C5527) /* 470 */, CONST64(0xEA038E6246777839) /* 471 */, + CONST64(0xF9ABF3CE5A3E2469) /* 472 */, CONST64(0x741E768D0FD312D2) /* 473 */, + CONST64(0x0144B883CED652C6) /* 474 */, CONST64(0xC20B5A5BA33F8552) /* 475 */, + CONST64(0x1AE69633C3435A9D) /* 476 */, CONST64(0x97A28CA4088CFDEC) /* 477 */, + CONST64(0x8824A43C1E96F420) /* 478 */, CONST64(0x37612FA66EEEA746) /* 479 */, + CONST64(0x6B4CB165F9CF0E5A) /* 480 */, CONST64(0x43AA1C06A0ABFB4A) /* 481 */, + CONST64(0x7F4DC26FF162796B) /* 482 */, CONST64(0x6CBACC8E54ED9B0F) /* 483 */, + CONST64(0xA6B7FFEFD2BB253E) /* 484 */, CONST64(0x2E25BC95B0A29D4F) /* 485 */, + CONST64(0x86D6A58BDEF1388C) /* 486 */, CONST64(0xDED74AC576B6F054) /* 487 */, + CONST64(0x8030BDBC2B45805D) /* 488 */, CONST64(0x3C81AF70E94D9289) /* 489 */, + CONST64(0x3EFF6DDA9E3100DB) /* 490 */, CONST64(0xB38DC39FDFCC8847) /* 491 */, + CONST64(0x123885528D17B87E) /* 492 */, CONST64(0xF2DA0ED240B1B642) /* 493 */, + CONST64(0x44CEFADCD54BF9A9) /* 494 */, CONST64(0x1312200E433C7EE6) /* 495 */, + CONST64(0x9FFCC84F3A78C748) /* 496 */, CONST64(0xF0CD1F72248576BB) /* 497 */, + CONST64(0xEC6974053638CFE4) /* 498 */, CONST64(0x2BA7B67C0CEC4E4C) /* 499 */, + CONST64(0xAC2F4DF3E5CE32ED) /* 500 */, CONST64(0xCB33D14326EA4C11) /* 501 */, + CONST64(0xA4E9044CC77E58BC) /* 502 */, CONST64(0x5F513293D934FCEF) /* 503 */, + CONST64(0x5DC9645506E55444) /* 504 */, CONST64(0x50DE418F317DE40A) /* 505 */, + CONST64(0x388CB31A69DDE259) /* 506 */, CONST64(0x2DB4A83455820A86) /* 507 */, + CONST64(0x9010A91E84711AE9) /* 508 */, CONST64(0x4DF7F0B7B1498371) /* 509 */, + CONST64(0xD62A2EABC0977179) /* 510 */, CONST64(0x22FAC097AA8D5C0E) /* 511 */, + CONST64(0xF49FCC2FF1DAF39B) /* 512 */, CONST64(0x487FD5C66FF29281) /* 513 */, + CONST64(0xE8A30667FCDCA83F) /* 514 */, CONST64(0x2C9B4BE3D2FCCE63) /* 515 */, + CONST64(0xDA3FF74B93FBBBC2) /* 516 */, CONST64(0x2FA165D2FE70BA66) /* 517 */, + CONST64(0xA103E279970E93D4) /* 518 */, CONST64(0xBECDEC77B0E45E71) /* 519 */, + CONST64(0xCFB41E723985E497) /* 520 */, CONST64(0xB70AAA025EF75017) /* 521 */, + CONST64(0xD42309F03840B8E0) /* 522 */, CONST64(0x8EFC1AD035898579) /* 523 */, + CONST64(0x96C6920BE2B2ABC5) /* 524 */, CONST64(0x66AF4163375A9172) /* 525 */, + CONST64(0x2174ABDCCA7127FB) /* 526 */, CONST64(0xB33CCEA64A72FF41) /* 527 */, + CONST64(0xF04A4933083066A5) /* 528 */, CONST64(0x8D970ACDD7289AF5) /* 529 */, + CONST64(0x8F96E8E031C8C25E) /* 530 */, CONST64(0xF3FEC02276875D47) /* 531 */, + CONST64(0xEC7BF310056190DD) /* 532 */, CONST64(0xF5ADB0AEBB0F1491) /* 533 */, + CONST64(0x9B50F8850FD58892) /* 534 */, CONST64(0x4975488358B74DE8) /* 535 */, + CONST64(0xA3354FF691531C61) /* 536 */, CONST64(0x0702BBE481D2C6EE) /* 537 */, + CONST64(0x89FB24057DEDED98) /* 538 */, CONST64(0xAC3075138596E902) /* 539 */, + CONST64(0x1D2D3580172772ED) /* 540 */, CONST64(0xEB738FC28E6BC30D) /* 541 */, + CONST64(0x5854EF8F63044326) /* 542 */, CONST64(0x9E5C52325ADD3BBE) /* 543 */, + CONST64(0x90AA53CF325C4623) /* 544 */, CONST64(0xC1D24D51349DD067) /* 545 */, + CONST64(0x2051CFEEA69EA624) /* 546 */, CONST64(0x13220F0A862E7E4F) /* 547 */, + CONST64(0xCE39399404E04864) /* 548 */, CONST64(0xD9C42CA47086FCB7) /* 549 */, + CONST64(0x685AD2238A03E7CC) /* 550 */, CONST64(0x066484B2AB2FF1DB) /* 551 */, + CONST64(0xFE9D5D70EFBF79EC) /* 552 */, CONST64(0x5B13B9DD9C481854) /* 553 */, + CONST64(0x15F0D475ED1509AD) /* 554 */, CONST64(0x0BEBCD060EC79851) /* 555 */, + CONST64(0xD58C6791183AB7F8) /* 556 */, CONST64(0xD1187C5052F3EEE4) /* 557 */, + CONST64(0xC95D1192E54E82FF) /* 558 */, CONST64(0x86EEA14CB9AC6CA2) /* 559 */, + CONST64(0x3485BEB153677D5D) /* 560 */, CONST64(0xDD191D781F8C492A) /* 561 */, + CONST64(0xF60866BAA784EBF9) /* 562 */, CONST64(0x518F643BA2D08C74) /* 563 */, + CONST64(0x8852E956E1087C22) /* 564 */, CONST64(0xA768CB8DC410AE8D) /* 565 */, + CONST64(0x38047726BFEC8E1A) /* 566 */, CONST64(0xA67738B4CD3B45AA) /* 567 */, + CONST64(0xAD16691CEC0DDE19) /* 568 */, CONST64(0xC6D4319380462E07) /* 569 */, + CONST64(0xC5A5876D0BA61938) /* 570 */, CONST64(0x16B9FA1FA58FD840) /* 571 */, + CONST64(0x188AB1173CA74F18) /* 572 */, CONST64(0xABDA2F98C99C021F) /* 573 */, + CONST64(0x3E0580AB134AE816) /* 574 */, CONST64(0x5F3B05B773645ABB) /* 575 */, + CONST64(0x2501A2BE5575F2F6) /* 576 */, CONST64(0x1B2F74004E7E8BA9) /* 577 */, + CONST64(0x1CD7580371E8D953) /* 578 */, CONST64(0x7F6ED89562764E30) /* 579 */, + CONST64(0xB15926FF596F003D) /* 580 */, CONST64(0x9F65293DA8C5D6B9) /* 581 */, + CONST64(0x6ECEF04DD690F84C) /* 582 */, CONST64(0x4782275FFF33AF88) /* 583 */, + CONST64(0xE41433083F820801) /* 584 */, CONST64(0xFD0DFE409A1AF9B5) /* 585 */, + CONST64(0x4325A3342CDB396B) /* 586 */, CONST64(0x8AE77E62B301B252) /* 587 */, + CONST64(0xC36F9E9F6655615A) /* 588 */, CONST64(0x85455A2D92D32C09) /* 589 */, + CONST64(0xF2C7DEA949477485) /* 590 */, CONST64(0x63CFB4C133A39EBA) /* 591 */, + CONST64(0x83B040CC6EBC5462) /* 592 */, CONST64(0x3B9454C8FDB326B0) /* 593 */, + CONST64(0x56F56A9E87FFD78C) /* 594 */, CONST64(0x2DC2940D99F42BC6) /* 595 */, + CONST64(0x98F7DF096B096E2D) /* 596 */, CONST64(0x19A6E01E3AD852BF) /* 597 */, + CONST64(0x42A99CCBDBD4B40B) /* 598 */, CONST64(0xA59998AF45E9C559) /* 599 */, + CONST64(0x366295E807D93186) /* 600 */, CONST64(0x6B48181BFAA1F773) /* 601 */, + CONST64(0x1FEC57E2157A0A1D) /* 602 */, CONST64(0x4667446AF6201AD5) /* 603 */, + CONST64(0xE615EBCACFB0F075) /* 604 */, CONST64(0xB8F31F4F68290778) /* 605 */, + CONST64(0x22713ED6CE22D11E) /* 606 */, CONST64(0x3057C1A72EC3C93B) /* 607 */, + CONST64(0xCB46ACC37C3F1F2F) /* 608 */, CONST64(0xDBB893FD02AAF50E) /* 609 */, + CONST64(0x331FD92E600B9FCF) /* 610 */, CONST64(0xA498F96148EA3AD6) /* 611 */, + CONST64(0xA8D8426E8B6A83EA) /* 612 */, CONST64(0xA089B274B7735CDC) /* 613 */, + CONST64(0x87F6B3731E524A11) /* 614 */, CONST64(0x118808E5CBC96749) /* 615 */, + CONST64(0x9906E4C7B19BD394) /* 616 */, CONST64(0xAFED7F7E9B24A20C) /* 617 */, + CONST64(0x6509EADEEB3644A7) /* 618 */, CONST64(0x6C1EF1D3E8EF0EDE) /* 619 */, + CONST64(0xB9C97D43E9798FB4) /* 620 */, CONST64(0xA2F2D784740C28A3) /* 621 */, + CONST64(0x7B8496476197566F) /* 622 */, CONST64(0x7A5BE3E6B65F069D) /* 623 */, + CONST64(0xF96330ED78BE6F10) /* 624 */, CONST64(0xEEE60DE77A076A15) /* 625 */, + CONST64(0x2B4BEE4AA08B9BD0) /* 626 */, CONST64(0x6A56A63EC7B8894E) /* 627 */, + CONST64(0x02121359BA34FEF4) /* 628 */, CONST64(0x4CBF99F8283703FC) /* 629 */, + CONST64(0x398071350CAF30C8) /* 630 */, CONST64(0xD0A77A89F017687A) /* 631 */, + CONST64(0xF1C1A9EB9E423569) /* 632 */, CONST64(0x8C7976282DEE8199) /* 633 */, + CONST64(0x5D1737A5DD1F7ABD) /* 634 */, CONST64(0x4F53433C09A9FA80) /* 635 */, + CONST64(0xFA8B0C53DF7CA1D9) /* 636 */, CONST64(0x3FD9DCBC886CCB77) /* 637 */, + CONST64(0xC040917CA91B4720) /* 638 */, CONST64(0x7DD00142F9D1DCDF) /* 639 */, + CONST64(0x8476FC1D4F387B58) /* 640 */, CONST64(0x23F8E7C5F3316503) /* 641 */, + CONST64(0x032A2244E7E37339) /* 642 */, CONST64(0x5C87A5D750F5A74B) /* 643 */, + CONST64(0x082B4CC43698992E) /* 644 */, CONST64(0xDF917BECB858F63C) /* 645 */, + CONST64(0x3270B8FC5BF86DDA) /* 646 */, CONST64(0x10AE72BB29B5DD76) /* 647 */, + CONST64(0x576AC94E7700362B) /* 648 */, CONST64(0x1AD112DAC61EFB8F) /* 649 */, + CONST64(0x691BC30EC5FAA427) /* 650 */, CONST64(0xFF246311CC327143) /* 651 */, + CONST64(0x3142368E30E53206) /* 652 */, CONST64(0x71380E31E02CA396) /* 653 */, + CONST64(0x958D5C960AAD76F1) /* 654 */, CONST64(0xF8D6F430C16DA536) /* 655 */, + CONST64(0xC8FFD13F1BE7E1D2) /* 656 */, CONST64(0x7578AE66004DDBE1) /* 657 */, + CONST64(0x05833F01067BE646) /* 658 */, CONST64(0xBB34B5AD3BFE586D) /* 659 */, + CONST64(0x095F34C9A12B97F0) /* 660 */, CONST64(0x247AB64525D60CA8) /* 661 */, + CONST64(0xDCDBC6F3017477D1) /* 662 */, CONST64(0x4A2E14D4DECAD24D) /* 663 */, + CONST64(0xBDB5E6D9BE0A1EEB) /* 664 */, CONST64(0x2A7E70F7794301AB) /* 665 */, + CONST64(0xDEF42D8A270540FD) /* 666 */, CONST64(0x01078EC0A34C22C1) /* 667 */, + CONST64(0xE5DE511AF4C16387) /* 668 */, CONST64(0x7EBB3A52BD9A330A) /* 669 */, + CONST64(0x77697857AA7D6435) /* 670 */, CONST64(0x004E831603AE4C32) /* 671 */, + CONST64(0xE7A21020AD78E312) /* 672 */, CONST64(0x9D41A70C6AB420F2) /* 673 */, + CONST64(0x28E06C18EA1141E6) /* 674 */, CONST64(0xD2B28CBD984F6B28) /* 675 */, + CONST64(0x26B75F6C446E9D83) /* 676 */, CONST64(0xBA47568C4D418D7F) /* 677 */, + CONST64(0xD80BADBFE6183D8E) /* 678 */, CONST64(0x0E206D7F5F166044) /* 679 */, + CONST64(0xE258A43911CBCA3E) /* 680 */, CONST64(0x723A1746B21DC0BC) /* 681 */, + CONST64(0xC7CAA854F5D7CDD3) /* 682 */, CONST64(0x7CAC32883D261D9C) /* 683 */, + CONST64(0x7690C26423BA942C) /* 684 */, CONST64(0x17E55524478042B8) /* 685 */, + CONST64(0xE0BE477656A2389F) /* 686 */, CONST64(0x4D289B5E67AB2DA0) /* 687 */, + CONST64(0x44862B9C8FBBFD31) /* 688 */, CONST64(0xB47CC8049D141365) /* 689 */, + CONST64(0x822C1B362B91C793) /* 690 */, CONST64(0x4EB14655FB13DFD8) /* 691 */, + CONST64(0x1ECBBA0714E2A97B) /* 692 */, CONST64(0x6143459D5CDE5F14) /* 693 */, + CONST64(0x53A8FBF1D5F0AC89) /* 694 */, CONST64(0x97EA04D81C5E5B00) /* 695 */, + CONST64(0x622181A8D4FDB3F3) /* 696 */, CONST64(0xE9BCD341572A1208) /* 697 */, + CONST64(0x1411258643CCE58A) /* 698 */, CONST64(0x9144C5FEA4C6E0A4) /* 699 */, + CONST64(0x0D33D06565CF620F) /* 700 */, CONST64(0x54A48D489F219CA1) /* 701 */, + CONST64(0xC43E5EAC6D63C821) /* 702 */, CONST64(0xA9728B3A72770DAF) /* 703 */, + CONST64(0xD7934E7B20DF87EF) /* 704 */, CONST64(0xE35503B61A3E86E5) /* 705 */, + CONST64(0xCAE321FBC819D504) /* 706 */, CONST64(0x129A50B3AC60BFA6) /* 707 */, + CONST64(0xCD5E68EA7E9FB6C3) /* 708 */, CONST64(0xB01C90199483B1C7) /* 709 */, + CONST64(0x3DE93CD5C295376C) /* 710 */, CONST64(0xAED52EDF2AB9AD13) /* 711 */, + CONST64(0x2E60F512C0A07884) /* 712 */, CONST64(0xBC3D86A3E36210C9) /* 713 */, + CONST64(0x35269D9B163951CE) /* 714 */, CONST64(0x0C7D6E2AD0CDB5FA) /* 715 */, + CONST64(0x59E86297D87F5733) /* 716 */, CONST64(0x298EF221898DB0E7) /* 717 */, + CONST64(0x55000029D1A5AA7E) /* 718 */, CONST64(0x8BC08AE1B5061B45) /* 719 */, + CONST64(0xC2C31C2B6C92703A) /* 720 */, CONST64(0x94CC596BAF25EF42) /* 721 */, + CONST64(0x0A1D73DB22540456) /* 722 */, CONST64(0x04B6A0F9D9C4179A) /* 723 */, + CONST64(0xEFFDAFA2AE3D3C60) /* 724 */, CONST64(0xF7C8075BB49496C4) /* 725 */, + CONST64(0x9CC5C7141D1CD4E3) /* 726 */, CONST64(0x78BD1638218E5534) /* 727 */, + CONST64(0xB2F11568F850246A) /* 728 */, CONST64(0xEDFABCFA9502BC29) /* 729 */, + CONST64(0x796CE5F2DA23051B) /* 730 */, CONST64(0xAAE128B0DC93537C) /* 731 */, + CONST64(0x3A493DA0EE4B29AE) /* 732 */, CONST64(0xB5DF6B2C416895D7) /* 733 */, + CONST64(0xFCABBD25122D7F37) /* 734 */, CONST64(0x70810B58105DC4B1) /* 735 */, + CONST64(0xE10FDD37F7882A90) /* 736 */, CONST64(0x524DCAB5518A3F5C) /* 737 */, + CONST64(0x3C9E85878451255B) /* 738 */, CONST64(0x4029828119BD34E2) /* 739 */, + CONST64(0x74A05B6F5D3CECCB) /* 740 */, CONST64(0xB610021542E13ECA) /* 741 */, + CONST64(0x0FF979D12F59E2AC) /* 742 */, CONST64(0x6037DA27E4F9CC50) /* 743 */, + CONST64(0x5E92975A0DF1847D) /* 744 */, CONST64(0xD66DE190D3E623FE) /* 745 */, + CONST64(0x5032D6B87B568048) /* 746 */, CONST64(0x9A36B7CE8235216E) /* 747 */, + CONST64(0x80272A7A24F64B4A) /* 748 */, CONST64(0x93EFED8B8C6916F7) /* 749 */, + CONST64(0x37DDBFF44CCE1555) /* 750 */, CONST64(0x4B95DB5D4B99BD25) /* 751 */, + CONST64(0x92D3FDA169812FC0) /* 752 */, CONST64(0xFB1A4A9A90660BB6) /* 753 */, + CONST64(0x730C196946A4B9B2) /* 754 */, CONST64(0x81E289AA7F49DA68) /* 755 */, + CONST64(0x64669A0F83B1A05F) /* 756 */, CONST64(0x27B3FF7D9644F48B) /* 757 */, + CONST64(0xCC6B615C8DB675B3) /* 758 */, CONST64(0x674F20B9BCEBBE95) /* 759 */, + CONST64(0x6F31238275655982) /* 760 */, CONST64(0x5AE488713E45CF05) /* 761 */, + CONST64(0xBF619F9954C21157) /* 762 */, CONST64(0xEABAC46040A8EAE9) /* 763 */, + CONST64(0x454C6FE9F2C0C1CD) /* 764 */, CONST64(0x419CF6496412691C) /* 765 */, + CONST64(0xD3DC3BEF265B0F70) /* 766 */, CONST64(0x6D0E60F5C3578A9E) /* 767 */, + CONST64(0x5B0E608526323C55) /* 768 */, CONST64(0x1A46C1A9FA1B59F5) /* 769 */, + CONST64(0xA9E245A17C4C8FFA) /* 770 */, CONST64(0x65CA5159DB2955D7) /* 771 */, + CONST64(0x05DB0A76CE35AFC2) /* 772 */, CONST64(0x81EAC77EA9113D45) /* 773 */, + CONST64(0x528EF88AB6AC0A0D) /* 774 */, CONST64(0xA09EA253597BE3FF) /* 775 */, + CONST64(0x430DDFB3AC48CD56) /* 776 */, CONST64(0xC4B3A67AF45CE46F) /* 777 */, + CONST64(0x4ECECFD8FBE2D05E) /* 778 */, CONST64(0x3EF56F10B39935F0) /* 779 */, + CONST64(0x0B22D6829CD619C6) /* 780 */, CONST64(0x17FD460A74DF2069) /* 781 */, + CONST64(0x6CF8CC8E8510ED40) /* 782 */, CONST64(0xD6C824BF3A6ECAA7) /* 783 */, + CONST64(0x61243D581A817049) /* 784 */, CONST64(0x048BACB6BBC163A2) /* 785 */, + CONST64(0xD9A38AC27D44CC32) /* 786 */, CONST64(0x7FDDFF5BAAF410AB) /* 787 */, + CONST64(0xAD6D495AA804824B) /* 788 */, CONST64(0xE1A6A74F2D8C9F94) /* 789 */, + CONST64(0xD4F7851235DEE8E3) /* 790 */, CONST64(0xFD4B7F886540D893) /* 791 */, + CONST64(0x247C20042AA4BFDA) /* 792 */, CONST64(0x096EA1C517D1327C) /* 793 */, + CONST64(0xD56966B4361A6685) /* 794 */, CONST64(0x277DA5C31221057D) /* 795 */, + CONST64(0x94D59893A43ACFF7) /* 796 */, CONST64(0x64F0C51CCDC02281) /* 797 */, + CONST64(0x3D33BCC4FF6189DB) /* 798 */, CONST64(0xE005CB184CE66AF1) /* 799 */, + CONST64(0xFF5CCD1D1DB99BEA) /* 800 */, CONST64(0xB0B854A7FE42980F) /* 801 */, + CONST64(0x7BD46A6A718D4B9F) /* 802 */, CONST64(0xD10FA8CC22A5FD8C) /* 803 */, + CONST64(0xD31484952BE4BD31) /* 804 */, CONST64(0xC7FA975FCB243847) /* 805 */, + CONST64(0x4886ED1E5846C407) /* 806 */, CONST64(0x28CDDB791EB70B04) /* 807 */, + CONST64(0xC2B00BE2F573417F) /* 808 */, CONST64(0x5C9590452180F877) /* 809 */, + CONST64(0x7A6BDDFFF370EB00) /* 810 */, CONST64(0xCE509E38D6D9D6A4) /* 811 */, + CONST64(0xEBEB0F00647FA702) /* 812 */, CONST64(0x1DCC06CF76606F06) /* 813 */, + CONST64(0xE4D9F28BA286FF0A) /* 814 */, CONST64(0xD85A305DC918C262) /* 815 */, + CONST64(0x475B1D8732225F54) /* 816 */, CONST64(0x2D4FB51668CCB5FE) /* 817 */, + CONST64(0xA679B9D9D72BBA20) /* 818 */, CONST64(0x53841C0D912D43A5) /* 819 */, + CONST64(0x3B7EAA48BF12A4E8) /* 820 */, CONST64(0x781E0E47F22F1DDF) /* 821 */, + CONST64(0xEFF20CE60AB50973) /* 822 */, CONST64(0x20D261D19DFFB742) /* 823 */, + CONST64(0x16A12B03062A2E39) /* 824 */, CONST64(0x1960EB2239650495) /* 825 */, + CONST64(0x251C16FED50EB8B8) /* 826 */, CONST64(0x9AC0C330F826016E) /* 827 */, + CONST64(0xED152665953E7671) /* 828 */, CONST64(0x02D63194A6369570) /* 829 */, + CONST64(0x5074F08394B1C987) /* 830 */, CONST64(0x70BA598C90B25CE1) /* 831 */, + CONST64(0x794A15810B9742F6) /* 832 */, CONST64(0x0D5925E9FCAF8C6C) /* 833 */, + CONST64(0x3067716CD868744E) /* 834 */, CONST64(0x910AB077E8D7731B) /* 835 */, + CONST64(0x6A61BBDB5AC42F61) /* 836 */, CONST64(0x93513EFBF0851567) /* 837 */, + CONST64(0xF494724B9E83E9D5) /* 838 */, CONST64(0xE887E1985C09648D) /* 839 */, + CONST64(0x34B1D3C675370CFD) /* 840 */, CONST64(0xDC35E433BC0D255D) /* 841 */, + CONST64(0xD0AAB84234131BE0) /* 842 */, CONST64(0x08042A50B48B7EAF) /* 843 */, + CONST64(0x9997C4EE44A3AB35) /* 844 */, CONST64(0x829A7B49201799D0) /* 845 */, + CONST64(0x263B8307B7C54441) /* 846 */, CONST64(0x752F95F4FD6A6CA6) /* 847 */, + CONST64(0x927217402C08C6E5) /* 848 */, CONST64(0x2A8AB754A795D9EE) /* 849 */, + CONST64(0xA442F7552F72943D) /* 850 */, CONST64(0x2C31334E19781208) /* 851 */, + CONST64(0x4FA98D7CEAEE6291) /* 852 */, CONST64(0x55C3862F665DB309) /* 853 */, + CONST64(0xBD0610175D53B1F3) /* 854 */, CONST64(0x46FE6CB840413F27) /* 855 */, + CONST64(0x3FE03792DF0CFA59) /* 856 */, CONST64(0xCFE700372EB85E8F) /* 857 */, + CONST64(0xA7BE29E7ADBCE118) /* 858 */, CONST64(0xE544EE5CDE8431DD) /* 859 */, + CONST64(0x8A781B1B41F1873E) /* 860 */, CONST64(0xA5C94C78A0D2F0E7) /* 861 */, + CONST64(0x39412E2877B60728) /* 862 */, CONST64(0xA1265EF3AFC9A62C) /* 863 */, + CONST64(0xBCC2770C6A2506C5) /* 864 */, CONST64(0x3AB66DD5DCE1CE12) /* 865 */, + CONST64(0xE65499D04A675B37) /* 866 */, CONST64(0x7D8F523481BFD216) /* 867 */, + CONST64(0x0F6F64FCEC15F389) /* 868 */, CONST64(0x74EFBE618B5B13C8) /* 869 */, + CONST64(0xACDC82B714273E1D) /* 870 */, CONST64(0xDD40BFE003199D17) /* 871 */, + CONST64(0x37E99257E7E061F8) /* 872 */, CONST64(0xFA52626904775AAA) /* 873 */, + CONST64(0x8BBBF63A463D56F9) /* 874 */, CONST64(0xF0013F1543A26E64) /* 875 */, + CONST64(0xA8307E9F879EC898) /* 876 */, CONST64(0xCC4C27A4150177CC) /* 877 */, + CONST64(0x1B432F2CCA1D3348) /* 878 */, CONST64(0xDE1D1F8F9F6FA013) /* 879 */, + CONST64(0x606602A047A7DDD6) /* 880 */, CONST64(0xD237AB64CC1CB2C7) /* 881 */, + CONST64(0x9B938E7225FCD1D3) /* 882 */, CONST64(0xEC4E03708E0FF476) /* 883 */, + CONST64(0xFEB2FBDA3D03C12D) /* 884 */, CONST64(0xAE0BCED2EE43889A) /* 885 */, + CONST64(0x22CB8923EBFB4F43) /* 886 */, CONST64(0x69360D013CF7396D) /* 887 */, + CONST64(0x855E3602D2D4E022) /* 888 */, CONST64(0x073805BAD01F784C) /* 889 */, + CONST64(0x33E17A133852F546) /* 890 */, CONST64(0xDF4874058AC7B638) /* 891 */, + CONST64(0xBA92B29C678AA14A) /* 892 */, CONST64(0x0CE89FC76CFAADCD) /* 893 */, + CONST64(0x5F9D4E0908339E34) /* 894 */, CONST64(0xF1AFE9291F5923B9) /* 895 */, + CONST64(0x6E3480F60F4A265F) /* 896 */, CONST64(0xEEBF3A2AB29B841C) /* 897 */, + CONST64(0xE21938A88F91B4AD) /* 898 */, CONST64(0x57DFEFF845C6D3C3) /* 899 */, + CONST64(0x2F006B0BF62CAAF2) /* 900 */, CONST64(0x62F479EF6F75EE78) /* 901 */, + CONST64(0x11A55AD41C8916A9) /* 902 */, CONST64(0xF229D29084FED453) /* 903 */, + CONST64(0x42F1C27B16B000E6) /* 904 */, CONST64(0x2B1F76749823C074) /* 905 */, + CONST64(0x4B76ECA3C2745360) /* 906 */, CONST64(0x8C98F463B91691BD) /* 907 */, + CONST64(0x14BCC93CF1ADE66A) /* 908 */, CONST64(0x8885213E6D458397) /* 909 */, + CONST64(0x8E177DF0274D4711) /* 910 */, CONST64(0xB49B73B5503F2951) /* 911 */, + CONST64(0x10168168C3F96B6B) /* 912 */, CONST64(0x0E3D963B63CAB0AE) /* 913 */, + CONST64(0x8DFC4B5655A1DB14) /* 914 */, CONST64(0xF789F1356E14DE5C) /* 915 */, + CONST64(0x683E68AF4E51DAC1) /* 916 */, CONST64(0xC9A84F9D8D4B0FD9) /* 917 */, + CONST64(0x3691E03F52A0F9D1) /* 918 */, CONST64(0x5ED86E46E1878E80) /* 919 */, + CONST64(0x3C711A0E99D07150) /* 920 */, CONST64(0x5A0865B20C4E9310) /* 921 */, + CONST64(0x56FBFC1FE4F0682E) /* 922 */, CONST64(0xEA8D5DE3105EDF9B) /* 923 */, + CONST64(0x71ABFDB12379187A) /* 924 */, CONST64(0x2EB99DE1BEE77B9C) /* 925 */, + CONST64(0x21ECC0EA33CF4523) /* 926 */, CONST64(0x59A4D7521805C7A1) /* 927 */, + CONST64(0x3896F5EB56AE7C72) /* 928 */, CONST64(0xAA638F3DB18F75DC) /* 929 */, + CONST64(0x9F39358DABE9808E) /* 930 */, CONST64(0xB7DEFA91C00B72AC) /* 931 */, + CONST64(0x6B5541FD62492D92) /* 932 */, CONST64(0x6DC6DEE8F92E4D5B) /* 933 */, + CONST64(0x353F57ABC4BEEA7E) /* 934 */, CONST64(0x735769D6DA5690CE) /* 935 */, + CONST64(0x0A234AA642391484) /* 936 */, CONST64(0xF6F9508028F80D9D) /* 937 */, + CONST64(0xB8E319A27AB3F215) /* 938 */, CONST64(0x31AD9C1151341A4D) /* 939 */, + CONST64(0x773C22A57BEF5805) /* 940 */, CONST64(0x45C7561A07968633) /* 941 */, + CONST64(0xF913DA9E249DBE36) /* 942 */, CONST64(0xDA652D9B78A64C68) /* 943 */, + CONST64(0x4C27A97F3BC334EF) /* 944 */, CONST64(0x76621220E66B17F4) /* 945 */, + CONST64(0x967743899ACD7D0B) /* 946 */, CONST64(0xF3EE5BCAE0ED6782) /* 947 */, + CONST64(0x409F753600C879FC) /* 948 */, CONST64(0x06D09A39B5926DB6) /* 949 */, + CONST64(0x6F83AEB0317AC588) /* 950 */, CONST64(0x01E6CA4A86381F21) /* 951 */, + CONST64(0x66FF3462D19F3025) /* 952 */, CONST64(0x72207C24DDFD3BFB) /* 953 */, + CONST64(0x4AF6B6D3E2ECE2EB) /* 954 */, CONST64(0x9C994DBEC7EA08DE) /* 955 */, + CONST64(0x49ACE597B09A8BC4) /* 956 */, CONST64(0xB38C4766CF0797BA) /* 957 */, + CONST64(0x131B9373C57C2A75) /* 958 */, CONST64(0xB1822CCE61931E58) /* 959 */, + CONST64(0x9D7555B909BA1C0C) /* 960 */, CONST64(0x127FAFDD937D11D2) /* 961 */, + CONST64(0x29DA3BADC66D92E4) /* 962 */, CONST64(0xA2C1D57154C2ECBC) /* 963 */, + CONST64(0x58C5134D82F6FE24) /* 964 */, CONST64(0x1C3AE3515B62274F) /* 965 */, + CONST64(0xE907C82E01CB8126) /* 966 */, CONST64(0xF8ED091913E37FCB) /* 967 */, + CONST64(0x3249D8F9C80046C9) /* 968 */, CONST64(0x80CF9BEDE388FB63) /* 969 */, + CONST64(0x1881539A116CF19E) /* 970 */, CONST64(0x5103F3F76BD52457) /* 971 */, + CONST64(0x15B7E6F5AE47F7A8) /* 972 */, CONST64(0xDBD7C6DED47E9CCF) /* 973 */, + CONST64(0x44E55C410228BB1A) /* 974 */, CONST64(0xB647D4255EDB4E99) /* 975 */, + CONST64(0x5D11882BB8AAFC30) /* 976 */, CONST64(0xF5098BBB29D3212A) /* 977 */, + CONST64(0x8FB5EA14E90296B3) /* 978 */, CONST64(0x677B942157DD025A) /* 979 */, + CONST64(0xFB58E7C0A390ACB5) /* 980 */, CONST64(0x89D3674C83BD4A01) /* 981 */, + CONST64(0x9E2DA4DF4BF3B93B) /* 982 */, CONST64(0xFCC41E328CAB4829) /* 983 */, + CONST64(0x03F38C96BA582C52) /* 984 */, CONST64(0xCAD1BDBD7FD85DB2) /* 985 */, + CONST64(0xBBB442C16082AE83) /* 986 */, CONST64(0xB95FE86BA5DA9AB0) /* 987 */, + CONST64(0xB22E04673771A93F) /* 988 */, CONST64(0x845358C9493152D8) /* 989 */, + CONST64(0xBE2A488697B4541E) /* 990 */, CONST64(0x95A2DC2DD38E6966) /* 991 */, + CONST64(0xC02C11AC923C852B) /* 992 */, CONST64(0x2388B1990DF2A87B) /* 993 */, + CONST64(0x7C8008FA1B4F37BE) /* 994 */, CONST64(0x1F70D0C84D54E503) /* 995 */, + CONST64(0x5490ADEC7ECE57D4) /* 996 */, CONST64(0x002B3C27D9063A3A) /* 997 */, + CONST64(0x7EAEA3848030A2BF) /* 998 */, CONST64(0xC602326DED2003C0) /* 999 */, + CONST64(0x83A7287D69A94086) /* 1000 */, CONST64(0xC57A5FCB30F57A8A) /* 1001 */, + CONST64(0xB56844E479EBE779) /* 1002 */, CONST64(0xA373B40F05DCBCE9) /* 1003 */, + CONST64(0xD71A786E88570EE2) /* 1004 */, CONST64(0x879CBACDBDE8F6A0) /* 1005 */, + CONST64(0x976AD1BCC164A32F) /* 1006 */, CONST64(0xAB21E25E9666D78B) /* 1007 */, + CONST64(0x901063AAE5E5C33C) /* 1008 */, CONST64(0x9818B34448698D90) /* 1009 */, + CONST64(0xE36487AE3E1E8ABB) /* 1010 */, CONST64(0xAFBDF931893BDCB4) /* 1011 */, + CONST64(0x6345A0DC5FBBD519) /* 1012 */, CONST64(0x8628FE269B9465CA) /* 1013 */, + CONST64(0x1E5D01603F9C51EC) /* 1014 */, CONST64(0x4DE44006A15049B7) /* 1015 */, + CONST64(0xBF6C70E5F776CBB1) /* 1016 */, CONST64(0x411218F2EF552BED) /* 1017 */, + CONST64(0xCB0C0708705A36A3) /* 1018 */, CONST64(0xE74D14754F986044) /* 1019 */, + CONST64(0xCD56D9430EA8280E) /* 1020 */, CONST64(0xC12591D7535F5065) /* 1021 */, + CONST64(0xC83223F1720AEF96) /* 1022 */, CONST64(0xC3A0396F7363A51F) /* 1023 */}; + +/* one round of the hash function */ +static void round(ulong64 *a, ulong64 *b, ulong64 *c, ulong64 x, ulong64 mul) +{ + *c ^= x; + *a -= t1[(*c)&255] ^ t2[((*c)>>16)&255] ^ t3[((*c)>>32)&255] ^ t4[((*c)>>48)&255]; + *b += t4[((*c)>>8)&255] ^ t3[((*c)>>24)&255] ^ t2[((*c)>>40)&255] ^ t1[((*c)>>56)&255]; + *b *= mul; +} + +/* one complete pass */ +static void pass(ulong64 *a, ulong64 *b, ulong64 *c, ulong64 *x, ulong64 mul) +{ + round(a,b,c,x[0],mul); + round(b,c,a,x[1],mul); + round(c,a,b,x[2],mul); + round(a,b,c,x[3],mul); + round(b,c,a,x[4],mul); + round(c,a,b,x[5],mul); + round(a,b,c,x[6],mul); + round(b,c,a,x[7],mul); +} + +/* The key mixing schedule */ +static void key_schedule(ulong64 *x) { + x[0] -= x[7] ^ CONST64(0xA5A5A5A5A5A5A5A5); + x[1] ^= x[0]; + x[2] += x[1]; + x[3] -= x[2] ^ ((~x[1])<<19); + x[4] ^= x[3]; + x[5] += x[4]; + x[6] -= x[5] ^ ((~x[4])>>23); + x[7] ^= x[6]; + x[0] += x[7]; + x[1] -= x[0] ^ ((~x[7])<<19); + x[2] ^= x[1]; + x[3] += x[2]; + x[4] -= x[3] ^ ((~x[2])>>23); + x[5] ^= x[4]; + x[6] += x[5]; + x[7] -= x[6] ^ CONST64(0x0123456789ABCDEF); +} + +#ifdef CLEAN_STACK +static void _tiger_compress(hash_state *md) +#else +static void tiger_compress(hash_state *md) +#endif +{ + ulong64 a, b, c, x[8]; + unsigned long i; + + _ARGCHK(md != NULL); + + /* load words */ + for (i = 0; i < 8; i++) { + LOAD64L(x[i],&md->tiger.buf[8*i]); + } + a = md->tiger.state[0]; + b = md->tiger.state[1]; + c = md->tiger.state[2]; + + pass(&a,&b,&c,x,5); + key_schedule(x); + pass(&c,&a,&b,x,7); + key_schedule(x); + pass(&b,&c,&a,x,9); + + /* store state */ + md->tiger.state[0] = a ^ md->tiger.state[0]; + md->tiger.state[1] = b - md->tiger.state[1]; + md->tiger.state[2] = c + md->tiger.state[2]; +} + +#ifdef CLEAN_STACK +static void tiger_compress(hash_state *md) +{ + _tiger_compress(md); + burn_stack(sizeof(ulong64) * 11 + sizeof(unsigned long)); +} +#endif + +void tiger_init(hash_state *md) +{ + _ARGCHK(md != NULL); + md->tiger.state[0] = CONST64(0x0123456789ABCDEF); + md->tiger.state[1] = CONST64(0xFEDCBA9876543210); + md->tiger.state[2] = CONST64(0xF096A5B4C3B2E187); + md->tiger.curlen = 0; + md->tiger.length = 0; +} + +void tiger_process(hash_state * md, const unsigned char *buf, unsigned long len) +{ + unsigned long n; + _ARGCHK(md != NULL); + _ARGCHK(buf != NULL); + while (len) { + n = MIN(len, (64 - md->tiger.curlen)); + memcpy(md->tiger.buf + md->tiger.curlen, buf, n); + md->tiger.curlen += n; + buf += n; + len -= n; + + /* is 64 bytes full? */ + if (md->tiger.curlen == 64) { + tiger_compress(md); + md->tiger.length += 512; /* add the number of bits not bytes */ + md->tiger.curlen = 0; + } + } +} + +void tiger_done(hash_state * md, unsigned char *hash) +{ + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + /* increase the length of the message */ + md->tiger.length += md->tiger.curlen * 8; + + /* append the '1' bit */ + md->tiger.buf[md->tiger.curlen++] = 0x01; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. */ + if (md->tiger.curlen > 56) { + while (md->tiger.curlen < 64) { + md->tiger.buf[md->tiger.curlen++] = 0; + } + tiger_compress(md); + md->tiger.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->tiger.curlen < 56) { + md->tiger.buf[md->tiger.curlen++] = 0; + } + + /* store length */ + STORE64L(md->tiger.length, md->tiger.buf+56); + tiger_compress(md); + + /* copy output */ + STORE64L(md->tiger.state[0], &hash[0]); + STORE64L(md->tiger.state[1], &hash[8]); + STORE64L(md->tiger.state[2], &hash[16]); +#ifdef CLEAN_STACK + zeromem(md, sizeof(hash_state)); +#endif +} + +int tiger_test(void) +{ + static const struct { + unsigned char *msg; + unsigned char hash[24]; + } tests[] = { + { "", + { 0x32, 0x93, 0xac, 0x63, 0x0c, 0x13, 0xf0, 0x24, + 0x5f, 0x92, 0xbb, 0xb1, 0x76, 0x6e, 0x16, 0x16, + 0x7a, 0x4e, 0x58, 0x49, 0x2d, 0xde, 0x73, 0xf3 } + }, + { "abc", + { 0x2a, 0xab, 0x14, 0x84, 0xe8, 0xc1, 0x58, 0xf2, + 0xbf, 0xb8, 0xc5, 0xff, 0x41, 0xb5, 0x7a, 0x52, + 0x51, 0x29, 0x13, 0x1c, 0x95, 0x7b, 0x5f, 0x93 } + }, + { "Tiger", + { 0xdd, 0x00, 0x23, 0x07, 0x99, 0xf5, 0x00, 0x9f, + 0xec, 0x6d, 0xeb, 0xc8, 0x38, 0xbb, 0x6a, 0x27, + 0xdf, 0x2b, 0x9d, 0x6f, 0x11, 0x0c, 0x79, 0x37 } + }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", + { 0xf7, 0x1c, 0x85, 0x83, 0x90, 0x2a, 0xfb, 0x87, + 0x9e, 0xdf, 0xe6, 0x10, 0xf8, 0x2c, 0x0d, 0x47, + 0x86, 0xa3, 0xa5, 0x34, 0x50, 0x44, 0x86, 0xb5 } + }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", + { 0xc5, 0x40, 0x34, 0xe5, 0xb4, 0x3e, 0xb8, 0x00, + 0x58, 0x48, 0xa7, 0xe0, 0xae, 0x6a, 0xac, 0x76, + 0xe4, 0xff, 0x59, 0x0a, 0xe7, 0x15, 0xfd, 0x25 } + }, + { NULL, { 0 }} + }; + + int failed, i; + unsigned char tmp[24]; + hash_state md; + + for (failed = i = 0; tests[i].msg != NULL; i++) { + tiger_init(&md); + tiger_process(&md, tests[i].msg, strlen(tests[i].msg)); + tiger_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 24)) { +#if 0 + int j; + printf("\nTIGER-192 Test %d failed\nGot (as a result): ", i); + for (j = 0; j < 24; j++) { + printf("%02x ", tmp[j]); + } + printf("\n"); +#endif + failed = 1; + } + } + if (failed == 1) { + return CRYPT_FAIL_TESTVECTOR; + } else { + return CRYPT_OK; + } +} + +#endif + +/* +Hash of "": + 24F0130C63AC9332 16166E76B1BB925F F373DE2D49584E7A +Hash of "abc": + F258C1E88414AB2A 527AB541FFC5B8BF 935F7B951C132951 +Hash of "Tiger": + 9F00F599072300DD 276ABB38C8EB6DEC 37790C116F9D2BDF +Hash of "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-": + 87FB2A9083851CF7 470D2CF810E6DF9E B586445034A5A386 +Hash of "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789": + 467DB80863EBCE48 8DF1CD1261655DE9 57896565975F9197 +Hash of "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham": + 0C410A042968868A 1671DA5A3FD29A72 5EC1E457D3CDB303 +Hash of "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge.": + EBF591D5AFA655CE 7F22894FF87F54AC 89C811B6B0DA3193 +Hash of "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge, 1996.": + 3D9AEB03D1BD1A63 57B2774DFD6D5B24 DD68151D503974FC +Hash of "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-": + 00B83EB4E53440C5 76AC6AAEE0A74858 25FD15E70A59FFE4 +*/ + + + diff --git a/twofish.c b/twofish.c new file mode 100644 index 0000000..b057c6e --- /dev/null +++ b/twofish.c @@ -0,0 +1,727 @@ +/* Implementation of Twofish by Tom St Denis */ +#include "mycrypt.h" + +#ifdef TWOFISH + +const struct _cipher_descriptor twofish_desc = +{ + "twofish", + 7, + 16, 32, 16, 16, + &twofish_setup, + &twofish_ecb_encrypt, + &twofish_ecb_decrypt, + &twofish_test, + &twofish_keysize +}; + +/* the two polynomials */ +#define MDS_POLY 0x169 +#define RS_POLY 0x14D + +/* The 4x4 MDS Linear Transform */ +static const unsigned char MDS[4][4] = { + { 0x01, 0xEF, 0x5B, 0x5B }, + { 0x5B, 0xEF, 0xEF, 0x01 }, + { 0xEF, 0x5B, 0x01, 0xEF }, + { 0xEF, 0x01, 0xEF, 0x5B } +}; + +/* The 4x8 RS Linear Transform */ +static const unsigned char RS[4][8] = { + { 0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E }, + { 0xA4, 0x56, 0x82, 0xF3, 0X1E, 0XC6, 0X68, 0XE5 }, + { 0X02, 0XA1, 0XFC, 0XC1, 0X47, 0XAE, 0X3D, 0X19 }, + { 0XA4, 0X55, 0X87, 0X5A, 0X58, 0XDB, 0X9E, 0X03 } +}; + +/* sbox usage orderings */ +static const unsigned char qord[4][5] = { + { 1, 1, 0, 0, 1 }, + { 0, 1, 1, 0, 0 }, + { 0, 0, 0, 1, 1 }, + { 1, 0, 1, 1, 0 } +}; + +#ifdef TWOFISH_TABLES +static const unsigned char SBOX[2][256] = { +{ + 0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92, + 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38, 0x0d, 0xc6, 0x35, 0x98, + 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13, + 0x94, 0x48, 0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23, + 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82, 0x63, 0x01, + 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe, + 0x16, 0x0c, 0xe3, 0x61, 0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c, + 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1, + 0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95, + 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7, 0xfb, 0xc3, 0x8e, 0xb5, + 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9, + 0x62, 0x71, 0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8, + 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7, 0xa1, 0x1d, + 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11, + 0x31, 0xc2, 0x27, 0x90, 0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c, + 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef, + 0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87, + 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64, 0x2a, 0xce, 0xcb, 0x2f, + 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e, + 0xa7, 0x5a, 0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02, + 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d, 0x57, 0xc7, + 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12, + 0x58, 0x07, 0x99, 0x34, 0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc, + 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4, + 0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d, + 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0}, +{ + 0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3, + 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b, 0xd6, 0x32, 0xd8, 0xfd, + 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa, + 0x06, 0x3f, 0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d, + 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5, 0xa0, 0x84, + 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54, + 0x92, 0x74, 0x36, 0x51, 0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60, + 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c, + 0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3, + 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8, 0xa6, 0x83, 0x20, 0xff, + 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7, + 0x2b, 0xe2, 0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9, + 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17, 0x66, 0x94, + 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c, + 0xef, 0xd1, 0x53, 0x3e, 0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76, + 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9, + 0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23, + 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48, 0x4f, 0xf2, 0x65, 0x8e, + 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f, + 0x05, 0x64, 0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5, + 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69, 0x29, 0x2e, + 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34, + 0x35, 0x6a, 0xcf, 0xdc, 0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4, + 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9, + 0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25, + 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91} +}; + +static const unsigned char GF_EF[256] = { + 0x00, 0xef, 0xb7, 0x58, 0x07, 0xe8, 0xb0, 0x5f, 0x0e, 0xe1, + 0xb9, 0x56, 0x09, 0xe6, 0xbe, 0x51, 0x1c, 0xf3, 0xab, 0x44, + 0x1b, 0xf4, 0xac, 0x43, 0x12, 0xfd, 0xa5, 0x4a, 0x15, 0xfa, + 0xa2, 0x4d, 0x38, 0xd7, 0x8f, 0x60, 0x3f, 0xd0, 0x88, 0x67, + 0x36, 0xd9, 0x81, 0x6e, 0x31, 0xde, 0x86, 0x69, 0x24, 0xcb, + 0x93, 0x7c, 0x23, 0xcc, 0x94, 0x7b, 0x2a, 0xc5, 0x9d, 0x72, + 0x2d, 0xc2, 0x9a, 0x75, 0x70, 0x9f, 0xc7, 0x28, 0x77, 0x98, + 0xc0, 0x2f, 0x7e, 0x91, 0xc9, 0x26, 0x79, 0x96, 0xce, 0x21, + 0x6c, 0x83, 0xdb, 0x34, 0x6b, 0x84, 0xdc, 0x33, 0x62, 0x8d, + 0xd5, 0x3a, 0x65, 0x8a, 0xd2, 0x3d, 0x48, 0xa7, 0xff, 0x10, + 0x4f, 0xa0, 0xf8, 0x17, 0x46, 0xa9, 0xf1, 0x1e, 0x41, 0xae, + 0xf6, 0x19, 0x54, 0xbb, 0xe3, 0x0c, 0x53, 0xbc, 0xe4, 0x0b, + 0x5a, 0xb5, 0xed, 0x02, 0x5d, 0xb2, 0xea, 0x05, 0xe0, 0x0f, + 0x57, 0xb8, 0xe7, 0x08, 0x50, 0xbf, 0xee, 0x01, 0x59, 0xb6, + 0xe9, 0x06, 0x5e, 0xb1, 0xfc, 0x13, 0x4b, 0xa4, 0xfb, 0x14, + 0x4c, 0xa3, 0xf2, 0x1d, 0x45, 0xaa, 0xf5, 0x1a, 0x42, 0xad, + 0xd8, 0x37, 0x6f, 0x80, 0xdf, 0x30, 0x68, 0x87, 0xd6, 0x39, + 0x61, 0x8e, 0xd1, 0x3e, 0x66, 0x89, 0xc4, 0x2b, 0x73, 0x9c, + 0xc3, 0x2c, 0x74, 0x9b, 0xca, 0x25, 0x7d, 0x92, 0xcd, 0x22, + 0x7a, 0x95, 0x90, 0x7f, 0x27, 0xc8, 0x97, 0x78, 0x20, 0xcf, + 0x9e, 0x71, 0x29, 0xc6, 0x99, 0x76, 0x2e, 0xc1, 0x8c, 0x63, + 0x3b, 0xd4, 0x8b, 0x64, 0x3c, 0xd3, 0x82, 0x6d, 0x35, 0xda, + 0x85, 0x6a, 0x32, 0xdd, 0xa8, 0x47, 0x1f, 0xf0, 0xaf, 0x40, + 0x18, 0xf7, 0xa6, 0x49, 0x11, 0xfe, 0xa1, 0x4e, 0x16, 0xf9, + 0xb4, 0x5b, 0x03, 0xec, 0xb3, 0x5c, 0x04, 0xeb, 0xba, 0x55, + 0x0d, 0xe2, 0xbd, 0x52, 0x0a, 0xe5}; + +static const unsigned char GF_5B[256] = { + 0x00, 0x5b, 0xb6, 0xed, 0x05, 0x5e, 0xb3, 0xe8, 0x0a, 0x51, + 0xbc, 0xe7, 0x0f, 0x54, 0xb9, 0xe2, 0x14, 0x4f, 0xa2, 0xf9, + 0x11, 0x4a, 0xa7, 0xfc, 0x1e, 0x45, 0xa8, 0xf3, 0x1b, 0x40, + 0xad, 0xf6, 0x28, 0x73, 0x9e, 0xc5, 0x2d, 0x76, 0x9b, 0xc0, + 0x22, 0x79, 0x94, 0xcf, 0x27, 0x7c, 0x91, 0xca, 0x3c, 0x67, + 0x8a, 0xd1, 0x39, 0x62, 0x8f, 0xd4, 0x36, 0x6d, 0x80, 0xdb, + 0x33, 0x68, 0x85, 0xde, 0x50, 0x0b, 0xe6, 0xbd, 0x55, 0x0e, + 0xe3, 0xb8, 0x5a, 0x01, 0xec, 0xb7, 0x5f, 0x04, 0xe9, 0xb2, + 0x44, 0x1f, 0xf2, 0xa9, 0x41, 0x1a, 0xf7, 0xac, 0x4e, 0x15, + 0xf8, 0xa3, 0x4b, 0x10, 0xfd, 0xa6, 0x78, 0x23, 0xce, 0x95, + 0x7d, 0x26, 0xcb, 0x90, 0x72, 0x29, 0xc4, 0x9f, 0x77, 0x2c, + 0xc1, 0x9a, 0x6c, 0x37, 0xda, 0x81, 0x69, 0x32, 0xdf, 0x84, + 0x66, 0x3d, 0xd0, 0x8b, 0x63, 0x38, 0xd5, 0x8e, 0xa0, 0xfb, + 0x16, 0x4d, 0xa5, 0xfe, 0x13, 0x48, 0xaa, 0xf1, 0x1c, 0x47, + 0xaf, 0xf4, 0x19, 0x42, 0xb4, 0xef, 0x02, 0x59, 0xb1, 0xea, + 0x07, 0x5c, 0xbe, 0xe5, 0x08, 0x53, 0xbb, 0xe0, 0x0d, 0x56, + 0x88, 0xd3, 0x3e, 0x65, 0x8d, 0xd6, 0x3b, 0x60, 0x82, 0xd9, + 0x34, 0x6f, 0x87, 0xdc, 0x31, 0x6a, 0x9c, 0xc7, 0x2a, 0x71, + 0x99, 0xc2, 0x2f, 0x74, 0x96, 0xcd, 0x20, 0x7b, 0x93, 0xc8, + 0x25, 0x7e, 0xf0, 0xab, 0x46, 0x1d, 0xf5, 0xae, 0x43, 0x18, + 0xfa, 0xa1, 0x4c, 0x17, 0xff, 0xa4, 0x49, 0x12, 0xe4, 0xbf, + 0x52, 0x09, 0xe1, 0xba, 0x57, 0x0c, 0xee, 0xb5, 0x58, 0x03, + 0xeb, 0xb0, 0x5d, 0x06, 0xd8, 0x83, 0x6e, 0x35, 0xdd, 0x86, + 0x6b, 0x30, 0xd2, 0x89, 0x64, 0x3f, 0xd7, 0x8c, 0x61, 0x3a, + 0xcc, 0x97, 0x7a, 0x21, 0xc9, 0x92, 0x7f, 0x24, 0xc6, 0x9d, + 0x70, 0x2b, 0xc3, 0x98, 0x75, 0x2e}; + +#define sbox(i, x) ((unsigned long)SBOX[i][(x)&255]) + +#else + +/* The Q-box tables */ +static const unsigned char qbox[2][4][16] = { +{ + { 0x8, 0x1, 0x7, 0xD, 0x6, 0xF, 0x3, 0x2, 0x0, 0xB, 0x5, 0x9, 0xE, 0xC, 0xA, 0x4 }, + { 0xE, 0XC, 0XB, 0X8, 0X1, 0X2, 0X3, 0X5, 0XF, 0X4, 0XA, 0X6, 0X7, 0X0, 0X9, 0XD }, + { 0XB, 0XA, 0X5, 0XE, 0X6, 0XD, 0X9, 0X0, 0XC, 0X8, 0XF, 0X3, 0X2, 0X4, 0X7, 0X1 }, + { 0XD, 0X7, 0XF, 0X4, 0X1, 0X2, 0X6, 0XE, 0X9, 0XB, 0X3, 0X0, 0X8, 0X5, 0XC, 0XA } +}, +{ + { 0X2, 0X8, 0XB, 0XD, 0XF, 0X7, 0X6, 0XE, 0X3, 0X1, 0X9, 0X4, 0X0, 0XA, 0XC, 0X5 }, + { 0X1, 0XE, 0X2, 0XB, 0X4, 0XC, 0X3, 0X7, 0X6, 0XD, 0XA, 0X5, 0XF, 0X9, 0X0, 0X8 }, + { 0X4, 0XC, 0X7, 0X5, 0X1, 0X6, 0X9, 0XA, 0X0, 0XE, 0XD, 0X8, 0X2, 0XB, 0X3, 0XF }, + { 0xB, 0X9, 0X5, 0X1, 0XC, 0X3, 0XD, 0XE, 0X6, 0X4, 0X7, 0XF, 0X2, 0X0, 0X8, 0XA } +} +}; + +/* computes S_i[x] */ +#ifdef CLEAN_STACK +static unsigned long _sbox(int i, unsigned long x) +#else +unsigned long sbox(int i, unsigned long x) +#endif +{ + unsigned char a0,b0,a1,b1,a2,b2,a3,b3,a4,b4,y; + + /* a0,b0 = [x/16], x mod 16 */ + a0 = (x>>4)&15; + b0 = (x)&15; + + /* a1 = a0 ^ b0 */ + a1 = a0 ^ b0; + + /* b1 = a0 ^ ROR(b0, 1) ^ 8a0 */ + b1 = (a0 ^ ((b0<<3)|(b0>>1)) ^ (a0<<3)) & 15; + + /* a2,b2 = t0[a1], t1[b1] */ + a2 = qbox[i][0][a1]; + b2 = qbox[i][1][b1]; + + /* a3 = a2 ^ b2 */ + a3 = a2 ^ b2; + + /* b3 = a2 ^ ROR(b2, 1) ^ 8a2 */ + b3 = (a2 ^ ((b2<<3)|(b2>>1)) ^ (a2<<3)) & 15; + + /* a4,b4 = t2[a3], t3[b3] */ + a4 = qbox[i][2][a3]; + b4 = qbox[i][3][b3]; + + /* y = 16b4 + a4 */ + y = (b4 << 4) + a4; + + /* return result */ + return (unsigned long)y; +} + +#ifdef CLEAN_STACK +static unsigned long sbox(int i, unsigned long x) +{ + unsigned long y; + y = _sbox(i, x); + burn_stack(sizeof(unsigned char) * 11); + return y; +} +#endif + +#endif + +/* computes ab mod p */ +static unsigned long gf_mult(unsigned long a, unsigned long b, unsigned long p) +{ + unsigned long result = 0; + while (a) { + if (a&1) + result ^= b; + a >>= 1; + b <<= 1; + if (b & 0x100) + b ^= p; + } + return result & 255; +} + + +/* Computes [y0 y1 y2 y3] = MDS . [x0 x1 x2 x3] */ +static void mds_mult(const unsigned char *in, unsigned char *out) +{ + int x, y; + unsigned char tmp[4]; + + for (x = 0; x < 4; x++) { + tmp[x] = 0; + for (y = 0; y < 4; y++) + tmp[x] ^= gf_mult(in[y], MDS[x][y], MDS_POLY); + } + for (x = 0; x < 4; x++) + out[x] = tmp[x]; + zeromem(tmp, 4); +} + +/* computes [y0 y1 y2 y3] = RS . [x0 x1 x2 x3 x4 x5 x6 x7] */ +static void rs_mult(const unsigned char *in, unsigned char *out) +{ + int x, y; + unsigned char tmp[4]; + + for (x = 0; x < 4; x++) { + tmp[x] = 0; + for (y = 0; y < 8; y++) + tmp[x] ^= gf_mult(in[y], RS[x][y], RS_POLY); + } + for (x = 0; x < 4; x++) + out[x] = tmp[x]; + zeromem(tmp, 4); +} + +/* computes [y0 y1 y2 y3] = MDS . [x0] */ +#ifndef TWOFISH_TABLES +static unsigned long mds_column_mult(unsigned char in, int col) +{ + return + (gf_mult(in, MDS[0][col], MDS_POLY) << 0) | + (gf_mult(in, MDS[1][col], MDS_POLY) << 8) | + (gf_mult(in, MDS[2][col], MDS_POLY) << 16) | + (gf_mult(in, MDS[3][col], MDS_POLY) << 24); +} +#else +static unsigned long mds_column_mult(unsigned char in, int col) +{ + unsigned long x01, x5B, xEF; + + x01 = in; + x5B = GF_5B[in]; + xEF = GF_EF[in]; + + switch (col) { + case 0: + return (x01 << 0 ) | + (x5B << 8 ) | + (xEF << 16) | + (xEF << 24); + case 1: + return (xEF << 0 ) | + (xEF << 8 ) | + (x5B << 16) | + (x01 << 24); + case 2: + return (x5B << 0 ) | + (xEF << 8 ) | + (x01 << 16) | + (xEF << 24); + case 3: + return (x5B << 0 ) | + (x01 << 8 ) | + (xEF << 16) | + (x5B << 24); + } + /* avoid warnings, we'd never get here normally but just to calm compiler warnings... */ + return 0; +} +#endif + +/* computes h(x) */ +static void h_func(const unsigned char *in, unsigned char *out, unsigned char *M, int k, int offset) +{ + int x; + unsigned char y[4]; + + for (x = 0; x < 4; x++) + y[x] = in[x]; + + switch (k) { + case 4: + y[0] = sbox(1, y[0]) ^ M[4 * (6 + offset) + 0]; + y[1] = sbox(0, y[1]) ^ M[4 * (6 + offset) + 1]; + y[2] = sbox(0, y[2]) ^ M[4 * (6 + offset) + 2]; + y[3] = sbox(1, y[3]) ^ M[4 * (6 + offset) + 3]; + case 3: + y[0] = sbox(1, y[0]) ^ M[4 * (4 + offset) + 0]; + y[1] = sbox(1, y[1]) ^ M[4 * (4 + offset) + 1]; + y[2] = sbox(0, y[2]) ^ M[4 * (4 + offset) + 2]; + y[3] = sbox(0, y[3]) ^ M[4 * (4 + offset) + 3]; + case 2: + y[0] = sbox(1, sbox(0, sbox(0, y[0]) ^ M[4 * (2 + offset) + 0]) ^ M[4 * (0 + offset) + 0]); + y[1] = sbox(0, sbox(0, sbox(1, y[1]) ^ M[4 * (2 + offset) + 1]) ^ M[4 * (0 + offset) + 1]); + y[2] = sbox(1, sbox(1, sbox(0, y[2]) ^ M[4 * (2 + offset) + 2]) ^ M[4 * (0 + offset) + 2]); + y[3] = sbox(0, sbox(1, sbox(1, y[3]) ^ M[4 * (2 + offset) + 3]) ^ M[4 * (0 + offset) + 3]); + } + mds_mult(y, out); +} + +#ifndef TWOFISH_SMALL + +static unsigned long g_func(unsigned long x, symmetric_key *key) +{ + return + key->twofish.S[0][(x>>0)&255] ^ + key->twofish.S[1][(x>>8)&255] ^ + key->twofish.S[2][(x>>16)&255] ^ + key->twofish.S[3][(x>>24)&255]; +} + +#else + +#ifdef CLEAN_STACK +static unsigned long _g_func(unsigned long x, symmetric_key *key) +#else +unsigned long g_func(unsigned long x, symmetric_key *key) +#endif +{ + unsigned char g, i, y, z; + unsigned long res; + + res = 0; + for (y = 0; y < 4; y++) { + z = key->twofish.start; + + /* do unkeyed substitution */ + g = sbox(qord[y][z++], (x >> (8*y)) & 255); + + /* first subkey */ + i = 0; + + /* do key mixing+sbox until z==5 */ + while (z != 5) { + g = g ^ key->twofish.S[4*i++ + y]; + g = sbox(qord[y][z++], g); + } + + /* multiply g by a column of the MDS */ + res ^= mds_column_mult(g, y); + } + return res; +} + +#ifdef CLEAN_STACK +static unsigned long g_func(unsigned long x, symmetric_key *key) +{ + unsigned long y; + y = _g_func(x, key); + burn_stack(sizeof(unsigned char) * 4 + sizeof(unsigned long)); + return y; +} +#endif + +#endif + +#ifdef CLEAN_STACK +static int _twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +#else +int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +#endif +{ +#ifndef TWOFISH_SMALL + int g, z, i; + unsigned char S[4*4]; +#endif + int k, x, y, start; + unsigned char tmp[4], tmp2[4], M[8*4]; + unsigned long A, B; + + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + /* invalid arguments? */ + if (num_rounds != 16 && num_rounds != 0) { + return CRYPT_INVALID_ROUNDS; + } + + if (keylen != 16 && keylen != 24 && keylen != 32) { + return CRYPT_INVALID_KEYSIZE; + } + + /* k = keysize/64 [but since our keysize is in bytes...] */ + k = keylen / 8; + + /* copy the key into M */ + for (x = 0; x < keylen; x++) + M[x] = key[x]; + + /* create the S[..] words */ +#ifndef TWOFISH_SMALL + for (x = 0; x < k; x++) + rs_mult(M+(x*8), S+(x*4)); +#else + for (x = 0; x < k; x++) + rs_mult(M+(x*8), skey->twofish.S+(x*4)); +#endif + + /* make subkeys */ + for (x = 0; x < 20; x++) { + /* A = h(p * 2x, Me) */ + for (y = 0; y < 4; y++) + tmp[y] = x+x; + h_func(tmp, tmp2, M, k, 0); + LOAD32L(A, tmp2); + + /* B = ROL(h(p * (2x + 1), Mo), 8) */ + for (y = 0; y < 4; y++) + tmp[y] = x+x+1; + h_func(tmp, tmp2, M, k, 1); + LOAD32L(B, tmp2); + B = ROL(B, 8); + + /* K[2i] = A + B */ + skey->twofish.K[x+x] = (A + B) & 0xFFFFFFFFUL; + + /* K[2i+1] = (A + 2B) <<< 9 */ + skey->twofish.K[x+x+1] = ROL(B + B + A, 9); + } + + /* where to start in the sbox layers */ + switch (k) { + case 4 : start = 0; break; + case 3 : start = 1; break; + default: start = 2; break; + } + +#ifndef TWOFISH_SMALL + /* make the sboxes (large ram variant) */ + for (y = 0; y < 4; y++) { + for (x = 0; x < 256; x++) { + z = start; + + /* do unkeyed substitution */ + g = sbox(qord[y][z++], x); + + /* first subkey */ + i = 0; + + /* do key mixing+sbox until z==5 */ + while (z != 5) { + g = g ^ S[4*i++ + y]; + g = sbox(qord[y][z++], g); + } + + /* multiply g by a column of the MDS */ + skey->twofish.S[y][x] = mds_column_mult(g, y); + } + } +#else + /* small ram variant */ + skey->twofish.start = start; +#endif + return CRYPT_OK; +} + +#ifdef CLEAN_STACK +int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + int x; + x = _twofish_setup(key, keylen, num_rounds, skey); + burn_stack(sizeof(int) * 7 + sizeof(unsigned char) * 56 + sizeof(unsigned long) * 2); + return x; +} +#endif + +#ifdef CLEAN_STACK +static void _twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#else +void twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#endif +{ + unsigned long a,b,c,d,ta,tb,tc,td,t1,t2; + int r; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + + LOAD32L(a,&pt[0]); LOAD32L(b,&pt[4]); + LOAD32L(c,&pt[8]); LOAD32L(d,&pt[12]); + a ^= key->twofish.K[0]; + b ^= key->twofish.K[1]; + c ^= key->twofish.K[2]; + d ^= key->twofish.K[3]; + + for (r = 0; r < 16; r += 2) { + t1 = g_func(a, key); + t2 = g_func(ROL(b, 8), key); + t2 += (t1 += t2); + t1 += key->twofish.K[r+r+8]; + t2 += key->twofish.K[r+r+9]; + c ^= t1; c = ROR(c, 1); + d = ROL(d, 1) ^ t2; + + t1 = g_func(c, key); + t2 = g_func(ROL(d, 8), key); + t2 += (t1 += t2); + t1 += key->twofish.K[r+r+10]; + t2 += key->twofish.K[r+r+11]; + a ^= t1; a = ROR(a, 1); + b = ROL(b, 1) ^ t2; + } + + /* output with "undo last swap" */ + ta = c ^ key->twofish.K[4]; + tb = d ^ key->twofish.K[5]; + tc = a ^ key->twofish.K[6]; + td = b ^ key->twofish.K[7]; + + /* store output */ + STORE32L(ta,&ct[0]); STORE32L(tb,&ct[4]); + STORE32L(tc,&ct[8]); STORE32L(td,&ct[12]); +} + +#ifdef CLEAN_STACK +void twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + _twofish_ecb_encrypt(pt, ct, key); + burn_stack(sizeof(unsigned long) * 10 + sizeof(int)); +} +#endif + +#ifdef CLEAN_STACK +static void _twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#else +void twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#endif +{ + unsigned long a,b,c,d,ta,tb,tc,td,t1,t2; + int r; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + + /* load input */ + LOAD32L(ta,&ct[0]); LOAD32L(tb,&ct[4]); + LOAD32L(tc,&ct[8]); LOAD32L(td,&ct[12]); + + /* undo undo final swap */ + a = tc ^ key->twofish.K[6]; + b = td ^ key->twofish.K[7]; + c = ta ^ key->twofish.K[4]; + d = tb ^ key->twofish.K[5]; + + for (r = 14; r >= 0; r -= 2) { + t1 = g_func(c, key); + t2 = g_func(ROL(d, 8), key); + t2 += (t1 += t2); + t1 += key->twofish.K[r+r+10]; + t2 += key->twofish.K[r+r+11]; + a = ROL(a, 1) ^ t1; + b = b ^ t2; b = ROR(b, 1); + + t1 = g_func(a, key); + t2 = g_func(ROL(b, 8), key); + t2 += (t1 += t2); + t1 += key->twofish.K[r+r+8]; + t2 += key->twofish.K[r+r+9]; + c = ROL(c, 1) ^ t1; + d = d ^ t2; d = ROR(d, 1); + } + + /* pre-white */ + a ^= key->twofish.K[0]; + b ^= key->twofish.K[1]; + c ^= key->twofish.K[2]; + d ^= key->twofish.K[3]; + + /* store */ + STORE32L(a, &pt[0]); STORE32L(b, &pt[4]); + STORE32L(c, &pt[8]); STORE32L(d, &pt[12]); +} + +#ifdef CLEAN_STACK +void twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +{ + _twofish_ecb_decrypt(ct, pt, key); + burn_stack(sizeof(unsigned long) * 10 + sizeof(int)); +} +#endif + +int twofish_test(void) +{ + static const unsigned char key128[16] = { + 0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, + 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A }; + static const unsigned char pt128[16] = { + 0xD4, 0x91, 0xDB, 0x16, 0xE7, 0xB1, 0xC3, 0x9E, + 0x86, 0xCB, 0x08, 0x6B, 0x78, 0x9F, 0x54, 0x19 }; + static const unsigned char ct128[16] = { + 0x01, 0x9F, 0x98, 0x09, 0xDE, 0x17, 0x11, 0x85, + 0x8F, 0xAA, 0xC3, 0xA3, 0xBA, 0x20, 0xFB, 0xC3 }; + + static const unsigned char key192[24] = { + 0x88, 0xB2, 0xB2, 0x70, 0x6B, 0x10, 0x5E, 0x36, + 0xB4, 0x46, 0xBB, 0x6D, 0x73, 0x1A, 0x1E, 0x88, + 0xEF, 0xA7, 0x1F, 0x78, 0x89, 0x65, 0xBD, 0x44 }; + static const unsigned char pt192[16] = { + 0x39, 0xDA, 0x69, 0xD6, 0xBA, 0x49, 0x97, 0xD5, + 0x85, 0xB6, 0xDC, 0x07, 0x3C, 0xA3, 0x41, 0xB2 }; + static const unsigned char ct192[16] = { + 0x18, 0x2B, 0x02, 0xD8, 0x14, 0x97, 0xEA, 0x45, + 0xF9, 0xDA, 0xAC, 0xDC, 0x29, 0x19, 0x3A, 0x65 }; + + static const unsigned char key256[32] = { + 0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46, + 0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D, + 0x57, 0xFF, 0x73, 0x9D, 0x4D, 0xC9, 0x2C, 0x1B, + 0xD7, 0xFC, 0x01, 0x70, 0x0C, 0xC8, 0x21, 0x6F }; + static const unsigned char pt256[16] = { + 0x90, 0xAF, 0xE9, 0x1B, 0xB2, 0x88, 0x54, 0x4F, + 0x2C, 0x32, 0xDC, 0x23, 0x9B, 0x26, 0x35, 0xE6 }; + static const unsigned char ct256[16] = { + 0x6C, 0xB4, 0x56, 0x1C, 0x40, 0xBF, 0x0A, 0x97, + 0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA }; + + symmetric_key key; + unsigned char tmp[2][16]; + int errno; + + if ((errno = twofish_setup(key128, 16, 0, &key)) != CRYPT_OK) { + return errno; + } + twofish_ecb_encrypt(pt128, tmp[0], &key); + twofish_ecb_decrypt(tmp[0], tmp[1], &key); + if (memcmp(tmp[0], ct128, 16) || memcmp(tmp[1], pt128, 16)) { + return CRYPT_FAIL_TESTVECTOR; + } + + if ((errno = twofish_setup(key192, 24, 0, &key)) != CRYPT_OK) { + return errno; + } + twofish_ecb_encrypt(pt192, tmp[0], &key); + twofish_ecb_decrypt(tmp[0], tmp[1], &key); + if (memcmp(tmp[0], ct192, 16) || memcmp(tmp[1], pt192, 16)) { + return CRYPT_FAIL_TESTVECTOR; + } + + if ((errno = twofish_setup(key256, 32, 0, &key)) != CRYPT_OK) { + return errno; + } + twofish_ecb_encrypt(pt256, tmp[0], &key); + twofish_ecb_decrypt(tmp[0], tmp[1], &key); + if (memcmp(tmp[0], ct256, 16) || memcmp(tmp[1], pt256, 16)) { + return CRYPT_FAIL_TESTVECTOR; + } + + return CRYPT_OK; +} + +int twofish_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize); + if (*desired_keysize < 16) + return CRYPT_INVALID_KEYSIZE; + if (*desired_keysize < 24) { + *desired_keysize = 16; + return CRYPT_OK; + } else if (*desired_keysize < 32) { + *desired_keysize = 24; + return CRYPT_OK; + } else { + *desired_keysize = 32; + return CRYPT_OK; + } +} + +#endif + + + diff --git a/xtea.c b/xtea.c new file mode 100644 index 0000000..a477d0b --- /dev/null +++ b/xtea.c @@ -0,0 +1,121 @@ +#include "mycrypt.h" + +#ifdef XTEA + +const struct _cipher_descriptor xtea_desc = +{ + "xtea", + 1, + 16, 16, 8, 32, + &xtea_setup, + &xtea_ecb_encrypt, + &xtea_ecb_decrypt, + &xtea_test, + &xtea_keysize +}; + +int xtea_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + /* check arguments */ + if (keylen != 16) { + return CRYPT_INVALID_KEYSIZE; + } + + if (num_rounds != 0 && num_rounds != 32) { + return CRYPT_INVALID_ROUNDS; + } + + /* load key */ + LOAD32L(skey->xtea.K[0], key+0); + LOAD32L(skey->xtea.K[1], key+4); + LOAD32L(skey->xtea.K[2], key+8); + LOAD32L(skey->xtea.K[3], key+12); + return CRYPT_OK; +} + +void xtea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + unsigned long y, z, sum; + int r; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + + LOAD32L(y, &pt[0]); + LOAD32L(z, &pt[4]); + sum = 0; + for (r = 0; r < 32; r++) { + y = (y + ((((z<<4)^(z>>5)) + z) ^ (sum + key->xtea.K[sum&3]))) & 0xFFFFFFFFUL; + sum = (sum + 0x9E3779B9UL) & 0xFFFFFFFFUL; + z = (z + ((((y<<4)^(y>>5)) + y) ^ (sum + key->xtea.K[(sum>>11)&3]))) & 0xFFFFFFFFUL; + } + STORE32L(y, &ct[0]); + STORE32L(z, &ct[4]); +} + +void xtea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +{ + unsigned long y, z, sum; + int r; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + + LOAD32L(y, &ct[0]); + LOAD32L(z, &ct[4]); + sum = (32UL*0x9E3779B9UL)&0xFFFFFFFFUL; + for (r = 0; r < 32; r++) { + z = (z - ((((y<<4)^(y>>5)) + y) ^ (sum + key->xtea.K[(sum>>11)&3]))) & 0xFFFFFFFFUL; + sum = (sum - 0x9E3779B9UL) & 0xFFFFFFFFUL; + y = (y - ((((z<<4)^(z>>5)) + z) ^ (sum + key->xtea.K[sum&3]))) & 0xFFFFFFFFUL; + } + STORE32L(y, &pt[0]); + STORE32L(z, &pt[4]); +} + +int xtea_test(void) +{ + static const unsigned char key[16] = + { 0x78, 0x56, 0x34, 0x12, 0xf0, 0xcd, 0xcb, 0x9a, + 0x48, 0x37, 0x26, 0x15, 0xc0, 0xbf, 0xae, 0x9d }; + static const unsigned char pt[8] = + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; + static const unsigned char ct[8] = + { 0x75, 0xd7, 0xc5, 0xbf, 0xcf, 0x58, 0xc9, 0x3f }; + unsigned char tmp[2][8]; + symmetric_key skey; + int errno; + + if ((errno = xtea_setup(key, 16, 0, &skey)) != CRYPT_OK) { + return errno; + } + xtea_ecb_encrypt(pt, tmp[0], &skey); + xtea_ecb_decrypt(tmp[0], tmp[1], &skey); + + if (memcmp(tmp[0], ct, 8) || memcmp(tmp[1], pt, 8)) { + return CRYPT_FAIL_TESTVECTOR; + } + + return CRYPT_OK; +} + +int xtea_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize); + if (*desired_keysize < 16) { + return CRYPT_INVALID_KEYSIZE; + } + *desired_keysize = 16; + return CRYPT_OK; +} + + +#endif + + + diff --git a/yarrow.c b/yarrow.c new file mode 100644 index 0000000..7ceab90 --- /dev/null +++ b/yarrow.c @@ -0,0 +1,144 @@ +#include "mycrypt.h" + +#ifdef YARROW + +const struct _prng_descriptor yarrow_desc = +{ + "yarrow", + &yarrow_start, + &yarrow_add_entropy, + &yarrow_ready, + &yarrow_read +}; + +int yarrow_start(prng_state *prng) +{ + int errno; + + _ARGCHK(prng != NULL); + + /* these are the default hash/cipher combo used */ +#ifdef RIJNDAEL + prng->yarrow.cipher = register_cipher(&rijndael_desc); +#elif defined(BLOWFISH) + prng->yarrow.cipher = register_cipher(&blowfish_desc); +#elif defined(TWOFISH) + prng->yarrow.cipher = register_cipher(&twofish_desc); +#elif defined(CAST5) + prng->yarrow.cipher = register_cipher(&cast5_desc); +#elif defined(SERPENT) + prng->yarrow.cipher = register_cipher(&serpent_desc); +#elif defined(SAFER) + prng->yarrow.cipher = register_cipher(&saferp_desc); +#elif defined(RC5) + prng->yarrow.cipher = register_cipher(&rc5_desc); +#elif defined(RC6) + prng->yarrow.cipher = register_cipher(&rc6_desc); +#elif defined(XTEA) + prng->yarrow.cipher = register_cipher(&xtea_desc); +#elif defined(RC2) + prng->yarrow.cipher = register_cipher(&rc2_desc); +#elif defined(DES) + prng->yarrow.cipher = register_cipher(&des3_desc); +#elif + #error YARROW needs at least one CIPHER +#endif + if ((errno = cipher_is_valid(prng->yarrow.cipher)) != CRYPT_OK) { + return errno; + } + +#ifdef SHA256 + prng->yarrow.hash = register_hash(&sha256_desc); +#elif defined(SHA512) + prng->yarrow.hash = register_hash(&sha512_desc); +#elif defined(SHA384) + prng->yarrow.hash = register_hash(&sha384_desc); +#elif defined(SHA1) + prng->yarrow.hash = register_hash(&sha1_desc); +#elif defined(TIGER) + prng->yarrow.hash = register_hash(&tiger_desc); +#elif defined(MD5) + prng->yarrow.hash = register_hash(&md5_desc); +#elif defined(MD4) + prng->yarrow.hash = register_hash(&md4_desc); +#elif defined(MD2) + prng->yarrow.hash = register_hash(&md2_desc); +#else + #error YARROW needs at least one HASH +#endif + if ((errno = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) { + return errno; + } + + /* zero the memory used */ + zeromem(prng->yarrow.pool, sizeof(prng->yarrow.pool)); + + return CRYPT_OK; +} + +int yarrow_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng) +{ + hash_state md; + int errno; + + _ARGCHK(buf != NULL); + _ARGCHK(prng != NULL); + + if ((errno = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) { + return errno; + } + + /* start the hash */ + hash_descriptor[prng->yarrow.hash].init(&md); + + /* hash the current pool */ + hash_descriptor[prng->yarrow.hash].process(&md, prng->yarrow.pool, hash_descriptor[prng->yarrow.hash].hashsize); + + /* add the new entropy */ + hash_descriptor[prng->yarrow.hash].process(&md, buf, len); + + /* store result */ + hash_descriptor[prng->yarrow.hash].done(&md, prng->yarrow.pool); + + return CRYPT_OK; +} + +int yarrow_ready(prng_state *prng) +{ + int ks, errno; + + _ARGCHK(prng != NULL); + + if ((errno = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) { + return errno; + } + + if ((errno = cipher_is_valid(prng->yarrow.cipher)) != CRYPT_OK) { + return errno; + } + + /* setup CTR mode using the "pool" as the key */ + ks = hash_descriptor[prng->yarrow.hash].hashsize; + if ((errno = cipher_descriptor[prng->yarrow.cipher].keysize(&ks)) != CRYPT_OK) { + return errno; + } + + if ((errno = ctr_start(prng->yarrow.cipher, prng->yarrow.pool, prng->yarrow.pool, ks, 0, &prng->yarrow.ctr)) != CRYPT_OK) { + return errno; + } + return CRYPT_OK; +} + +unsigned long yarrow_read(unsigned char *buf, unsigned long len, prng_state *prng) +{ + _ARGCHK(buf != NULL); + _ARGCHK(prng != NULL); + + if (ctr_encrypt(buf, buf, len, &prng->yarrow.ctr) != CRYPT_OK) { + return 0; + } + return len; +} + +#endif +