From dad9dbb0bd0f48526539b9d0ebbafd3e59b78592 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 31 May 2004 18:21:40 +0000 Subject: [PATCH 1/9] put back the 0.95 makefile which was inadvertently merged over --HG-- branch : libtomcrypt extra : convert_revision : a8432150cae4fe7441284bef582b002687ede6e0 --- LICENSE | 9 + PLAN | 38 + aes.c | 606 +++ aes_tab.c | 1008 ++++ ampi.c | 55 + authors | 55 + base64.c | 121 + blowfish.c | 541 ++ burn_stack.c | 21 + cast5.c | 669 +++ cbc_decrypt.c | 56 + cbc_encrypt.c | 52 + cbc_start.c | 43 + cfb_decrypt.c | 48 + cfb_encrypt.c | 46 + cfb_start.c | 47 + changes | 957 ++++ crypt.c | 232 + crypt.out | 88 + crypt.pdf | Bin 0 -> 404940 bytes crypt.tex | 3040 +++++++++++ crypt_argchk.c | 21 + crypt_cipher_descriptor.c | 18 + crypt_cipher_is_valid.c | 19 + crypt_find_cipher.c | 24 + crypt_find_cipher_any.c | 32 + crypt_find_cipher_id.c | 22 + crypt_find_hash.c | 23 + crypt_find_hash_any.c | 34 + crypt_find_hash_id.c | 22 + crypt_find_prng.c | 24 + crypt_hash_descriptor.c | 17 + crypt_hash_is_valid.c | 19 + crypt_prng_descriptor.c | 18 + crypt_prng_is_valid.c | 19 + crypt_register_cipher.c | 36 + crypt_register_hash.c | 36 + crypt_register_prng.c | 36 + crypt_unregister_cipher.c | 28 + crypt_unregister_hash.c | 27 + crypt_unregister_prng.c | 27 + ctr_decrypt.c | 25 + ctr_encrypt.c | 64 + ctr_start.c | 46 + demos/encrypt.c | 231 + demos/hashsum.c | 106 + demos/small.c | 11 + demos/test.c | 1982 +++++++ demos/tv_gen.c | 492 ++ demos/x86_prof.c | 358 ++ des.c | 1813 +++++++ dh.c | 452 ++ dh_sys.c | 399 ++ dsa_export.c | 62 + dsa_free.c | 21 + dsa_import.c | 59 + dsa_make_key.c | 117 + dsa_sign_hash.c | 125 + dsa_verify_hash.c | 97 + dsa_verify_key.c | 86 + eax_addheader.c | 25 + eax_decrypt.c | 34 + eax_decrypt_verify_memory.c | 60 + eax_done.c | 56 + eax_encrypt.c | 35 + eax_encrypt_authenticate_memory.c | 43 + eax_init.c | 106 + eax_test.c | 271 + ecb_decrypt.c | 31 + ecb_encrypt.c | 29 + ecb_start.c | 29 + ecc.c | 937 ++++ ecc_sys.c | 432 ++ examples/ch1-01.c | 18 + examples/ch1-02.c | 25 + examples/ch1-03.c | 29 + examples/ch2-01.c | 35 + gf.c | 305 ++ hash_file.c | 41 + hash_filehandle.c | 49 + hash_memory.c | 35 + hmac_done.c | 84 + hmac_file.c | 96 + hmac_init.c | 87 + hmac_memory.c | 67 + hmac_process.c | 48 + hmac_test.c | 325 ++ is_prime.c | 27 + keyring.c | 862 +++ makefile | 254 + makefile.cygwin_dll | 84 + makefile.icc | 213 + makefile.msvc | 86 + md2.c | 214 + md4.c | 266 + md5.c | 258 + mpi.c | 8414 +++++++++++++++++++++++++++++ mycrypt.h | 83 + mycrypt_argchk.h | 24 + mycrypt_cfg.h | 78 + mycrypt_cipher.h | 378 ++ mycrypt_custom.h | 68 + mycrypt_gf.h | 32 + mycrypt_hash.h | 447 ++ mycrypt_kr.h | 81 + mycrypt_macros.h | 241 + mycrypt_misc.h | 20 + mycrypt_pk.h | 245 + mycrypt_pkcs.h | 53 + mycrypt_prng.h | 66 + noekeon.c | 270 + notes/base64_tv.txt | 35 + notes/cipher_tv.txt | 1539 ++++++ notes/eax_tv.txt | 331 ++ notes/etc/whirlgen.c | 91 + notes/etc/whirltest.c | 15 + notes/hash_tv.txt | 1736 ++++++ notes/hmac_tv.txt | 1736 ++++++ notes/ocb_tv.txt | 331 ++ notes/omac_tv.txt | 331 ++ notes/pmac_tv.txt | 331 ++ notes/tech0001.txt | 73 + notes/tech0002.txt | 52 + notes/tech0003.txt | 52 + ocb_decrypt.c | 58 + ocb_decrypt_verify_memory.c | 52 + ocb_done_decrypt.c | 51 + ocb_done_encrypt.c | 29 + ocb_encrypt.c | 56 + ocb_encrypt_authenticate_memory.c | 50 + ocb_init.c | 117 + ocb_ntz.c | 29 + ocb_shift_xor.c | 27 + ocb_test.c | 226 + ofb_decrypt.c | 26 + ofb_encrypt.c | 41 + ofb_start.c | 40 + omac_done.c | 66 + omac_file.c | 65 + omac_init.c | 76 + omac_memory.c | 42 + omac_process.c | 53 + omac_test.c | 95 + packet_store_header.c | 29 + packet_valid_header.c | 37 + pkcs_1_i2osp.c | 40 + pkcs_1_mgf1.c | 66 + pkcs_1_oaep_decode.c | 135 + pkcs_1_oaep_encode.c | 128 + pkcs_1_os2ip.c | 27 + pkcs_1_pss_decode.c | 121 + pkcs_1_pss_encode.c | 122 + pkcs_5_1.c | 63 + pkcs_5_2.c | 88 + pmac_done.c | 64 + pmac_file.c | 67 + pmac_init.c | 114 + pmac_memory.c | 44 + pmac_ntz.c | 29 + pmac_process.c | 62 + pmac_shift_xor.c | 26 + pmac_test.c | 153 + rand_prime.c | 65 + rc2.c | 319 ++ rc4.c | 107 + rc5.c | 269 + rc6.c | 298 + rmd128.c | 368 ++ rmd160.c | 427 ++ rng_get_bytes.c | 129 + rng_make_prng.c | 53 + rsa.c | 273 + rsa_exptmod.c | 87 + rsa_free.c | 24 + rsa_make_key.c | 113 + rsa_sys.c | 274 + s_ocb_done.c | 102 + safer.c | 468 ++ safer_tab.c | 59 + saferp.c | 510 ++ serpent.c | 698 +++ sha1.c | 223 + sha224.c | 93 + sha256.c | 305 ++ sha384.c | 107 + sha512.c | 282 + skipjack.c | 290 + sprng.c | 53 + strings.c | 86 + tiger.c | 772 +++ tommath.h | 558 ++ twofish.c | 661 +++ twofish_tab.c | 488 ++ whirl.c | 275 + whirltab.c | 575 ++ xtea.c | 169 + yarrow.c | 167 + zeromem.c | 19 + 198 files changed, 49909 insertions(+) create mode 100644 LICENSE create mode 100644 PLAN 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 blowfish.c create mode 100644 burn_stack.c create mode 100644 cast5.c create mode 100644 cbc_decrypt.c create mode 100644 cbc_encrypt.c create mode 100644 cbc_start.c create mode 100644 cfb_decrypt.c create mode 100644 cfb_encrypt.c create mode 100644 cfb_start.c create mode 100644 changes create mode 100644 crypt.c create mode 100644 crypt.out create mode 100644 crypt.pdf create mode 100644 crypt.tex create mode 100644 crypt_argchk.c create mode 100644 crypt_cipher_descriptor.c create mode 100644 crypt_cipher_is_valid.c create mode 100644 crypt_find_cipher.c create mode 100644 crypt_find_cipher_any.c create mode 100644 crypt_find_cipher_id.c create mode 100644 crypt_find_hash.c create mode 100644 crypt_find_hash_any.c create mode 100644 crypt_find_hash_id.c create mode 100644 crypt_find_prng.c create mode 100644 crypt_hash_descriptor.c create mode 100644 crypt_hash_is_valid.c create mode 100644 crypt_prng_descriptor.c create mode 100644 crypt_prng_is_valid.c create mode 100644 crypt_register_cipher.c create mode 100644 crypt_register_hash.c create mode 100644 crypt_register_prng.c create mode 100644 crypt_unregister_cipher.c create mode 100644 crypt_unregister_hash.c create mode 100644 crypt_unregister_prng.c create mode 100644 ctr_decrypt.c create mode 100644 ctr_encrypt.c create mode 100644 ctr_start.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/tv_gen.c create mode 100644 demos/x86_prof.c create mode 100644 des.c create mode 100644 dh.c create mode 100644 dh_sys.c create mode 100644 dsa_export.c create mode 100644 dsa_free.c create mode 100644 dsa_import.c create mode 100644 dsa_make_key.c create mode 100644 dsa_sign_hash.c create mode 100644 dsa_verify_hash.c create mode 100644 dsa_verify_key.c create mode 100644 eax_addheader.c create mode 100644 eax_decrypt.c create mode 100644 eax_decrypt_verify_memory.c create mode 100644 eax_done.c create mode 100644 eax_encrypt.c create mode 100644 eax_encrypt_authenticate_memory.c create mode 100644 eax_init.c create mode 100644 eax_test.c create mode 100644 ecb_decrypt.c create mode 100644 ecb_encrypt.c create mode 100644 ecb_start.c create mode 100644 ecc.c create mode 100644 ecc_sys.c create mode 100644 examples/ch1-01.c create mode 100644 examples/ch1-02.c create mode 100644 examples/ch1-03.c create mode 100644 examples/ch2-01.c create mode 100644 gf.c create mode 100644 hash_file.c create mode 100644 hash_filehandle.c create mode 100644 hash_memory.c create mode 100644 hmac_done.c create mode 100644 hmac_file.c create mode 100644 hmac_init.c create mode 100644 hmac_memory.c create mode 100644 hmac_process.c create mode 100644 hmac_test.c create mode 100644 is_prime.c create mode 100644 keyring.c create mode 100644 makefile create mode 100644 makefile.cygwin_dll create mode 100644 makefile.icc create mode 100644 makefile.msvc create mode 100644 md2.c create mode 100644 md4.c create mode 100644 md5.c create mode 100644 mpi.c 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_custom.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_pkcs.h create mode 100644 mycrypt_prng.h create mode 100644 noekeon.c create mode 100644 notes/base64_tv.txt create mode 100644 notes/cipher_tv.txt create mode 100644 notes/eax_tv.txt create mode 100644 notes/etc/whirlgen.c create mode 100644 notes/etc/whirltest.c create mode 100644 notes/hash_tv.txt create mode 100644 notes/hmac_tv.txt create mode 100644 notes/ocb_tv.txt create mode 100644 notes/omac_tv.txt create mode 100644 notes/pmac_tv.txt create mode 100644 notes/tech0001.txt create mode 100644 notes/tech0002.txt create mode 100644 notes/tech0003.txt create mode 100644 ocb_decrypt.c create mode 100644 ocb_decrypt_verify_memory.c create mode 100644 ocb_done_decrypt.c create mode 100644 ocb_done_encrypt.c create mode 100644 ocb_encrypt.c create mode 100644 ocb_encrypt_authenticate_memory.c create mode 100644 ocb_init.c create mode 100644 ocb_ntz.c create mode 100644 ocb_shift_xor.c create mode 100644 ocb_test.c create mode 100644 ofb_decrypt.c create mode 100644 ofb_encrypt.c create mode 100644 ofb_start.c create mode 100644 omac_done.c create mode 100644 omac_file.c create mode 100644 omac_init.c create mode 100644 omac_memory.c create mode 100644 omac_process.c create mode 100644 omac_test.c create mode 100644 packet_store_header.c create mode 100644 packet_valid_header.c create mode 100644 pkcs_1_i2osp.c create mode 100644 pkcs_1_mgf1.c create mode 100644 pkcs_1_oaep_decode.c create mode 100644 pkcs_1_oaep_encode.c create mode 100644 pkcs_1_os2ip.c create mode 100644 pkcs_1_pss_decode.c create mode 100644 pkcs_1_pss_encode.c create mode 100644 pkcs_5_1.c create mode 100644 pkcs_5_2.c create mode 100644 pmac_done.c create mode 100644 pmac_file.c create mode 100644 pmac_init.c create mode 100644 pmac_memory.c create mode 100644 pmac_ntz.c create mode 100644 pmac_process.c create mode 100644 pmac_shift_xor.c create mode 100644 pmac_test.c create mode 100644 rand_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 rmd128.c create mode 100644 rmd160.c create mode 100644 rng_get_bytes.c create mode 100644 rng_make_prng.c create mode 100644 rsa.c create mode 100644 rsa_exptmod.c create mode 100644 rsa_free.c create mode 100644 rsa_make_key.c create mode 100644 rsa_sys.c create mode 100644 s_ocb_done.c create mode 100644 safer.c create mode 100644 safer_tab.c create mode 100644 saferp.c create mode 100644 serpent.c create mode 100644 sha1.c create mode 100644 sha224.c create mode 100644 sha256.c create mode 100644 sha384.c create mode 100644 sha512.c create mode 100644 skipjack.c create mode 100644 sprng.c create mode 100644 strings.c create mode 100644 tiger.c create mode 100644 tommath.h create mode 100644 twofish.c create mode 100644 twofish_tab.c create mode 100644 whirl.c create mode 100644 whirltab.c create mode 100644 xtea.c create mode 100644 yarrow.c create mode 100644 zeromem.c diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2e83cda --- /dev/null +++ b/LICENSE @@ -0,0 +1,9 @@ +LibTomCrypt is public domain. As should all quality software be. + +All of the software was either written by or donated to Tom St Denis for the purposes +of this project. The only exception is the SAFER.C source which has no known +license status (assumed copyrighted) which is why SAFER,C is shipped as disabled. + +Tom St Denis + + diff --git a/PLAN b/PLAN new file mode 100644 index 0000000..71ebc1a --- /dev/null +++ b/PLAN @@ -0,0 +1,38 @@ +The following functions are marked for removal and/or behavioural change by v1.00 of LibTomCrypt + +1. RSA Support + + rsa_pad, rsa_signpad, rsa_depad, rsa_signdepad, rsa_import, rsa_export + +They will be replaced with PKCS #1 compliant OAEP/PSS padding function as early as v0.96 + +2. DSA Support + + dsa_import, dsa_export + +Will be replaced with suitable DSS [what is the standard?] compliant formats. Planned for v0.96 + +3. Key Ring Support + + (all) + +The entire API will be dropped as early as v0.96. It was just an experiment and nobody uses it anyways. + +4. Test Harness + + demos/test.c + +The test harness is well overdue for a makeover. Planned for as early as v0.97 + + +Put things in order... + +v0.96 -- removed keyring.c and gf.c + -- removed LTC RSA padding + -- DSS support [whatever this entails] + -- Bug fixes/updates to the PKCS/DSS support, should be stable in this release + +v0.97 -- Re-written test harness + -- More demos in the manual and demos/ directory + +... future??? diff --git a/aes.c b/aes.c new file mode 100644 index 0000000..342948d --- /dev/null +++ b/aes.c @@ -0,0 +1,606 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* AES implementation by Tom St Denis + * + * Derived from the Public Domain source code by + +--- + * rijndael-alg-fst.c + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto +--- + */ + +#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 +}; + +const struct _cipher_descriptor aes_desc = +{ + "aes", + 6, + 16, 32, 16, 10, + &rijndael_setup, + &rijndael_ecb_encrypt, + &rijndael_ecb_decrypt, + &rijndael_test, + &rijndael_keysize +}; + +#include "aes_tab.c" + +int rijndael_setup(const unsigned char *key, int keylen, int rounds, symmetric_key *skey) +{ + int i, j; + ulong32 temp, *rk, *rrk; + + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + if (keylen != 16 && keylen != 24 && keylen != 32) { + return CRYPT_INVALID_KEYSIZE; + } + + if (rounds != 0 && rounds != (10 + ((keylen/8)-2)*2)) { + return CRYPT_INVALID_ROUNDS; + } + + skey->rijndael.Nr = 10 + ((keylen/8)-2)*2; + + /* setup the forward key */ + i = 0; + rk = skey->rijndael.eK; + LOAD32H(rk[0], key ); + LOAD32H(rk[1], key + 4); + LOAD32H(rk[2], key + 8); + LOAD32H(rk[3], key + 12); + if (keylen == 16) { + j = 44; + for (;;) { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te4_3[byte(temp, 2)]) ^ + (Te4_2[byte(temp, 1)]) ^ + (Te4_1[byte(temp, 0)]) ^ + (Te4_0[byte(temp, 3)]) ^ + rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) { + break; + } + rk += 4; + } + } else if (keylen == 24) { + j = 52; + LOAD32H(rk[4], key + 16); + LOAD32H(rk[5], key + 20); + for (;;) { + #ifdef _MSC_VER + temp = skey->rijndael.eK[rk - skey->rijndael.eK + 5]; + #else + temp = rk[5]; + #endif + rk[ 6] = rk[ 0] ^ + (Te4_3[byte(temp, 2)]) ^ + (Te4_2[byte(temp, 1)]) ^ + (Te4_1[byte(temp, 0)]) ^ + (Te4_0[byte(temp, 3)]) ^ + rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) { + break; + } + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + } else if (keylen == 32) { + j = 60; + LOAD32H(rk[4], key + 16); + LOAD32H(rk[5], key + 20); + LOAD32H(rk[6], key + 24); + LOAD32H(rk[7], key + 28); + for (;;) { + #ifdef _MSC_VER + temp = skey->rijndael.eK[rk - skey->rijndael.eK + 7]; + #else + temp = rk[7]; + #endif + rk[ 8] = rk[ 0] ^ + (Te4_3[byte(temp, 2)]) ^ + (Te4_2[byte(temp, 1)]) ^ + (Te4_1[byte(temp, 0)]) ^ + (Te4_0[byte(temp, 3)]) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) { + break; + } + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4_3[byte(temp, 3)]) ^ + (Te4_2[byte(temp, 2)]) ^ + (Te4_1[byte(temp, 1)]) ^ + (Te4_0[byte(temp, 0)]); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + rk += 8; + } + } else { + /* this can't happen */ + j = 4; + } + + /* setup the inverse key now */ + rk = skey->rijndael.dK; + rrk = skey->rijndael.eK + j - 4; + + /* apply the inverse MixColumn transform to all round keys but the first and the last: */ + /* copy first */ + *rk++ = *rrk++; + *rk++ = *rrk++; + *rk++ = *rrk++; + *rk = *rrk; + rk -= 3; rrk -= 3; + + for (i = 1; i < skey->rijndael.Nr; i++) { + rrk -= 4; + rk += 4; + #ifdef SMALL_CODE + temp = rrk[0]; + rk[0] = + Td0(255 & Te4[byte(temp, 3)]) ^ + Td1(255 & Te4[byte(temp, 2)]) ^ + Td2(255 & Te4[byte(temp, 1)]) ^ + Td3(255 & Te4[byte(temp, 0)]); + temp = rrk[1]; + rk[1] = + Td0(255 & Te4[byte(temp, 3)]) ^ + Td1(255 & Te4[byte(temp, 2)]) ^ + Td2(255 & Te4[byte(temp, 1)]) ^ + Td3(255 & Te4[byte(temp, 0)]); + temp = rrk[2]; + rk[2] = + Td0(255 & Te4[byte(temp, 3)]) ^ + Td1(255 & Te4[byte(temp, 2)]) ^ + Td2(255 & Te4[byte(temp, 1)]) ^ + Td3(255 & Te4[byte(temp, 0)]); + temp = rrk[3]; + rk[3] = + Td0(255 & Te4[byte(temp, 3)]) ^ + Td1(255 & Te4[byte(temp, 2)]) ^ + Td2(255 & Te4[byte(temp, 1)]) ^ + Td3(255 & Te4[byte(temp, 0)]); + #else + temp = rrk[0]; + rk[0] = + Tks0[byte(temp, 3)] ^ + Tks1[byte(temp, 2)] ^ + Tks2[byte(temp, 1)] ^ + Tks3[byte(temp, 0)]; + temp = rrk[1]; + rk[1] = + Tks0[byte(temp, 3)] ^ + Tks1[byte(temp, 2)] ^ + Tks2[byte(temp, 1)] ^ + Tks3[byte(temp, 0)]; + temp = rrk[2]; + rk[2] = + Tks0[byte(temp, 3)] ^ + Tks1[byte(temp, 2)] ^ + Tks2[byte(temp, 1)] ^ + Tks3[byte(temp, 0)]; + temp = rrk[3]; + rk[3] = + Tks0[byte(temp, 3)] ^ + Tks1[byte(temp, 2)] ^ + Tks2[byte(temp, 1)] ^ + Tks3[byte(temp, 0)]; + #endif + + } + + /* copy last */ + rrk -= 4; + rk += 4; + *rk++ = *rrk++; + *rk++ = *rrk++; + *rk++ = *rrk++; + *rk = *rrk; + + return CRYPT_OK; +} + +#ifdef CLEAN_STACK +static void _rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) +#else +void rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) +#endif +{ + ulong32 s0, s1, s2, s3, t0, t1, t2, t3, *rk; + int Nr, r; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(skey != NULL); + + Nr = skey->rijndael.Nr; + rk = skey->rijndael.eK; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + LOAD32H(s0, pt ); s0 ^= rk[0]; + LOAD32H(s1, pt + 4); s1 ^= rk[1]; + LOAD32H(s2, pt + 8); s2 ^= rk[2]; + LOAD32H(s3, pt + 12); s3 ^= rk[3]; + + /* + * Nr - 1 full rounds: + */ + r = Nr >> 1; + for (;;) { + t0 = + Te0(byte(s0, 3)) ^ + Te1(byte(s1, 2)) ^ + Te2(byte(s2, 1)) ^ + Te3(byte(s3, 0)) ^ + rk[4]; + t1 = + Te0(byte(s1, 3)) ^ + Te1(byte(s2, 2)) ^ + Te2(byte(s3, 1)) ^ + Te3(byte(s0, 0)) ^ + rk[5]; + t2 = + Te0(byte(s2, 3)) ^ + Te1(byte(s3, 2)) ^ + Te2(byte(s0, 1)) ^ + Te3(byte(s1, 0)) ^ + rk[6]; + t3 = + Te0(byte(s3, 3)) ^ + Te1(byte(s0, 2)) ^ + Te2(byte(s1, 1)) ^ + Te3(byte(s2, 0)) ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Te0(byte(t0, 3)) ^ + Te1(byte(t1, 2)) ^ + Te2(byte(t2, 1)) ^ + Te3(byte(t3, 0)) ^ + rk[0]; + s1 = + Te0(byte(t1, 3)) ^ + Te1(byte(t2, 2)) ^ + Te2(byte(t3, 1)) ^ + Te3(byte(t0, 0)) ^ + rk[1]; + s2 = + Te0(byte(t2, 3)) ^ + Te1(byte(t3, 2)) ^ + Te2(byte(t0, 1)) ^ + Te3(byte(t1, 0)) ^ + rk[2]; + s3 = + Te0(byte(t3, 3)) ^ + Te1(byte(t0, 2)) ^ + Te2(byte(t1, 1)) ^ + Te3(byte(t2, 0)) ^ + rk[3]; + } + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Te4_3[(t0 >> 24) ]) ^ + (Te4_2[(t1 >> 16) & 0xff]) ^ + (Te4_1[(t2 >> 8) & 0xff]) ^ + (Te4_0[(t3 ) & 0xff]) ^ + rk[0]; + STORE32H(s0, ct); + s1 = + (Te4_3[(t1 >> 24) ]) ^ + (Te4_2[(t2 >> 16) & 0xff]) ^ + (Te4_1[(t3 >> 8) & 0xff]) ^ + (Te4_0[(t0 ) & 0xff]) ^ + rk[1]; + STORE32H(s1, ct+4); + s2 = + (Te4_3[(t2 >> 24) ]) ^ + (Te4_2[(t3 >> 16) & 0xff]) ^ + (Te4_1[(t0 >> 8) & 0xff]) ^ + (Te4_0[(t1 ) & 0xff]) ^ + rk[2]; + STORE32H(s2, ct+8); + s3 = + (Te4_3[(t3 >> 24) ]) ^ + (Te4_2[(t0 >> 16) & 0xff]) ^ + (Te4_1[(t1 >> 8) & 0xff]) ^ + (Te4_0[(t2 ) & 0xff]) ^ + rk[3]; + STORE32H(s3, ct+12); +} + +#ifdef CLEAN_STACK +void rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) +{ + _rijndael_ecb_encrypt(pt, ct, skey); + burn_stack(sizeof(unsigned long)*8 + sizeof(unsigned long*) + sizeof(int)*2); +} +#endif + +#ifdef CLEAN_STACK +static void _rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) +#else +void rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) +#endif +{ + ulong32 s0, s1, s2, s3, t0, t1, t2, t3, *rk; + int Nr, r; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(skey != NULL); + + Nr = skey->rijndael.Nr; + rk = skey->rijndael.dK; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + LOAD32H(s0, ct ); s0 ^= rk[0]; + LOAD32H(s1, ct + 4); s1 ^= rk[1]; + LOAD32H(s2, ct + 8); s2 ^= rk[2]; + LOAD32H(s3, ct + 12); s3 ^= rk[3]; + + /* + * Nr - 1 full rounds: + */ + r = Nr >> 1; + for (;;) { + + t0 = + Td0(byte(s0, 3)) ^ + Td1(byte(s3, 2)) ^ + Td2(byte(s2, 1)) ^ + Td3(byte(s1, 0)) ^ + rk[4]; + t1 = + Td0(byte(s1, 3)) ^ + Td1(byte(s0, 2)) ^ + Td2(byte(s3, 1)) ^ + Td3(byte(s2, 0)) ^ + rk[5]; + t2 = + Td0(byte(s2, 3)) ^ + Td1(byte(s1, 2)) ^ + Td2(byte(s0, 1)) ^ + Td3(byte(s3, 0)) ^ + rk[6]; + t3 = + Td0(byte(s3, 3)) ^ + Td1(byte(s2, 2)) ^ + Td2(byte(s1, 1)) ^ + Td3(byte(s0, 0)) ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + + s0 = + Td0(byte(t0, 3)) ^ + Td1(byte(t3, 2)) ^ + Td2(byte(t2, 1)) ^ + Td3(byte(t1, 0)) ^ + rk[0]; + s1 = + Td0(byte(t1, 3)) ^ + Td1(byte(t0, 2)) ^ + Td2(byte(t3, 1)) ^ + Td3(byte(t2, 0)) ^ + rk[1]; + s2 = + Td0(byte(t2, 3)) ^ + Td1(byte(t1, 2)) ^ + Td2(byte(t0, 1)) ^ + Td3(byte(t3, 0)) ^ + rk[2]; + s3 = + Td0(byte(t3, 3)) ^ + Td1(byte(t2, 2)) ^ + Td2(byte(t1, 1)) ^ + Td3(byte(t0, 0)) ^ + rk[3]; + } + + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[(t0 >> 24) ] & 0xff000000) ^ + (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[0]; + STORE32H(s0, pt); + s1 = + (Td4[(t1 >> 24) ] & 0xff000000) ^ + (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[1]; + STORE32H(s1, pt+4); + s2 = + (Td4[(t2 >> 24) ] & 0xff000000) ^ + (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[2]; + STORE32H(s2, pt+8); + s3 = + (Td4[(t3 >> 24) ] & 0xff000000) ^ + (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[3]; + STORE32H(s3, pt+12); +} + + +#ifdef CLEAN_STACK +void rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) +{ + _rijndael_ecb_decrypt(ct, pt, skey); + burn_stack(sizeof(unsigned long)*8 + sizeof(unsigned long*) + sizeof(int)*2); +} +#endif + +int rijndael_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + int err; + static const struct { + int keylen; + unsigned char key[32], pt[16], ct[16]; + } tests[] = { + { 16, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + { 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, + 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a } + }, { + 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 }, + { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + { 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, + 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91 } + }, { + 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 }, + { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + { 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, + 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 } + } + }; + + symmetric_key key; + unsigned char tmp[2][16]; + int i, y; + + for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) { + zeromem(&key, sizeof(key)); + if ((err = rijndael_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) { + return err; + } + + rijndael_ecb_encrypt(tests[i].pt, tmp[0], &key); + rijndael_ecb_decrypt(tmp[0], tmp[1], &key); + if (memcmp(tmp[0], tests[i].ct, 16) || memcmp(tmp[1], tests[i].pt, 16)) { +#if 0 + printf("\n\nTest %d failed\n", i); + if (memcmp(tmp[0], tests[i].ct, 16)) { + printf("CT: "); + for (i = 0; i < 16; i++) { + printf("%02x ", tmp[0][i]); + } + printf("\n"); + } else { + printf("PT: "); + for (i = 0; i < 16; i++) { + printf("%02x ", tmp[1][i]); + } + printf("\n"); + } +#endif + return CRYPT_FAIL_TESTVECTOR; + } + + /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ + for (y = 0; y < 16; y++) tmp[0][y] = 0; + for (y = 0; y < 1000; y++) rijndael_ecb_encrypt(tmp[0], tmp[0], &key); + for (y = 0; y < 1000; y++) rijndael_ecb_decrypt(tmp[0], tmp[0], &key); + for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; + } + return CRYPT_OK; + #endif +} + +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..a93c746 --- /dev/null +++ b/aes_tab.c @@ -0,0 +1,1008 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* The precomputed tables for AES */ +/* +Te0[x] = S [x].[02, 01, 01, 03]; +Te1[x] = S [x].[03, 02, 01, 01]; +Te2[x] = S [x].[01, 03, 02, 01]; +Te3[x] = S [x].[01, 01, 03, 02]; +Te4[x] = S [x].[01, 01, 01, 01]; + +Td0[x] = Si[x].[0e, 09, 0d, 0b]; +Td1[x] = Si[x].[0b, 0e, 09, 0d]; +Td2[x] = Si[x].[0d, 0b, 0e, 09]; +Td3[x] = Si[x].[09, 0d, 0b, 0e]; +Td4[x] = Si[x].[01, 01, 01, 01]; +*/ + +static const ulong32 TE0[256] = { + 0xc66363a5UL, 0xf87c7c84UL, 0xee777799UL, 0xf67b7b8dUL, + 0xfff2f20dUL, 0xd66b6bbdUL, 0xde6f6fb1UL, 0x91c5c554UL, + 0x60303050UL, 0x02010103UL, 0xce6767a9UL, 0x562b2b7dUL, + 0xe7fefe19UL, 0xb5d7d762UL, 0x4dababe6UL, 0xec76769aUL, + 0x8fcaca45UL, 0x1f82829dUL, 0x89c9c940UL, 0xfa7d7d87UL, + 0xeffafa15UL, 0xb25959ebUL, 0x8e4747c9UL, 0xfbf0f00bUL, + 0x41adadecUL, 0xb3d4d467UL, 0x5fa2a2fdUL, 0x45afafeaUL, + 0x239c9cbfUL, 0x53a4a4f7UL, 0xe4727296UL, 0x9bc0c05bUL, + 0x75b7b7c2UL, 0xe1fdfd1cUL, 0x3d9393aeUL, 0x4c26266aUL, + 0x6c36365aUL, 0x7e3f3f41UL, 0xf5f7f702UL, 0x83cccc4fUL, + 0x6834345cUL, 0x51a5a5f4UL, 0xd1e5e534UL, 0xf9f1f108UL, + 0xe2717193UL, 0xabd8d873UL, 0x62313153UL, 0x2a15153fUL, + 0x0804040cUL, 0x95c7c752UL, 0x46232365UL, 0x9dc3c35eUL, + 0x30181828UL, 0x379696a1UL, 0x0a05050fUL, 0x2f9a9ab5UL, + 0x0e070709UL, 0x24121236UL, 0x1b80809bUL, 0xdfe2e23dUL, + 0xcdebeb26UL, 0x4e272769UL, 0x7fb2b2cdUL, 0xea75759fUL, + 0x1209091bUL, 0x1d83839eUL, 0x582c2c74UL, 0x341a1a2eUL, + 0x361b1b2dUL, 0xdc6e6eb2UL, 0xb45a5aeeUL, 0x5ba0a0fbUL, + 0xa45252f6UL, 0x763b3b4dUL, 0xb7d6d661UL, 0x7db3b3ceUL, + 0x5229297bUL, 0xdde3e33eUL, 0x5e2f2f71UL, 0x13848497UL, + 0xa65353f5UL, 0xb9d1d168UL, 0x00000000UL, 0xc1eded2cUL, + 0x40202060UL, 0xe3fcfc1fUL, 0x79b1b1c8UL, 0xb65b5bedUL, + 0xd46a6abeUL, 0x8dcbcb46UL, 0x67bebed9UL, 0x7239394bUL, + 0x944a4adeUL, 0x984c4cd4UL, 0xb05858e8UL, 0x85cfcf4aUL, + 0xbbd0d06bUL, 0xc5efef2aUL, 0x4faaaae5UL, 0xedfbfb16UL, + 0x864343c5UL, 0x9a4d4dd7UL, 0x66333355UL, 0x11858594UL, + 0x8a4545cfUL, 0xe9f9f910UL, 0x04020206UL, 0xfe7f7f81UL, + 0xa05050f0UL, 0x783c3c44UL, 0x259f9fbaUL, 0x4ba8a8e3UL, + 0xa25151f3UL, 0x5da3a3feUL, 0x804040c0UL, 0x058f8f8aUL, + 0x3f9292adUL, 0x219d9dbcUL, 0x70383848UL, 0xf1f5f504UL, + 0x63bcbcdfUL, 0x77b6b6c1UL, 0xafdada75UL, 0x42212163UL, + 0x20101030UL, 0xe5ffff1aUL, 0xfdf3f30eUL, 0xbfd2d26dUL, + 0x81cdcd4cUL, 0x180c0c14UL, 0x26131335UL, 0xc3ecec2fUL, + 0xbe5f5fe1UL, 0x359797a2UL, 0x884444ccUL, 0x2e171739UL, + 0x93c4c457UL, 0x55a7a7f2UL, 0xfc7e7e82UL, 0x7a3d3d47UL, + 0xc86464acUL, 0xba5d5de7UL, 0x3219192bUL, 0xe6737395UL, + 0xc06060a0UL, 0x19818198UL, 0x9e4f4fd1UL, 0xa3dcdc7fUL, + 0x44222266UL, 0x542a2a7eUL, 0x3b9090abUL, 0x0b888883UL, + 0x8c4646caUL, 0xc7eeee29UL, 0x6bb8b8d3UL, 0x2814143cUL, + 0xa7dede79UL, 0xbc5e5ee2UL, 0x160b0b1dUL, 0xaddbdb76UL, + 0xdbe0e03bUL, 0x64323256UL, 0x743a3a4eUL, 0x140a0a1eUL, + 0x924949dbUL, 0x0c06060aUL, 0x4824246cUL, 0xb85c5ce4UL, + 0x9fc2c25dUL, 0xbdd3d36eUL, 0x43acacefUL, 0xc46262a6UL, + 0x399191a8UL, 0x319595a4UL, 0xd3e4e437UL, 0xf279798bUL, + 0xd5e7e732UL, 0x8bc8c843UL, 0x6e373759UL, 0xda6d6db7UL, + 0x018d8d8cUL, 0xb1d5d564UL, 0x9c4e4ed2UL, 0x49a9a9e0UL, + 0xd86c6cb4UL, 0xac5656faUL, 0xf3f4f407UL, 0xcfeaea25UL, + 0xca6565afUL, 0xf47a7a8eUL, 0x47aeaee9UL, 0x10080818UL, + 0x6fbabad5UL, 0xf0787888UL, 0x4a25256fUL, 0x5c2e2e72UL, + 0x381c1c24UL, 0x57a6a6f1UL, 0x73b4b4c7UL, 0x97c6c651UL, + 0xcbe8e823UL, 0xa1dddd7cUL, 0xe874749cUL, 0x3e1f1f21UL, + 0x964b4bddUL, 0x61bdbddcUL, 0x0d8b8b86UL, 0x0f8a8a85UL, + 0xe0707090UL, 0x7c3e3e42UL, 0x71b5b5c4UL, 0xcc6666aaUL, + 0x904848d8UL, 0x06030305UL, 0xf7f6f601UL, 0x1c0e0e12UL, + 0xc26161a3UL, 0x6a35355fUL, 0xae5757f9UL, 0x69b9b9d0UL, + 0x17868691UL, 0x99c1c158UL, 0x3a1d1d27UL, 0x279e9eb9UL, + 0xd9e1e138UL, 0xebf8f813UL, 0x2b9898b3UL, 0x22111133UL, + 0xd26969bbUL, 0xa9d9d970UL, 0x078e8e89UL, 0x339494a7UL, + 0x2d9b9bb6UL, 0x3c1e1e22UL, 0x15878792UL, 0xc9e9e920UL, + 0x87cece49UL, 0xaa5555ffUL, 0x50282878UL, 0xa5dfdf7aUL, + 0x038c8c8fUL, 0x59a1a1f8UL, 0x09898980UL, 0x1a0d0d17UL, + 0x65bfbfdaUL, 0xd7e6e631UL, 0x844242c6UL, 0xd06868b8UL, + 0x824141c3UL, 0x299999b0UL, 0x5a2d2d77UL, 0x1e0f0f11UL, + 0x7bb0b0cbUL, 0xa85454fcUL, 0x6dbbbbd6UL, 0x2c16163aUL, +}; + +static const ulong32 Te4[256] = { + 0x63636363UL, 0x7c7c7c7cUL, 0x77777777UL, 0x7b7b7b7bUL, + 0xf2f2f2f2UL, 0x6b6b6b6bUL, 0x6f6f6f6fUL, 0xc5c5c5c5UL, + 0x30303030UL, 0x01010101UL, 0x67676767UL, 0x2b2b2b2bUL, + 0xfefefefeUL, 0xd7d7d7d7UL, 0xababababUL, 0x76767676UL, + 0xcacacacaUL, 0x82828282UL, 0xc9c9c9c9UL, 0x7d7d7d7dUL, + 0xfafafafaUL, 0x59595959UL, 0x47474747UL, 0xf0f0f0f0UL, + 0xadadadadUL, 0xd4d4d4d4UL, 0xa2a2a2a2UL, 0xafafafafUL, + 0x9c9c9c9cUL, 0xa4a4a4a4UL, 0x72727272UL, 0xc0c0c0c0UL, + 0xb7b7b7b7UL, 0xfdfdfdfdUL, 0x93939393UL, 0x26262626UL, + 0x36363636UL, 0x3f3f3f3fUL, 0xf7f7f7f7UL, 0xccccccccUL, + 0x34343434UL, 0xa5a5a5a5UL, 0xe5e5e5e5UL, 0xf1f1f1f1UL, + 0x71717171UL, 0xd8d8d8d8UL, 0x31313131UL, 0x15151515UL, + 0x04040404UL, 0xc7c7c7c7UL, 0x23232323UL, 0xc3c3c3c3UL, + 0x18181818UL, 0x96969696UL, 0x05050505UL, 0x9a9a9a9aUL, + 0x07070707UL, 0x12121212UL, 0x80808080UL, 0xe2e2e2e2UL, + 0xebebebebUL, 0x27272727UL, 0xb2b2b2b2UL, 0x75757575UL, + 0x09090909UL, 0x83838383UL, 0x2c2c2c2cUL, 0x1a1a1a1aUL, + 0x1b1b1b1bUL, 0x6e6e6e6eUL, 0x5a5a5a5aUL, 0xa0a0a0a0UL, + 0x52525252UL, 0x3b3b3b3bUL, 0xd6d6d6d6UL, 0xb3b3b3b3UL, + 0x29292929UL, 0xe3e3e3e3UL, 0x2f2f2f2fUL, 0x84848484UL, + 0x53535353UL, 0xd1d1d1d1UL, 0x00000000UL, 0xededededUL, + 0x20202020UL, 0xfcfcfcfcUL, 0xb1b1b1b1UL, 0x5b5b5b5bUL, + 0x6a6a6a6aUL, 0xcbcbcbcbUL, 0xbebebebeUL, 0x39393939UL, + 0x4a4a4a4aUL, 0x4c4c4c4cUL, 0x58585858UL, 0xcfcfcfcfUL, + 0xd0d0d0d0UL, 0xefefefefUL, 0xaaaaaaaaUL, 0xfbfbfbfbUL, + 0x43434343UL, 0x4d4d4d4dUL, 0x33333333UL, 0x85858585UL, + 0x45454545UL, 0xf9f9f9f9UL, 0x02020202UL, 0x7f7f7f7fUL, + 0x50505050UL, 0x3c3c3c3cUL, 0x9f9f9f9fUL, 0xa8a8a8a8UL, + 0x51515151UL, 0xa3a3a3a3UL, 0x40404040UL, 0x8f8f8f8fUL, + 0x92929292UL, 0x9d9d9d9dUL, 0x38383838UL, 0xf5f5f5f5UL, + 0xbcbcbcbcUL, 0xb6b6b6b6UL, 0xdadadadaUL, 0x21212121UL, + 0x10101010UL, 0xffffffffUL, 0xf3f3f3f3UL, 0xd2d2d2d2UL, + 0xcdcdcdcdUL, 0x0c0c0c0cUL, 0x13131313UL, 0xececececUL, + 0x5f5f5f5fUL, 0x97979797UL, 0x44444444UL, 0x17171717UL, + 0xc4c4c4c4UL, 0xa7a7a7a7UL, 0x7e7e7e7eUL, 0x3d3d3d3dUL, + 0x64646464UL, 0x5d5d5d5dUL, 0x19191919UL, 0x73737373UL, + 0x60606060UL, 0x81818181UL, 0x4f4f4f4fUL, 0xdcdcdcdcUL, + 0x22222222UL, 0x2a2a2a2aUL, 0x90909090UL, 0x88888888UL, + 0x46464646UL, 0xeeeeeeeeUL, 0xb8b8b8b8UL, 0x14141414UL, + 0xdedededeUL, 0x5e5e5e5eUL, 0x0b0b0b0bUL, 0xdbdbdbdbUL, + 0xe0e0e0e0UL, 0x32323232UL, 0x3a3a3a3aUL, 0x0a0a0a0aUL, + 0x49494949UL, 0x06060606UL, 0x24242424UL, 0x5c5c5c5cUL, + 0xc2c2c2c2UL, 0xd3d3d3d3UL, 0xacacacacUL, 0x62626262UL, + 0x91919191UL, 0x95959595UL, 0xe4e4e4e4UL, 0x79797979UL, + 0xe7e7e7e7UL, 0xc8c8c8c8UL, 0x37373737UL, 0x6d6d6d6dUL, + 0x8d8d8d8dUL, 0xd5d5d5d5UL, 0x4e4e4e4eUL, 0xa9a9a9a9UL, + 0x6c6c6c6cUL, 0x56565656UL, 0xf4f4f4f4UL, 0xeaeaeaeaUL, + 0x65656565UL, 0x7a7a7a7aUL, 0xaeaeaeaeUL, 0x08080808UL, + 0xbabababaUL, 0x78787878UL, 0x25252525UL, 0x2e2e2e2eUL, + 0x1c1c1c1cUL, 0xa6a6a6a6UL, 0xb4b4b4b4UL, 0xc6c6c6c6UL, + 0xe8e8e8e8UL, 0xddddddddUL, 0x74747474UL, 0x1f1f1f1fUL, + 0x4b4b4b4bUL, 0xbdbdbdbdUL, 0x8b8b8b8bUL, 0x8a8a8a8aUL, + 0x70707070UL, 0x3e3e3e3eUL, 0xb5b5b5b5UL, 0x66666666UL, + 0x48484848UL, 0x03030303UL, 0xf6f6f6f6UL, 0x0e0e0e0eUL, + 0x61616161UL, 0x35353535UL, 0x57575757UL, 0xb9b9b9b9UL, + 0x86868686UL, 0xc1c1c1c1UL, 0x1d1d1d1dUL, 0x9e9e9e9eUL, + 0xe1e1e1e1UL, 0xf8f8f8f8UL, 0x98989898UL, 0x11111111UL, + 0x69696969UL, 0xd9d9d9d9UL, 0x8e8e8e8eUL, 0x94949494UL, + 0x9b9b9b9bUL, 0x1e1e1e1eUL, 0x87878787UL, 0xe9e9e9e9UL, + 0xcecececeUL, 0x55555555UL, 0x28282828UL, 0xdfdfdfdfUL, + 0x8c8c8c8cUL, 0xa1a1a1a1UL, 0x89898989UL, 0x0d0d0d0dUL, + 0xbfbfbfbfUL, 0xe6e6e6e6UL, 0x42424242UL, 0x68686868UL, + 0x41414141UL, 0x99999999UL, 0x2d2d2d2dUL, 0x0f0f0f0fUL, + 0xb0b0b0b0UL, 0x54545454UL, 0xbbbbbbbbUL, 0x16161616UL, +}; + +static const ulong32 TD0[256] = { + 0x51f4a750UL, 0x7e416553UL, 0x1a17a4c3UL, 0x3a275e96UL, + 0x3bab6bcbUL, 0x1f9d45f1UL, 0xacfa58abUL, 0x4be30393UL, + 0x2030fa55UL, 0xad766df6UL, 0x88cc7691UL, 0xf5024c25UL, + 0x4fe5d7fcUL, 0xc52acbd7UL, 0x26354480UL, 0xb562a38fUL, + 0xdeb15a49UL, 0x25ba1b67UL, 0x45ea0e98UL, 0x5dfec0e1UL, + 0xc32f7502UL, 0x814cf012UL, 0x8d4697a3UL, 0x6bd3f9c6UL, + 0x038f5fe7UL, 0x15929c95UL, 0xbf6d7aebUL, 0x955259daUL, + 0xd4be832dUL, 0x587421d3UL, 0x49e06929UL, 0x8ec9c844UL, + 0x75c2896aUL, 0xf48e7978UL, 0x99583e6bUL, 0x27b971ddUL, + 0xbee14fb6UL, 0xf088ad17UL, 0xc920ac66UL, 0x7dce3ab4UL, + 0x63df4a18UL, 0xe51a3182UL, 0x97513360UL, 0x62537f45UL, + 0xb16477e0UL, 0xbb6bae84UL, 0xfe81a01cUL, 0xf9082b94UL, + 0x70486858UL, 0x8f45fd19UL, 0x94de6c87UL, 0x527bf8b7UL, + 0xab73d323UL, 0x724b02e2UL, 0xe31f8f57UL, 0x6655ab2aUL, + 0xb2eb2807UL, 0x2fb5c203UL, 0x86c57b9aUL, 0xd33708a5UL, + 0x302887f2UL, 0x23bfa5b2UL, 0x02036abaUL, 0xed16825cUL, + 0x8acf1c2bUL, 0xa779b492UL, 0xf307f2f0UL, 0x4e69e2a1UL, + 0x65daf4cdUL, 0x0605bed5UL, 0xd134621fUL, 0xc4a6fe8aUL, + 0x342e539dUL, 0xa2f355a0UL, 0x058ae132UL, 0xa4f6eb75UL, + 0x0b83ec39UL, 0x4060efaaUL, 0x5e719f06UL, 0xbd6e1051UL, + 0x3e218af9UL, 0x96dd063dUL, 0xdd3e05aeUL, 0x4de6bd46UL, + 0x91548db5UL, 0x71c45d05UL, 0x0406d46fUL, 0x605015ffUL, + 0x1998fb24UL, 0xd6bde997UL, 0x894043ccUL, 0x67d99e77UL, + 0xb0e842bdUL, 0x07898b88UL, 0xe7195b38UL, 0x79c8eedbUL, + 0xa17c0a47UL, 0x7c420fe9UL, 0xf8841ec9UL, 0x00000000UL, + 0x09808683UL, 0x322bed48UL, 0x1e1170acUL, 0x6c5a724eUL, + 0xfd0efffbUL, 0x0f853856UL, 0x3daed51eUL, 0x362d3927UL, + 0x0a0fd964UL, 0x685ca621UL, 0x9b5b54d1UL, 0x24362e3aUL, + 0x0c0a67b1UL, 0x9357e70fUL, 0xb4ee96d2UL, 0x1b9b919eUL, + 0x80c0c54fUL, 0x61dc20a2UL, 0x5a774b69UL, 0x1c121a16UL, + 0xe293ba0aUL, 0xc0a02ae5UL, 0x3c22e043UL, 0x121b171dUL, + 0x0e090d0bUL, 0xf28bc7adUL, 0x2db6a8b9UL, 0x141ea9c8UL, + 0x57f11985UL, 0xaf75074cUL, 0xee99ddbbUL, 0xa37f60fdUL, + 0xf701269fUL, 0x5c72f5bcUL, 0x44663bc5UL, 0x5bfb7e34UL, + 0x8b432976UL, 0xcb23c6dcUL, 0xb6edfc68UL, 0xb8e4f163UL, + 0xd731dccaUL, 0x42638510UL, 0x13972240UL, 0x84c61120UL, + 0x854a247dUL, 0xd2bb3df8UL, 0xaef93211UL, 0xc729a16dUL, + 0x1d9e2f4bUL, 0xdcb230f3UL, 0x0d8652ecUL, 0x77c1e3d0UL, + 0x2bb3166cUL, 0xa970b999UL, 0x119448faUL, 0x47e96422UL, + 0xa8fc8cc4UL, 0xa0f03f1aUL, 0x567d2cd8UL, 0x223390efUL, + 0x87494ec7UL, 0xd938d1c1UL, 0x8ccaa2feUL, 0x98d40b36UL, + 0xa6f581cfUL, 0xa57ade28UL, 0xdab78e26UL, 0x3fadbfa4UL, + 0x2c3a9de4UL, 0x5078920dUL, 0x6a5fcc9bUL, 0x547e4662UL, + 0xf68d13c2UL, 0x90d8b8e8UL, 0x2e39f75eUL, 0x82c3aff5UL, + 0x9f5d80beUL, 0x69d0937cUL, 0x6fd52da9UL, 0xcf2512b3UL, + 0xc8ac993bUL, 0x10187da7UL, 0xe89c636eUL, 0xdb3bbb7bUL, + 0xcd267809UL, 0x6e5918f4UL, 0xec9ab701UL, 0x834f9aa8UL, + 0xe6956e65UL, 0xaaffe67eUL, 0x21bccf08UL, 0xef15e8e6UL, + 0xbae79bd9UL, 0x4a6f36ceUL, 0xea9f09d4UL, 0x29b07cd6UL, + 0x31a4b2afUL, 0x2a3f2331UL, 0xc6a59430UL, 0x35a266c0UL, + 0x744ebc37UL, 0xfc82caa6UL, 0xe090d0b0UL, 0x33a7d815UL, + 0xf104984aUL, 0x41ecdaf7UL, 0x7fcd500eUL, 0x1791f62fUL, + 0x764dd68dUL, 0x43efb04dUL, 0xccaa4d54UL, 0xe49604dfUL, + 0x9ed1b5e3UL, 0x4c6a881bUL, 0xc12c1fb8UL, 0x4665517fUL, + 0x9d5eea04UL, 0x018c355dUL, 0xfa877473UL, 0xfb0b412eUL, + 0xb3671d5aUL, 0x92dbd252UL, 0xe9105633UL, 0x6dd64713UL, + 0x9ad7618cUL, 0x37a10c7aUL, 0x59f8148eUL, 0xeb133c89UL, + 0xcea927eeUL, 0xb761c935UL, 0xe11ce5edUL, 0x7a47b13cUL, + 0x9cd2df59UL, 0x55f2733fUL, 0x1814ce79UL, 0x73c737bfUL, + 0x53f7cdeaUL, 0x5ffdaa5bUL, 0xdf3d6f14UL, 0x7844db86UL, + 0xcaaff381UL, 0xb968c43eUL, 0x3824342cUL, 0xc2a3405fUL, + 0x161dc372UL, 0xbce2250cUL, 0x283c498bUL, 0xff0d9541UL, + 0x39a80171UL, 0x080cb3deUL, 0xd8b4e49cUL, 0x6456c190UL, + 0x7bcb8461UL, 0xd532b670UL, 0x486c5c74UL, 0xd0b85742UL, +}; + +static const ulong32 Td4[256] = { + 0x52525252UL, 0x09090909UL, 0x6a6a6a6aUL, 0xd5d5d5d5UL, + 0x30303030UL, 0x36363636UL, 0xa5a5a5a5UL, 0x38383838UL, + 0xbfbfbfbfUL, 0x40404040UL, 0xa3a3a3a3UL, 0x9e9e9e9eUL, + 0x81818181UL, 0xf3f3f3f3UL, 0xd7d7d7d7UL, 0xfbfbfbfbUL, + 0x7c7c7c7cUL, 0xe3e3e3e3UL, 0x39393939UL, 0x82828282UL, + 0x9b9b9b9bUL, 0x2f2f2f2fUL, 0xffffffffUL, 0x87878787UL, + 0x34343434UL, 0x8e8e8e8eUL, 0x43434343UL, 0x44444444UL, + 0xc4c4c4c4UL, 0xdedededeUL, 0xe9e9e9e9UL, 0xcbcbcbcbUL, + 0x54545454UL, 0x7b7b7b7bUL, 0x94949494UL, 0x32323232UL, + 0xa6a6a6a6UL, 0xc2c2c2c2UL, 0x23232323UL, 0x3d3d3d3dUL, + 0xeeeeeeeeUL, 0x4c4c4c4cUL, 0x95959595UL, 0x0b0b0b0bUL, + 0x42424242UL, 0xfafafafaUL, 0xc3c3c3c3UL, 0x4e4e4e4eUL, + 0x08080808UL, 0x2e2e2e2eUL, 0xa1a1a1a1UL, 0x66666666UL, + 0x28282828UL, 0xd9d9d9d9UL, 0x24242424UL, 0xb2b2b2b2UL, + 0x76767676UL, 0x5b5b5b5bUL, 0xa2a2a2a2UL, 0x49494949UL, + 0x6d6d6d6dUL, 0x8b8b8b8bUL, 0xd1d1d1d1UL, 0x25252525UL, + 0x72727272UL, 0xf8f8f8f8UL, 0xf6f6f6f6UL, 0x64646464UL, + 0x86868686UL, 0x68686868UL, 0x98989898UL, 0x16161616UL, + 0xd4d4d4d4UL, 0xa4a4a4a4UL, 0x5c5c5c5cUL, 0xccccccccUL, + 0x5d5d5d5dUL, 0x65656565UL, 0xb6b6b6b6UL, 0x92929292UL, + 0x6c6c6c6cUL, 0x70707070UL, 0x48484848UL, 0x50505050UL, + 0xfdfdfdfdUL, 0xededededUL, 0xb9b9b9b9UL, 0xdadadadaUL, + 0x5e5e5e5eUL, 0x15151515UL, 0x46464646UL, 0x57575757UL, + 0xa7a7a7a7UL, 0x8d8d8d8dUL, 0x9d9d9d9dUL, 0x84848484UL, + 0x90909090UL, 0xd8d8d8d8UL, 0xababababUL, 0x00000000UL, + 0x8c8c8c8cUL, 0xbcbcbcbcUL, 0xd3d3d3d3UL, 0x0a0a0a0aUL, + 0xf7f7f7f7UL, 0xe4e4e4e4UL, 0x58585858UL, 0x05050505UL, + 0xb8b8b8b8UL, 0xb3b3b3b3UL, 0x45454545UL, 0x06060606UL, + 0xd0d0d0d0UL, 0x2c2c2c2cUL, 0x1e1e1e1eUL, 0x8f8f8f8fUL, + 0xcacacacaUL, 0x3f3f3f3fUL, 0x0f0f0f0fUL, 0x02020202UL, + 0xc1c1c1c1UL, 0xafafafafUL, 0xbdbdbdbdUL, 0x03030303UL, + 0x01010101UL, 0x13131313UL, 0x8a8a8a8aUL, 0x6b6b6b6bUL, + 0x3a3a3a3aUL, 0x91919191UL, 0x11111111UL, 0x41414141UL, + 0x4f4f4f4fUL, 0x67676767UL, 0xdcdcdcdcUL, 0xeaeaeaeaUL, + 0x97979797UL, 0xf2f2f2f2UL, 0xcfcfcfcfUL, 0xcecececeUL, + 0xf0f0f0f0UL, 0xb4b4b4b4UL, 0xe6e6e6e6UL, 0x73737373UL, + 0x96969696UL, 0xacacacacUL, 0x74747474UL, 0x22222222UL, + 0xe7e7e7e7UL, 0xadadadadUL, 0x35353535UL, 0x85858585UL, + 0xe2e2e2e2UL, 0xf9f9f9f9UL, 0x37373737UL, 0xe8e8e8e8UL, + 0x1c1c1c1cUL, 0x75757575UL, 0xdfdfdfdfUL, 0x6e6e6e6eUL, + 0x47474747UL, 0xf1f1f1f1UL, 0x1a1a1a1aUL, 0x71717171UL, + 0x1d1d1d1dUL, 0x29292929UL, 0xc5c5c5c5UL, 0x89898989UL, + 0x6f6f6f6fUL, 0xb7b7b7b7UL, 0x62626262UL, 0x0e0e0e0eUL, + 0xaaaaaaaaUL, 0x18181818UL, 0xbebebebeUL, 0x1b1b1b1bUL, + 0xfcfcfcfcUL, 0x56565656UL, 0x3e3e3e3eUL, 0x4b4b4b4bUL, + 0xc6c6c6c6UL, 0xd2d2d2d2UL, 0x79797979UL, 0x20202020UL, + 0x9a9a9a9aUL, 0xdbdbdbdbUL, 0xc0c0c0c0UL, 0xfefefefeUL, + 0x78787878UL, 0xcdcdcdcdUL, 0x5a5a5a5aUL, 0xf4f4f4f4UL, + 0x1f1f1f1fUL, 0xddddddddUL, 0xa8a8a8a8UL, 0x33333333UL, + 0x88888888UL, 0x07070707UL, 0xc7c7c7c7UL, 0x31313131UL, + 0xb1b1b1b1UL, 0x12121212UL, 0x10101010UL, 0x59595959UL, + 0x27272727UL, 0x80808080UL, 0xececececUL, 0x5f5f5f5fUL, + 0x60606060UL, 0x51515151UL, 0x7f7f7f7fUL, 0xa9a9a9a9UL, + 0x19191919UL, 0xb5b5b5b5UL, 0x4a4a4a4aUL, 0x0d0d0d0dUL, + 0x2d2d2d2dUL, 0xe5e5e5e5UL, 0x7a7a7a7aUL, 0x9f9f9f9fUL, + 0x93939393UL, 0xc9c9c9c9UL, 0x9c9c9c9cUL, 0xefefefefUL, + 0xa0a0a0a0UL, 0xe0e0e0e0UL, 0x3b3b3b3bUL, 0x4d4d4d4dUL, + 0xaeaeaeaeUL, 0x2a2a2a2aUL, 0xf5f5f5f5UL, 0xb0b0b0b0UL, + 0xc8c8c8c8UL, 0xebebebebUL, 0xbbbbbbbbUL, 0x3c3c3c3cUL, + 0x83838383UL, 0x53535353UL, 0x99999999UL, 0x61616161UL, + 0x17171717UL, 0x2b2b2b2bUL, 0x04040404UL, 0x7e7e7e7eUL, + 0xbabababaUL, 0x77777777UL, 0xd6d6d6d6UL, 0x26262626UL, + 0xe1e1e1e1UL, 0x69696969UL, 0x14141414UL, 0x63636363UL, + 0x55555555UL, 0x21212121UL, 0x0c0c0c0cUL, 0x7d7d7d7dUL, +}; + +#ifdef SMALL_CODE + +#define Te0(x) TE0[x] +#define Te1(x) ROR(TE0[x], 8) +#define Te2(x) ROR(TE0[x], 16) +#define Te3(x) ROR(TE0[x], 24) + +#define Td0(x) TD0[x] +#define Td1(x) ROR(TD0[x], 8) +#define Td2(x) ROR(TD0[x], 16) +#define Td3(x) ROR(TD0[x], 24) + +#define Te4_0 0x000000FF & Te4 +#define Te4_1 0x0000FF00 & Te4 +#define Te4_2 0x00FF0000 & Te4 +#define Te4_3 0xFF000000 & Te4 + +#else + +#define Te0(x) TE0[x] +#define Te1(x) TE1[x] +#define Te2(x) TE2[x] +#define Te3(x) TE3[x] + +#define Td0(x) TD0[x] +#define Td1(x) TD1[x] +#define Td2(x) TD2[x] +#define Td3(x) TD3[x] + +static const ulong32 TE1[256] = { + 0xa5c66363UL, 0x84f87c7cUL, 0x99ee7777UL, 0x8df67b7bUL, + 0x0dfff2f2UL, 0xbdd66b6bUL, 0xb1de6f6fUL, 0x5491c5c5UL, + 0x50603030UL, 0x03020101UL, 0xa9ce6767UL, 0x7d562b2bUL, + 0x19e7fefeUL, 0x62b5d7d7UL, 0xe64dababUL, 0x9aec7676UL, + 0x458fcacaUL, 0x9d1f8282UL, 0x4089c9c9UL, 0x87fa7d7dUL, + 0x15effafaUL, 0xebb25959UL, 0xc98e4747UL, 0x0bfbf0f0UL, + 0xec41adadUL, 0x67b3d4d4UL, 0xfd5fa2a2UL, 0xea45afafUL, + 0xbf239c9cUL, 0xf753a4a4UL, 0x96e47272UL, 0x5b9bc0c0UL, + 0xc275b7b7UL, 0x1ce1fdfdUL, 0xae3d9393UL, 0x6a4c2626UL, + 0x5a6c3636UL, 0x417e3f3fUL, 0x02f5f7f7UL, 0x4f83ccccUL, + 0x5c683434UL, 0xf451a5a5UL, 0x34d1e5e5UL, 0x08f9f1f1UL, + 0x93e27171UL, 0x73abd8d8UL, 0x53623131UL, 0x3f2a1515UL, + 0x0c080404UL, 0x5295c7c7UL, 0x65462323UL, 0x5e9dc3c3UL, + 0x28301818UL, 0xa1379696UL, 0x0f0a0505UL, 0xb52f9a9aUL, + 0x090e0707UL, 0x36241212UL, 0x9b1b8080UL, 0x3ddfe2e2UL, + 0x26cdebebUL, 0x694e2727UL, 0xcd7fb2b2UL, 0x9fea7575UL, + 0x1b120909UL, 0x9e1d8383UL, 0x74582c2cUL, 0x2e341a1aUL, + 0x2d361b1bUL, 0xb2dc6e6eUL, 0xeeb45a5aUL, 0xfb5ba0a0UL, + 0xf6a45252UL, 0x4d763b3bUL, 0x61b7d6d6UL, 0xce7db3b3UL, + 0x7b522929UL, 0x3edde3e3UL, 0x715e2f2fUL, 0x97138484UL, + 0xf5a65353UL, 0x68b9d1d1UL, 0x00000000UL, 0x2cc1ededUL, + 0x60402020UL, 0x1fe3fcfcUL, 0xc879b1b1UL, 0xedb65b5bUL, + 0xbed46a6aUL, 0x468dcbcbUL, 0xd967bebeUL, 0x4b723939UL, + 0xde944a4aUL, 0xd4984c4cUL, 0xe8b05858UL, 0x4a85cfcfUL, + 0x6bbbd0d0UL, 0x2ac5efefUL, 0xe54faaaaUL, 0x16edfbfbUL, + 0xc5864343UL, 0xd79a4d4dUL, 0x55663333UL, 0x94118585UL, + 0xcf8a4545UL, 0x10e9f9f9UL, 0x06040202UL, 0x81fe7f7fUL, + 0xf0a05050UL, 0x44783c3cUL, 0xba259f9fUL, 0xe34ba8a8UL, + 0xf3a25151UL, 0xfe5da3a3UL, 0xc0804040UL, 0x8a058f8fUL, + 0xad3f9292UL, 0xbc219d9dUL, 0x48703838UL, 0x04f1f5f5UL, + 0xdf63bcbcUL, 0xc177b6b6UL, 0x75afdadaUL, 0x63422121UL, + 0x30201010UL, 0x1ae5ffffUL, 0x0efdf3f3UL, 0x6dbfd2d2UL, + 0x4c81cdcdUL, 0x14180c0cUL, 0x35261313UL, 0x2fc3ececUL, + 0xe1be5f5fUL, 0xa2359797UL, 0xcc884444UL, 0x392e1717UL, + 0x5793c4c4UL, 0xf255a7a7UL, 0x82fc7e7eUL, 0x477a3d3dUL, + 0xacc86464UL, 0xe7ba5d5dUL, 0x2b321919UL, 0x95e67373UL, + 0xa0c06060UL, 0x98198181UL, 0xd19e4f4fUL, 0x7fa3dcdcUL, + 0x66442222UL, 0x7e542a2aUL, 0xab3b9090UL, 0x830b8888UL, + 0xca8c4646UL, 0x29c7eeeeUL, 0xd36bb8b8UL, 0x3c281414UL, + 0x79a7dedeUL, 0xe2bc5e5eUL, 0x1d160b0bUL, 0x76addbdbUL, + 0x3bdbe0e0UL, 0x56643232UL, 0x4e743a3aUL, 0x1e140a0aUL, + 0xdb924949UL, 0x0a0c0606UL, 0x6c482424UL, 0xe4b85c5cUL, + 0x5d9fc2c2UL, 0x6ebdd3d3UL, 0xef43acacUL, 0xa6c46262UL, + 0xa8399191UL, 0xa4319595UL, 0x37d3e4e4UL, 0x8bf27979UL, + 0x32d5e7e7UL, 0x438bc8c8UL, 0x596e3737UL, 0xb7da6d6dUL, + 0x8c018d8dUL, 0x64b1d5d5UL, 0xd29c4e4eUL, 0xe049a9a9UL, + 0xb4d86c6cUL, 0xfaac5656UL, 0x07f3f4f4UL, 0x25cfeaeaUL, + 0xafca6565UL, 0x8ef47a7aUL, 0xe947aeaeUL, 0x18100808UL, + 0xd56fbabaUL, 0x88f07878UL, 0x6f4a2525UL, 0x725c2e2eUL, + 0x24381c1cUL, 0xf157a6a6UL, 0xc773b4b4UL, 0x5197c6c6UL, + 0x23cbe8e8UL, 0x7ca1ddddUL, 0x9ce87474UL, 0x213e1f1fUL, + 0xdd964b4bUL, 0xdc61bdbdUL, 0x860d8b8bUL, 0x850f8a8aUL, + 0x90e07070UL, 0x427c3e3eUL, 0xc471b5b5UL, 0xaacc6666UL, + 0xd8904848UL, 0x05060303UL, 0x01f7f6f6UL, 0x121c0e0eUL, + 0xa3c26161UL, 0x5f6a3535UL, 0xf9ae5757UL, 0xd069b9b9UL, + 0x91178686UL, 0x5899c1c1UL, 0x273a1d1dUL, 0xb9279e9eUL, + 0x38d9e1e1UL, 0x13ebf8f8UL, 0xb32b9898UL, 0x33221111UL, + 0xbbd26969UL, 0x70a9d9d9UL, 0x89078e8eUL, 0xa7339494UL, + 0xb62d9b9bUL, 0x223c1e1eUL, 0x92158787UL, 0x20c9e9e9UL, + 0x4987ceceUL, 0xffaa5555UL, 0x78502828UL, 0x7aa5dfdfUL, + 0x8f038c8cUL, 0xf859a1a1UL, 0x80098989UL, 0x171a0d0dUL, + 0xda65bfbfUL, 0x31d7e6e6UL, 0xc6844242UL, 0xb8d06868UL, + 0xc3824141UL, 0xb0299999UL, 0x775a2d2dUL, 0x111e0f0fUL, + 0xcb7bb0b0UL, 0xfca85454UL, 0xd66dbbbbUL, 0x3a2c1616UL, +}; +static const ulong32 TE2[256] = { + 0x63a5c663UL, 0x7c84f87cUL, 0x7799ee77UL, 0x7b8df67bUL, + 0xf20dfff2UL, 0x6bbdd66bUL, 0x6fb1de6fUL, 0xc55491c5UL, + 0x30506030UL, 0x01030201UL, 0x67a9ce67UL, 0x2b7d562bUL, + 0xfe19e7feUL, 0xd762b5d7UL, 0xabe64dabUL, 0x769aec76UL, + 0xca458fcaUL, 0x829d1f82UL, 0xc94089c9UL, 0x7d87fa7dUL, + 0xfa15effaUL, 0x59ebb259UL, 0x47c98e47UL, 0xf00bfbf0UL, + 0xadec41adUL, 0xd467b3d4UL, 0xa2fd5fa2UL, 0xafea45afUL, + 0x9cbf239cUL, 0xa4f753a4UL, 0x7296e472UL, 0xc05b9bc0UL, + 0xb7c275b7UL, 0xfd1ce1fdUL, 0x93ae3d93UL, 0x266a4c26UL, + 0x365a6c36UL, 0x3f417e3fUL, 0xf702f5f7UL, 0xcc4f83ccUL, + 0x345c6834UL, 0xa5f451a5UL, 0xe534d1e5UL, 0xf108f9f1UL, + 0x7193e271UL, 0xd873abd8UL, 0x31536231UL, 0x153f2a15UL, + 0x040c0804UL, 0xc75295c7UL, 0x23654623UL, 0xc35e9dc3UL, + 0x18283018UL, 0x96a13796UL, 0x050f0a05UL, 0x9ab52f9aUL, + 0x07090e07UL, 0x12362412UL, 0x809b1b80UL, 0xe23ddfe2UL, + 0xeb26cdebUL, 0x27694e27UL, 0xb2cd7fb2UL, 0x759fea75UL, + 0x091b1209UL, 0x839e1d83UL, 0x2c74582cUL, 0x1a2e341aUL, + 0x1b2d361bUL, 0x6eb2dc6eUL, 0x5aeeb45aUL, 0xa0fb5ba0UL, + 0x52f6a452UL, 0x3b4d763bUL, 0xd661b7d6UL, 0xb3ce7db3UL, + 0x297b5229UL, 0xe33edde3UL, 0x2f715e2fUL, 0x84971384UL, + 0x53f5a653UL, 0xd168b9d1UL, 0x00000000UL, 0xed2cc1edUL, + 0x20604020UL, 0xfc1fe3fcUL, 0xb1c879b1UL, 0x5bedb65bUL, + 0x6abed46aUL, 0xcb468dcbUL, 0xbed967beUL, 0x394b7239UL, + 0x4ade944aUL, 0x4cd4984cUL, 0x58e8b058UL, 0xcf4a85cfUL, + 0xd06bbbd0UL, 0xef2ac5efUL, 0xaae54faaUL, 0xfb16edfbUL, + 0x43c58643UL, 0x4dd79a4dUL, 0x33556633UL, 0x85941185UL, + 0x45cf8a45UL, 0xf910e9f9UL, 0x02060402UL, 0x7f81fe7fUL, + 0x50f0a050UL, 0x3c44783cUL, 0x9fba259fUL, 0xa8e34ba8UL, + 0x51f3a251UL, 0xa3fe5da3UL, 0x40c08040UL, 0x8f8a058fUL, + 0x92ad3f92UL, 0x9dbc219dUL, 0x38487038UL, 0xf504f1f5UL, + 0xbcdf63bcUL, 0xb6c177b6UL, 0xda75afdaUL, 0x21634221UL, + 0x10302010UL, 0xff1ae5ffUL, 0xf30efdf3UL, 0xd26dbfd2UL, + 0xcd4c81cdUL, 0x0c14180cUL, 0x13352613UL, 0xec2fc3ecUL, + 0x5fe1be5fUL, 0x97a23597UL, 0x44cc8844UL, 0x17392e17UL, + 0xc45793c4UL, 0xa7f255a7UL, 0x7e82fc7eUL, 0x3d477a3dUL, + 0x64acc864UL, 0x5de7ba5dUL, 0x192b3219UL, 0x7395e673UL, + 0x60a0c060UL, 0x81981981UL, 0x4fd19e4fUL, 0xdc7fa3dcUL, + 0x22664422UL, 0x2a7e542aUL, 0x90ab3b90UL, 0x88830b88UL, + 0x46ca8c46UL, 0xee29c7eeUL, 0xb8d36bb8UL, 0x143c2814UL, + 0xde79a7deUL, 0x5ee2bc5eUL, 0x0b1d160bUL, 0xdb76addbUL, + 0xe03bdbe0UL, 0x32566432UL, 0x3a4e743aUL, 0x0a1e140aUL, + 0x49db9249UL, 0x060a0c06UL, 0x246c4824UL, 0x5ce4b85cUL, + 0xc25d9fc2UL, 0xd36ebdd3UL, 0xacef43acUL, 0x62a6c462UL, + 0x91a83991UL, 0x95a43195UL, 0xe437d3e4UL, 0x798bf279UL, + 0xe732d5e7UL, 0xc8438bc8UL, 0x37596e37UL, 0x6db7da6dUL, + 0x8d8c018dUL, 0xd564b1d5UL, 0x4ed29c4eUL, 0xa9e049a9UL, + 0x6cb4d86cUL, 0x56faac56UL, 0xf407f3f4UL, 0xea25cfeaUL, + 0x65afca65UL, 0x7a8ef47aUL, 0xaee947aeUL, 0x08181008UL, + 0xbad56fbaUL, 0x7888f078UL, 0x256f4a25UL, 0x2e725c2eUL, + 0x1c24381cUL, 0xa6f157a6UL, 0xb4c773b4UL, 0xc65197c6UL, + 0xe823cbe8UL, 0xdd7ca1ddUL, 0x749ce874UL, 0x1f213e1fUL, + 0x4bdd964bUL, 0xbddc61bdUL, 0x8b860d8bUL, 0x8a850f8aUL, + 0x7090e070UL, 0x3e427c3eUL, 0xb5c471b5UL, 0x66aacc66UL, + 0x48d89048UL, 0x03050603UL, 0xf601f7f6UL, 0x0e121c0eUL, + 0x61a3c261UL, 0x355f6a35UL, 0x57f9ae57UL, 0xb9d069b9UL, + 0x86911786UL, 0xc15899c1UL, 0x1d273a1dUL, 0x9eb9279eUL, + 0xe138d9e1UL, 0xf813ebf8UL, 0x98b32b98UL, 0x11332211UL, + 0x69bbd269UL, 0xd970a9d9UL, 0x8e89078eUL, 0x94a73394UL, + 0x9bb62d9bUL, 0x1e223c1eUL, 0x87921587UL, 0xe920c9e9UL, + 0xce4987ceUL, 0x55ffaa55UL, 0x28785028UL, 0xdf7aa5dfUL, + 0x8c8f038cUL, 0xa1f859a1UL, 0x89800989UL, 0x0d171a0dUL, + 0xbfda65bfUL, 0xe631d7e6UL, 0x42c68442UL, 0x68b8d068UL, + 0x41c38241UL, 0x99b02999UL, 0x2d775a2dUL, 0x0f111e0fUL, + 0xb0cb7bb0UL, 0x54fca854UL, 0xbbd66dbbUL, 0x163a2c16UL, +}; +static const ulong32 TE3[256] = { + + 0x6363a5c6UL, 0x7c7c84f8UL, 0x777799eeUL, 0x7b7b8df6UL, + 0xf2f20dffUL, 0x6b6bbdd6UL, 0x6f6fb1deUL, 0xc5c55491UL, + 0x30305060UL, 0x01010302UL, 0x6767a9ceUL, 0x2b2b7d56UL, + 0xfefe19e7UL, 0xd7d762b5UL, 0xababe64dUL, 0x76769aecUL, + 0xcaca458fUL, 0x82829d1fUL, 0xc9c94089UL, 0x7d7d87faUL, + 0xfafa15efUL, 0x5959ebb2UL, 0x4747c98eUL, 0xf0f00bfbUL, + 0xadadec41UL, 0xd4d467b3UL, 0xa2a2fd5fUL, 0xafafea45UL, + 0x9c9cbf23UL, 0xa4a4f753UL, 0x727296e4UL, 0xc0c05b9bUL, + 0xb7b7c275UL, 0xfdfd1ce1UL, 0x9393ae3dUL, 0x26266a4cUL, + 0x36365a6cUL, 0x3f3f417eUL, 0xf7f702f5UL, 0xcccc4f83UL, + 0x34345c68UL, 0xa5a5f451UL, 0xe5e534d1UL, 0xf1f108f9UL, + 0x717193e2UL, 0xd8d873abUL, 0x31315362UL, 0x15153f2aUL, + 0x04040c08UL, 0xc7c75295UL, 0x23236546UL, 0xc3c35e9dUL, + 0x18182830UL, 0x9696a137UL, 0x05050f0aUL, 0x9a9ab52fUL, + 0x0707090eUL, 0x12123624UL, 0x80809b1bUL, 0xe2e23ddfUL, + 0xebeb26cdUL, 0x2727694eUL, 0xb2b2cd7fUL, 0x75759feaUL, + 0x09091b12UL, 0x83839e1dUL, 0x2c2c7458UL, 0x1a1a2e34UL, + 0x1b1b2d36UL, 0x6e6eb2dcUL, 0x5a5aeeb4UL, 0xa0a0fb5bUL, + 0x5252f6a4UL, 0x3b3b4d76UL, 0xd6d661b7UL, 0xb3b3ce7dUL, + 0x29297b52UL, 0xe3e33eddUL, 0x2f2f715eUL, 0x84849713UL, + 0x5353f5a6UL, 0xd1d168b9UL, 0x00000000UL, 0xeded2cc1UL, + 0x20206040UL, 0xfcfc1fe3UL, 0xb1b1c879UL, 0x5b5bedb6UL, + 0x6a6abed4UL, 0xcbcb468dUL, 0xbebed967UL, 0x39394b72UL, + 0x4a4ade94UL, 0x4c4cd498UL, 0x5858e8b0UL, 0xcfcf4a85UL, + 0xd0d06bbbUL, 0xefef2ac5UL, 0xaaaae54fUL, 0xfbfb16edUL, + 0x4343c586UL, 0x4d4dd79aUL, 0x33335566UL, 0x85859411UL, + 0x4545cf8aUL, 0xf9f910e9UL, 0x02020604UL, 0x7f7f81feUL, + 0x5050f0a0UL, 0x3c3c4478UL, 0x9f9fba25UL, 0xa8a8e34bUL, + 0x5151f3a2UL, 0xa3a3fe5dUL, 0x4040c080UL, 0x8f8f8a05UL, + 0x9292ad3fUL, 0x9d9dbc21UL, 0x38384870UL, 0xf5f504f1UL, + 0xbcbcdf63UL, 0xb6b6c177UL, 0xdada75afUL, 0x21216342UL, + 0x10103020UL, 0xffff1ae5UL, 0xf3f30efdUL, 0xd2d26dbfUL, + 0xcdcd4c81UL, 0x0c0c1418UL, 0x13133526UL, 0xecec2fc3UL, + 0x5f5fe1beUL, 0x9797a235UL, 0x4444cc88UL, 0x1717392eUL, + 0xc4c45793UL, 0xa7a7f255UL, 0x7e7e82fcUL, 0x3d3d477aUL, + 0x6464acc8UL, 0x5d5de7baUL, 0x19192b32UL, 0x737395e6UL, + 0x6060a0c0UL, 0x81819819UL, 0x4f4fd19eUL, 0xdcdc7fa3UL, + 0x22226644UL, 0x2a2a7e54UL, 0x9090ab3bUL, 0x8888830bUL, + 0x4646ca8cUL, 0xeeee29c7UL, 0xb8b8d36bUL, 0x14143c28UL, + 0xdede79a7UL, 0x5e5ee2bcUL, 0x0b0b1d16UL, 0xdbdb76adUL, + 0xe0e03bdbUL, 0x32325664UL, 0x3a3a4e74UL, 0x0a0a1e14UL, + 0x4949db92UL, 0x06060a0cUL, 0x24246c48UL, 0x5c5ce4b8UL, + 0xc2c25d9fUL, 0xd3d36ebdUL, 0xacacef43UL, 0x6262a6c4UL, + 0x9191a839UL, 0x9595a431UL, 0xe4e437d3UL, 0x79798bf2UL, + 0xe7e732d5UL, 0xc8c8438bUL, 0x3737596eUL, 0x6d6db7daUL, + 0x8d8d8c01UL, 0xd5d564b1UL, 0x4e4ed29cUL, 0xa9a9e049UL, + 0x6c6cb4d8UL, 0x5656faacUL, 0xf4f407f3UL, 0xeaea25cfUL, + 0x6565afcaUL, 0x7a7a8ef4UL, 0xaeaee947UL, 0x08081810UL, + 0xbabad56fUL, 0x787888f0UL, 0x25256f4aUL, 0x2e2e725cUL, + 0x1c1c2438UL, 0xa6a6f157UL, 0xb4b4c773UL, 0xc6c65197UL, + 0xe8e823cbUL, 0xdddd7ca1UL, 0x74749ce8UL, 0x1f1f213eUL, + 0x4b4bdd96UL, 0xbdbddc61UL, 0x8b8b860dUL, 0x8a8a850fUL, + 0x707090e0UL, 0x3e3e427cUL, 0xb5b5c471UL, 0x6666aaccUL, + 0x4848d890UL, 0x03030506UL, 0xf6f601f7UL, 0x0e0e121cUL, + 0x6161a3c2UL, 0x35355f6aUL, 0x5757f9aeUL, 0xb9b9d069UL, + 0x86869117UL, 0xc1c15899UL, 0x1d1d273aUL, 0x9e9eb927UL, + 0xe1e138d9UL, 0xf8f813ebUL, 0x9898b32bUL, 0x11113322UL, + 0x6969bbd2UL, 0xd9d970a9UL, 0x8e8e8907UL, 0x9494a733UL, + 0x9b9bb62dUL, 0x1e1e223cUL, 0x87879215UL, 0xe9e920c9UL, + 0xcece4987UL, 0x5555ffaaUL, 0x28287850UL, 0xdfdf7aa5UL, + 0x8c8c8f03UL, 0xa1a1f859UL, 0x89898009UL, 0x0d0d171aUL, + 0xbfbfda65UL, 0xe6e631d7UL, 0x4242c684UL, 0x6868b8d0UL, + 0x4141c382UL, 0x9999b029UL, 0x2d2d775aUL, 0x0f0f111eUL, + 0xb0b0cb7bUL, 0x5454fca8UL, 0xbbbbd66dUL, 0x16163a2cUL, +}; + +static const ulong32 Te4_0[] = { +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 +}; + +static const ulong32 Te4_1[] = { +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 +}; + +static const ulong32 Te4_2[] = { +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 +}; + +static const ulong32 Te4_3[] = { +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 ulong32 TD1[256] = { + 0x5051f4a7UL, 0x537e4165UL, 0xc31a17a4UL, 0x963a275eUL, + 0xcb3bab6bUL, 0xf11f9d45UL, 0xabacfa58UL, 0x934be303UL, + 0x552030faUL, 0xf6ad766dUL, 0x9188cc76UL, 0x25f5024cUL, + 0xfc4fe5d7UL, 0xd7c52acbUL, 0x80263544UL, 0x8fb562a3UL, + 0x49deb15aUL, 0x6725ba1bUL, 0x9845ea0eUL, 0xe15dfec0UL, + 0x02c32f75UL, 0x12814cf0UL, 0xa38d4697UL, 0xc66bd3f9UL, + 0xe7038f5fUL, 0x9515929cUL, 0xebbf6d7aUL, 0xda955259UL, + 0x2dd4be83UL, 0xd3587421UL, 0x2949e069UL, 0x448ec9c8UL, + 0x6a75c289UL, 0x78f48e79UL, 0x6b99583eUL, 0xdd27b971UL, + 0xb6bee14fUL, 0x17f088adUL, 0x66c920acUL, 0xb47dce3aUL, + 0x1863df4aUL, 0x82e51a31UL, 0x60975133UL, 0x4562537fUL, + 0xe0b16477UL, 0x84bb6baeUL, 0x1cfe81a0UL, 0x94f9082bUL, + 0x58704868UL, 0x198f45fdUL, 0x8794de6cUL, 0xb7527bf8UL, + 0x23ab73d3UL, 0xe2724b02UL, 0x57e31f8fUL, 0x2a6655abUL, + 0x07b2eb28UL, 0x032fb5c2UL, 0x9a86c57bUL, 0xa5d33708UL, + 0xf2302887UL, 0xb223bfa5UL, 0xba02036aUL, 0x5ced1682UL, + 0x2b8acf1cUL, 0x92a779b4UL, 0xf0f307f2UL, 0xa14e69e2UL, + 0xcd65daf4UL, 0xd50605beUL, 0x1fd13462UL, 0x8ac4a6feUL, + 0x9d342e53UL, 0xa0a2f355UL, 0x32058ae1UL, 0x75a4f6ebUL, + 0x390b83ecUL, 0xaa4060efUL, 0x065e719fUL, 0x51bd6e10UL, + 0xf93e218aUL, 0x3d96dd06UL, 0xaedd3e05UL, 0x464de6bdUL, + 0xb591548dUL, 0x0571c45dUL, 0x6f0406d4UL, 0xff605015UL, + 0x241998fbUL, 0x97d6bde9UL, 0xcc894043UL, 0x7767d99eUL, + 0xbdb0e842UL, 0x8807898bUL, 0x38e7195bUL, 0xdb79c8eeUL, + 0x47a17c0aUL, 0xe97c420fUL, 0xc9f8841eUL, 0x00000000UL, + 0x83098086UL, 0x48322bedUL, 0xac1e1170UL, 0x4e6c5a72UL, + 0xfbfd0effUL, 0x560f8538UL, 0x1e3daed5UL, 0x27362d39UL, + 0x640a0fd9UL, 0x21685ca6UL, 0xd19b5b54UL, 0x3a24362eUL, + 0xb10c0a67UL, 0x0f9357e7UL, 0xd2b4ee96UL, 0x9e1b9b91UL, + 0x4f80c0c5UL, 0xa261dc20UL, 0x695a774bUL, 0x161c121aUL, + 0x0ae293baUL, 0xe5c0a02aUL, 0x433c22e0UL, 0x1d121b17UL, + 0x0b0e090dUL, 0xadf28bc7UL, 0xb92db6a8UL, 0xc8141ea9UL, + 0x8557f119UL, 0x4caf7507UL, 0xbbee99ddUL, 0xfda37f60UL, + 0x9ff70126UL, 0xbc5c72f5UL, 0xc544663bUL, 0x345bfb7eUL, + 0x768b4329UL, 0xdccb23c6UL, 0x68b6edfcUL, 0x63b8e4f1UL, + 0xcad731dcUL, 0x10426385UL, 0x40139722UL, 0x2084c611UL, + 0x7d854a24UL, 0xf8d2bb3dUL, 0x11aef932UL, 0x6dc729a1UL, + 0x4b1d9e2fUL, 0xf3dcb230UL, 0xec0d8652UL, 0xd077c1e3UL, + 0x6c2bb316UL, 0x99a970b9UL, 0xfa119448UL, 0x2247e964UL, + 0xc4a8fc8cUL, 0x1aa0f03fUL, 0xd8567d2cUL, 0xef223390UL, + 0xc787494eUL, 0xc1d938d1UL, 0xfe8ccaa2UL, 0x3698d40bUL, + 0xcfa6f581UL, 0x28a57adeUL, 0x26dab78eUL, 0xa43fadbfUL, + 0xe42c3a9dUL, 0x0d507892UL, 0x9b6a5fccUL, 0x62547e46UL, + 0xc2f68d13UL, 0xe890d8b8UL, 0x5e2e39f7UL, 0xf582c3afUL, + 0xbe9f5d80UL, 0x7c69d093UL, 0xa96fd52dUL, 0xb3cf2512UL, + 0x3bc8ac99UL, 0xa710187dUL, 0x6ee89c63UL, 0x7bdb3bbbUL, + 0x09cd2678UL, 0xf46e5918UL, 0x01ec9ab7UL, 0xa8834f9aUL, + 0x65e6956eUL, 0x7eaaffe6UL, 0x0821bccfUL, 0xe6ef15e8UL, + 0xd9bae79bUL, 0xce4a6f36UL, 0xd4ea9f09UL, 0xd629b07cUL, + 0xaf31a4b2UL, 0x312a3f23UL, 0x30c6a594UL, 0xc035a266UL, + 0x37744ebcUL, 0xa6fc82caUL, 0xb0e090d0UL, 0x1533a7d8UL, + 0x4af10498UL, 0xf741ecdaUL, 0x0e7fcd50UL, 0x2f1791f6UL, + 0x8d764dd6UL, 0x4d43efb0UL, 0x54ccaa4dUL, 0xdfe49604UL, + 0xe39ed1b5UL, 0x1b4c6a88UL, 0xb8c12c1fUL, 0x7f466551UL, + 0x049d5eeaUL, 0x5d018c35UL, 0x73fa8774UL, 0x2efb0b41UL, + 0x5ab3671dUL, 0x5292dbd2UL, 0x33e91056UL, 0x136dd647UL, + 0x8c9ad761UL, 0x7a37a10cUL, 0x8e59f814UL, 0x89eb133cUL, + 0xeecea927UL, 0x35b761c9UL, 0xede11ce5UL, 0x3c7a47b1UL, + 0x599cd2dfUL, 0x3f55f273UL, 0x791814ceUL, 0xbf73c737UL, + 0xea53f7cdUL, 0x5b5ffdaaUL, 0x14df3d6fUL, 0x867844dbUL, + 0x81caaff3UL, 0x3eb968c4UL, 0x2c382434UL, 0x5fc2a340UL, + 0x72161dc3UL, 0x0cbce225UL, 0x8b283c49UL, 0x41ff0d95UL, + 0x7139a801UL, 0xde080cb3UL, 0x9cd8b4e4UL, 0x906456c1UL, + 0x617bcb84UL, 0x70d532b6UL, 0x74486c5cUL, 0x42d0b857UL, +}; +static const ulong32 TD2[256] = { + 0xa75051f4UL, 0x65537e41UL, 0xa4c31a17UL, 0x5e963a27UL, + 0x6bcb3babUL, 0x45f11f9dUL, 0x58abacfaUL, 0x03934be3UL, + 0xfa552030UL, 0x6df6ad76UL, 0x769188ccUL, 0x4c25f502UL, + 0xd7fc4fe5UL, 0xcbd7c52aUL, 0x44802635UL, 0xa38fb562UL, + 0x5a49deb1UL, 0x1b6725baUL, 0x0e9845eaUL, 0xc0e15dfeUL, + 0x7502c32fUL, 0xf012814cUL, 0x97a38d46UL, 0xf9c66bd3UL, + 0x5fe7038fUL, 0x9c951592UL, 0x7aebbf6dUL, 0x59da9552UL, + 0x832dd4beUL, 0x21d35874UL, 0x692949e0UL, 0xc8448ec9UL, + 0x896a75c2UL, 0x7978f48eUL, 0x3e6b9958UL, 0x71dd27b9UL, + 0x4fb6bee1UL, 0xad17f088UL, 0xac66c920UL, 0x3ab47dceUL, + 0x4a1863dfUL, 0x3182e51aUL, 0x33609751UL, 0x7f456253UL, + 0x77e0b164UL, 0xae84bb6bUL, 0xa01cfe81UL, 0x2b94f908UL, + 0x68587048UL, 0xfd198f45UL, 0x6c8794deUL, 0xf8b7527bUL, + 0xd323ab73UL, 0x02e2724bUL, 0x8f57e31fUL, 0xab2a6655UL, + 0x2807b2ebUL, 0xc2032fb5UL, 0x7b9a86c5UL, 0x08a5d337UL, + 0x87f23028UL, 0xa5b223bfUL, 0x6aba0203UL, 0x825ced16UL, + 0x1c2b8acfUL, 0xb492a779UL, 0xf2f0f307UL, 0xe2a14e69UL, + 0xf4cd65daUL, 0xbed50605UL, 0x621fd134UL, 0xfe8ac4a6UL, + 0x539d342eUL, 0x55a0a2f3UL, 0xe132058aUL, 0xeb75a4f6UL, + 0xec390b83UL, 0xefaa4060UL, 0x9f065e71UL, 0x1051bd6eUL, + 0x8af93e21UL, 0x063d96ddUL, 0x05aedd3eUL, 0xbd464de6UL, + 0x8db59154UL, 0x5d0571c4UL, 0xd46f0406UL, 0x15ff6050UL, + 0xfb241998UL, 0xe997d6bdUL, 0x43cc8940UL, 0x9e7767d9UL, + 0x42bdb0e8UL, 0x8b880789UL, 0x5b38e719UL, 0xeedb79c8UL, + 0x0a47a17cUL, 0x0fe97c42UL, 0x1ec9f884UL, 0x00000000UL, + 0x86830980UL, 0xed48322bUL, 0x70ac1e11UL, 0x724e6c5aUL, + 0xfffbfd0eUL, 0x38560f85UL, 0xd51e3daeUL, 0x3927362dUL, + 0xd9640a0fUL, 0xa621685cUL, 0x54d19b5bUL, 0x2e3a2436UL, + 0x67b10c0aUL, 0xe70f9357UL, 0x96d2b4eeUL, 0x919e1b9bUL, + 0xc54f80c0UL, 0x20a261dcUL, 0x4b695a77UL, 0x1a161c12UL, + 0xba0ae293UL, 0x2ae5c0a0UL, 0xe0433c22UL, 0x171d121bUL, + 0x0d0b0e09UL, 0xc7adf28bUL, 0xa8b92db6UL, 0xa9c8141eUL, + 0x198557f1UL, 0x074caf75UL, 0xddbbee99UL, 0x60fda37fUL, + 0x269ff701UL, 0xf5bc5c72UL, 0x3bc54466UL, 0x7e345bfbUL, + 0x29768b43UL, 0xc6dccb23UL, 0xfc68b6edUL, 0xf163b8e4UL, + 0xdccad731UL, 0x85104263UL, 0x22401397UL, 0x112084c6UL, + 0x247d854aUL, 0x3df8d2bbUL, 0x3211aef9UL, 0xa16dc729UL, + 0x2f4b1d9eUL, 0x30f3dcb2UL, 0x52ec0d86UL, 0xe3d077c1UL, + 0x166c2bb3UL, 0xb999a970UL, 0x48fa1194UL, 0x642247e9UL, + 0x8cc4a8fcUL, 0x3f1aa0f0UL, 0x2cd8567dUL, 0x90ef2233UL, + 0x4ec78749UL, 0xd1c1d938UL, 0xa2fe8ccaUL, 0x0b3698d4UL, + 0x81cfa6f5UL, 0xde28a57aUL, 0x8e26dab7UL, 0xbfa43fadUL, + 0x9de42c3aUL, 0x920d5078UL, 0xcc9b6a5fUL, 0x4662547eUL, + 0x13c2f68dUL, 0xb8e890d8UL, 0xf75e2e39UL, 0xaff582c3UL, + 0x80be9f5dUL, 0x937c69d0UL, 0x2da96fd5UL, 0x12b3cf25UL, + 0x993bc8acUL, 0x7da71018UL, 0x636ee89cUL, 0xbb7bdb3bUL, + 0x7809cd26UL, 0x18f46e59UL, 0xb701ec9aUL, 0x9aa8834fUL, + 0x6e65e695UL, 0xe67eaaffUL, 0xcf0821bcUL, 0xe8e6ef15UL, + 0x9bd9bae7UL, 0x36ce4a6fUL, 0x09d4ea9fUL, 0x7cd629b0UL, + 0xb2af31a4UL, 0x23312a3fUL, 0x9430c6a5UL, 0x66c035a2UL, + 0xbc37744eUL, 0xcaa6fc82UL, 0xd0b0e090UL, 0xd81533a7UL, + 0x984af104UL, 0xdaf741ecUL, 0x500e7fcdUL, 0xf62f1791UL, + 0xd68d764dUL, 0xb04d43efUL, 0x4d54ccaaUL, 0x04dfe496UL, + 0xb5e39ed1UL, 0x881b4c6aUL, 0x1fb8c12cUL, 0x517f4665UL, + 0xea049d5eUL, 0x355d018cUL, 0x7473fa87UL, 0x412efb0bUL, + 0x1d5ab367UL, 0xd25292dbUL, 0x5633e910UL, 0x47136dd6UL, + 0x618c9ad7UL, 0x0c7a37a1UL, 0x148e59f8UL, 0x3c89eb13UL, + 0x27eecea9UL, 0xc935b761UL, 0xe5ede11cUL, 0xb13c7a47UL, + 0xdf599cd2UL, 0x733f55f2UL, 0xce791814UL, 0x37bf73c7UL, + 0xcdea53f7UL, 0xaa5b5ffdUL, 0x6f14df3dUL, 0xdb867844UL, + 0xf381caafUL, 0xc43eb968UL, 0x342c3824UL, 0x405fc2a3UL, + 0xc372161dUL, 0x250cbce2UL, 0x498b283cUL, 0x9541ff0dUL, + 0x017139a8UL, 0xb3de080cUL, 0xe49cd8b4UL, 0xc1906456UL, + 0x84617bcbUL, 0xb670d532UL, 0x5c74486cUL, 0x5742d0b8UL, +}; +static const ulong32 TD3[256] = { + 0xf4a75051UL, 0x4165537eUL, 0x17a4c31aUL, 0x275e963aUL, + 0xab6bcb3bUL, 0x9d45f11fUL, 0xfa58abacUL, 0xe303934bUL, + 0x30fa5520UL, 0x766df6adUL, 0xcc769188UL, 0x024c25f5UL, + 0xe5d7fc4fUL, 0x2acbd7c5UL, 0x35448026UL, 0x62a38fb5UL, + 0xb15a49deUL, 0xba1b6725UL, 0xea0e9845UL, 0xfec0e15dUL, + 0x2f7502c3UL, 0x4cf01281UL, 0x4697a38dUL, 0xd3f9c66bUL, + 0x8f5fe703UL, 0x929c9515UL, 0x6d7aebbfUL, 0x5259da95UL, + 0xbe832dd4UL, 0x7421d358UL, 0xe0692949UL, 0xc9c8448eUL, + 0xc2896a75UL, 0x8e7978f4UL, 0x583e6b99UL, 0xb971dd27UL, + 0xe14fb6beUL, 0x88ad17f0UL, 0x20ac66c9UL, 0xce3ab47dUL, + 0xdf4a1863UL, 0x1a3182e5UL, 0x51336097UL, 0x537f4562UL, + 0x6477e0b1UL, 0x6bae84bbUL, 0x81a01cfeUL, 0x082b94f9UL, + 0x48685870UL, 0x45fd198fUL, 0xde6c8794UL, 0x7bf8b752UL, + 0x73d323abUL, 0x4b02e272UL, 0x1f8f57e3UL, 0x55ab2a66UL, + 0xeb2807b2UL, 0xb5c2032fUL, 0xc57b9a86UL, 0x3708a5d3UL, + 0x2887f230UL, 0xbfa5b223UL, 0x036aba02UL, 0x16825cedUL, + 0xcf1c2b8aUL, 0x79b492a7UL, 0x07f2f0f3UL, 0x69e2a14eUL, + 0xdaf4cd65UL, 0x05bed506UL, 0x34621fd1UL, 0xa6fe8ac4UL, + 0x2e539d34UL, 0xf355a0a2UL, 0x8ae13205UL, 0xf6eb75a4UL, + 0x83ec390bUL, 0x60efaa40UL, 0x719f065eUL, 0x6e1051bdUL, + 0x218af93eUL, 0xdd063d96UL, 0x3e05aeddUL, 0xe6bd464dUL, + 0x548db591UL, 0xc45d0571UL, 0x06d46f04UL, 0x5015ff60UL, + 0x98fb2419UL, 0xbde997d6UL, 0x4043cc89UL, 0xd99e7767UL, + 0xe842bdb0UL, 0x898b8807UL, 0x195b38e7UL, 0xc8eedb79UL, + 0x7c0a47a1UL, 0x420fe97cUL, 0x841ec9f8UL, 0x00000000UL, + 0x80868309UL, 0x2bed4832UL, 0x1170ac1eUL, 0x5a724e6cUL, + 0x0efffbfdUL, 0x8538560fUL, 0xaed51e3dUL, 0x2d392736UL, + 0x0fd9640aUL, 0x5ca62168UL, 0x5b54d19bUL, 0x362e3a24UL, + 0x0a67b10cUL, 0x57e70f93UL, 0xee96d2b4UL, 0x9b919e1bUL, + 0xc0c54f80UL, 0xdc20a261UL, 0x774b695aUL, 0x121a161cUL, + 0x93ba0ae2UL, 0xa02ae5c0UL, 0x22e0433cUL, 0x1b171d12UL, + 0x090d0b0eUL, 0x8bc7adf2UL, 0xb6a8b92dUL, 0x1ea9c814UL, + 0xf1198557UL, 0x75074cafUL, 0x99ddbbeeUL, 0x7f60fda3UL, + 0x01269ff7UL, 0x72f5bc5cUL, 0x663bc544UL, 0xfb7e345bUL, + 0x4329768bUL, 0x23c6dccbUL, 0xedfc68b6UL, 0xe4f163b8UL, + 0x31dccad7UL, 0x63851042UL, 0x97224013UL, 0xc6112084UL, + 0x4a247d85UL, 0xbb3df8d2UL, 0xf93211aeUL, 0x29a16dc7UL, + 0x9e2f4b1dUL, 0xb230f3dcUL, 0x8652ec0dUL, 0xc1e3d077UL, + 0xb3166c2bUL, 0x70b999a9UL, 0x9448fa11UL, 0xe9642247UL, + 0xfc8cc4a8UL, 0xf03f1aa0UL, 0x7d2cd856UL, 0x3390ef22UL, + 0x494ec787UL, 0x38d1c1d9UL, 0xcaa2fe8cUL, 0xd40b3698UL, + 0xf581cfa6UL, 0x7ade28a5UL, 0xb78e26daUL, 0xadbfa43fUL, + 0x3a9de42cUL, 0x78920d50UL, 0x5fcc9b6aUL, 0x7e466254UL, + 0x8d13c2f6UL, 0xd8b8e890UL, 0x39f75e2eUL, 0xc3aff582UL, + 0x5d80be9fUL, 0xd0937c69UL, 0xd52da96fUL, 0x2512b3cfUL, + 0xac993bc8UL, 0x187da710UL, 0x9c636ee8UL, 0x3bbb7bdbUL, + 0x267809cdUL, 0x5918f46eUL, 0x9ab701ecUL, 0x4f9aa883UL, + 0x956e65e6UL, 0xffe67eaaUL, 0xbccf0821UL, 0x15e8e6efUL, + 0xe79bd9baUL, 0x6f36ce4aUL, 0x9f09d4eaUL, 0xb07cd629UL, + 0xa4b2af31UL, 0x3f23312aUL, 0xa59430c6UL, 0xa266c035UL, + 0x4ebc3774UL, 0x82caa6fcUL, 0x90d0b0e0UL, 0xa7d81533UL, + 0x04984af1UL, 0xecdaf741UL, 0xcd500e7fUL, 0x91f62f17UL, + 0x4dd68d76UL, 0xefb04d43UL, 0xaa4d54ccUL, 0x9604dfe4UL, + 0xd1b5e39eUL, 0x6a881b4cUL, 0x2c1fb8c1UL, 0x65517f46UL, + 0x5eea049dUL, 0x8c355d01UL, 0x877473faUL, 0x0b412efbUL, + 0x671d5ab3UL, 0xdbd25292UL, 0x105633e9UL, 0xd647136dUL, + 0xd7618c9aUL, 0xa10c7a37UL, 0xf8148e59UL, 0x133c89ebUL, + 0xa927eeceUL, 0x61c935b7UL, 0x1ce5ede1UL, 0x47b13c7aUL, + 0xd2df599cUL, 0xf2733f55UL, 0x14ce7918UL, 0xc737bf73UL, + 0xf7cdea53UL, 0xfdaa5b5fUL, 0x3d6f14dfUL, 0x44db8678UL, + 0xaff381caUL, 0x68c43eb9UL, 0x24342c38UL, 0xa3405fc2UL, + 0x1dc37216UL, 0xe2250cbcUL, 0x3c498b28UL, 0x0d9541ffUL, + 0xa8017139UL, 0x0cb3de08UL, 0xb4e49cd8UL, 0x56c19064UL, + 0xcb84617bUL, 0x32b670d5UL, 0x6c5c7448UL, 0xb85742d0UL, +}; + +static const ulong32 Tks0[] = { +0x00000000UL, 0x0e090d0bUL, 0x1c121a16UL, 0x121b171dUL, 0x3824342cUL, 0x362d3927UL, 0x24362e3aUL, 0x2a3f2331UL, +0x70486858UL, 0x7e416553UL, 0x6c5a724eUL, 0x62537f45UL, 0x486c5c74UL, 0x4665517fUL, 0x547e4662UL, 0x5a774b69UL, +0xe090d0b0UL, 0xee99ddbbUL, 0xfc82caa6UL, 0xf28bc7adUL, 0xd8b4e49cUL, 0xd6bde997UL, 0xc4a6fe8aUL, 0xcaaff381UL, +0x90d8b8e8UL, 0x9ed1b5e3UL, 0x8ccaa2feUL, 0x82c3aff5UL, 0xa8fc8cc4UL, 0xa6f581cfUL, 0xb4ee96d2UL, 0xbae79bd9UL, +0xdb3bbb7bUL, 0xd532b670UL, 0xc729a16dUL, 0xc920ac66UL, 0xe31f8f57UL, 0xed16825cUL, 0xff0d9541UL, 0xf104984aUL, +0xab73d323UL, 0xa57ade28UL, 0xb761c935UL, 0xb968c43eUL, 0x9357e70fUL, 0x9d5eea04UL, 0x8f45fd19UL, 0x814cf012UL, +0x3bab6bcbUL, 0x35a266c0UL, 0x27b971ddUL, 0x29b07cd6UL, 0x038f5fe7UL, 0x0d8652ecUL, 0x1f9d45f1UL, 0x119448faUL, +0x4be30393UL, 0x45ea0e98UL, 0x57f11985UL, 0x59f8148eUL, 0x73c737bfUL, 0x7dce3ab4UL, 0x6fd52da9UL, 0x61dc20a2UL, +0xad766df6UL, 0xa37f60fdUL, 0xb16477e0UL, 0xbf6d7aebUL, 0x955259daUL, 0x9b5b54d1UL, 0x894043ccUL, 0x87494ec7UL, +0xdd3e05aeUL, 0xd33708a5UL, 0xc12c1fb8UL, 0xcf2512b3UL, 0xe51a3182UL, 0xeb133c89UL, 0xf9082b94UL, 0xf701269fUL, +0x4de6bd46UL, 0x43efb04dUL, 0x51f4a750UL, 0x5ffdaa5bUL, 0x75c2896aUL, 0x7bcb8461UL, 0x69d0937cUL, 0x67d99e77UL, +0x3daed51eUL, 0x33a7d815UL, 0x21bccf08UL, 0x2fb5c203UL, 0x058ae132UL, 0x0b83ec39UL, 0x1998fb24UL, 0x1791f62fUL, +0x764dd68dUL, 0x7844db86UL, 0x6a5fcc9bUL, 0x6456c190UL, 0x4e69e2a1UL, 0x4060efaaUL, 0x527bf8b7UL, 0x5c72f5bcUL, +0x0605bed5UL, 0x080cb3deUL, 0x1a17a4c3UL, 0x141ea9c8UL, 0x3e218af9UL, 0x302887f2UL, 0x223390efUL, 0x2c3a9de4UL, +0x96dd063dUL, 0x98d40b36UL, 0x8acf1c2bUL, 0x84c61120UL, 0xaef93211UL, 0xa0f03f1aUL, 0xb2eb2807UL, 0xbce2250cUL, +0xe6956e65UL, 0xe89c636eUL, 0xfa877473UL, 0xf48e7978UL, 0xdeb15a49UL, 0xd0b85742UL, 0xc2a3405fUL, 0xccaa4d54UL, +0x41ecdaf7UL, 0x4fe5d7fcUL, 0x5dfec0e1UL, 0x53f7cdeaUL, 0x79c8eedbUL, 0x77c1e3d0UL, 0x65daf4cdUL, 0x6bd3f9c6UL, +0x31a4b2afUL, 0x3fadbfa4UL, 0x2db6a8b9UL, 0x23bfa5b2UL, 0x09808683UL, 0x07898b88UL, 0x15929c95UL, 0x1b9b919eUL, +0xa17c0a47UL, 0xaf75074cUL, 0xbd6e1051UL, 0xb3671d5aUL, 0x99583e6bUL, 0x97513360UL, 0x854a247dUL, 0x8b432976UL, +0xd134621fUL, 0xdf3d6f14UL, 0xcd267809UL, 0xc32f7502UL, 0xe9105633UL, 0xe7195b38UL, 0xf5024c25UL, 0xfb0b412eUL, +0x9ad7618cUL, 0x94de6c87UL, 0x86c57b9aUL, 0x88cc7691UL, 0xa2f355a0UL, 0xacfa58abUL, 0xbee14fb6UL, 0xb0e842bdUL, +0xea9f09d4UL, 0xe49604dfUL, 0xf68d13c2UL, 0xf8841ec9UL, 0xd2bb3df8UL, 0xdcb230f3UL, 0xcea927eeUL, 0xc0a02ae5UL, +0x7a47b13cUL, 0x744ebc37UL, 0x6655ab2aUL, 0x685ca621UL, 0x42638510UL, 0x4c6a881bUL, 0x5e719f06UL, 0x5078920dUL, +0x0a0fd964UL, 0x0406d46fUL, 0x161dc372UL, 0x1814ce79UL, 0x322bed48UL, 0x3c22e043UL, 0x2e39f75eUL, 0x2030fa55UL, +0xec9ab701UL, 0xe293ba0aUL, 0xf088ad17UL, 0xfe81a01cUL, 0xd4be832dUL, 0xdab78e26UL, 0xc8ac993bUL, 0xc6a59430UL, +0x9cd2df59UL, 0x92dbd252UL, 0x80c0c54fUL, 0x8ec9c844UL, 0xa4f6eb75UL, 0xaaffe67eUL, 0xb8e4f163UL, 0xb6edfc68UL, +0x0c0a67b1UL, 0x02036abaUL, 0x10187da7UL, 0x1e1170acUL, 0x342e539dUL, 0x3a275e96UL, 0x283c498bUL, 0x26354480UL, +0x7c420fe9UL, 0x724b02e2UL, 0x605015ffUL, 0x6e5918f4UL, 0x44663bc5UL, 0x4a6f36ceUL, 0x587421d3UL, 0x567d2cd8UL, +0x37a10c7aUL, 0x39a80171UL, 0x2bb3166cUL, 0x25ba1b67UL, 0x0f853856UL, 0x018c355dUL, 0x13972240UL, 0x1d9e2f4bUL, +0x47e96422UL, 0x49e06929UL, 0x5bfb7e34UL, 0x55f2733fUL, 0x7fcd500eUL, 0x71c45d05UL, 0x63df4a18UL, 0x6dd64713UL, +0xd731dccaUL, 0xd938d1c1UL, 0xcb23c6dcUL, 0xc52acbd7UL, 0xef15e8e6UL, 0xe11ce5edUL, 0xf307f2f0UL, 0xfd0efffbUL, +0xa779b492UL, 0xa970b999UL, 0xbb6bae84UL, 0xb562a38fUL, 0x9f5d80beUL, 0x91548db5UL, 0x834f9aa8UL, 0x8d4697a3UL +}; + +static const ulong32 Tks1[] = { +0x00000000UL, 0x0b0e090dUL, 0x161c121aUL, 0x1d121b17UL, 0x2c382434UL, 0x27362d39UL, 0x3a24362eUL, 0x312a3f23UL, +0x58704868UL, 0x537e4165UL, 0x4e6c5a72UL, 0x4562537fUL, 0x74486c5cUL, 0x7f466551UL, 0x62547e46UL, 0x695a774bUL, +0xb0e090d0UL, 0xbbee99ddUL, 0xa6fc82caUL, 0xadf28bc7UL, 0x9cd8b4e4UL, 0x97d6bde9UL, 0x8ac4a6feUL, 0x81caaff3UL, +0xe890d8b8UL, 0xe39ed1b5UL, 0xfe8ccaa2UL, 0xf582c3afUL, 0xc4a8fc8cUL, 0xcfa6f581UL, 0xd2b4ee96UL, 0xd9bae79bUL, +0x7bdb3bbbUL, 0x70d532b6UL, 0x6dc729a1UL, 0x66c920acUL, 0x57e31f8fUL, 0x5ced1682UL, 0x41ff0d95UL, 0x4af10498UL, +0x23ab73d3UL, 0x28a57adeUL, 0x35b761c9UL, 0x3eb968c4UL, 0x0f9357e7UL, 0x049d5eeaUL, 0x198f45fdUL, 0x12814cf0UL, +0xcb3bab6bUL, 0xc035a266UL, 0xdd27b971UL, 0xd629b07cUL, 0xe7038f5fUL, 0xec0d8652UL, 0xf11f9d45UL, 0xfa119448UL, +0x934be303UL, 0x9845ea0eUL, 0x8557f119UL, 0x8e59f814UL, 0xbf73c737UL, 0xb47dce3aUL, 0xa96fd52dUL, 0xa261dc20UL, +0xf6ad766dUL, 0xfda37f60UL, 0xe0b16477UL, 0xebbf6d7aUL, 0xda955259UL, 0xd19b5b54UL, 0xcc894043UL, 0xc787494eUL, +0xaedd3e05UL, 0xa5d33708UL, 0xb8c12c1fUL, 0xb3cf2512UL, 0x82e51a31UL, 0x89eb133cUL, 0x94f9082bUL, 0x9ff70126UL, +0x464de6bdUL, 0x4d43efb0UL, 0x5051f4a7UL, 0x5b5ffdaaUL, 0x6a75c289UL, 0x617bcb84UL, 0x7c69d093UL, 0x7767d99eUL, +0x1e3daed5UL, 0x1533a7d8UL, 0x0821bccfUL, 0x032fb5c2UL, 0x32058ae1UL, 0x390b83ecUL, 0x241998fbUL, 0x2f1791f6UL, +0x8d764dd6UL, 0x867844dbUL, 0x9b6a5fccUL, 0x906456c1UL, 0xa14e69e2UL, 0xaa4060efUL, 0xb7527bf8UL, 0xbc5c72f5UL, +0xd50605beUL, 0xde080cb3UL, 0xc31a17a4UL, 0xc8141ea9UL, 0xf93e218aUL, 0xf2302887UL, 0xef223390UL, 0xe42c3a9dUL, +0x3d96dd06UL, 0x3698d40bUL, 0x2b8acf1cUL, 0x2084c611UL, 0x11aef932UL, 0x1aa0f03fUL, 0x07b2eb28UL, 0x0cbce225UL, +0x65e6956eUL, 0x6ee89c63UL, 0x73fa8774UL, 0x78f48e79UL, 0x49deb15aUL, 0x42d0b857UL, 0x5fc2a340UL, 0x54ccaa4dUL, +0xf741ecdaUL, 0xfc4fe5d7UL, 0xe15dfec0UL, 0xea53f7cdUL, 0xdb79c8eeUL, 0xd077c1e3UL, 0xcd65daf4UL, 0xc66bd3f9UL, +0xaf31a4b2UL, 0xa43fadbfUL, 0xb92db6a8UL, 0xb223bfa5UL, 0x83098086UL, 0x8807898bUL, 0x9515929cUL, 0x9e1b9b91UL, +0x47a17c0aUL, 0x4caf7507UL, 0x51bd6e10UL, 0x5ab3671dUL, 0x6b99583eUL, 0x60975133UL, 0x7d854a24UL, 0x768b4329UL, +0x1fd13462UL, 0x14df3d6fUL, 0x09cd2678UL, 0x02c32f75UL, 0x33e91056UL, 0x38e7195bUL, 0x25f5024cUL, 0x2efb0b41UL, +0x8c9ad761UL, 0x8794de6cUL, 0x9a86c57bUL, 0x9188cc76UL, 0xa0a2f355UL, 0xabacfa58UL, 0xb6bee14fUL, 0xbdb0e842UL, +0xd4ea9f09UL, 0xdfe49604UL, 0xc2f68d13UL, 0xc9f8841eUL, 0xf8d2bb3dUL, 0xf3dcb230UL, 0xeecea927UL, 0xe5c0a02aUL, +0x3c7a47b1UL, 0x37744ebcUL, 0x2a6655abUL, 0x21685ca6UL, 0x10426385UL, 0x1b4c6a88UL, 0x065e719fUL, 0x0d507892UL, +0x640a0fd9UL, 0x6f0406d4UL, 0x72161dc3UL, 0x791814ceUL, 0x48322bedUL, 0x433c22e0UL, 0x5e2e39f7UL, 0x552030faUL, +0x01ec9ab7UL, 0x0ae293baUL, 0x17f088adUL, 0x1cfe81a0UL, 0x2dd4be83UL, 0x26dab78eUL, 0x3bc8ac99UL, 0x30c6a594UL, +0x599cd2dfUL, 0x5292dbd2UL, 0x4f80c0c5UL, 0x448ec9c8UL, 0x75a4f6ebUL, 0x7eaaffe6UL, 0x63b8e4f1UL, 0x68b6edfcUL, +0xb10c0a67UL, 0xba02036aUL, 0xa710187dUL, 0xac1e1170UL, 0x9d342e53UL, 0x963a275eUL, 0x8b283c49UL, 0x80263544UL, +0xe97c420fUL, 0xe2724b02UL, 0xff605015UL, 0xf46e5918UL, 0xc544663bUL, 0xce4a6f36UL, 0xd3587421UL, 0xd8567d2cUL, +0x7a37a10cUL, 0x7139a801UL, 0x6c2bb316UL, 0x6725ba1bUL, 0x560f8538UL, 0x5d018c35UL, 0x40139722UL, 0x4b1d9e2fUL, +0x2247e964UL, 0x2949e069UL, 0x345bfb7eUL, 0x3f55f273UL, 0x0e7fcd50UL, 0x0571c45dUL, 0x1863df4aUL, 0x136dd647UL, +0xcad731dcUL, 0xc1d938d1UL, 0xdccb23c6UL, 0xd7c52acbUL, 0xe6ef15e8UL, 0xede11ce5UL, 0xf0f307f2UL, 0xfbfd0effUL, +0x92a779b4UL, 0x99a970b9UL, 0x84bb6baeUL, 0x8fb562a3UL, 0xbe9f5d80UL, 0xb591548dUL, 0xa8834f9aUL, 0xa38d4697UL +}; + +static const ulong32 Tks2[] = { +0x00000000UL, 0x0d0b0e09UL, 0x1a161c12UL, 0x171d121bUL, 0x342c3824UL, 0x3927362dUL, 0x2e3a2436UL, 0x23312a3fUL, +0x68587048UL, 0x65537e41UL, 0x724e6c5aUL, 0x7f456253UL, 0x5c74486cUL, 0x517f4665UL, 0x4662547eUL, 0x4b695a77UL, +0xd0b0e090UL, 0xddbbee99UL, 0xcaa6fc82UL, 0xc7adf28bUL, 0xe49cd8b4UL, 0xe997d6bdUL, 0xfe8ac4a6UL, 0xf381caafUL, +0xb8e890d8UL, 0xb5e39ed1UL, 0xa2fe8ccaUL, 0xaff582c3UL, 0x8cc4a8fcUL, 0x81cfa6f5UL, 0x96d2b4eeUL, 0x9bd9bae7UL, +0xbb7bdb3bUL, 0xb670d532UL, 0xa16dc729UL, 0xac66c920UL, 0x8f57e31fUL, 0x825ced16UL, 0x9541ff0dUL, 0x984af104UL, +0xd323ab73UL, 0xde28a57aUL, 0xc935b761UL, 0xc43eb968UL, 0xe70f9357UL, 0xea049d5eUL, 0xfd198f45UL, 0xf012814cUL, +0x6bcb3babUL, 0x66c035a2UL, 0x71dd27b9UL, 0x7cd629b0UL, 0x5fe7038fUL, 0x52ec0d86UL, 0x45f11f9dUL, 0x48fa1194UL, +0x03934be3UL, 0x0e9845eaUL, 0x198557f1UL, 0x148e59f8UL, 0x37bf73c7UL, 0x3ab47dceUL, 0x2da96fd5UL, 0x20a261dcUL, +0x6df6ad76UL, 0x60fda37fUL, 0x77e0b164UL, 0x7aebbf6dUL, 0x59da9552UL, 0x54d19b5bUL, 0x43cc8940UL, 0x4ec78749UL, +0x05aedd3eUL, 0x08a5d337UL, 0x1fb8c12cUL, 0x12b3cf25UL, 0x3182e51aUL, 0x3c89eb13UL, 0x2b94f908UL, 0x269ff701UL, +0xbd464de6UL, 0xb04d43efUL, 0xa75051f4UL, 0xaa5b5ffdUL, 0x896a75c2UL, 0x84617bcbUL, 0x937c69d0UL, 0x9e7767d9UL, +0xd51e3daeUL, 0xd81533a7UL, 0xcf0821bcUL, 0xc2032fb5UL, 0xe132058aUL, 0xec390b83UL, 0xfb241998UL, 0xf62f1791UL, +0xd68d764dUL, 0xdb867844UL, 0xcc9b6a5fUL, 0xc1906456UL, 0xe2a14e69UL, 0xefaa4060UL, 0xf8b7527bUL, 0xf5bc5c72UL, +0xbed50605UL, 0xb3de080cUL, 0xa4c31a17UL, 0xa9c8141eUL, 0x8af93e21UL, 0x87f23028UL, 0x90ef2233UL, 0x9de42c3aUL, +0x063d96ddUL, 0x0b3698d4UL, 0x1c2b8acfUL, 0x112084c6UL, 0x3211aef9UL, 0x3f1aa0f0UL, 0x2807b2ebUL, 0x250cbce2UL, +0x6e65e695UL, 0x636ee89cUL, 0x7473fa87UL, 0x7978f48eUL, 0x5a49deb1UL, 0x5742d0b8UL, 0x405fc2a3UL, 0x4d54ccaaUL, +0xdaf741ecUL, 0xd7fc4fe5UL, 0xc0e15dfeUL, 0xcdea53f7UL, 0xeedb79c8UL, 0xe3d077c1UL, 0xf4cd65daUL, 0xf9c66bd3UL, +0xb2af31a4UL, 0xbfa43fadUL, 0xa8b92db6UL, 0xa5b223bfUL, 0x86830980UL, 0x8b880789UL, 0x9c951592UL, 0x919e1b9bUL, +0x0a47a17cUL, 0x074caf75UL, 0x1051bd6eUL, 0x1d5ab367UL, 0x3e6b9958UL, 0x33609751UL, 0x247d854aUL, 0x29768b43UL, +0x621fd134UL, 0x6f14df3dUL, 0x7809cd26UL, 0x7502c32fUL, 0x5633e910UL, 0x5b38e719UL, 0x4c25f502UL, 0x412efb0bUL, +0x618c9ad7UL, 0x6c8794deUL, 0x7b9a86c5UL, 0x769188ccUL, 0x55a0a2f3UL, 0x58abacfaUL, 0x4fb6bee1UL, 0x42bdb0e8UL, +0x09d4ea9fUL, 0x04dfe496UL, 0x13c2f68dUL, 0x1ec9f884UL, 0x3df8d2bbUL, 0x30f3dcb2UL, 0x27eecea9UL, 0x2ae5c0a0UL, +0xb13c7a47UL, 0xbc37744eUL, 0xab2a6655UL, 0xa621685cUL, 0x85104263UL, 0x881b4c6aUL, 0x9f065e71UL, 0x920d5078UL, +0xd9640a0fUL, 0xd46f0406UL, 0xc372161dUL, 0xce791814UL, 0xed48322bUL, 0xe0433c22UL, 0xf75e2e39UL, 0xfa552030UL, +0xb701ec9aUL, 0xba0ae293UL, 0xad17f088UL, 0xa01cfe81UL, 0x832dd4beUL, 0x8e26dab7UL, 0x993bc8acUL, 0x9430c6a5UL, +0xdf599cd2UL, 0xd25292dbUL, 0xc54f80c0UL, 0xc8448ec9UL, 0xeb75a4f6UL, 0xe67eaaffUL, 0xf163b8e4UL, 0xfc68b6edUL, +0x67b10c0aUL, 0x6aba0203UL, 0x7da71018UL, 0x70ac1e11UL, 0x539d342eUL, 0x5e963a27UL, 0x498b283cUL, 0x44802635UL, +0x0fe97c42UL, 0x02e2724bUL, 0x15ff6050UL, 0x18f46e59UL, 0x3bc54466UL, 0x36ce4a6fUL, 0x21d35874UL, 0x2cd8567dUL, +0x0c7a37a1UL, 0x017139a8UL, 0x166c2bb3UL, 0x1b6725baUL, 0x38560f85UL, 0x355d018cUL, 0x22401397UL, 0x2f4b1d9eUL, +0x642247e9UL, 0x692949e0UL, 0x7e345bfbUL, 0x733f55f2UL, 0x500e7fcdUL, 0x5d0571c4UL, 0x4a1863dfUL, 0x47136dd6UL, +0xdccad731UL, 0xd1c1d938UL, 0xc6dccb23UL, 0xcbd7c52aUL, 0xe8e6ef15UL, 0xe5ede11cUL, 0xf2f0f307UL, 0xfffbfd0eUL, +0xb492a779UL, 0xb999a970UL, 0xae84bb6bUL, 0xa38fb562UL, 0x80be9f5dUL, 0x8db59154UL, 0x9aa8834fUL, 0x97a38d46UL +}; + +static const ulong32 Tks3[] = { +0x00000000UL, 0x090d0b0eUL, 0x121a161cUL, 0x1b171d12UL, 0x24342c38UL, 0x2d392736UL, 0x362e3a24UL, 0x3f23312aUL, +0x48685870UL, 0x4165537eUL, 0x5a724e6cUL, 0x537f4562UL, 0x6c5c7448UL, 0x65517f46UL, 0x7e466254UL, 0x774b695aUL, +0x90d0b0e0UL, 0x99ddbbeeUL, 0x82caa6fcUL, 0x8bc7adf2UL, 0xb4e49cd8UL, 0xbde997d6UL, 0xa6fe8ac4UL, 0xaff381caUL, +0xd8b8e890UL, 0xd1b5e39eUL, 0xcaa2fe8cUL, 0xc3aff582UL, 0xfc8cc4a8UL, 0xf581cfa6UL, 0xee96d2b4UL, 0xe79bd9baUL, +0x3bbb7bdbUL, 0x32b670d5UL, 0x29a16dc7UL, 0x20ac66c9UL, 0x1f8f57e3UL, 0x16825cedUL, 0x0d9541ffUL, 0x04984af1UL, +0x73d323abUL, 0x7ade28a5UL, 0x61c935b7UL, 0x68c43eb9UL, 0x57e70f93UL, 0x5eea049dUL, 0x45fd198fUL, 0x4cf01281UL, +0xab6bcb3bUL, 0xa266c035UL, 0xb971dd27UL, 0xb07cd629UL, 0x8f5fe703UL, 0x8652ec0dUL, 0x9d45f11fUL, 0x9448fa11UL, +0xe303934bUL, 0xea0e9845UL, 0xf1198557UL, 0xf8148e59UL, 0xc737bf73UL, 0xce3ab47dUL, 0xd52da96fUL, 0xdc20a261UL, +0x766df6adUL, 0x7f60fda3UL, 0x6477e0b1UL, 0x6d7aebbfUL, 0x5259da95UL, 0x5b54d19bUL, 0x4043cc89UL, 0x494ec787UL, +0x3e05aeddUL, 0x3708a5d3UL, 0x2c1fb8c1UL, 0x2512b3cfUL, 0x1a3182e5UL, 0x133c89ebUL, 0x082b94f9UL, 0x01269ff7UL, +0xe6bd464dUL, 0xefb04d43UL, 0xf4a75051UL, 0xfdaa5b5fUL, 0xc2896a75UL, 0xcb84617bUL, 0xd0937c69UL, 0xd99e7767UL, +0xaed51e3dUL, 0xa7d81533UL, 0xbccf0821UL, 0xb5c2032fUL, 0x8ae13205UL, 0x83ec390bUL, 0x98fb2419UL, 0x91f62f17UL, +0x4dd68d76UL, 0x44db8678UL, 0x5fcc9b6aUL, 0x56c19064UL, 0x69e2a14eUL, 0x60efaa40UL, 0x7bf8b752UL, 0x72f5bc5cUL, +0x05bed506UL, 0x0cb3de08UL, 0x17a4c31aUL, 0x1ea9c814UL, 0x218af93eUL, 0x2887f230UL, 0x3390ef22UL, 0x3a9de42cUL, +0xdd063d96UL, 0xd40b3698UL, 0xcf1c2b8aUL, 0xc6112084UL, 0xf93211aeUL, 0xf03f1aa0UL, 0xeb2807b2UL, 0xe2250cbcUL, +0x956e65e6UL, 0x9c636ee8UL, 0x877473faUL, 0x8e7978f4UL, 0xb15a49deUL, 0xb85742d0UL, 0xa3405fc2UL, 0xaa4d54ccUL, +0xecdaf741UL, 0xe5d7fc4fUL, 0xfec0e15dUL, 0xf7cdea53UL, 0xc8eedb79UL, 0xc1e3d077UL, 0xdaf4cd65UL, 0xd3f9c66bUL, +0xa4b2af31UL, 0xadbfa43fUL, 0xb6a8b92dUL, 0xbfa5b223UL, 0x80868309UL, 0x898b8807UL, 0x929c9515UL, 0x9b919e1bUL, +0x7c0a47a1UL, 0x75074cafUL, 0x6e1051bdUL, 0x671d5ab3UL, 0x583e6b99UL, 0x51336097UL, 0x4a247d85UL, 0x4329768bUL, +0x34621fd1UL, 0x3d6f14dfUL, 0x267809cdUL, 0x2f7502c3UL, 0x105633e9UL, 0x195b38e7UL, 0x024c25f5UL, 0x0b412efbUL, +0xd7618c9aUL, 0xde6c8794UL, 0xc57b9a86UL, 0xcc769188UL, 0xf355a0a2UL, 0xfa58abacUL, 0xe14fb6beUL, 0xe842bdb0UL, +0x9f09d4eaUL, 0x9604dfe4UL, 0x8d13c2f6UL, 0x841ec9f8UL, 0xbb3df8d2UL, 0xb230f3dcUL, 0xa927eeceUL, 0xa02ae5c0UL, +0x47b13c7aUL, 0x4ebc3774UL, 0x55ab2a66UL, 0x5ca62168UL, 0x63851042UL, 0x6a881b4cUL, 0x719f065eUL, 0x78920d50UL, +0x0fd9640aUL, 0x06d46f04UL, 0x1dc37216UL, 0x14ce7918UL, 0x2bed4832UL, 0x22e0433cUL, 0x39f75e2eUL, 0x30fa5520UL, +0x9ab701ecUL, 0x93ba0ae2UL, 0x88ad17f0UL, 0x81a01cfeUL, 0xbe832dd4UL, 0xb78e26daUL, 0xac993bc8UL, 0xa59430c6UL, +0xd2df599cUL, 0xdbd25292UL, 0xc0c54f80UL, 0xc9c8448eUL, 0xf6eb75a4UL, 0xffe67eaaUL, 0xe4f163b8UL, 0xedfc68b6UL, +0x0a67b10cUL, 0x036aba02UL, 0x187da710UL, 0x1170ac1eUL, 0x2e539d34UL, 0x275e963aUL, 0x3c498b28UL, 0x35448026UL, +0x420fe97cUL, 0x4b02e272UL, 0x5015ff60UL, 0x5918f46eUL, 0x663bc544UL, 0x6f36ce4aUL, 0x7421d358UL, 0x7d2cd856UL, +0xa10c7a37UL, 0xa8017139UL, 0xb3166c2bUL, 0xba1b6725UL, 0x8538560fUL, 0x8c355d01UL, 0x97224013UL, 0x9e2f4b1dUL, +0xe9642247UL, 0xe0692949UL, 0xfb7e345bUL, 0xf2733f55UL, 0xcd500e7fUL, 0xc45d0571UL, 0xdf4a1863UL, 0xd647136dUL, +0x31dccad7UL, 0x38d1c1d9UL, 0x23c6dccbUL, 0x2acbd7c5UL, 0x15e8e6efUL, 0x1ce5ede1UL, 0x07f2f0f3UL, 0x0efffbfdUL, +0x79b492a7UL, 0x70b999a9UL, 0x6bae84bbUL, 0x62a38fb5UL, 0x5d80be9fUL, 0x548db591UL, 0x4f9aa883UL, 0x4697a38dUL +}; + +#endif /* SMALL CODE */ + +static const ulong32 rcon[] = { + 0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, + 0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL, + 0x1B000000UL, 0x36000000UL, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; 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..ba4ea6b --- /dev/null +++ b/authors @@ -0,0 +1,55 @@ +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. Submited some other fixes too. :-) + Clay has helped find bugs in various pieces of code including the registry functions, base64 routines + and the make process. He is also now the primary author of the libtomcrypt reference manual and has plan + at making a HTML version. + +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. Submitted some ideas to improve the RSA key generation + as well. + +10) Sky Schulz (sky@ogn.com) + + Has submitted a set of ideas to improve the library and make it more attractive for professional users. + +11) Mike Frysinger + + Together with Clay came up with a more "unix friendly" makefile. Mike Frysinger has been keeping copies of + the library for the Gentoo linux distribution. \ No newline at end of file diff --git a/base64.c b/base64.c new file mode 100644 index 0000000..f2421fe --- /dev/null +++ b/base64.c @@ -0,0 +1,121 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* 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) & 0x3F]; + *p++ = codes[(((in[0] & 3) << 4) + (in[1] >> 4)) & 0x3F]; + *p++ = codes[(((in[1] & 0xf) << 2) + (in[2] >> 6)) & 0x3F]; + *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; + + *p++ = codes[(a >> 2) & 0x3F]; + *p++ = codes[(((a & 3) << 4) + (b >> 4)) & 0x3F]; + *p++ = (i+1 < len) ? codes[(((b & 0xf) << 2)) & 0x3F] : '='; + *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; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + g = 3; + for (x = y = z = t = 0; x < len; x++) { + c = map[in[x]&0xFF]; + if (c == 255) continue; + if (c == 254) { c = 0; g--; } + t = (t<<6)|c; + if (++y == 4) { + if (z + g > *outlen) { + return CRYPT_BUFFER_OVERFLOW; + } + 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; +} + +#endif + diff --git a/blowfish.c b/blowfish.c new file mode 100644 index 0000000..229ba88 --- /dev/null +++ b/blowfish.c @@ -0,0 +1,541 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#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 ulong32 ORIG_P[16 + 2] = { + 0x243F6A88UL, 0x85A308D3UL, 0x13198A2EUL, 0x03707344UL, + 0xA4093822UL, 0x299F31D0UL, 0x082EFA98UL, 0xEC4E6C89UL, + 0x452821E6UL, 0x38D01377UL, 0xBE5466CFUL, 0x34E90C6CUL, + 0xC0AC29B7UL, 0xC97C50DDUL, 0x3F84D5B5UL, 0xB5470917UL, + 0x9216D5D9UL, 0x8979FB1BUL +}; + +static const ulong32 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 } +}; + +int blowfish_setup(const unsigned char *key, int keylen, int num_rounds, + symmetric_key *skey) +{ + ulong32 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) | ((ulong32)key[y++] & 255); + if (y == (ulong32)keylen) { + y = 0; + } + } + 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 */ + for (x = 0; x < 8; x++) { + B[x] = 0; + } + + 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; +} + +#ifndef __GNUC__ +#define F(x) ((S1[byte(x,3)] + S2[byte(x,2)]) ^ S3[byte(x,1)]) + S4[byte(x,0)] +#else +#define F(x) ((key->blowfish.S[0][byte(x,3)] + key->blowfish.S[1][byte(x,2)]) ^ key->blowfish.S[2][byte(x,1)]) + key->blowfish.S[3][byte(x,0)] +#endif + +#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 +{ + ulong32 L, R; + int r; +#ifndef __GNUC__ + ulong32 *S1, *S2, *S3, *S4; +#endif + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + +#ifndef __GNUC__ + S1 = key->blowfish.S[0]; + S2 = key->blowfish.S[1]; + S3 = key->blowfish.S[2]; + S4 = key->blowfish.S[3]; +#endif + + /* load it */ + LOAD32H(L, &pt[0]); + LOAD32H(R, &pt[4]); + + /* do 16 rounds */ + for (r = 0; r < 16; ) { + L ^= key->blowfish.K[r++]; R ^= F(L); + R ^= key->blowfish.K[r++]; L ^= F(R); + L ^= key->blowfish.K[r++]; R ^= F(L); + R ^= key->blowfish.K[r++]; L ^= F(R); + } + + /* 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(ulong32) * 2 + sizeof(int)); +} +#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 +{ + ulong32 L, R; + int r; +#ifndef __GNUC__ + ulong32 *S1, *S2, *S3, *S4; +#endif + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + +#ifndef __GNUC__ + S1 = key->blowfish.S[0]; + S2 = key->blowfish.S[1]; + S3 = key->blowfish.S[2]; + S4 = key->blowfish.S[3]; +#endif + + /* 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 */ + for (r = 15; r > 0; ) { + L ^= F(R); R ^= key->blowfish.K[r--]; + R ^= F(L); L ^= key->blowfish.K[r--]; + L ^= F(R); R ^= key->blowfish.K[r--]; + R ^= F(L); L ^= key->blowfish.K[r--]; + } + + /* 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(ulong32) * 2 + sizeof(int)); +} +#endif + + +int blowfish_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + int err; + 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} + } + }; + unsigned char tmp[2][8]; + int x, y; + + for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) { + /* setup key */ + if ((err = blowfish_setup(tests[x].key, 8, 16, &key)) != CRYPT_OK) { + return err; + } + + /* encrypt and decrypt */ + blowfish_ecb_encrypt(tests[x].pt, tmp[0], &key); + blowfish_ecb_decrypt(tmp[0], tmp[1], &key); + + /* compare */ + if ((memcmp(tmp[0], tests[x].ct, 8) != 0) || (memcmp(tmp[1], tests[x].pt, 8) != 0)) { + return CRYPT_FAIL_TESTVECTOR; + } + + /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ + for (y = 0; y < 8; y++) tmp[0][y] = 0; + for (y = 0; y < 1000; y++) blowfish_ecb_encrypt(tmp[0], tmp[0], &key); + for (y = 0; y < 1000; y++) blowfish_ecb_decrypt(tmp[0], tmp[0], &key); + for (y = 0; y < 8; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; + } + return CRYPT_OK; + #endif +} + +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/burn_stack.c b/burn_stack.c new file mode 100644 index 0000000..17b1391 --- /dev/null +++ b/burn_stack.c @@ -0,0 +1,21 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +void burn_stack(unsigned long len) +{ + unsigned char buf[32]; + zeromem(buf, sizeof(buf)); + if (len > (unsigned long)sizeof(buf)) + burn_stack(len - sizeof(buf)); +} + + diff --git a/cast5.c b/cast5.c new file mode 100644 index 0000000..45a8433 --- /dev/null +++ b/cast5.c @@ -0,0 +1,669 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* 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 ulong32 S1[256] = { +0x30fb40d4UL, 0x9fa0ff0bUL, 0x6beccd2fUL, 0x3f258c7aUL, 0x1e213f2fUL, 0x9c004dd3UL, +0x6003e540UL, 0xcf9fc949UL, 0xbfd4af27UL, 0x88bbbdb5UL, 0xe2034090UL, 0x98d09675UL, +0x6e63a0e0UL, 0x15c361d2UL, 0xc2e7661dUL, 0x22d4ff8eUL, 0x28683b6fUL, 0xc07fd059UL, +0xff2379c8UL, 0x775f50e2UL, 0x43c340d3UL, 0xdf2f8656UL, 0x887ca41aUL, 0xa2d2bd2dUL, +0xa1c9e0d6UL, 0x346c4819UL, 0x61b76d87UL, 0x22540f2fUL, 0x2abe32e1UL, 0xaa54166bUL, +0x22568e3aUL, 0xa2d341d0UL, 0x66db40c8UL, 0xa784392fUL, 0x004dff2fUL, 0x2db9d2deUL, +0x97943facUL, 0x4a97c1d8UL, 0x527644b7UL, 0xb5f437a7UL, 0xb82cbaefUL, 0xd751d159UL, +0x6ff7f0edUL, 0x5a097a1fUL, 0x827b68d0UL, 0x90ecf52eUL, 0x22b0c054UL, 0xbc8e5935UL, +0x4b6d2f7fUL, 0x50bb64a2UL, 0xd2664910UL, 0xbee5812dUL, 0xb7332290UL, 0xe93b159fUL, +0xb48ee411UL, 0x4bff345dUL, 0xfd45c240UL, 0xad31973fUL, 0xc4f6d02eUL, 0x55fc8165UL, +0xd5b1caadUL, 0xa1ac2daeUL, 0xa2d4b76dUL, 0xc19b0c50UL, 0x882240f2UL, 0x0c6e4f38UL, +0xa4e4bfd7UL, 0x4f5ba272UL, 0x564c1d2fUL, 0xc59c5319UL, 0xb949e354UL, 0xb04669feUL, +0xb1b6ab8aUL, 0xc71358ddUL, 0x6385c545UL, 0x110f935dUL, 0x57538ad5UL, 0x6a390493UL, +0xe63d37e0UL, 0x2a54f6b3UL, 0x3a787d5fUL, 0x6276a0b5UL, 0x19a6fcdfUL, 0x7a42206aUL, +0x29f9d4d5UL, 0xf61b1891UL, 0xbb72275eUL, 0xaa508167UL, 0x38901091UL, 0xc6b505ebUL, +0x84c7cb8cUL, 0x2ad75a0fUL, 0x874a1427UL, 0xa2d1936bUL, 0x2ad286afUL, 0xaa56d291UL, +0xd7894360UL, 0x425c750dUL, 0x93b39e26UL, 0x187184c9UL, 0x6c00b32dUL, 0x73e2bb14UL, +0xa0bebc3cUL, 0x54623779UL, 0x64459eabUL, 0x3f328b82UL, 0x7718cf82UL, 0x59a2cea6UL, +0x04ee002eUL, 0x89fe78e6UL, 0x3fab0950UL, 0x325ff6c2UL, 0x81383f05UL, 0x6963c5c8UL, +0x76cb5ad6UL, 0xd49974c9UL, 0xca180dcfUL, 0x380782d5UL, 0xc7fa5cf6UL, 0x8ac31511UL, +0x35e79e13UL, 0x47da91d0UL, 0xf40f9086UL, 0xa7e2419eUL, 0x31366241UL, 0x051ef495UL, +0xaa573b04UL, 0x4a805d8dUL, 0x548300d0UL, 0x00322a3cUL, 0xbf64cddfUL, 0xba57a68eUL, +0x75c6372bUL, 0x50afd341UL, 0xa7c13275UL, 0x915a0bf5UL, 0x6b54bfabUL, 0x2b0b1426UL, +0xab4cc9d7UL, 0x449ccd82UL, 0xf7fbf265UL, 0xab85c5f3UL, 0x1b55db94UL, 0xaad4e324UL, +0xcfa4bd3fUL, 0x2deaa3e2UL, 0x9e204d02UL, 0xc8bd25acUL, 0xeadf55b3UL, 0xd5bd9e98UL, +0xe31231b2UL, 0x2ad5ad6cUL, 0x954329deUL, 0xadbe4528UL, 0xd8710f69UL, 0xaa51c90fUL, +0xaa786bf6UL, 0x22513f1eUL, 0xaa51a79bUL, 0x2ad344ccUL, 0x7b5a41f0UL, 0xd37cfbadUL, +0x1b069505UL, 0x41ece491UL, 0xb4c332e6UL, 0x032268d4UL, 0xc9600accUL, 0xce387e6dUL, +0xbf6bb16cUL, 0x6a70fb78UL, 0x0d03d9c9UL, 0xd4df39deUL, 0xe01063daUL, 0x4736f464UL, +0x5ad328d8UL, 0xb347cc96UL, 0x75bb0fc3UL, 0x98511bfbUL, 0x4ffbcc35UL, 0xb58bcf6aUL, +0xe11f0abcUL, 0xbfc5fe4aUL, 0xa70aec10UL, 0xac39570aUL, 0x3f04442fUL, 0x6188b153UL, +0xe0397a2eUL, 0x5727cb79UL, 0x9ceb418fUL, 0x1cacd68dUL, 0x2ad37c96UL, 0x0175cb9dUL, +0xc69dff09UL, 0xc75b65f0UL, 0xd9db40d8UL, 0xec0e7779UL, 0x4744ead4UL, 0xb11c3274UL, +0xdd24cb9eUL, 0x7e1c54bdUL, 0xf01144f9UL, 0xd2240eb1UL, 0x9675b3fdUL, 0xa3ac3755UL, +0xd47c27afUL, 0x51c85f4dUL, 0x56907596UL, 0xa5bb15e6UL, 0x580304f0UL, 0xca042cf1UL, +0x011a37eaUL, 0x8dbfaadbUL, 0x35ba3e4aUL, 0x3526ffa0UL, 0xc37b4d09UL, 0xbc306ed9UL, +0x98a52666UL, 0x5648f725UL, 0xff5e569dUL, 0x0ced63d0UL, 0x7c63b2cfUL, 0x700b45e1UL, +0xd5ea50f1UL, 0x85a92872UL, 0xaf1fbda7UL, 0xd4234870UL, 0xa7870bf3UL, 0x2d3b4d79UL, +0x42e04198UL, 0x0cd0ede7UL, 0x26470db8UL, 0xf881814cUL, 0x474d6ad7UL, 0x7c0c5e5cUL, +0xd1231959UL, 0x381b7298UL, 0xf5d2f4dbUL, 0xab838653UL, 0x6e2f1e23UL, 0x83719c9eUL, +0xbd91e046UL, 0x9a56456eUL, 0xdc39200cUL, 0x20c8c571UL, 0x962bda1cUL, 0xe1e696ffUL, +0xb141ab08UL, 0x7cca89b9UL, 0x1a69e783UL, 0x02cc4843UL, 0xa2f7c579UL, 0x429ef47dUL, +0x427b169cUL, 0x5ac9f049UL, 0xdd8f0f00UL, 0x5c8165bfUL}; + +static const ulong32 S2[256] = { +0x1f201094UL, 0xef0ba75bUL, 0x69e3cf7eUL, 0x393f4380UL, 0xfe61cf7aUL, 0xeec5207aUL, +0x55889c94UL, 0x72fc0651UL, 0xada7ef79UL, 0x4e1d7235UL, 0xd55a63ceUL, 0xde0436baUL, +0x99c430efUL, 0x5f0c0794UL, 0x18dcdb7dUL, 0xa1d6eff3UL, 0xa0b52f7bUL, 0x59e83605UL, +0xee15b094UL, 0xe9ffd909UL, 0xdc440086UL, 0xef944459UL, 0xba83ccb3UL, 0xe0c3cdfbUL, +0xd1da4181UL, 0x3b092ab1UL, 0xf997f1c1UL, 0xa5e6cf7bUL, 0x01420ddbUL, 0xe4e7ef5bUL, +0x25a1ff41UL, 0xe180f806UL, 0x1fc41080UL, 0x179bee7aUL, 0xd37ac6a9UL, 0xfe5830a4UL, +0x98de8b7fUL, 0x77e83f4eUL, 0x79929269UL, 0x24fa9f7bUL, 0xe113c85bUL, 0xacc40083UL, +0xd7503525UL, 0xf7ea615fUL, 0x62143154UL, 0x0d554b63UL, 0x5d681121UL, 0xc866c359UL, +0x3d63cf73UL, 0xcee234c0UL, 0xd4d87e87UL, 0x5c672b21UL, 0x071f6181UL, 0x39f7627fUL, +0x361e3084UL, 0xe4eb573bUL, 0x602f64a4UL, 0xd63acd9cUL, 0x1bbc4635UL, 0x9e81032dUL, +0x2701f50cUL, 0x99847ab4UL, 0xa0e3df79UL, 0xba6cf38cUL, 0x10843094UL, 0x2537a95eUL, +0xf46f6ffeUL, 0xa1ff3b1fUL, 0x208cfb6aUL, 0x8f458c74UL, 0xd9e0a227UL, 0x4ec73a34UL, +0xfc884f69UL, 0x3e4de8dfUL, 0xef0e0088UL, 0x3559648dUL, 0x8a45388cUL, 0x1d804366UL, +0x721d9bfdUL, 0xa58684bbUL, 0xe8256333UL, 0x844e8212UL, 0x128d8098UL, 0xfed33fb4UL, +0xce280ae1UL, 0x27e19ba5UL, 0xd5a6c252UL, 0xe49754bdUL, 0xc5d655ddUL, 0xeb667064UL, +0x77840b4dUL, 0xa1b6a801UL, 0x84db26a9UL, 0xe0b56714UL, 0x21f043b7UL, 0xe5d05860UL, +0x54f03084UL, 0x066ff472UL, 0xa31aa153UL, 0xdadc4755UL, 0xb5625dbfUL, 0x68561be6UL, +0x83ca6b94UL, 0x2d6ed23bUL, 0xeccf01dbUL, 0xa6d3d0baUL, 0xb6803d5cUL, 0xaf77a709UL, +0x33b4a34cUL, 0x397bc8d6UL, 0x5ee22b95UL, 0x5f0e5304UL, 0x81ed6f61UL, 0x20e74364UL, +0xb45e1378UL, 0xde18639bUL, 0x881ca122UL, 0xb96726d1UL, 0x8049a7e8UL, 0x22b7da7bUL, +0x5e552d25UL, 0x5272d237UL, 0x79d2951cUL, 0xc60d894cUL, 0x488cb402UL, 0x1ba4fe5bUL, +0xa4b09f6bUL, 0x1ca815cfUL, 0xa20c3005UL, 0x8871df63UL, 0xb9de2fcbUL, 0x0cc6c9e9UL, +0x0beeff53UL, 0xe3214517UL, 0xb4542835UL, 0x9f63293cUL, 0xee41e729UL, 0x6e1d2d7cUL, +0x50045286UL, 0x1e6685f3UL, 0xf33401c6UL, 0x30a22c95UL, 0x31a70850UL, 0x60930f13UL, +0x73f98417UL, 0xa1269859UL, 0xec645c44UL, 0x52c877a9UL, 0xcdff33a6UL, 0xa02b1741UL, +0x7cbad9a2UL, 0x2180036fUL, 0x50d99c08UL, 0xcb3f4861UL, 0xc26bd765UL, 0x64a3f6abUL, +0x80342676UL, 0x25a75e7bUL, 0xe4e6d1fcUL, 0x20c710e6UL, 0xcdf0b680UL, 0x17844d3bUL, +0x31eef84dUL, 0x7e0824e4UL, 0x2ccb49ebUL, 0x846a3baeUL, 0x8ff77888UL, 0xee5d60f6UL, +0x7af75673UL, 0x2fdd5cdbUL, 0xa11631c1UL, 0x30f66f43UL, 0xb3faec54UL, 0x157fd7faUL, +0xef8579ccUL, 0xd152de58UL, 0xdb2ffd5eUL, 0x8f32ce19UL, 0x306af97aUL, 0x02f03ef8UL, +0x99319ad5UL, 0xc242fa0fUL, 0xa7e3ebb0UL, 0xc68e4906UL, 0xb8da230cUL, 0x80823028UL, +0xdcdef3c8UL, 0xd35fb171UL, 0x088a1bc8UL, 0xbec0c560UL, 0x61a3c9e8UL, 0xbca8f54dUL, +0xc72feffaUL, 0x22822e99UL, 0x82c570b4UL, 0xd8d94e89UL, 0x8b1c34bcUL, 0x301e16e6UL, +0x273be979UL, 0xb0ffeaa6UL, 0x61d9b8c6UL, 0x00b24869UL, 0xb7ffce3fUL, 0x08dc283bUL, +0x43daf65aUL, 0xf7e19798UL, 0x7619b72fUL, 0x8f1c9ba4UL, 0xdc8637a0UL, 0x16a7d3b1UL, +0x9fc393b7UL, 0xa7136eebUL, 0xc6bcc63eUL, 0x1a513742UL, 0xef6828bcUL, 0x520365d6UL, +0x2d6a77abUL, 0x3527ed4bUL, 0x821fd216UL, 0x095c6e2eUL, 0xdb92f2fbUL, 0x5eea29cbUL, +0x145892f5UL, 0x91584f7fUL, 0x5483697bUL, 0x2667a8ccUL, 0x85196048UL, 0x8c4baceaUL, +0x833860d4UL, 0x0d23e0f9UL, 0x6c387e8aUL, 0x0ae6d249UL, 0xb284600cUL, 0xd835731dUL, +0xdcb1c647UL, 0xac4c56eaUL, 0x3ebd81b3UL, 0x230eabb0UL, 0x6438bc87UL, 0xf0b5b1faUL, +0x8f5ea2b3UL, 0xfc184642UL, 0x0a036b7aUL, 0x4fb089bdUL, 0x649da589UL, 0xa345415eUL, +0x5c038323UL, 0x3e5d3bb9UL, 0x43d79572UL, 0x7e6dd07cUL, 0x06dfdf1eUL, 0x6c6cc4efUL, +0x7160a539UL, 0x73bfbe70UL, 0x83877605UL, 0x4523ecf1UL}; + +static const ulong32 S3[256] = { +0x8defc240UL, 0x25fa5d9fUL, 0xeb903dbfUL, 0xe810c907UL, 0x47607fffUL, 0x369fe44bUL, +0x8c1fc644UL, 0xaececa90UL, 0xbeb1f9bfUL, 0xeefbcaeaUL, 0xe8cf1950UL, 0x51df07aeUL, +0x920e8806UL, 0xf0ad0548UL, 0xe13c8d83UL, 0x927010d5UL, 0x11107d9fUL, 0x07647db9UL, +0xb2e3e4d4UL, 0x3d4f285eUL, 0xb9afa820UL, 0xfade82e0UL, 0xa067268bUL, 0x8272792eUL, +0x553fb2c0UL, 0x489ae22bUL, 0xd4ef9794UL, 0x125e3fbcUL, 0x21fffceeUL, 0x825b1bfdUL, +0x9255c5edUL, 0x1257a240UL, 0x4e1a8302UL, 0xbae07fffUL, 0x528246e7UL, 0x8e57140eUL, +0x3373f7bfUL, 0x8c9f8188UL, 0xa6fc4ee8UL, 0xc982b5a5UL, 0xa8c01db7UL, 0x579fc264UL, +0x67094f31UL, 0xf2bd3f5fUL, 0x40fff7c1UL, 0x1fb78dfcUL, 0x8e6bd2c1UL, 0x437be59bUL, +0x99b03dbfUL, 0xb5dbc64bUL, 0x638dc0e6UL, 0x55819d99UL, 0xa197c81cUL, 0x4a012d6eUL, +0xc5884a28UL, 0xccc36f71UL, 0xb843c213UL, 0x6c0743f1UL, 0x8309893cUL, 0x0feddd5fUL, +0x2f7fe850UL, 0xd7c07f7eUL, 0x02507fbfUL, 0x5afb9a04UL, 0xa747d2d0UL, 0x1651192eUL, +0xaf70bf3eUL, 0x58c31380UL, 0x5f98302eUL, 0x727cc3c4UL, 0x0a0fb402UL, 0x0f7fef82UL, +0x8c96fdadUL, 0x5d2c2aaeUL, 0x8ee99a49UL, 0x50da88b8UL, 0x8427f4a0UL, 0x1eac5790UL, +0x796fb449UL, 0x8252dc15UL, 0xefbd7d9bUL, 0xa672597dUL, 0xada840d8UL, 0x45f54504UL, +0xfa5d7403UL, 0xe83ec305UL, 0x4f91751aUL, 0x925669c2UL, 0x23efe941UL, 0xa903f12eUL, +0x60270df2UL, 0x0276e4b6UL, 0x94fd6574UL, 0x927985b2UL, 0x8276dbcbUL, 0x02778176UL, +0xf8af918dUL, 0x4e48f79eUL, 0x8f616ddfUL, 0xe29d840eUL, 0x842f7d83UL, 0x340ce5c8UL, +0x96bbb682UL, 0x93b4b148UL, 0xef303cabUL, 0x984faf28UL, 0x779faf9bUL, 0x92dc560dUL, +0x224d1e20UL, 0x8437aa88UL, 0x7d29dc96UL, 0x2756d3dcUL, 0x8b907ceeUL, 0xb51fd240UL, +0xe7c07ce3UL, 0xe566b4a1UL, 0xc3e9615eUL, 0x3cf8209dUL, 0x6094d1e3UL, 0xcd9ca341UL, +0x5c76460eUL, 0x00ea983bUL, 0xd4d67881UL, 0xfd47572cUL, 0xf76cedd9UL, 0xbda8229cUL, +0x127dadaaUL, 0x438a074eUL, 0x1f97c090UL, 0x081bdb8aUL, 0x93a07ebeUL, 0xb938ca15UL, +0x97b03cffUL, 0x3dc2c0f8UL, 0x8d1ab2ecUL, 0x64380e51UL, 0x68cc7bfbUL, 0xd90f2788UL, +0x12490181UL, 0x5de5ffd4UL, 0xdd7ef86aUL, 0x76a2e214UL, 0xb9a40368UL, 0x925d958fUL, +0x4b39fffaUL, 0xba39aee9UL, 0xa4ffd30bUL, 0xfaf7933bUL, 0x6d498623UL, 0x193cbcfaUL, +0x27627545UL, 0x825cf47aUL, 0x61bd8ba0UL, 0xd11e42d1UL, 0xcead04f4UL, 0x127ea392UL, +0x10428db7UL, 0x8272a972UL, 0x9270c4a8UL, 0x127de50bUL, 0x285ba1c8UL, 0x3c62f44fUL, +0x35c0eaa5UL, 0xe805d231UL, 0x428929fbUL, 0xb4fcdf82UL, 0x4fb66a53UL, 0x0e7dc15bUL, +0x1f081fabUL, 0x108618aeUL, 0xfcfd086dUL, 0xf9ff2889UL, 0x694bcc11UL, 0x236a5caeUL, +0x12deca4dUL, 0x2c3f8cc5UL, 0xd2d02dfeUL, 0xf8ef5896UL, 0xe4cf52daUL, 0x95155b67UL, +0x494a488cUL, 0xb9b6a80cUL, 0x5c8f82bcUL, 0x89d36b45UL, 0x3a609437UL, 0xec00c9a9UL, +0x44715253UL, 0x0a874b49UL, 0xd773bc40UL, 0x7c34671cUL, 0x02717ef6UL, 0x4feb5536UL, +0xa2d02fffUL, 0xd2bf60c4UL, 0xd43f03c0UL, 0x50b4ef6dUL, 0x07478cd1UL, 0x006e1888UL, +0xa2e53f55UL, 0xb9e6d4bcUL, 0xa2048016UL, 0x97573833UL, 0xd7207d67UL, 0xde0f8f3dUL, +0x72f87b33UL, 0xabcc4f33UL, 0x7688c55dUL, 0x7b00a6b0UL, 0x947b0001UL, 0x570075d2UL, +0xf9bb88f8UL, 0x8942019eUL, 0x4264a5ffUL, 0x856302e0UL, 0x72dbd92bUL, 0xee971b69UL, +0x6ea22fdeUL, 0x5f08ae2bUL, 0xaf7a616dUL, 0xe5c98767UL, 0xcf1febd2UL, 0x61efc8c2UL, +0xf1ac2571UL, 0xcc8239c2UL, 0x67214cb8UL, 0xb1e583d1UL, 0xb7dc3e62UL, 0x7f10bdceUL, +0xf90a5c38UL, 0x0ff0443dUL, 0x606e6dc6UL, 0x60543a49UL, 0x5727c148UL, 0x2be98a1dUL, +0x8ab41738UL, 0x20e1be24UL, 0xaf96da0fUL, 0x68458425UL, 0x99833be5UL, 0x600d457dUL, +0x282f9350UL, 0x8334b362UL, 0xd91d1120UL, 0x2b6d8da0UL, 0x642b1e31UL, 0x9c305a00UL, +0x52bce688UL, 0x1b03588aUL, 0xf7baefd5UL, 0x4142ed9cUL, 0xa4315c11UL, 0x83323ec5UL, +0xdfef4636UL, 0xa133c501UL, 0xe9d3531cUL, 0xee353783UL}; + +static const ulong32 S4[256] = { +0x9db30420UL, 0x1fb6e9deUL, 0xa7be7befUL, 0xd273a298UL, 0x4a4f7bdbUL, 0x64ad8c57UL, +0x85510443UL, 0xfa020ed1UL, 0x7e287affUL, 0xe60fb663UL, 0x095f35a1UL, 0x79ebf120UL, +0xfd059d43UL, 0x6497b7b1UL, 0xf3641f63UL, 0x241e4adfUL, 0x28147f5fUL, 0x4fa2b8cdUL, +0xc9430040UL, 0x0cc32220UL, 0xfdd30b30UL, 0xc0a5374fUL, 0x1d2d00d9UL, 0x24147b15UL, +0xee4d111aUL, 0x0fca5167UL, 0x71ff904cUL, 0x2d195ffeUL, 0x1a05645fUL, 0x0c13fefeUL, +0x081b08caUL, 0x05170121UL, 0x80530100UL, 0xe83e5efeUL, 0xac9af4f8UL, 0x7fe72701UL, +0xd2b8ee5fUL, 0x06df4261UL, 0xbb9e9b8aUL, 0x7293ea25UL, 0xce84ffdfUL, 0xf5718801UL, +0x3dd64b04UL, 0xa26f263bUL, 0x7ed48400UL, 0x547eebe6UL, 0x446d4ca0UL, 0x6cf3d6f5UL, +0x2649abdfUL, 0xaea0c7f5UL, 0x36338cc1UL, 0x503f7e93UL, 0xd3772061UL, 0x11b638e1UL, +0x72500e03UL, 0xf80eb2bbUL, 0xabe0502eUL, 0xec8d77deUL, 0x57971e81UL, 0xe14f6746UL, +0xc9335400UL, 0x6920318fUL, 0x081dbb99UL, 0xffc304a5UL, 0x4d351805UL, 0x7f3d5ce3UL, +0xa6c866c6UL, 0x5d5bcca9UL, 0xdaec6feaUL, 0x9f926f91UL, 0x9f46222fUL, 0x3991467dUL, +0xa5bf6d8eUL, 0x1143c44fUL, 0x43958302UL, 0xd0214eebUL, 0x022083b8UL, 0x3fb6180cUL, +0x18f8931eUL, 0x281658e6UL, 0x26486e3eUL, 0x8bd78a70UL, 0x7477e4c1UL, 0xb506e07cUL, +0xf32d0a25UL, 0x79098b02UL, 0xe4eabb81UL, 0x28123b23UL, 0x69dead38UL, 0x1574ca16UL, +0xdf871b62UL, 0x211c40b7UL, 0xa51a9ef9UL, 0x0014377bUL, 0x041e8ac8UL, 0x09114003UL, +0xbd59e4d2UL, 0xe3d156d5UL, 0x4fe876d5UL, 0x2f91a340UL, 0x557be8deUL, 0x00eae4a7UL, +0x0ce5c2ecUL, 0x4db4bba6UL, 0xe756bdffUL, 0xdd3369acUL, 0xec17b035UL, 0x06572327UL, +0x99afc8b0UL, 0x56c8c391UL, 0x6b65811cUL, 0x5e146119UL, 0x6e85cb75UL, 0xbe07c002UL, +0xc2325577UL, 0x893ff4ecUL, 0x5bbfc92dUL, 0xd0ec3b25UL, 0xb7801ab7UL, 0x8d6d3b24UL, +0x20c763efUL, 0xc366a5fcUL, 0x9c382880UL, 0x0ace3205UL, 0xaac9548aUL, 0xeca1d7c7UL, +0x041afa32UL, 0x1d16625aUL, 0x6701902cUL, 0x9b757a54UL, 0x31d477f7UL, 0x9126b031UL, +0x36cc6fdbUL, 0xc70b8b46UL, 0xd9e66a48UL, 0x56e55a79UL, 0x026a4cebUL, 0x52437effUL, +0x2f8f76b4UL, 0x0df980a5UL, 0x8674cde3UL, 0xedda04ebUL, 0x17a9be04UL, 0x2c18f4dfUL, +0xb7747f9dUL, 0xab2af7b4UL, 0xefc34d20UL, 0x2e096b7cUL, 0x1741a254UL, 0xe5b6a035UL, +0x213d42f6UL, 0x2c1c7c26UL, 0x61c2f50fUL, 0x6552daf9UL, 0xd2c231f8UL, 0x25130f69UL, +0xd8167fa2UL, 0x0418f2c8UL, 0x001a96a6UL, 0x0d1526abUL, 0x63315c21UL, 0x5e0a72ecUL, +0x49bafefdUL, 0x187908d9UL, 0x8d0dbd86UL, 0x311170a7UL, 0x3e9b640cUL, 0xcc3e10d7UL, +0xd5cad3b6UL, 0x0caec388UL, 0xf73001e1UL, 0x6c728affUL, 0x71eae2a1UL, 0x1f9af36eUL, +0xcfcbd12fUL, 0xc1de8417UL, 0xac07be6bUL, 0xcb44a1d8UL, 0x8b9b0f56UL, 0x013988c3UL, +0xb1c52fcaUL, 0xb4be31cdUL, 0xd8782806UL, 0x12a3a4e2UL, 0x6f7de532UL, 0x58fd7eb6UL, +0xd01ee900UL, 0x24adffc2UL, 0xf4990fc5UL, 0x9711aac5UL, 0x001d7b95UL, 0x82e5e7d2UL, +0x109873f6UL, 0x00613096UL, 0xc32d9521UL, 0xada121ffUL, 0x29908415UL, 0x7fbb977fUL, +0xaf9eb3dbUL, 0x29c9ed2aUL, 0x5ce2a465UL, 0xa730f32cUL, 0xd0aa3fe8UL, 0x8a5cc091UL, +0xd49e2ce7UL, 0x0ce454a9UL, 0xd60acd86UL, 0x015f1919UL, 0x77079103UL, 0xdea03af6UL, +0x78a8565eUL, 0xdee356dfUL, 0x21f05cbeUL, 0x8b75e387UL, 0xb3c50651UL, 0xb8a5c3efUL, +0xd8eeb6d2UL, 0xe523be77UL, 0xc2154529UL, 0x2f69efdfUL, 0xafe67afbUL, 0xf470c4b2UL, +0xf3e0eb5bUL, 0xd6cc9876UL, 0x39e4460cUL, 0x1fda8538UL, 0x1987832fUL, 0xca007367UL, +0xa99144f8UL, 0x296b299eUL, 0x492fc295UL, 0x9266beabUL, 0xb5676e69UL, 0x9bd3dddaUL, +0xdf7e052fUL, 0xdb25701cUL, 0x1b5e51eeUL, 0xf65324e6UL, 0x6afce36cUL, 0x0316cc04UL, +0x8644213eUL, 0xb7dc59d0UL, 0x7965291fUL, 0xccd6fd43UL, 0x41823979UL, 0x932bcdf6UL, +0xb657c34dUL, 0x4edfd282UL, 0x7ae5290cUL, 0x3cb9536bUL, 0x851e20feUL, 0x9833557eUL, +0x13ecf0b0UL, 0xd3ffb372UL, 0x3f85c5c1UL, 0x0aef7ed2UL}; + +static const ulong32 S5[256] = { +0x7ec90c04UL, 0x2c6e74b9UL, 0x9b0e66dfUL, 0xa6337911UL, 0xb86a7fffUL, 0x1dd358f5UL, +0x44dd9d44UL, 0x1731167fUL, 0x08fbf1faUL, 0xe7f511ccUL, 0xd2051b00UL, 0x735aba00UL, +0x2ab722d8UL, 0x386381cbUL, 0xacf6243aUL, 0x69befd7aUL, 0xe6a2e77fUL, 0xf0c720cdUL, +0xc4494816UL, 0xccf5c180UL, 0x38851640UL, 0x15b0a848UL, 0xe68b18cbUL, 0x4caadeffUL, +0x5f480a01UL, 0x0412b2aaUL, 0x259814fcUL, 0x41d0efe2UL, 0x4e40b48dUL, 0x248eb6fbUL, +0x8dba1cfeUL, 0x41a99b02UL, 0x1a550a04UL, 0xba8f65cbUL, 0x7251f4e7UL, 0x95a51725UL, +0xc106ecd7UL, 0x97a5980aUL, 0xc539b9aaUL, 0x4d79fe6aUL, 0xf2f3f763UL, 0x68af8040UL, +0xed0c9e56UL, 0x11b4958bUL, 0xe1eb5a88UL, 0x8709e6b0UL, 0xd7e07156UL, 0x4e29fea7UL, +0x6366e52dUL, 0x02d1c000UL, 0xc4ac8e05UL, 0x9377f571UL, 0x0c05372aUL, 0x578535f2UL, +0x2261be02UL, 0xd642a0c9UL, 0xdf13a280UL, 0x74b55bd2UL, 0x682199c0UL, 0xd421e5ecUL, +0x53fb3ce8UL, 0xc8adedb3UL, 0x28a87fc9UL, 0x3d959981UL, 0x5c1ff900UL, 0xfe38d399UL, +0x0c4eff0bUL, 0x062407eaUL, 0xaa2f4fb1UL, 0x4fb96976UL, 0x90c79505UL, 0xb0a8a774UL, +0xef55a1ffUL, 0xe59ca2c2UL, 0xa6b62d27UL, 0xe66a4263UL, 0xdf65001fUL, 0x0ec50966UL, +0xdfdd55bcUL, 0x29de0655UL, 0x911e739aUL, 0x17af8975UL, 0x32c7911cUL, 0x89f89468UL, +0x0d01e980UL, 0x524755f4UL, 0x03b63cc9UL, 0x0cc844b2UL, 0xbcf3f0aaUL, 0x87ac36e9UL, +0xe53a7426UL, 0x01b3d82bUL, 0x1a9e7449UL, 0x64ee2d7eUL, 0xcddbb1daUL, 0x01c94910UL, +0xb868bf80UL, 0x0d26f3fdUL, 0x9342ede7UL, 0x04a5c284UL, 0x636737b6UL, 0x50f5b616UL, +0xf24766e3UL, 0x8eca36c1UL, 0x136e05dbUL, 0xfef18391UL, 0xfb887a37UL, 0xd6e7f7d4UL, +0xc7fb7dc9UL, 0x3063fcdfUL, 0xb6f589deUL, 0xec2941daUL, 0x26e46695UL, 0xb7566419UL, +0xf654efc5UL, 0xd08d58b7UL, 0x48925401UL, 0xc1bacb7fUL, 0xe5ff550fUL, 0xb6083049UL, +0x5bb5d0e8UL, 0x87d72e5aUL, 0xab6a6ee1UL, 0x223a66ceUL, 0xc62bf3cdUL, 0x9e0885f9UL, +0x68cb3e47UL, 0x086c010fUL, 0xa21de820UL, 0xd18b69deUL, 0xf3f65777UL, 0xfa02c3f6UL, +0x407edac3UL, 0xcbb3d550UL, 0x1793084dUL, 0xb0d70ebaUL, 0x0ab378d5UL, 0xd951fb0cUL, +0xded7da56UL, 0x4124bbe4UL, 0x94ca0b56UL, 0x0f5755d1UL, 0xe0e1e56eUL, 0x6184b5beUL, +0x580a249fUL, 0x94f74bc0UL, 0xe327888eUL, 0x9f7b5561UL, 0xc3dc0280UL, 0x05687715UL, +0x646c6bd7UL, 0x44904db3UL, 0x66b4f0a3UL, 0xc0f1648aUL, 0x697ed5afUL, 0x49e92ff6UL, +0x309e374fUL, 0x2cb6356aUL, 0x85808573UL, 0x4991f840UL, 0x76f0ae02UL, 0x083be84dUL, +0x28421c9aUL, 0x44489406UL, 0x736e4cb8UL, 0xc1092910UL, 0x8bc95fc6UL, 0x7d869cf4UL, +0x134f616fUL, 0x2e77118dUL, 0xb31b2be1UL, 0xaa90b472UL, 0x3ca5d717UL, 0x7d161bbaUL, +0x9cad9010UL, 0xaf462ba2UL, 0x9fe459d2UL, 0x45d34559UL, 0xd9f2da13UL, 0xdbc65487UL, +0xf3e4f94eUL, 0x176d486fUL, 0x097c13eaUL, 0x631da5c7UL, 0x445f7382UL, 0x175683f4UL, +0xcdc66a97UL, 0x70be0288UL, 0xb3cdcf72UL, 0x6e5dd2f3UL, 0x20936079UL, 0x459b80a5UL, +0xbe60e2dbUL, 0xa9c23101UL, 0xeba5315cUL, 0x224e42f2UL, 0x1c5c1572UL, 0xf6721b2cUL, +0x1ad2fff3UL, 0x8c25404eUL, 0x324ed72fUL, 0x4067b7fdUL, 0x0523138eUL, 0x5ca3bc78UL, +0xdc0fd66eUL, 0x75922283UL, 0x784d6b17UL, 0x58ebb16eUL, 0x44094f85UL, 0x3f481d87UL, +0xfcfeae7bUL, 0x77b5ff76UL, 0x8c2302bfUL, 0xaaf47556UL, 0x5f46b02aUL, 0x2b092801UL, +0x3d38f5f7UL, 0x0ca81f36UL, 0x52af4a8aUL, 0x66d5e7c0UL, 0xdf3b0874UL, 0x95055110UL, +0x1b5ad7a8UL, 0xf61ed5adUL, 0x6cf6e479UL, 0x20758184UL, 0xd0cefa65UL, 0x88f7be58UL, +0x4a046826UL, 0x0ff6f8f3UL, 0xa09c7f70UL, 0x5346aba0UL, 0x5ce96c28UL, 0xe176eda3UL, +0x6bac307fUL, 0x376829d2UL, 0x85360fa9UL, 0x17e3fe2aUL, 0x24b79767UL, 0xf5a96b20UL, +0xd6cd2595UL, 0x68ff1ebfUL, 0x7555442cUL, 0xf19f06beUL, 0xf9e0659aUL, 0xeeb9491dUL, +0x34010718UL, 0xbb30cab8UL, 0xe822fe15UL, 0x88570983UL, 0x750e6249UL, 0xda627e55UL, +0x5e76ffa8UL, 0xb1534546UL, 0x6d47de08UL, 0xefe9e7d4UL}; + +static const ulong32 S6[256] = { +0xf6fa8f9dUL, 0x2cac6ce1UL, 0x4ca34867UL, 0xe2337f7cUL, 0x95db08e7UL, 0x016843b4UL, +0xeced5cbcUL, 0x325553acUL, 0xbf9f0960UL, 0xdfa1e2edUL, 0x83f0579dUL, 0x63ed86b9UL, +0x1ab6a6b8UL, 0xde5ebe39UL, 0xf38ff732UL, 0x8989b138UL, 0x33f14961UL, 0xc01937bdUL, +0xf506c6daUL, 0xe4625e7eUL, 0xa308ea99UL, 0x4e23e33cUL, 0x79cbd7ccUL, 0x48a14367UL, +0xa3149619UL, 0xfec94bd5UL, 0xa114174aUL, 0xeaa01866UL, 0xa084db2dUL, 0x09a8486fUL, +0xa888614aUL, 0x2900af98UL, 0x01665991UL, 0xe1992863UL, 0xc8f30c60UL, 0x2e78ef3cUL, +0xd0d51932UL, 0xcf0fec14UL, 0xf7ca07d2UL, 0xd0a82072UL, 0xfd41197eUL, 0x9305a6b0UL, +0xe86be3daUL, 0x74bed3cdUL, 0x372da53cUL, 0x4c7f4448UL, 0xdab5d440UL, 0x6dba0ec3UL, +0x083919a7UL, 0x9fbaeed9UL, 0x49dbcfb0UL, 0x4e670c53UL, 0x5c3d9c01UL, 0x64bdb941UL, +0x2c0e636aUL, 0xba7dd9cdUL, 0xea6f7388UL, 0xe70bc762UL, 0x35f29adbUL, 0x5c4cdd8dUL, +0xf0d48d8cUL, 0xb88153e2UL, 0x08a19866UL, 0x1ae2eac8UL, 0x284caf89UL, 0xaa928223UL, +0x9334be53UL, 0x3b3a21bfUL, 0x16434be3UL, 0x9aea3906UL, 0xefe8c36eUL, 0xf890cdd9UL, +0x80226daeUL, 0xc340a4a3UL, 0xdf7e9c09UL, 0xa694a807UL, 0x5b7c5eccUL, 0x221db3a6UL, +0x9a69a02fUL, 0x68818a54UL, 0xceb2296fUL, 0x53c0843aUL, 0xfe893655UL, 0x25bfe68aUL, +0xb4628abcUL, 0xcf222ebfUL, 0x25ac6f48UL, 0xa9a99387UL, 0x53bddb65UL, 0xe76ffbe7UL, +0xe967fd78UL, 0x0ba93563UL, 0x8e342bc1UL, 0xe8a11be9UL, 0x4980740dUL, 0xc8087dfcUL, +0x8de4bf99UL, 0xa11101a0UL, 0x7fd37975UL, 0xda5a26c0UL, 0xe81f994fUL, 0x9528cd89UL, +0xfd339fedUL, 0xb87834bfUL, 0x5f04456dUL, 0x22258698UL, 0xc9c4c83bUL, 0x2dc156beUL, +0x4f628daaUL, 0x57f55ec5UL, 0xe2220abeUL, 0xd2916ebfUL, 0x4ec75b95UL, 0x24f2c3c0UL, +0x42d15d99UL, 0xcd0d7fa0UL, 0x7b6e27ffUL, 0xa8dc8af0UL, 0x7345c106UL, 0xf41e232fUL, +0x35162386UL, 0xe6ea8926UL, 0x3333b094UL, 0x157ec6f2UL, 0x372b74afUL, 0x692573e4UL, +0xe9a9d848UL, 0xf3160289UL, 0x3a62ef1dUL, 0xa787e238UL, 0xf3a5f676UL, 0x74364853UL, +0x20951063UL, 0x4576698dUL, 0xb6fad407UL, 0x592af950UL, 0x36f73523UL, 0x4cfb6e87UL, +0x7da4cec0UL, 0x6c152daaUL, 0xcb0396a8UL, 0xc50dfe5dUL, 0xfcd707abUL, 0x0921c42fUL, +0x89dff0bbUL, 0x5fe2be78UL, 0x448f4f33UL, 0x754613c9UL, 0x2b05d08dUL, 0x48b9d585UL, +0xdc049441UL, 0xc8098f9bUL, 0x7dede786UL, 0xc39a3373UL, 0x42410005UL, 0x6a091751UL, +0x0ef3c8a6UL, 0x890072d6UL, 0x28207682UL, 0xa9a9f7beUL, 0xbf32679dUL, 0xd45b5b75UL, +0xb353fd00UL, 0xcbb0e358UL, 0x830f220aUL, 0x1f8fb214UL, 0xd372cf08UL, 0xcc3c4a13UL, +0x8cf63166UL, 0x061c87beUL, 0x88c98f88UL, 0x6062e397UL, 0x47cf8e7aUL, 0xb6c85283UL, +0x3cc2acfbUL, 0x3fc06976UL, 0x4e8f0252UL, 0x64d8314dUL, 0xda3870e3UL, 0x1e665459UL, +0xc10908f0UL, 0x513021a5UL, 0x6c5b68b7UL, 0x822f8aa0UL, 0x3007cd3eUL, 0x74719eefUL, +0xdc872681UL, 0x073340d4UL, 0x7e432fd9UL, 0x0c5ec241UL, 0x8809286cUL, 0xf592d891UL, +0x08a930f6UL, 0x957ef305UL, 0xb7fbffbdUL, 0xc266e96fUL, 0x6fe4ac98UL, 0xb173ecc0UL, +0xbc60b42aUL, 0x953498daUL, 0xfba1ae12UL, 0x2d4bd736UL, 0x0f25faabUL, 0xa4f3fcebUL, +0xe2969123UL, 0x257f0c3dUL, 0x9348af49UL, 0x361400bcUL, 0xe8816f4aUL, 0x3814f200UL, +0xa3f94043UL, 0x9c7a54c2UL, 0xbc704f57UL, 0xda41e7f9UL, 0xc25ad33aUL, 0x54f4a084UL, +0xb17f5505UL, 0x59357cbeUL, 0xedbd15c8UL, 0x7f97c5abUL, 0xba5ac7b5UL, 0xb6f6deafUL, +0x3a479c3aUL, 0x5302da25UL, 0x653d7e6aUL, 0x54268d49UL, 0x51a477eaUL, 0x5017d55bUL, +0xd7d25d88UL, 0x44136c76UL, 0x0404a8c8UL, 0xb8e5a121UL, 0xb81a928aUL, 0x60ed5869UL, +0x97c55b96UL, 0xeaec991bUL, 0x29935913UL, 0x01fdb7f1UL, 0x088e8dfaUL, 0x9ab6f6f5UL, +0x3b4cbf9fUL, 0x4a5de3abUL, 0xe6051d35UL, 0xa0e1d855UL, 0xd36b4cf1UL, 0xf544edebUL, +0xb0e93524UL, 0xbebb8fbdUL, 0xa2d762cfUL, 0x49c92f54UL, 0x38b5f331UL, 0x7128a454UL, +0x48392905UL, 0xa65b1db8UL, 0x851c97bdUL, 0xd675cf2fUL}; + +static const ulong32 S7[256] = { +0x85e04019UL, 0x332bf567UL, 0x662dbfffUL, 0xcfc65693UL, 0x2a8d7f6fUL, 0xab9bc912UL, +0xde6008a1UL, 0x2028da1fUL, 0x0227bce7UL, 0x4d642916UL, 0x18fac300UL, 0x50f18b82UL, +0x2cb2cb11UL, 0xb232e75cUL, 0x4b3695f2UL, 0xb28707deUL, 0xa05fbcf6UL, 0xcd4181e9UL, +0xe150210cUL, 0xe24ef1bdUL, 0xb168c381UL, 0xfde4e789UL, 0x5c79b0d8UL, 0x1e8bfd43UL, +0x4d495001UL, 0x38be4341UL, 0x913cee1dUL, 0x92a79c3fUL, 0x089766beUL, 0xbaeeadf4UL, +0x1286becfUL, 0xb6eacb19UL, 0x2660c200UL, 0x7565bde4UL, 0x64241f7aUL, 0x8248dca9UL, +0xc3b3ad66UL, 0x28136086UL, 0x0bd8dfa8UL, 0x356d1cf2UL, 0x107789beUL, 0xb3b2e9ceUL, +0x0502aa8fUL, 0x0bc0351eUL, 0x166bf52aUL, 0xeb12ff82UL, 0xe3486911UL, 0xd34d7516UL, +0x4e7b3affUL, 0x5f43671bUL, 0x9cf6e037UL, 0x4981ac83UL, 0x334266ceUL, 0x8c9341b7UL, +0xd0d854c0UL, 0xcb3a6c88UL, 0x47bc2829UL, 0x4725ba37UL, 0xa66ad22bUL, 0x7ad61f1eUL, +0x0c5cbafaUL, 0x4437f107UL, 0xb6e79962UL, 0x42d2d816UL, 0x0a961288UL, 0xe1a5c06eUL, +0x13749e67UL, 0x72fc081aUL, 0xb1d139f7UL, 0xf9583745UL, 0xcf19df58UL, 0xbec3f756UL, +0xc06eba30UL, 0x07211b24UL, 0x45c28829UL, 0xc95e317fUL, 0xbc8ec511UL, 0x38bc46e9UL, +0xc6e6fa14UL, 0xbae8584aUL, 0xad4ebc46UL, 0x468f508bUL, 0x7829435fUL, 0xf124183bUL, +0x821dba9fUL, 0xaff60ff4UL, 0xea2c4e6dUL, 0x16e39264UL, 0x92544a8bUL, 0x009b4fc3UL, +0xaba68cedUL, 0x9ac96f78UL, 0x06a5b79aUL, 0xb2856e6eUL, 0x1aec3ca9UL, 0xbe838688UL, +0x0e0804e9UL, 0x55f1be56UL, 0xe7e5363bUL, 0xb3a1f25dUL, 0xf7debb85UL, 0x61fe033cUL, +0x16746233UL, 0x3c034c28UL, 0xda6d0c74UL, 0x79aac56cUL, 0x3ce4e1adUL, 0x51f0c802UL, +0x98f8f35aUL, 0x1626a49fUL, 0xeed82b29UL, 0x1d382fe3UL, 0x0c4fb99aUL, 0xbb325778UL, +0x3ec6d97bUL, 0x6e77a6a9UL, 0xcb658b5cUL, 0xd45230c7UL, 0x2bd1408bUL, 0x60c03eb7UL, +0xb9068d78UL, 0xa33754f4UL, 0xf430c87dUL, 0xc8a71302UL, 0xb96d8c32UL, 0xebd4e7beUL, +0xbe8b9d2dUL, 0x7979fb06UL, 0xe7225308UL, 0x8b75cf77UL, 0x11ef8da4UL, 0xe083c858UL, +0x8d6b786fUL, 0x5a6317a6UL, 0xfa5cf7a0UL, 0x5dda0033UL, 0xf28ebfb0UL, 0xf5b9c310UL, +0xa0eac280UL, 0x08b9767aUL, 0xa3d9d2b0UL, 0x79d34217UL, 0x021a718dUL, 0x9ac6336aUL, +0x2711fd60UL, 0x438050e3UL, 0x069908a8UL, 0x3d7fedc4UL, 0x826d2befUL, 0x4eeb8476UL, +0x488dcf25UL, 0x36c9d566UL, 0x28e74e41UL, 0xc2610acaUL, 0x3d49a9cfUL, 0xbae3b9dfUL, +0xb65f8de6UL, 0x92aeaf64UL, 0x3ac7d5e6UL, 0x9ea80509UL, 0xf22b017dUL, 0xa4173f70UL, +0xdd1e16c3UL, 0x15e0d7f9UL, 0x50b1b887UL, 0x2b9f4fd5UL, 0x625aba82UL, 0x6a017962UL, +0x2ec01b9cUL, 0x15488aa9UL, 0xd716e740UL, 0x40055a2cUL, 0x93d29a22UL, 0xe32dbf9aUL, +0x058745b9UL, 0x3453dc1eUL, 0xd699296eUL, 0x496cff6fUL, 0x1c9f4986UL, 0xdfe2ed07UL, +0xb87242d1UL, 0x19de7eaeUL, 0x053e561aUL, 0x15ad6f8cUL, 0x66626c1cUL, 0x7154c24cUL, +0xea082b2aUL, 0x93eb2939UL, 0x17dcb0f0UL, 0x58d4f2aeUL, 0x9ea294fbUL, 0x52cf564cUL, +0x9883fe66UL, 0x2ec40581UL, 0x763953c3UL, 0x01d6692eUL, 0xd3a0c108UL, 0xa1e7160eUL, +0xe4f2dfa6UL, 0x693ed285UL, 0x74904698UL, 0x4c2b0eddUL, 0x4f757656UL, 0x5d393378UL, +0xa132234fUL, 0x3d321c5dUL, 0xc3f5e194UL, 0x4b269301UL, 0xc79f022fUL, 0x3c997e7eUL, +0x5e4f9504UL, 0x3ffafbbdUL, 0x76f7ad0eUL, 0x296693f4UL, 0x3d1fce6fUL, 0xc61e45beUL, +0xd3b5ab34UL, 0xf72bf9b7UL, 0x1b0434c0UL, 0x4e72b567UL, 0x5592a33dUL, 0xb5229301UL, +0xcfd2a87fUL, 0x60aeb767UL, 0x1814386bUL, 0x30bcc33dUL, 0x38a0c07dUL, 0xfd1606f2UL, +0xc363519bUL, 0x589dd390UL, 0x5479f8e6UL, 0x1cb8d647UL, 0x97fd61a9UL, 0xea7759f4UL, +0x2d57539dUL, 0x569a58cfUL, 0xe84e63adUL, 0x462e1b78UL, 0x6580f87eUL, 0xf3817914UL, +0x91da55f4UL, 0x40a230f3UL, 0xd1988f35UL, 0xb6e318d2UL, 0x3ffa50bcUL, 0x3d40f021UL, +0xc3c0bdaeUL, 0x4958c24cUL, 0x518f36b2UL, 0x84b1d370UL, 0x0fedce83UL, 0x878ddadaUL, +0xf2a279c7UL, 0x94e01be8UL, 0x90716f4bUL, 0x954b8aa3UL}; + +static const ulong32 S8[256] = { +0xe216300dUL, 0xbbddfffcUL, 0xa7ebdabdUL, 0x35648095UL, 0x7789f8b7UL, 0xe6c1121bUL, +0x0e241600UL, 0x052ce8b5UL, 0x11a9cfb0UL, 0xe5952f11UL, 0xece7990aUL, 0x9386d174UL, +0x2a42931cUL, 0x76e38111UL, 0xb12def3aUL, 0x37ddddfcUL, 0xde9adeb1UL, 0x0a0cc32cUL, +0xbe197029UL, 0x84a00940UL, 0xbb243a0fUL, 0xb4d137cfUL, 0xb44e79f0UL, 0x049eedfdUL, +0x0b15a15dUL, 0x480d3168UL, 0x8bbbde5aUL, 0x669ded42UL, 0xc7ece831UL, 0x3f8f95e7UL, +0x72df191bUL, 0x7580330dUL, 0x94074251UL, 0x5c7dcdfaUL, 0xabbe6d63UL, 0xaa402164UL, +0xb301d40aUL, 0x02e7d1caUL, 0x53571daeUL, 0x7a3182a2UL, 0x12a8ddecUL, 0xfdaa335dUL, +0x176f43e8UL, 0x71fb46d4UL, 0x38129022UL, 0xce949ad4UL, 0xb84769adUL, 0x965bd862UL, +0x82f3d055UL, 0x66fb9767UL, 0x15b80b4eUL, 0x1d5b47a0UL, 0x4cfde06fUL, 0xc28ec4b8UL, +0x57e8726eUL, 0x647a78fcUL, 0x99865d44UL, 0x608bd593UL, 0x6c200e03UL, 0x39dc5ff6UL, +0x5d0b00a3UL, 0xae63aff2UL, 0x7e8bd632UL, 0x70108c0cUL, 0xbbd35049UL, 0x2998df04UL, +0x980cf42aUL, 0x9b6df491UL, 0x9e7edd53UL, 0x06918548UL, 0x58cb7e07UL, 0x3b74ef2eUL, +0x522fffb1UL, 0xd24708ccUL, 0x1c7e27cdUL, 0xa4eb215bUL, 0x3cf1d2e2UL, 0x19b47a38UL, +0x424f7618UL, 0x35856039UL, 0x9d17dee7UL, 0x27eb35e6UL, 0xc9aff67bUL, 0x36baf5b8UL, +0x09c467cdUL, 0xc18910b1UL, 0xe11dbf7bUL, 0x06cd1af8UL, 0x7170c608UL, 0x2d5e3354UL, +0xd4de495aUL, 0x64c6d006UL, 0xbcc0c62cUL, 0x3dd00db3UL, 0x708f8f34UL, 0x77d51b42UL, +0x264f620fUL, 0x24b8d2bfUL, 0x15c1b79eUL, 0x46a52564UL, 0xf8d7e54eUL, 0x3e378160UL, +0x7895cda5UL, 0x859c15a5UL, 0xe6459788UL, 0xc37bc75fUL, 0xdb07ba0cUL, 0x0676a3abUL, +0x7f229b1eUL, 0x31842e7bUL, 0x24259fd7UL, 0xf8bef472UL, 0x835ffcb8UL, 0x6df4c1f2UL, +0x96f5b195UL, 0xfd0af0fcUL, 0xb0fe134cUL, 0xe2506d3dUL, 0x4f9b12eaUL, 0xf215f225UL, +0xa223736fUL, 0x9fb4c428UL, 0x25d04979UL, 0x34c713f8UL, 0xc4618187UL, 0xea7a6e98UL, +0x7cd16efcUL, 0x1436876cUL, 0xf1544107UL, 0xbedeee14UL, 0x56e9af27UL, 0xa04aa441UL, +0x3cf7c899UL, 0x92ecbae6UL, 0xdd67016dUL, 0x151682ebUL, 0xa842eedfUL, 0xfdba60b4UL, +0xf1907b75UL, 0x20e3030fUL, 0x24d8c29eUL, 0xe139673bUL, 0xefa63fb8UL, 0x71873054UL, +0xb6f2cf3bUL, 0x9f326442UL, 0xcb15a4ccUL, 0xb01a4504UL, 0xf1e47d8dUL, 0x844a1be5UL, +0xbae7dfdcUL, 0x42cbda70UL, 0xcd7dae0aUL, 0x57e85b7aUL, 0xd53f5af6UL, 0x20cf4d8cUL, +0xcea4d428UL, 0x79d130a4UL, 0x3486ebfbUL, 0x33d3cddcUL, 0x77853b53UL, 0x37effcb5UL, +0xc5068778UL, 0xe580b3e6UL, 0x4e68b8f4UL, 0xc5c8b37eUL, 0x0d809ea2UL, 0x398feb7cUL, +0x132a4f94UL, 0x43b7950eUL, 0x2fee7d1cUL, 0x223613bdUL, 0xdd06caa2UL, 0x37df932bUL, +0xc4248289UL, 0xacf3ebc3UL, 0x5715f6b7UL, 0xef3478ddUL, 0xf267616fUL, 0xc148cbe4UL, +0x9052815eUL, 0x5e410fabUL, 0xb48a2465UL, 0x2eda7fa4UL, 0xe87b40e4UL, 0xe98ea084UL, +0x5889e9e1UL, 0xefd390fcUL, 0xdd07d35bUL, 0xdb485694UL, 0x38d7e5b2UL, 0x57720101UL, +0x730edebcUL, 0x5b643113UL, 0x94917e4fUL, 0x503c2fbaUL, 0x646f1282UL, 0x7523d24aUL, +0xe0779695UL, 0xf9c17a8fUL, 0x7a5b2121UL, 0xd187b896UL, 0x29263a4dUL, 0xba510cdfUL, +0x81f47c9fUL, 0xad1163edUL, 0xea7b5965UL, 0x1a00726eUL, 0x11403092UL, 0x00da6d77UL, +0x4a0cdd61UL, 0xad1f4603UL, 0x605bdfb0UL, 0x9eedc364UL, 0x22ebe6a8UL, 0xcee7d28aUL, +0xa0e736a0UL, 0x5564a6b9UL, 0x10853209UL, 0xc7eb8f37UL, 0x2de705caUL, 0x8951570fUL, +0xdf09822bUL, 0xbd691a6cUL, 0xaa12e4f2UL, 0x87451c0fUL, 0xe0f6a27aUL, 0x3ada4819UL, +0x4cf1764fUL, 0x0d771c2bUL, 0x67cdb156UL, 0x350d8384UL, 0x5938fa0fUL, 0x42399ef3UL, +0x36997b07UL, 0x0e84093dUL, 0x4aa93e61UL, 0x8360d87bUL, 0x1fa98b0cUL, 0x1149382cUL, +0xe97625a5UL, 0x0614d1b7UL, 0x0e25244bUL, 0x0c768347UL, 0x589e8d82UL, 0x0d2059d1UL, +0xa466bb1eUL, 0xf8da0a82UL, 0x04f19130UL, 0xba6e4ec0UL, 0x99265164UL, 0x1ee7230dUL, +0x50b2ad80UL, 0xeaee6801UL, 0x8db2a283UL, 0xea8bf59eUL}; + +/* returns the i'th byte of a variable */ +#ifdef _MSC_VER + #define GB(x, i) ((unsigned char)((x[(15-i)>>2])>>(unsigned)(8*((15-i)&3)))) +#else + #define GB(x, i) (((x[(15-i)>>2])>>(unsigned)(8*((15-i)&3)))&255) +#endif + +#ifdef CLEAN_STACK +static int _cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +#else +int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +#endif +{ + ulong32 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, (size_t)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; +} + +#ifdef CLEAN_STACK +int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + int z; + z = _cast5_setup(key, keylen, num_rounds, skey); + burn_stack(sizeof(ulong32)*8 + 16 + sizeof(int)*2); + return z; +} +#endif + +#ifdef _MSC_VER + #define INLINE __inline +#else + #define INLINE +#endif + +INLINE static ulong32 FI(ulong32 R, ulong32 Km, ulong32 Kr) +{ + ulong32 I; + I = (Km + R); + I = ROL(I, Kr); + return ((S1[byte(I, 3)] ^ S2[byte(I,2)]) - S3[byte(I,1)]) + S4[byte(I,0)]; +} + +INLINE static ulong32 FII(ulong32 R, ulong32 Km, ulong32 Kr) +{ + ulong32 I; + I = (Km ^ R); + I = ROL(I, Kr); + return ((S1[byte(I, 3)] - S2[byte(I,2)]) + S3[byte(I,1)]) ^ S4[byte(I,0)]; +} + +INLINE static ulong32 FIII(ulong32 R, ulong32 Km, ulong32 Kr) +{ + ulong32 I; + I = (Km - R); + I = ROL(I, Kr); + return ((S1[byte(I, 3)] + S2[byte(I,2)]) ^ S3[byte(I,1)]) - S4[byte(I,0)]; +} + +#ifdef CLEAN_STACK +static void _cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#else +void cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#endif +{ + ulong32 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]); +} + + +#ifdef CLEAN_STACK +void cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + _cast5_ecb_encrypt(pt,ct,key); + burn_stack(sizeof(ulong32)*3); +} +#endif + +#ifdef CLEAN_STACK +static void _cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#else +void cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#endif +{ + ulong32 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]); +} + +#ifdef CLEAN_STACK +void cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +{ + _cast5_ecb_decrypt(ct,pt,key); + burn_stack(sizeof(ulong32)*3); +} +#endif + +int cast5_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, + {0xEB, 0x6A, 0x71, 0x1A, 0x2C, 0x02, 0x27, 0x1B}, + }, + { 5, + {0x01, 0x23, 0x45, 0x67, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, + {0x7A, 0xC8, 0x16, 0xD1, 0x6E, 0x9B, 0x30, 0x2E} + } + }; + int i, y, err; + symmetric_key key; + unsigned char tmp[2][8]; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + if ((err = cast5_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) { + return err; + } + cast5_ecb_encrypt(tests[i].pt, tmp[0], &key); + cast5_ecb_decrypt(tmp[0], tmp[1], &key); + if ((memcmp(tmp[0], tests[i].ct, 8) != 0) || (memcmp(tmp[1], tests[i].pt, 8) != 0)) { + return CRYPT_FAIL_TESTVECTOR; + } + /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ + for (y = 0; y < 8; y++) tmp[0][y] = 0; + for (y = 0; y < 1000; y++) cast5_ecb_encrypt(tmp[0], tmp[0], &key); + for (y = 0; y < 1000; y++) cast5_ecb_decrypt(tmp[0], tmp[0], &key); + for (y = 0; y < 8; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; + + } + return CRYPT_OK; + #endif +} + +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_decrypt.c b/cbc_decrypt.c new file mode 100644 index 0000000..add5438 --- /dev/null +++ b/cbc_decrypt.c @@ -0,0 +1,56 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef CBC + +int cbc_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_CBC *cbc) +{ + int x, err; + unsigned char tmp[MAXBLOCKSIZE], tmp2[MAXBLOCKSIZE]; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(cbc != NULL); + + /* decrypt the block from ct into tmp */ + if ((err = cipher_is_valid(cbc->cipher)) != CRYPT_OK) { + return err; + } + cipher_descriptor[cbc->cipher].ecb_decrypt(ct, tmp, &cbc->key); + + /* is blocklen valid? */ + if (cbc->blocklen < 0 || cbc->blocklen > (int)sizeof(cbc->IV)) { + return CRYPT_INVALID_ARG; + } + + /* 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/cbc_encrypt.c b/cbc_encrypt.c new file mode 100644 index 0000000..8db5b5b --- /dev/null +++ b/cbc_encrypt.c @@ -0,0 +1,52 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef CBC + +int cbc_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_CBC *cbc) +{ + int x, err; + unsigned char tmp[MAXBLOCKSIZE]; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(cbc != NULL); + + if ((err = cipher_is_valid(cbc->cipher)) != CRYPT_OK) { + return err; + } + + /* is blocklen valid? */ + if (cbc->blocklen < 0 || cbc->blocklen > (int)sizeof(cbc->IV)) { + return CRYPT_INVALID_ARG; + } + + /* 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; +} + +#endif diff --git a/cbc_start.c b/cbc_start.c new file mode 100644 index 0000000..f0d5fb6 --- /dev/null +++ b/cbc_start.c @@ -0,0 +1,43 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#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, err; + + _ARGCHK(IV != NULL); + _ARGCHK(key != NULL); + _ARGCHK(cbc != NULL); + + /* bad param? */ + if ((err = cipher_is_valid(cipher)) != CRYPT_OK) { + return err; + } + + /* setup cipher */ + if ((err = cipher_descriptor[cipher].setup(key, keylen, num_rounds, &cbc->key)) != CRYPT_OK) { + return err; + } + + /* 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; +} + +#endif diff --git a/cfb_decrypt.c b/cfb_decrypt.c new file mode 100644 index 0000000..1e1d3c0 --- /dev/null +++ b/cfb_decrypt.c @@ -0,0 +1,48 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef CFB + +int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CFB *cfb) +{ + int err; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(cfb != NULL); + + if ((err = cipher_is_valid(cfb->cipher)) != CRYPT_OK) { + return err; + } + + /* is blocklen/padlen valid? */ + if (cfb->blocklen < 0 || cfb->blocklen > (int)sizeof(cfb->IV) || + cfb->padlen < 0 || cfb->padlen > (int)sizeof(cfb->pad)) { + return CRYPT_INVALID_ARG; + } + + while (len-- > 0) { + 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/cfb_encrypt.c b/cfb_encrypt.c new file mode 100644 index 0000000..8016959 --- /dev/null +++ b/cfb_encrypt.c @@ -0,0 +1,46 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef CFB + +int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CFB *cfb) +{ + int err; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(cfb != NULL); + + if ((err = cipher_is_valid(cfb->cipher)) != CRYPT_OK) { + return err; + } + + /* is blocklen/padlen valid? */ + if (cfb->blocklen < 0 || cfb->blocklen > (int)sizeof(cfb->IV) || + cfb->padlen < 0 || cfb->padlen > (int)sizeof(cfb->pad)) { + return CRYPT_INVALID_ARG; + } + + while (len-- > 0) { + 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; +} + +#endif diff --git a/cfb_start.c b/cfb_start.c new file mode 100644 index 0000000..d471412 --- /dev/null +++ b/cfb_start.c @@ -0,0 +1,47 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#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, err; + + _ARGCHK(IV != NULL); + _ARGCHK(key != NULL); + _ARGCHK(cfb != NULL); + + if ((err = cipher_is_valid(cipher)) != CRYPT_OK) { + return err; + } + + + /* 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 ((err = cipher_descriptor[cipher].setup(key, keylen, num_rounds, &cfb->key)) != CRYPT_OK) { + return err; + } + + /* encrypt the IV */ + cipher_descriptor[cfb->cipher].ecb_encrypt(cfb->IV, cfb->IV, &cfb->key); + cfb->padlen = 0; + + return CRYPT_OK; +} + +#endif diff --git a/changes b/changes new file mode 100644 index 0000000..e050ddc --- /dev/null +++ b/changes @@ -0,0 +1,957 @@ +May 12th, 2004 +v0.95 -- Optimized AES and WHIRLPOOL for SMALL_CODE by taking advantage of the fact + the transforms are circulant. AES dropped 5KB and WHIRLPOOL dropped 13KB + using the default build options on the x86. + -- Updated eax so the eax_done() would clear the state [like hmac,pmac,ocb] when + CLEAN_STACK has been defined. + -- added LTC_TEST support to rmd160 + -- updates to mycrypt_pk.h + -- updated rand_prime() to faciliate making RSA composites + -- DSA/RSA now makes composites of the exact size desired. + -- Refactored quite a bit of the code, fewer functions per C file + -- cleaned up the makefiles to organize the objects logically + -- added ICC makefile along with "profiled" targets for both GNU and ICC compilers + -- Marked functions for removal before v1.00 see PLAN for more information + -- GCC 3.4.0 tested and seems to work + -- Added PKCS #5 support + -- Fixed typo in comment header of .C files ;-) + -- Added PKCS #1 OAEP and PSS support. + +Feb 20th, 2004 +v0.94 -- removed unused variables from ocb.c and fixed it to match known test vectors. + -- Added PMAC support, minor changes to OMAC/EAX code [I think....] + -- Teamed up with Brian Gladman. His code verifies against my vectors and my code + verifies against his test vectors. Hazaa for co-operation! + -- Various small changes (added missing ARGCHKs and cleaned up indentation) + -- Optimization to base64, removed unused variable "c" + -- Added base64 gen to demos/tv_gen.c + -- Fix to demos/x86_prof.c to correctly identify the i386 architecture... weird... + -- Fixed up all of the PK code by adding missing error checking, removed "res" variables, + shrunk some stack variables, removed non-required stack variables and added proper + error conversion from MPI to LTC codes. I also spotted a few "off by one" error + checking which could have been used to force the code to read past the end of + the buffer (in theory, haven't checked if it would work) by a few bytes. + -- Added checks to OUTPUT_BIGNUM so the *_export() functions cannot overflow the output and I + also modded it so it stores in the output provided to the function (that is not on + the local stack) which saves memory and time. + -- Made SAFER default to disabled for now (plans are to cleanhouse write an implementation later) + -- Added the 512-bit one-way hash WHIRLPOOL which clocks in at 138 cycles per byte on my + Athlon XP [for comparison, SHA-512 clocks in at 77 cycles per byte]. This code uses the + teams new sbox design (not the original NESSIE one). + + +Jan 25th, 2004 +v0.93 -- [note: deleted v0.93 changes by accident... recreating from memory...] + -- Fix to RC2 to not deference pointer before ARGCHK + -- Fix to NOEKEON to match published test vectors as well as cleaned up the code a bit + -- Optimized Twofish [down to 28 cycles/byte on my box] and Blowfish + -- Fix to OMAC to test cipher block size first [prevents wasting any time] + -- Added more OMAC test vectors + -- Added EAX Encrypt+Authenticate support + -- Fix to DSA to check return of a few LTM functions I forgot [mp_to_unsigned_bin] + -- Added common headers to all C files + -- CTR mode supports big and little [default] endian counters now. + -- fix to find_cipher_any() so that it can handle a fragmented cipher_descriptor table. + -- added find_hash_any() akin to find_cipher_any(). + -- Added EAX code to demos/tv_gen.c Hazaa! + -- Removed SONY defines and files from codebase. + -- Added OCB support [patents be damned] and to demos/tv_gen.c + -- Merge all of the INPUT/OUTPUT BIGNUM macros (less toc) into mycrypt_pk.h + -- Made appropriate changes to the debug string in crypt.c + +Dec 24th, 2003 +v0.92 -- Updated the config.pl script so the options have more details. + -- Updated demos/tv_gen to include RIPEMD hashes + -- Updated Twofish so when TWOFISH_ALL_TABLES is defined a pre-computed RS table + is included [speedup: slight, about 4k cycles on my Athlon]. + -- Re-wrote the twofish large key generation [the four 8x32 key dependent tables]. Now about twice as fast. + With both optimizations [e.g. TWOFISH_ALL_TABLES defined] a 128-bit Twofish key can now be scheduled + in 26,000 cycles on my Athlon XP [as opposed to 49,000 before] when optimized for size. + -- config.pl has been updated so rmd128.o and rmd160.o are objects included in the build [oops] + -- Andrew Mann found a bug in rsa_exptmod() which wouldn't indicate if the wrong type of key was specified + (e.g. not PK_PRIVATE or PK_PUBLIC) + -- Fixed up demos/x86_prof so it sorts the output now :-) + -- The project is now powered by radioactive rubber pants. + -- Fixed dh_encrypt_key() so if you pass it a hash with a smaller output than the input key it + will return CRYPT_INVALID_HASH [to match what ecc_encrypt_key() will do] + -- Merge the store/encrypt key part of ecc_encrypt_key() as per dh_encrypt_key() [can you guess what I'm upto?] + -- Massive updates to the prime generation code. I use the LTM random prime functions [and provide a nice + interface between the LTC PRNG's and the LTM generic prng prototype]. I also use a variable number of tests + depending on the input size. This nicely speeds up most prime generation/testing within the library. + -- Added SHA-224 to the list of hashes. + -- Made HMAC test vectors constant and static [takes ROM space instead of RAM] + -- This release was brought to you by the letter P which stands for Patent Infringement. + -- Added generic HASH_PROCESS macro to mycrypt_hash.h which simplifies the hash "process" functions + I also optimized the compression functions of all but MD2 to not perform input copies when avoidable. + -- Removed the division from the Blowfish setup function [dropped 3k cycles on my Athlon] + -- Added stack cleaning to rijndael, cast5 so now all ciphers have CLEAN_STACK code. + -- Added Skipjack to the list of ciphers [made appropriate changes to demos/test.c, demos/tv_gen.c and + demos/x86_prof.c] + -- Added mechanical testing to cipher test vector routines. Now it encrypts 1000 times, then decrypts and + compares. Any fault (e.g. bug in code, compiler) in the routines is likely to show through. Doesn't + stress test the key gen though... + -- Matt Johnson found a bug in the blowfish.c apparently I was out of my mind and put twofish defines in there + The code now builds with any config. Thanks. + -- Added OMAC1 Message Authentication Code support to the library. + -- Re-prototyped the hash "process" and "done" to prevent buffer overflows [which don't seem easy to exploit]. + Updated HMAC code to use them too. Hazaa! + -- Fixed bug in ECC code which wouldn't do an _ARGCHK on stat in ecc_verify_hash(). + -- Fixed [temp fix] bug in all PK where the OUTPUT_BIGNUM macros would not trap errors on the to_unsigned_bin + conversion [now returns CRYPT_MEM, will fix it up better later] + -- Added DSA to the list of supported PK algorithms. + -- Fixed up various ciphers to &255 the input key bytes where required [e.g. where used to index a table] to prevent + problems on platforms where CHAR_BIT != 8 + -- Merged in LibTomMath v0.28 + -- Updated demos/x86_prof.c to use Yarrow during the key sched testing [was horribly slow on platforms with blockable + /dev/random]. + -- Added OMAC/HMAC tests to demos/tv_gen and I now store the output of this in notes/ + -- Fixed a bug in config.pl that wouldn't have TWOFISH_TABLES defined by default (too many commas on the line) + -- Fixed bug in hmac_done(). Apparently FIPS-198 [HMAC] specifies that the output can be truncated. My code + would not support that (does now just like the new OMAC code). + -- Removed "hashsize" from hmac_state as it wasn't being used. + -- Made demos/test.c stop if OMAC or HMAC tests fail (instead of just printing a failed message and keep going). + -- Updated notes/tech0003.txt to take into account the existence of Skipjack [also I fixed a few typos]. + -- Slight changes to Noekeon, with SMALL_CODE undefined it uses a fully unrolled version. Dropped +10 cycles/byte + on my Athlon (35 cycles per byte or 410.4Mbit/sec at 1795Mhz) + -- Added _ARGCHK() calls to is_prime() for the two input pointers. + +Sept 25th, 2003 +v0.91 -- HMAC fix of 0.90 was incorrect for keys larger than the block size of the hash. + -- Added error CRYPT_FILE_NOTFOUND for the file [hmac/hash] routines. + -- Added RIPEMD hashes to the hashsum demo. + -- Added hashsum demo to MSVC makefile. + -- Added RMD160 to the x86_prof demo [oops] + -- Merged in LibTomMath-0.27 with a patch to mp_shrink() that will be in LibTomMath-0.28 + Fixes another potential memory leak. + +Sept 7th, 2003 +v0.90 -- new ROL/ROR for x86 GCC + -- Jochen Katz submitted a patch to the makefile to prevent "make" from making the .a library + when not required. + == By default the KR code is not enabled [it's only a demo anyways!] + -- changed the "buf" in ecc_make_key from 4KB to 128 bytes [since the largest key is 65 bytes] + -- hmac_done() now requires you pass it the size of the destination buffer to prevent + buffer overflows. (API CHANGE) + -- hmac/hash filebased routines now return CRYPT_NOP if NO_FILE is defined. + -- I've removed the primes from dh.c and replaced them with DR safe primes suitable for the default + configuration of LibTomMath. Check out these comparisons on a 1.3Ghz Athlon XP, optimized for size, + +768-bit, 4 vs. 10 +1024-bit, 8 vs. 18 +1280-bit, 12 vs. 34 +1536-bit, 20 vs. 56 +1792-bit 28 vs. 88 +2048-bit, 40 vs. 124 +2560-bit, 71 vs. 234 +3072-bit, 113 vs. 386 +4096-bit, 283 vs. 916 + + Times are all in milliseconds for key generation. New primes times on the left. This makes the code binary + incompatible with previous releases. However, this addition is long overdue as LibTomMath has supported DR + reductions for quite some time. + -- Added RIPE-MD 128 and 160 to the list of supported hashes [10 in total]. + -- The project has been released as public domain. TDCAL no longer applies. + +July 15th, 2003 +v0.89 -- Fix a bug in bits.c which would prevent it from building with msvc + -- Merged in LibTomMath v0.24 [and I used the alloc/free macros this time!] + -- Removed the LTC version of next_prime() and replaced it with a call to the + mp_prime_next_prime() from LibTomMath + -- reverted bits.c to the 0.86 copy since the new one doesn't build in MSVC + or cygwin. + +Jul 10th, 2003 +v0.88 -- Sped up CAST5 key schedule for MSVC + -- added "ulong32" which allows people on 64-bit platforms to force the 32-bit tables in + ciphers like blowfish and AES to be 32-bits. E.g. when unsigned long is 64-bits. + -- Optimized the SAFER-SK64, SAFER-SK128, SAFER+, RC5 and RC6 key schedule [big time!] + -- Optimized SHA-1 and SHA-256 quite a bit too. + -- Fixed up the makefile to use -fomit-frame-pointer more liberally + -- Added tv_gen program which makes test vectors for ciphers/hashes + -- Merged in LibTomMath v0.22 + +Jun 19th, 2003 +v0.87 -- Many MSVC optimizations to the code base + -- Improved the AES and Twofish key schedule [faster, more constant time] + -- Tons of optimizations here and there. + +Jun 15th, 2003 +v0.86 -- Fixed up AES to workaround MSVC optimizer bug + -- Merged in fresh LTM base [based on v0.20] so there are no warnings with MSVC + -- Wrote x86_prof which will time the hashes and ciphers downto cycles per byte. + -- Fixed up demos/encrypt to remove serpent_desc from the list + -- Re-enabled MSVC optimizations w00t w00t + -- Replaced "errno" with "err" in all functions that had it so it wouldn't clash + with the global "errno" + -- Removed a set of unused variables from certain functions + -- Removed {#line 0 "..."} stuff from mpi.c to comply with ISO C :-) + +Jun 11th, 2003 +v0.85 -- Swapped in a new AES routine + -- Removed Serpent + -- Added TDCAL policy document + +Jun 1st, 2003 +v0.84 -- Removed a 4KB buffer from rsa_decrypt_key that wasn't being used no more + -- Fixed another potential buffer problem. Not an overflow but could cause the + PK import routines to read past the end of the buffer. + -- Optimized the ECC mulmod more by removing a if condition that will always be false + -- Optimized prime.c to not include a 2nd prime table, removed code from is_prime calls prime + test from LibTomMath now + -- Added LTC_TEST define which when defined will enable the test vector routines [see mycrypt_custom.h] + -- Removed ampi.o from the depends cuz it ain't no not working in *nix with it [routines are in mpi.c now]. + + +Mar 29th, 2003 +v0.83 -- Optimized the ecc_mulmod, it's faster and takes less heap/stack space + -- Fixed a free memory error in ecc_mulmod and del_point which would try to free NULL + -- Fixed two serious bugs in rsa_decrypt_key and rsa_verify_hash that would allow a trivialy + buffer overflow. + -- Fixed a bug in the hmac testing code if you don't register all the hashes it won't return + errors now. + +Mar 15th, 2003 +v0.82 -- Manual updated + -- Added MSVC makefile [back, actually its written from scratch to work with NMAKE] + -- Change to HMAC helper functions API to avoid buffer overflow [source changes] + -- the rsa_encrypt_key was supposed to reject key sizes out of bounds ... + same fix to the rsa_sign_hash + -- Added code to ensure that that chaining mode code (cfb/ofb/ctr/cbc) have valid + structures when being called. E.g. the indexes to the pad/ivs are not out of bounds + -- Cleaned up the DES code and simplified the core desfunc routine. + -- Simplified one of the boolean functions in MD4 + +Jan 16th, 2003 +v0.81 -- Merged in new makefile from Clay Culver and Mike Frysinger + -- Sped up the ECC mulmod() routine by making the word size adapt to the input. Saves a whopping 9 point + operations on 521-bit keys now (translates to about 8ms on my Athlon XP). I also now use barrett reduction + as much as possible. This sped the routine up quite a bit. + -- Fixed a huge flaw in ecc_verify_hash() where it would return CRYPT_OK on error... Now fixed. + -- Fixed up config.pl by fixing an invalid query and the file is saved in non-windows [e.g. not CR/LF] format + (fix due to Mika Boström) + -- Merged in LibTomMath for kicks + -- Changed the build process so that by default "mycrypt_custom.h" is included and provided + The makefile doesn't include any build options anymore + -- Removed the PS2 and VC makefiles. + +Dec 16th, 2002 +v0.80 -- Found a change I made to the MPI that is questionable. Not quite a bug but definately not desired. Had todo + with the digit shifting. In v0.79 I simply truncated without zeroing. It didn't cause problems during my + testing but I fixed it up none the less. + -- Optimized s_mp_mul_dig() from MPI to do a minimal number of passes. + -- Fixed in rsa_exptmod() where I was getting the size of the result. Basically it accomplishes the same thing + but the fixed code is more readable. + -- Fixed slight bug in dh_sign_hash() where the random "k" value was 1 byte shorter than it should have been. I've + also made the #define FAST_PK speed up signatures as well. Essentially FAST_PK tells the DH sub-system to + limit any private exponent to 256-bits. Note that when FAST_PK is defined does not make the library + binary or source incompatible with a copy of the library with it undefined. + -- Removed the DSA code. If you want fast diffie-hellman just define FAST_PK :-) + -- Updated dh_sign_hash()/dh_verify_hash() to export "unsigned" bignums. Saves two bytes but is not binary + compatible with the previous release... sorry! I've performed the same fix to the ecc code as well. + -- Fixed up the PK code to remove all use of mp_toraw() and mp_read_raw() [get all the changes out of the way now] + -- Fixed a bug in the DH code where it missed trapping a few errors if they occurred. + -- Fixed a slight "its-not-a-bug-but-could-be-done-better" bug in the next_prime() function. Essentially it was + testing to ensure that in the loop that searches for the next candidate that the step never grows beyond + 65000. Should have been testing for MP_DIGIT_MAX + -- Spruced up the config.pl script. It now makes a header file "mycrypt_custom.h" which can be included *before* + you include mycrypt.h. This allows you to add libtomcrypt to a project without completely changing your make + system around. Note that you should use the makefile it writes to at least build the library initially. + -- Used splint to check alot of the code out. Tons of minor fixes and explicit casts added. + -- Also made all the internal functions of MPI are now static to avoid poluting the namespace + -- **Notice**: There are no planned future releases for at least a month from the this release date. + +Dec 14th, 2002 +v0.79 -- Change to PK code [binary and source]. I made it so you have to pass the buffer size to the *_decrypt_key and + *_verify_hash functions. This prevents malformed packets from performing buffer overflows. I've also trimmed + the packet header size [by 4 bytes]. + -- Made the test program halt on the first error it occurs. Also made it trap more errors than before. + -- Wrote the first chapter of my new book [DRAFT!], not in this package but check my website! + -- Included a perl script "config.pl" that will make "makefile.out" according to the users needs. + -- Added shell script to look for latest release + -- Merge DH and ECC key defines from mycrypt_cfg.h into the makefiles + -- updated the makefile to use BSD friendly archiving invokations + -- Changed the DH and ECC code to use base64 static key settings [e.g. the primes]. Dropped the code size by 3KB + and is ever-so-slightly faster than before. + -- added "mp_shrink" function to shrink the size of bignums. Specially useful for PK code :-) + -- Added new exptmod function that calculates a^b mod c with fewer multiplies then before [~20% for crypto + sized numbers]. Also added a "low mem" variant that doesn't use more than 20KB [upto 4096 bit nums] of + heap todo the calculation. Both are #define'able controlled + -- Added XREALLOC macro to provide realloc() functionality. + -- Added fix where in rsa_import() if you imported a public key or a non-optimized key it would free the mp_int's + not being used. + -- Fixed potential bug in the ECC code. Only would occur on platforms where char is not eight bits [which isn't + often!] + -- Fixed up the ECC point multiplication, its about 15% faster now + -- While I was at it [since the lib isn't binary backwards compatible anyways] I've fixed the PK export routines + so they export as "unsigned" types saving 1 byte per bignum outputted. Not a lot but heck why not. + +Nov 28th, 2002 +v0.78 -- Made the default ARGCHK macro a function call instead which reduced the code size from 264KB to 239KB. + -- Fixed a bug in the XTEA keysize function which called ARGCHK incorrectly. + -- Added Noekeon block cipher at 2,800 bytes of object code and 345Mbit/sec it is a welcome addition. + -- Made the KR code check if the other PK systems are included [provides error when building otherwise]. + -- Made "aes" an alias for Rijndael via a pre-processor macro. Now you can use "aes_ecb_encrypt", etc... :-) + Thanks to Jean-Luc Cooke for the "buzzword conformance" suggestion. + -- Removed the old PK code entirely (e.g. rsa_sign, dh_encrypt). The *_sign_hash and *_encrypt_key functions + are all that is to remain. + -- **NOTE** Changed the PK *_import (including the keyring) routine to accept a "inlen" parameter. This fixes a + bug where improperly made key packets could result in reading passed the end of the buffer. This means + the code is no longer source compatible but still binary compatible. + -- Fixed a few other minor bugs in the PK import code while I was at it. + +Nov 26th, 2002 +v0.77 -- Updated the XTEA code to use pre-computed keys. With optimizations for speed it achieves 222Mbit/sec + compared to the 121Mbit/sec before. It is 288 bytes bigger than before. + -- Cleaned up some of the ciphers and hashes (coding style, cosmetic changes) + -- Optimized AES slightly for 256-bit keys [only one if statement now, still two for 192-bit keys] + -- Removed most test cases from Blowfish, left three of them there. Makes it smaller and faster to test. + -- Changed the primality routines around. I now use 8 rounds of Rabin-Miller, I use 256 primes in the sieve + step and the "rand_prime" function uses a modified sieve that avoids alot of un-needed bignum work. + -- Fixed a bug in the ECC/DH signatures where the keys "setting" value was not checked for validity. This means + that a invalid value could have caused segfaults, etc... + -- **NOTE** Changed the way the ECC/DH export/import functions work. They are source but not binary compatible + with v0.76. Essentially insteading of exporting the setting index like before I export the key size. Now + if you ever re-configure which key settings are supported the lib will still be able to make use of your + keys. + -- Optimized Blowfish by inlining the round function, unrolling it for four rounds then using a for loop for the + rest. It achieves a rate of 425Mbit/sec with the new code compared to 314Mbit/sec before. The new blowfish + object file is 7,813 bytes compared to 8,663 before and is 850 bytes smaller. So the code is both smaller and + faster! + -- Optimized Twofish as well by inlining the round function. Gets ~400Mbit/sec compared to 280Mbit/sec before + and the code is only 78 bytes larger than the previous copy. + -- Removed SMALL_PRIME_TAB build option. I use the smaller table always. + -- Fixed some mistakes concerning prime generation in the manual. + -- [Note: sizes/speeds are for GCC 3.2 on an x86 Athlon XP @ 1.53Ghz] + +Nov 25th, 2002 +v0.76 -- Updated makefiles a bit more, use "-Os" instead of "-O2" to optimize for size. Got the lib + downto 265KB using GCC 3.2 on my x86 box. + -- Updated the SAFER+, Twofish and Rijndael test vector routine to use the table driven design. + -- Updated all other test vector routines to return as soon as an error is found + -- fixed a bug in the test program where errors in the hash test routines would not be reported + correctly. I found this by temporarily changing one of the bytes of the test vectors. All the + hashes check out [the demos/test.c would still have reported an error, just the wrong one]. + + +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..7e85dda --- /dev/null +++ b/crypt.c @@ -0,0 +1,232 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +/* Dropbear doesn't need these + +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(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 +#if defined(NOEKEON) + " Noekeon\n" +#endif +#if defined(SKIPJACK) + " Skipjack\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(SHA224) + " SHA-224\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 +#if defined(RIPEMD128) + " RIPEMD128\n" +#endif +#if defined(RIPEMD160) + " RIPEMD160\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 +#if defined(MDSA) + " DSA\n" +#endif +#if defined(KR) + " KR\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 +#if defined(INTEL_CC) + " Intel C 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(OMAC) + " OMAC " +#endif +#if defined(PMAC) + " PMAC " +#endif +#if defined(EAX_MODE) + " EAX_MODE " +#endif +#if defined(OCB_MODE) + " OCB_MODE " +#endif +#if defined(TRY_UNRANDOM_FIRST) + " TRY_UNRANDOM_FIRST " +#endif +#if defined(LTC_TEST) + " LTC_TEST " +#endif +#if defined(PKCS_1) + " PKCS#1 " +#endif +#if defined(PKCS_5) + " PKCS#5 " +#endif + "\n" + "\n\n\n" + ; + */ + diff --git a/crypt.out b/crypt.out new file mode 100644 index 0000000..0b8ba59 --- /dev/null +++ b/crypt.out @@ -0,0 +1,88 @@ +\BOOKMARK [0][-]{chapter.1}{Introduction}{} +\BOOKMARK [1][-]{section.1.1}{What is the LibTomCrypt?}{chapter.1} +\BOOKMARK [2][-]{subsection.1.1.1}{What the library IS for?}{section.1.1} +\BOOKMARK [2][-]{subsection.1.1.2}{What the library IS NOT for?}{section.1.1} +\BOOKMARK [1][-]{section.1.2}{Why did I write it?}{chapter.1} +\BOOKMARK [2][-]{subsection.1.2.1}{Modular}{section.1.2} +\BOOKMARK [1][-]{section.1.3}{License}{chapter.1} +\BOOKMARK [1][-]{section.1.4}{Patent Disclosure}{chapter.1} +\BOOKMARK [1][-]{section.1.5}{Building the library}{chapter.1} +\BOOKMARK [1][-]{section.1.6}{Building against the library}{chapter.1} +\BOOKMARK [1][-]{section.1.7}{Thanks}{chapter.1} +\BOOKMARK [0][-]{chapter.2}{The Application Programming Interface \(API\)}{} +\BOOKMARK [1][-]{section.2.1}{Introduction}{chapter.2} +\BOOKMARK [1][-]{section.2.2}{Macros}{chapter.2} +\BOOKMARK [1][-]{section.2.3}{Functions with Variable Length Output}{chapter.2} +\BOOKMARK [1][-]{section.2.4}{Functions that need a PRNG}{chapter.2} +\BOOKMARK [1][-]{section.2.5}{Functions that use Arrays of Octets}{chapter.2} +\BOOKMARK [0][-]{chapter.3}{Symmetric Block Ciphers}{} +\BOOKMARK [1][-]{section.3.1}{Core Functions}{chapter.3} +\BOOKMARK [1][-]{section.3.2}{Key Sizes and Number of Rounds}{chapter.3} +\BOOKMARK [1][-]{section.3.3}{The Cipher Descriptors}{chapter.3} +\BOOKMARK [2][-]{subsection.3.3.1}{Notes}{section.3.3} +\BOOKMARK [1][-]{section.3.4}{Symmetric Modes of Operations}{chapter.3} +\BOOKMARK [2][-]{subsection.3.4.1}{Background}{section.3.4} +\BOOKMARK [2][-]{subsection.3.4.2}{Choice of Mode}{section.3.4} +\BOOKMARK [2][-]{subsection.3.4.3}{Implementation}{section.3.4} +\BOOKMARK [1][-]{section.3.5}{Encrypt and Authenticate Modes}{chapter.3} +\BOOKMARK [2][-]{subsection.3.5.1}{EAX Mode}{section.3.5} +\BOOKMARK [2][-]{subsection.3.5.2}{OCB Mode}{section.3.5} +\BOOKMARK [0][-]{chapter.4}{One-Way Cryptographic Hash Functions}{} +\BOOKMARK [1][-]{section.4.1}{Core Functions}{chapter.4} +\BOOKMARK [1][-]{section.4.2}{Hash Descriptors}{chapter.4} +\BOOKMARK [2][-]{subsection.4.2.1}{Notice}{section.4.2} +\BOOKMARK [0][-]{chapter.5}{Message Authentication Codes}{} +\BOOKMARK [1][-]{section.5.1}{HMAC Protocol}{chapter.5} +\BOOKMARK [1][-]{section.5.2}{OMAC Support}{chapter.5} +\BOOKMARK [1][-]{section.5.3}{PMAC Support}{chapter.5} +\BOOKMARK [0][-]{chapter.6}{Pseudo-Random Number Generators}{} +\BOOKMARK [1][-]{section.6.1}{Core Functions}{chapter.6} +\BOOKMARK [2][-]{subsection.6.1.1}{Remarks}{section.6.1} +\BOOKMARK [2][-]{subsection.6.1.2}{Example}{section.6.1} +\BOOKMARK [1][-]{section.6.2}{PRNG Descriptors}{chapter.6} +\BOOKMARK [1][-]{section.6.3}{The Secure RNG}{chapter.6} +\BOOKMARK [2][-]{subsection.6.3.1}{The Secure PRNG Interface}{section.6.3} +\BOOKMARK [0][-]{chapter.7}{RSA Routines}{} +\BOOKMARK [1][-]{section.7.1}{Background}{chapter.7} +\BOOKMARK [1][-]{section.7.2}{Core Functions}{chapter.7} +\BOOKMARK [1][-]{section.7.3}{Packet Routines}{chapter.7} +\BOOKMARK [1][-]{section.7.4}{Remarks}{chapter.7} +\BOOKMARK [0][-]{chapter.8}{Diffie-Hellman Key Exchange}{} +\BOOKMARK [1][-]{section.8.1}{Background}{chapter.8} +\BOOKMARK [1][-]{section.8.2}{Core Functions}{chapter.8} +\BOOKMARK [2][-]{subsection.8.2.1}{Remarks on Usage}{section.8.2} +\BOOKMARK [2][-]{subsection.8.2.2}{Remarks on The Snippet}{section.8.2} +\BOOKMARK [1][-]{section.8.3}{Other Diffie-Hellman Functions}{chapter.8} +\BOOKMARK [1][-]{section.8.4}{DH Packet}{chapter.8} +\BOOKMARK [0][-]{chapter.9}{Elliptic Curve Cryptography}{} +\BOOKMARK [1][-]{section.9.1}{Background}{chapter.9} +\BOOKMARK [1][-]{section.9.2}{Core Functions}{chapter.9} +\BOOKMARK [1][-]{section.9.3}{ECC Packet}{chapter.9} +\BOOKMARK [1][-]{section.9.4}{ECC Keysizes}{chapter.9} +\BOOKMARK [0][-]{chapter.10}{Digital Signature Algorithm}{} +\BOOKMARK [1][-]{section.10.1}{Introduction}{chapter.10} +\BOOKMARK [1][-]{section.10.2}{Key Generation}{chapter.10} +\BOOKMARK [1][-]{section.10.3}{Key Verification}{chapter.10} +\BOOKMARK [1][-]{section.10.4}{Signatures}{chapter.10} +\BOOKMARK [1][-]{section.10.5}{Import and Export}{chapter.10} +\BOOKMARK [0][-]{chapter.11}{Public Keyrings}{} +\BOOKMARK [1][-]{section.11.1}{Introduction}{chapter.11} +\BOOKMARK [1][-]{section.11.2}{The Keyring API}{chapter.11} +\BOOKMARK [0][-]{chapter.12}{GF\(2w\) Math Routines}{} +\BOOKMARK [0][-]{chapter.13}{Miscellaneous}{} +\BOOKMARK [1][-]{section.13.1}{Base64 Encoding and Decoding}{chapter.13} +\BOOKMARK [1][-]{section.13.2}{The Multiple Precision Integer Library \(MPI\)}{chapter.13} +\BOOKMARK [2][-]{subsection.13.2.1}{Binary Forms of ``mp\137int'' Variables}{section.13.2} +\BOOKMARK [2][-]{subsection.13.2.2}{Primality Testing}{section.13.2} +\BOOKMARK [0][-]{chapter.14}{Programming Guidelines}{} +\BOOKMARK [1][-]{section.14.1}{Secure Pseudo Random Number Generators}{chapter.14} +\BOOKMARK [1][-]{section.14.2}{Preventing Trivial Errors}{chapter.14} +\BOOKMARK [1][-]{section.14.3}{Registering Your Algorithms}{chapter.14} +\BOOKMARK [1][-]{section.14.4}{Key Sizes}{chapter.14} +\BOOKMARK [2][-]{subsection.14.4.1}{Symmetric Ciphers}{section.14.4} +\BOOKMARK [2][-]{subsection.14.4.2}{Assymetric Ciphers}{section.14.4} +\BOOKMARK [1][-]{section.14.5}{Thread Safety}{chapter.14} +\BOOKMARK [0][-]{chapter.15}{Configuring the Library}{} +\BOOKMARK [1][-]{section.15.1}{Introduction}{chapter.15} +\BOOKMARK [1][-]{section.15.2}{mycrypt\137cfg.h}{chapter.15} +\BOOKMARK [1][-]{section.15.3}{The Configure Script}{chapter.15} diff --git a/crypt.pdf b/crypt.pdf new file mode 100644 index 0000000000000000000000000000000000000000..749b9da772d279a3fe0ebe9c3e06c195c49f24fa GIT binary patch literal 404940 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

^Hgqnya3crJzj>Q=2W5!P}8e$<`h6t@p z^_bPI!x1lyk$AyC=d;kJzbU- zMk>qqm>MuLD{curF=cF2wBq)3DL>pBYk^%gW1spFDa@N4*mTVjQG?Y>9w1RtP;dzc zNbz}ZcCX)iFoB^c*mW#3i)3zEoa*jf95nJpArFU~8}Ab|E+W1GTDtN?C-x$P5QRN} zbZT3SSS;!1E$+?n!XF(e74z<*=oPc%CQT}B1H~f};l5Lr`DbFgzcWb%g=ak(bsa}B z%+=U;z5(aP*_)kyV?RuTG_pBUiImZ5v65~MCePm|huzoCBUgaFlcVSF(7^6-1@-Hr z!K5@sU8MAH5Jt!VA`yKqqQ|I2OiYORWI4ud6#~{PTi{=%K+=MX=!&7D$fTVaEz_a{j?Jq*Rg8XGd6Kk zG(p=;gBGtl?AShi8F)F`Fzs3Bom2;v>IQ%z9MS={=ngZh1D8^OXv9jbb;Ol%=a&16 zIhAxV&^x)sSo=jc&*7HRF=1`cewy^Y^$4_4y5m`CSPI7_tACX?%Ez2`b*ZJl4fKLK zbe8m0(#l%^QWVPCpW7jL4|*zpF*MOb1(JKl7k5qSe%bEo1X~o}CPrULMOhndUpNUe zLIK7bWq(c{{K)VMYmK;yv#rpKW_vo2QIyO-2esXp>@i0mKorCTB3{Ux@e_Z~a|A|; z8P1yWCJ41Ph0n-XQXK@zbeMq4f+sXOAq@JxR%v%w1-8{wI{Jjr^UzUUNmX$T@E8VA zhLG@PR3D^)^^i*toJfUMIE^ZV(ZYOM@!8mj0VQJI949w&e-amL!&nZx;QkW7?rWQA zf5obP!-(-2y8o%9|DnU?jKv5zRAVq5Um)P)MGm);5vX1?_Vw-8@GB;f*;z0){HL-qD77wlkWu)mhI&L zVP@BTc``+F?1=crYX(R;TH(h5)9~v;XRVnKim!S@wy)encY6V-c!A+DZ2MDU5Tvx-Acei|i5CVqRB*|6~s4_2mxdBfzD^v;F%_#*R;kHVCjm($-M1%ZMrP z1S@;!+LPw+g}eTIIK53O4SE3Ul8*h)>^ z9aXFn@z4_3A8F)yg5LLzd%64=)UNL$dKVhhZcD*{(ST@{)Gtu=_fw;G%Z23q%Fz z3~5UcDmx&5>~;k+ucAjfC{(%RB`89Yjnftxlz2aKZbK*LN#p`c$bTV7mj*Lj2ocO+ z=RkriMpVhzws-LaPCx%F9$2@sE&e!;zG-%QH-5rZ&r-;>qu1wlEUn_3lJdiq+=*H4 zc#yNuLGLo0Mvy#-xo5G#1b#zf=aHv08>ocIxo$IbzwV8SJKMnM6!>HNF&u9emj#~_ zAx&#!z()h5_k%JZ~rf&*}n`SEUfIT|C0V$nEulc!ou`F8A6N`+HKaEP{cgFA>+pwTqbrD zy^D0Er1PrKP=@z7uXQIMkmy)vuTpf!;rI zYmc)WO??h0{`pWW+~WfL>px>b zbuVV#7D7}7f05xT{k4KYq^h?<2dmIO8XD;4(Sv30?^QIDh3o ztQAaqCv4`hbj?7sTJ68*pUU5cHg6pZeqAPm9#`M$Ut?NS`DSPrr}Y*y1L#U-S}EXx zGVx2StEkP6aqe~!Ui~fk)(-@(5B+}EBD+0jU1A(J3W8LFYrdf$3}bY5o`C*N&i)K$X`I?ZETk`luJgIp55c~yNc7xK(862@6 z3Nxx&Mm`*0eJiQXSu+MJhO&0kQS7L9ICn(t(lub{ApS4k|G$WSHs=4!A7o+vPokfN z`F|q%)gt+j0|Ze-fk4dP1`V5=*f!LuGDOk?hTklsf?**)yW>@;CNL5^+#CGF!L;ii z*eb;61$CR3*hENA(@r3w@MZ0Y7$100n25iXel;Nqny6{I#yyquJe7QlJfHB0FDWLq;sotsn5<+J2I05 z3a=3nf(#i7OuT@;8Lcc#RqN@D$1|NAQ$`*RgI!kdPu5C0*U?0!0A^Bcz-#WkmW^qy zNiH1L;&t6R79(~;WJ?Bi7FyLG1}u(-XHeQkKV6|9I;^#ohH>YnZ>R5fgSo5{;dS$U zfI*8#+1KL8mHxQ1Go5(#w|7d<-v~9Kb%d%7shTAr_$*0{g0cX zrpRVOn8O0{TXZwK`@+fdwF)=3$53GPcV=smB4tGi9CK18ZM3ff8L6^aq@&vR-2afM znnx9^7NTBe$w!_gNl<|v%;uk9FcA&z?{CT$CgSt5G%7b$=&hobJ04b~5z^p{pP2K9 zddL09AqHVq&D=(e+i~zvUr;Po8%4;#5pEUbDz-oI!M0+7>ETQ1XRvPgwTHU2L4n_a zv5qZ)S?p^Y>tGXxi+l*B8ut13YxB~Gs#fBiP8U|IL)w$Y2|XW`sw}xB2Y=d)=XZ^ql z8F4f5r%3;%3Z^@!rJ?t7Y86( z9xtv~Oo*;e&0|1kLx&5uc2pe>xe#Q}9ljrk{K+l)njhQK6eAf(8T|}Wz$0USG3es_ z{#KIst5yk}#+&N>X9lBCvVr zTmaS;Z7@mNO+e?20ea$?E3RpsrAOw0{tU9!);`eN+JF*)fu1@ zu{v*0nV6Dzut2bwixs9qLIYBPu?*dc<07stniT{2T&ii!Rff}GTTRi)tf#O5d``K0 ziNP1^4m5$tU3>)hc9M|A9Tt)RE&D65Q}-%!4T2wbdydYxw)zoyvcqf@eQ5gkiW7B< z1dzkoQ=Tv=V3!lu;h2O|_rZIEgmZz4H*ZvlSZ@P1cu4;T86+NV;hcp@{Ah;)Rk(Mq zf9WAy6e*;dd(rdyc_=tH=7$%C?vD%fxKZw|Hn(wOP;(|9yr4V~|1lgD!7JFzm9i0k zPO)$vhgA?xc5F*H3viUFye^qLvVB?0WJB@tKb3scmCDahf(K4C&u-5It8+B98hy({ z2qxyJuvo|W1lQ;z%(sr3P38zJs>>2o*s)Mx3`~LTaAO_P7x5Jn{Q$Wn(}_d0mTu*p zAe+QiYvi>W1Ua@SsQH~>^BQ8FcGKd>pSmX?wsJ;ymiC?)&5k!aW46=QA_eK47cJNU z5;+fRDCb_R+LaCGo{6P8AahO-c1zAY8cvve6ZAK7r&L&(*&4(s-|0aef@ba0-mnB* zH+&i*eir-3^H+3o^E`mYRLv*4Z59{2(iV>JA@P=km=yJqR3nXZPg|W5X966jrM7*( ziATpHFOMtKxt=16hstI5RBrUo@N5L8F$w-9*$Q^*xC(SW$^GnCgCWxq8ukY;b;9Gu zacSEf+@MqoFMDhon7qmM^$Bnnb*Cn;H^3h9682;=90beRV(3$xCjQb)UVux6>=^a> zvSILu9Ep8Jjs(LQezB)f5F?oUjAoLzjP-9vVc?06!vAJ@AW0%4|;+V#wD$AOdW zjcvSK`0~S_5nRPKQ|W1zl!x-cDqJYYmN5fZhbYV+?E@9`T(F+dtYNkic;fqN7$n1Dih4spR3^n zQ9O+VTzY*NPB08oqw^el(~IU4oBo)Bx2JjUFW);TmU+MA#POt~ zvuNw?;kf@;q_UX-KRM!uf#n*6a zrc^9YXhGRaBJ9lpH0kC0z!Ol%QN9lWN{|zwJx6g^2Vo7N@IhLPpKr-_Nt5zO_y{lS zgT4(pP;}LpRxDUwgX-BaVJDr1$?%=g^uoadZwhfI>yUT4x0g@=oCmUhHniurafQ7& zECvDnk&+JQfSKA)D-$om;1eO~zkgaY_4%_>1p0PX9BDU|q5u79UYTmq1h@HHfjl(5 zYSs8wj5DWh*;*xUUBf$0T@HWn-o3PMFF=u@VL|hIfeF&_W&LFH8XI$=UJ9{~Yliih zOUtQpMsn{R4a5-6v&BX#f^3Q3p%e=dkUQ(gB%N9bDsL#3^lvn3D)!vJ218(_V#R$~ zU0gPlncCH`q0CjJ!KJkfgcktDc0a3vl7%Q?3hsEM`yvPB9fqfoPWa&)7 zeBs0Dy487(PRN)iYZne;U13yxQIqKhfD{Uxk!r{S8gc9#{SL<5S4WjP^Tb%__rG{> z%-d8y>V6tgRadvy$6N!R{LPiXuEdLXZCmqLI8`!%6oC)q3t5~L*YK9`ATfTMU&lHxIt%PX} z96NXW^(UXl2ab>ShpHEchXd}pSELcVoIhY{3w$1_;CuVt{XLmlTq8{hT1106$iAVg(Bo)ag^R33WV=)bmh4XhBM_CoJ zePEgwxYkq=bxr7ZxWO*!c5M~)ctvHmQ{%mMn}!_c1>W&OFax-3?O47b5oCY<-Cm-v zjOJ4pDV+Rh>BH-(Jw~JqCbF6DMPyR`tW=P?C^Ar~)M@@cks2PKfG2*N^1&k`nHP!1 zT(`WG^L(rDoccg8)QGDc0z`OLwuv2ELx((b50wFGzO2m zi}qCNf&5@|=q0AKSg^oqpDuVxK?zR$=kl{O{lZG7LH*RfudTR_iu|%X^LxAxqQqKI zoDcJQJ- zNy7SHZ8lXcWsaPE<_uNM)y-?79D{a7(qQ09C%t9~PU~mrr_X}B+g?QW%vTY;-8{o4 zE6BpR*@4Z!%vS>W=kdRg5i7^^#VO={VSlPF)dc$MtRG66|cQF@77C|(xud;6>}H^%bEfQ z^)YSEnKVj<^YKL2lnJLB@FnmMsN7qvb&MlV8Y%?ye0aAm4pYw>In~yFf4u7;qb!U* zL&${e;B+hHQjBq|-^bxX9@3YXHO^n1>8ze3$=>32ddE?;)`c)$TOgz?WxKh2^#z_- z885c-dk`{H1fF~Jn@i?oOL<%<52LPm&_hR&f3194yY6B@;Z|%DbVCnrz&hF|EYrGw z{sh}f6@+G%K%w1vP4dabfR;vX4n>fdHA6a?PJ0g{dd~d>jocw{|Ie}FpTojGB|;|F ze_zE}{)m0-I>qM28D!ztVU};JdMk#sV{kuqroFpUzEk_Gq`*F;(X&=TYUZ3Tf@4E0;8#E z4d*lhOM-NccD3mT$SB$PKN{=L9e8+l!wUAsKPRa~RM9|r7}OgIu@x9}mes^jeh3FI z935d#>r8fczg;c_zq>s~9PdD?;)<%SPpB>jj@r#p8zN9s)T@;1Em&K(o3xy-d!xb1 zyD{AyQrOyVRz|q2B(-R7EPwy1+fGN~@oA7Lfp8pPN+X-EVz6~+NtG6*V%NWtO16!Z zxDDPejg!k72D01)7Dmy)9hZo{oKq@m1LFfD``M)7l%;B8RqEuB7$|N{^B{r$gO-2?b*3+~P*1eNa zkwlH$kIvLw+)lZZQ6~fp)lfznPLuZ$|CH#0aL{zVp-2(-%e2Y#&}_Web&Cg6#={*l zSn0f>1C=b6f_CfsSf-#@~^%a1~9RLnq3sBf8@QyZ4v)>crHkfB3b1R8}b3J^dYIq5H)OwU0q#+!L`y_#I8oAib~< zO($v1A(11K=ZIfyxfW;HK>y)Ph{{Er6mx9RQHZtr(ISj0s4V8dA~rNE4ZvLBap8g{ z+PWfubiL!mn@ki~#rw6pC^uGLl+Q>DNl2dAB2rIrzL+t%?dm69T?!Lh+#U0*AILA+s18{{9DVAgdO~#?8TY;KjCx}~3 zDT$Yz7uF{hrDn|~jwb0(DH#*slx>pkda}w-~xtm zYpFWXXRN4#qLcCJrefu&$XD~EMLed4up4R65RoBW9L2ORx3gn}qXYFZjV^Ynqo7()RMhmfi z(wN(`B4!8}R2`F)Ws2gWPCE6y$;=XPmq_31k0H5e$6MrBHh=eok6(W3i}_O$X|~c3 zY#%qeu;I9DT4e5&sp(xR?nKJq`T20v#FWnRC*S)A?pwOR^anFfE)P#==n-E!Qa`Kl zc093NtZ+gb>?+OJu337Y!F$p&87g|2sV1%tzJOiS4wLs?&bmV<}VK(6T03T09TjazxbA)qe#m{PB08vj~ zD#fqX>KDaku_z=mOJSZq^b4eLiQg2v;Nzk+$McF1Gb-NSalQ-S=)uIv4tgBlRz%lG z>mf3uPR>K7^XF}VuVJxoX_kV*H#Z0d-o$;JkAoQC%03GPB^`&>cfd^s9^c2UxQ}E( zl_{|2@`L&JtfM9b?9rVd4NV6Ib_b_{>a2zP|4N*3-Iu}h*0266 zC0FBe<~;Kz&E#_-trmAjFg^uh+Z-KwUkKMG-@d@tARK)GQ*Q zj0W*3w}EIY1%|K!@6Olh6kqMV=h@fYOuOULb)8P8h(;!t8A}KapGE;+LU#U@RN%9Z z0;ca4hJfa?26B5gI1_jWxRFiCE1vz!htXF=Nv3L4@G^b`)|&)TqN+26=iC6drJ>FxC%8)4?nT36jhGK$0J_ttiPb$SV z(blHR9LSOowm4u8Xg(0P9!s`YWexpKDJrZMQAERUH8zH;??NS+E#Ogwg8(R$zEaVG zoEV}eXuR=PSzM?AJjKph52LY{_dGbyG({4@BbT_Ym@0I}e8U>HiTv`E7n;kofIUce zM}ep?nNZ{CFqLv`xaA0=GOwwqht>ZV~LLZ0~4 zV>jOF@W{1&yE2Wli|e1hyBY^wTko;?d%EAD1~x6_d+@v7**OfVRW;!YW9cpT{fMEifeB>-X2$;MURM%vZ) zQhmL>A5RAd9f3?GL5Flc7lSLA*q4S;c7;wF?}zObM|+W}>b7qyIH~>kNU7oL1U3W7 zBnYxmts!bp;wmm{0GAX_W)_a#*)YDQNYZrF#QxJTX5nJb`$X>^+|ixx)WE&DVM<+u zG_s_-=i34^Y#a2f(DK$_3z^nODUN+fF*D1H+D+@aT{>6~z}kr)42%_R2ms?40AVh- zX}YSY%7*J=+ii{JihQQUTvg^(#mWY9QF(=p!`twJmBVfy19jcYQ*#cKijOsfJJ|Lz zbW5a#<|Pj|SI*ZmgNLhYbLzJHto$2RCY`RTwT3@u4>da*o?vWr;Doyhj>!Pa(`A5yBKP1FXX6>31j#l0DUe zlF9nYIeiLBe!VQ(1m?TQy4!#P!FXg%In@Pnybgegm>{p3PQpv{`CukVw{ zL=>tZLG{>Uv^>Rw(lYk0TR8q*FrwEK^L67ill#`Xf`1nQ%bx&x_x-90XKZ&rSh_-+ z9V|_8h)L3(7Hj*xr`4Vr$vb++?ey1##?m<$-5(& zNR95_JI7}wVb=V;CWRn2(2qd#0}K?$fX6}<2DY#xhe3C;_p|uIG!FN^KR1%Bi!Rnj z%$h7jo^j@t$&L#CP-jZ6a=FyoD9xK`4qiQoT;OGq2p7KKm{y@M_3&_P1Pl<+?wSt6 zUm=9H0l0@?s2By)OLAW80{R?0{e7BZ5VV8r4*#ms9o_Y;RYaS59oMss7Z{Hp#p7^V z1OVShYFdbISM@GS_%W^-j@$y8&ja!lxhP)pgmO8?N8A7g@W-@meiWq?fxH@Qa;Q3g z0}4y%DRjkJzzn$skCU1i?mg0XxNIv9SaNjiMBTBwN%w{_?Wj-$Sk$ti8`u#J{tko3 zS!YcS@GL01x@Rf}SQcTuHg+J)s*-Yqu`B5osE z-dXcqlsjL1jj;M)E!fmC8lo*am$>9+S~RKS0+7OiO!qj}15QY-yWTqB1kRhv3A7j} z)ufeU3vGXL2fm}EAmF*%4kwmE|A-_`|8l%&U_qs}IRD<5KcE8}dc3&qD=-67W09{D zn~JEuPU^=9;$YPvMV2+MP^|m4^f1{)UAjXFtjN7mT!Zvwqh$HInZ`~#pWJw?X-c67 zLuWCif(3=X1xHN?Asg^F)*`&?7Vnu(an?kt;mS)P>fNg6)SJf4f)j%)P&e*O%jj>- z%6AayD;A+JqIv_JM)Ghcw6^i1s_-LZw{^jX*twFSg;ye1IIvTXpbdU5>_q)3cJ+CV z$_1|tg?-z~YpO647is8@8?LGF(jy?io_ zAdY!HtwgZ08F)JaAG3a26Ene1Pj~R=%AX3{z-Kv`YX+g+frW+)Pww_dkTk2+g|>ZX zlt&axL*X!I8Z)%@9RZ0~H`D<25KwIgI%{r8k@mfefE%-UJYgLLp$>&dH=qb0w84dZ z5h_I>61K+@_4jYjOZ8n|M&VtoMQGyP&Gl6vvIu-perF_(R06UPo6zuhsIUV#Y!e6G zGy_x#_7+mR$!{e2Eu@w0`{4JZm5QV5vt7piErcn?tm6J90%QgJ8a@zh(SXyyD?wye zY(kq6?nm%G29h1c^u@X|S$P->bxef}kTEmlJkS%QLOZtpYrt;d)pI(4cc{s%JPZ^x zA@17?N@LzAx>-wA4F@Fw>Px9Qn^>oVBrxS01d4P3AZ7OPiG;DEb$@ zf;u5%M`Wz--M1x!4w~*rAV&H*yuUe|7=r;^*0@sb}GeY)t&V-uo`(w9Y#<8TW* zPSz3-0ujRD_B1!Mraajx7hdgJZA(R<<+HnqL#qr~vHebofWbiM>jp(Vvto3lBhX=& zG_hi}r^pc7_yO!q($JYhEisSR+{ zV~y+tUA7Lr1#!-E%7WYLY+gTdTQzh8Bo9(>MD(e?`073PW3T106A9ybK?^4Gg!p3o zSX2_!p;)-&+)F?z7uh@bJ=46FOc=8Rs__1Jjl-F)nsf1fE3yLWL*vPeO1DIO*U9`G zU*enQ7QHLQ{<|g{I_v(}2)#}C>b-ubx`!-*6HI~J+d+Fl%<&4{4BCq3wXsfmiGBpY zI=$@2@;7tlUJN@+?_{xy1CEl~Z;1;3P)F2*NQdXwC918s5y|FkMF=#-O*xH>HWeg_ zB0baWjj^2En{37;wGJqou^BFkK=pH%1daKhd-8bYrj?Q-=ikKj+gW86wxsz1kR8V! zs_GX7S;53x%SaWksWpaM#A3E_NWz%+oP8I5-;BYVI^lHop=zYjqwAfTcRdJyb>Bwx z&E+TyA8$;+153aIiB3oe>Jcy>EdYHaGM(>vk#`R)>#)C21AAK$C#Q7098poZw1KyQ zm+>~&W6O8AhrVr_45mUUR1q%%^G@$v`t?2IA{8UM(L+vn%C#$Ptw^-8oE%;OroUhS1SVcyWv`+T>zWWK`h=c`=RP%ui zio_2;$NebFbZR2*NF)SxwD$e3+qGdcbTc$+eyMMIgU*xn_`9}a4z3Z|SAfj=(>gd= zBAtpX30*^PrRxZ)7$el@nNmn88Q3p`q0aufC61Cu8qzSl{I`X@#LSi@Q}w{{vu~bv z#~H^a(EnI7nN395ins&vz6_B! z*TJ1@$SuGiqKPy1?)g}IQ8KN;k-s*MgU@p^0`k?tH|lrg8L7S%la3KMLzU*o_FYs2 zhcC;Up=%UM=l zPf+F@6Vz@^h{2#LOd{{^?RvMXk+);#!{oK|_N#)GKC0a7MPu?zQ!pOjK|Tjg8b4## zw3Di9N!d1%wG{vI2+zp3|7}@oP&5Ox_RjvJthoeLjYf-sqt$2cju~+M{7V)VdNQEd zfcvAdx-up~2<5}=gdpezhEOo55IUcbBzRN&aKnsSTjJtGRk)hj&zV(^>D>jdx8T`V z2aJURo1wEI7NED6ELVQqd5Aw{!O81- z)|HeRi5=Gc55G9hNXYsl;tlz+v@mrU=#=8}X-k2!`-BHxf?{lfR z4H-R~L+*_?7uXiHEqN%tzc_f_o#)zMDlBrTAn2_V{YA132As4suVi9DAyRH&7KTX} zSR+_xuPwT+#~U!{+-z0L&ty!!z=PbRh4SOgDndTzT+`7i!m&q2 z_5@E61K6RfG&qeVJ};tfnd=XMC=+)hFFM6;CXr`E1u}z-zL*lCGl1$!nOm2WV_Y9M zAqj|HqD*D9fFSch4a4E9jw5ME_{uYX-OTL%SSOOCsp5`&;LbpBEy%MsB0H$RS2p~tooOWp;jYJV z3LB3tFMCGXX^-#6p^>=QXXu}x*zyLOHw&?{?$OgB^U z!i_n%&Hw*tuq${CZQBEHL`A%I7Lgn)3)HJ|{d8s>h)p&z+FiNe^$<@79ndFAI5XR` zRmrwusb={2M@mb~Wn~_kUVN3>$p@~Q&e&r5#pE^KFPp_=6Z5Is7-#6GXBd}Owq^=U z41GPS`i8m6KRP>wnIV#I(o1qJ6fSE0-ei$B6Bln`r@K0N0_@e4fxtJp`gm6vi%{rnr#V3;G4Yz>iflLe^UC2j zX;s(Bi1sU@vPjpS8^`t%<6a+I+4L>34fs%@iper#n)6a1==rEze=_~>WnrMRVN|J# zeZ13@zJ}U5tI9>choR|0MR_rGL~}uBXfgdfm*Uh-6UzB?Qu?UAs2}B<)DWIc)l`)n zeaxGviwDhajykqtoM^IDM7hacQ;my5YQZ8@N)bN^+Te@Q!)<@enu zqy;fvwsS6BQD&G>zo3^y)RIs_1qt!bE%(zAMGWf1HqN zKVKPf_7yhqg{RqRK{n+(t%M4gkc`LA#zsR%nCLK`9c|pm%DfT`U?h8zd09rZ*b{$< z7SlB6Nl4G75$B?;B9DE}vKre_>p?l5;Ficw%;U5%Q?6fzatS%$c*pZlg$>`m-`>*Z z3wV#=RqE}R#?nBzAy`TgOEB(3erF5HpO=Gph%6%H{XNoeP8O8jF@2?#@Uotq&Uuz0 zoDX@n-iV3XKS8{UEZ8q!1F(gbXiqSR0y3B1 zj;>{yXo{-{abkeN^$I9mwBF_k-ONce!F4L(;7j?2msM^8_O|!GD?NJi34!bMvna#e zklX<5j?7jEO2X(gg~i*IU5knbLnd~#xKU(((4oFi+b` zU9f1c1-Y@@Qz4IevO$CKrUG)uEDs11QLFq~^$zi({GB9pt)I}gh(_M9lVANd^s-S$ zdGx@@iEE>;w`=QN5vg_YV^%#&Lsj4fAw9uA;eGDdhU?>;PX-+pvUotgv+1WDs@4*E z49Z)TSN zz`nBlckHX`n9UhG(#9K2gG@w5>Xk&B^xQppBzfttf)+tPSQS+(^rrpe8A9K`+A-#w zv||HJ7XXOwV_`YMz2*891f2ic_5GvA%aFr@VR%x#ZYppPDNkd<@{hc6lb1Qe)o$jY zu)XxZf#cZ+Zv*LtM=yFc+M|01y-0t@W^^we_Ac(;_PKhM@4{qZtTIE03C{p!q+jfV zmp0WYzRxvrqV|=B&%L3niZLu$B6__h(s2E=QaecGVT;sww+H-PZ|$uuU7dgK3H|}@ zIITVm^f_}zAzvni&*=Gdb&T6y+7J}4%4yZ^t0IBcl5rrx0>+z@5gnw_#2Dp`lwaFBzDT+3!QRxI77&q%ffRsr@F)oNZLRO9Qr4G!?BwC~PBG3#Si9ZeWcH*)6HCqu zsXE?(ReI9;zlad_rw-@wyTli81f47c^skQzZe}xJizuoC6yH4bEo9kI+#cZz@l>AX z7c(TcLWI26G+f9q7(qo;|6x$DJ5w*3JZYzOXln&OsfuQcaf&34>XuBjsVFRM{w2u? zULy2*)25Ycbv|tv?2vsEux(3iqE++z4b*Z_8K7xk-U>llOgNYprYxUw(3o~njGu>wH|I7t#*>!Y))Np_2-#;zDL(|Y#EF- zib5tT^uF@=cIA(3{4TV0A--uZ@$>ojzGXaOtZ0^~WEgKc;JEQuOz%@Ie zG}aSNyG(OZqWXP;2YJ9bL7FTsx*9#(+jQgDvXBD7F`48o7@7>ty$o|%7aM9T8ExCM!qZ|Es^4kubd2rU4Eeg zC1ThxxEwfVTg(x_a+xC{Eqt5}r=?dMohHcyr>vKw?WwMZabM^g~aC`v;C?U45}oZ83urM;S;zudV$ zPh3XQ!%YQorl>IC^az=cM>VF-(x5JO59*vQ{#2g}qog#cy1e14mpK^f?6_8%MCc}= zz%?X;^uCKg%Cnu|p>;`FES1vzZzrogUUz^A48OJ>?aI>)mJu9_ggt(v7}o0R-uaLZ z26<6wrUOS6iQ(DXU`C{O!wsrA}Ws{#HxN~P_iO~$78>Swq_e@l(axj=sNZ$ z@|7x1Wcgj@lp2kjNl+P@HtZ-fuJI|{HF@;5dZC2*_Q6ab&?#|~6v?xyv3k^A8Uiyb zEtv02A^$rX)1P}QSzylTbu^riIQF4=4Di1CiIB0MbNr1teu+wm>8#~Pj8J1H!>|qF zu0rNUd%?O;ZJjp3<#j-9dwpiV+2p;MrbTx9yw3Kp4u3P&pc zLy>F1;P9|1F^;sysiH3JuGWX0Y+Y({pvKad2d3{BY#CTuWj<=!TY;uvVtFB8y6Nw_D# zCzVKZ%()1zwW+eiTAQBc1Z~o*tmKiaK*T|hsr!r%^Jc75pKdvSq=(zk8kClV`l6x) zO&lQniJqPC5$<0XLpv3Y(mTxN)h%8Q(ChggF*eHbRVe&bOczuTQO*~%p%1(V;LA~Y zA5r!FfDCiO=PT_)3hHx=fvtut%e+k)N4Y#hvrPNl5Ul>~Rmt2Jfxu~i6ji z8Kpz&Pe2-|@Wp}`xTG%$!O`0In#bhzZA>r6eVZA?d^Qp|5S;&K1hK0!ml}vV%>5F7 zvTQ_y)(~6G0e2Nfz!X=jFQ82zjyBHW9@3q{XD}g0D@Z|Dze-@y8BnR z&xK2y46^WUe@VllaMJW+%I#5bv1Vzm3!Ru$L217zh+Whz0p>VXTWYgcQxisLIT~`M zKg8X%2#n`3i|}4d=$>0R2Kjhg<7O6Ef+yHMS!;!BoBwHKo}YFRDU(nc9s0WBm7qTu zWp2T?lC!yP*%>D&3y?1AwZj{-EP_!sWjK=jrMrD}OzMJl^%dI8~N?WRNK)u}V zsf}F4ZXt#T1OtI_xELi{A7_*7F3^03HSlGspH`on=m35tSuyqU@jG}Og&a;Xm$RQI zG?{5Y@kp{;X=#IV-4Cdu7x=4^BYR0YjN2(XCZh;lQEKR52tCf-zahAenXt^)?4jz{ z5-8Ug;9vneQG%SFnEryRQN<1D&bX9bJz~)hdBs1M36o%* zZJ7XMiEWoGFq{Vu+#Q06O1Xu^c4;&ocI!*XqJ%aoihi*9gW$<$W3{%zfw7M?k_{Aw zHeXh&B5;1j`E=+Yg)sa^op9U$#xF`t|4K#`S(8toy?>h?VOM=}`7TR1(^! zjCLBc`kF}qu{v2U%>NwmeZeWg170H*PTMGc?{)}p2(;)>McM> zb&^_7O3vdJ3jxd>5HAH&;H^|(-T@)?eQTLc0g?!fG4##N9=K=PlBy9Z#{u6C_*2wT zK|oySRR-b;+KneoY*1Qr*-<2oNb?+?{e*4jb3f{ z6_HkhEsFn4^4jv!jVUSgGzR0oF^c<3w&Z-?IE7 zX3xszmjH2Yxl3tL_tgOhFQPI(zRhkT&ZjiC$4Gc1O09=su-rOPS`ujXJ=CrtrdQgi z9PxDbjN27%W&^GrxmXNd#sO)yHMkghqvr_~0x2{}P7WgOTU(xl1(#8BwW8?H>BOhz zn>|`G5{GB5hpN~05?}18A6GIfd{t733kVlS|7iJCiGFr2V1pZ#JFO5xSqGO+6vgyhEo#3+rv+ znUq(izl&q|L(_e*K_-h|!NcceXK8Q=*#Vw)_Ke+kJ0;r{(DJ?gYy#&L!}Dy7wfSv* z1n!r(2Ob*X@mSk>(b%A97x%W)buBM0x2JS7O`9I17rAzP-x9q!=5H3PR_q0=O?_V} zEl@!s^ZbE+!4B#nCnv9s1_6g_X6;^C#Sl*R*FXIgfyzNrL$i_t z{7UFGbDxJdz0&lRUh3k0tIp0- z{5+N)uwy0}hL&TOZG3?}us}inqd=Wxa@X zc1Axjgi%okeOh0hZzMRz#f0E%4W6qxe9Gvf5?G^N%v?rM3!$XEsX*eHq>G{>vbLlgztHk*B*)zwk(QkKt0 z4{UQ|LV*jcuwMckL+YF=USqbhIC5pQ{Aw;ng-B8TvZ^-27}yn<@-Kl}H_^>u)JeU+ z=n>y+RODcb%~>DKx8_~nEDn5-Vc6whPsCzqAe>RRZ40f8s?TV$D(8&d((?@Z&3RXUIQ3n5E|7))t1D3H>51?(0l+VD!OCvjziK+FA7k>&TpAIfa310^xC0fhL}>km33Seww<)q8EIZ~(gBGMhEbXNA*Y6=GU4yxyiwLsJt&tvqIDUM9bJ26AHq;WKTQ$gk$lO3?$P-u(4NF6QuAB+gFU7UH=f>Ii(0SWsx2H&pG0b99xDC&_bk#PF+WV7D_6e!5nfV@b5 zKh!J$mo@W=5RwvHZ*^u_{WnsQQ3#xK>b=L2xH>29LSZGf46z1|%s%rrn2<*BbRg}D zD@93yqgN{*Zh5jR2qi^jT;J!y9|aS#@%k0S8q}$!pS6>WG73%(m}r|rVD}-!!#DAb zLELIaM0@4D*gD0qK~(U3sLb78;|OeJle5+ff}IQ`(b6y@GvXARIX+9Jq`A;VSv6O$ zc2NnNk`XT$X#xhh7CDb7c~(RxD{kYG$D33E=pkihHBahk_Wd^VVc5*Z+PnAAzt%+~ z0}7!G1u=yS@_NwDAnI^g8m9rs+ZAm#{NG=f%mf=)uZR8=HO{4A`U{lCN?k{yjr}_D za@Gt<#I|FOIDx3Rrb^QyX9F#u<^C?CA9waB@^{Rm%+Lo$9iAkM35J0bm`($&U~>&Z zQlZWcdYJd3SP+y7^2in$_$0z!r5d?}=LnWhP20OEL9ZN~Xg%Y2R7(zZqK4J!Cd9u1 zDK$@}9z%cOR7um3wEs=Qw3jGSlBT9QfOE$Ln}Wy9*Zs&B1QfvoTBNbFoI3#Y3hd;s z2Zc&O>*S-$YSRNk9Kn9=S?V(+zi47D^(Pc`Phqp_T2a@n%XY zDU`$v)Zn&mNq}-IFW88vFvtlJN(C6HkbNfj2yzt1NaR#ux|V1gzdX65Al*_d^tbFhv-K?hZC%oNWTpdwI8E#riIl7}yi%BW1v3kCC- zHx{kKJO`~-si;@I4VT>gP-1j6Cj6Xr5t<1&2oNkOq(g0Y7>2V4?sp)353I&EC4wcyFx`9*7T zHJ~$!0g&ldJ0OLG*W_B9L&d9A9p6GLp)K&p^WZ|&G$90BhTST-kdg3B0hHr@`pn4B z|R`{h7_mPtYB9vn;&fdPBmn767$hMLj#&Y#mS3!%a=!Fj7nXTO5T{ z>qr&8ZpgcQ1>hu2Js??oWktij!l2ki1nshTNonLBDrJnvGB!zio|qnTqKb(TM`Geq*DAvDHjXVG(QRgx+Ia#bFdU%P z6R5hp(`e%&pZ&gVGy0%_sg!;fMe&(hD`AR7%%Xt@Zt1m`DknuHd;J#U;2D7mMBy-l z_;J2%y@{Gfk7dXdd09wjMEWNLf&1v@8PYr|gRIe9h*oanIHpOlJ_nKD<&XPOwLXkoLa!q7hoB zK9dX{3ErO>)|+|Re4~~g*&UK4hxrojWIZ9iDzBx7CgF|pKW#Ff(k=XEn=hk025 zAq^(@fr^kZl{m%J-+7zK_s1D~-uM162~IyDG;F34#z?%6D7H8s6jc|SUpf~!j&qhl zAyN*wl}q?}4ciim8Dyq4l;rf_zv28LYi}buEiF94nc1JMcJ&&`=`_wrQWS>ySnuF> zj`aKlO+QoC)szprLmYmk5MVPGSoY}W!Reb%$L&a;`t&*Y{6JLMp#Ae7#QwjiXJ#(8 z|8YQPX8jM;GwXjxJ*!*GuZtsH9=)Mos>l+J(rsc^yUrCWxf$lYXy1xR=53|ea#w)4snT%YT%4PyGxeR`@ z?q!ljIi=*>PH4epG~ zOB)Po$y{iR41_qCR2`3o|3#WIyOKgJP>s1NXVhPG%{jCO8_IW>22o=7Hccv@4--_f zbE%<%DEo=qjeJE`o`o8bZr9|IAH@`W8f=$Xm&HlLdkLC}3odOZb3K8}3C)GZ?ww$G zK9{>#R;4XqEd4Q;8B8tfM64Kvbs|_mEJ&@=sJnP*LdgpMXrWk<%A))&N=e9Dmw+yU zHNHPH$udn4#Q__XdoPb(nvF#T{L$^K^fQwrV>*rf4yCf)LIq1woj9Z@HZi?GGUx_l zlAVH*uY*9UB={k9FzSVPDv2VA^km|3(A?~5@Q^6eJqc68=aP$@b4%E1Ly{1OzH_&c zBh$TB8@o`Qa8$S@8WvK+0Yy_l?`V#j=C;IUn($+=u!oU}RR2|cdkjG(W$kcCFpsf3 za>3Z6IFoVnMccUkrmB-H_*3b0=>Div3Sa7(1hUustMuZzO^lrl8EQAnJquRNgSHQl zRHmEi4*cld=Xmc0B#`dA=?{?kpN0~Dy$mv*U9-O8{fre(5uX=-#mo{GGD5abK>=@s zG+!6MKF8~bId!On^t>YGUG~iPJ@4Z3i~Y4#a0MAEF{s?-(=_A$(NFaof(+^Vybu7H z&u4|kjZraev#?PHT$V>PZcXt6Mh~l3igN#;unOF zWI+44GHLelG}rji1-V^T(FpL^tsDccPzFDlmuPdO7U3VdKd$h~ z$3X>D-_qanmpV)P`C|$#aSX>t)j*jfIp(Ecxj>(nz;P2HH%>hNwJIKKtV9h|Rx`YM zNnLnoXz#3;*;Shp_jLxZ%^QO+^_#&+dl{@I*Vz0S9^b_q@G6P(5P3vttLeD`tS_gi z+LR%67^`Z3UfCu({hHxDy@ms|=$@Q?WU*K|=)^?T#z;T^ z;5jb9d$Nh>+4HtE^|kEl>~(#6F{2ksU?qbK8~5~u>7W75XBz}QR1>9ci`xRCSA$~E zg>u37SOgRe`NKEm7X{?#U&EY|Snfw+bStfX+2h;OWdxV$tHhXSyBs3wUNKan8{~;C z8vxIp_{r7?=NAkeo<}>C!-ZMX;EqXhereVC8A+!>j2xp^8-AkdPXDu6_-w3d z&QOQ@SsSuq;lZNlbe5h%h5;(c=BT~eRmWJQ5{h6P2UOMo9(Kq;{Y7)x%O90fX8UKS zQH;>cXzLo8uXJN~50$f>B`?4Vf9U(k_lG=(m$*sSi#oSX>H{PM5k;j`@Bjy*3=z(H57L zwR&eey>Y8$(sx8$7py?;K|wOu)D(rW_h>p63k8G3sJbt`9=1Qb4n#vA z_MKW^Ioxn>c5Hq3oY$ez~RZla4a?BcGy`LIci@YLF zJ=&p>4R=;8swPjp>bm>2j%?tjYxns%F`&Zg-;)P{(@?V+!qkjLPcC6(qt80NX;tp* z$>MGARlBjcW*0)d*lKkm+gOz$*4X)=Cj~ziB&kQII&gkw*GVRm?)9lQ;nd2{4-M(K zTQ~uk`WYl|{ZVSZGrd+ypuRMhI+yBumpC*IwVQ+!jYaY^glw&D!+PmWD_TQ)mjOIA zm~38R#`odJwZ;3DfXAaO#=%$@K9wx^f;VgcXn4Qylni_E4whWp5r?%81p; zgNPRU2?;`gj2~{_{01+;0`mRSm z_@E`=vBTso=93Ied<{8^uJ90_p=SAbTTG0T6Vahx!D80rYD-Lkrx*G22zvJCu+{B? zO+EA-YkY>u)Y2NekW*Ze5u|!b)b~{N6@kz|`7E}NKsf=h&W;B#B`{T-Uamb4(y*N* zakUzeAxYw3$L;6OaU^=N20!zYq&G42>mJ-0&4Xw9_c$_`I@Yy~h5--!JVMGDxdY41 z{-l7&4A3XZ-20W-GlzHU7o_f9zaMrtFK2hgoSX9637p7;NE#H9 zZ^c?vgv?ANog-NJG6-W$x@2&YRnJJ0-57BGPLDfvjwS*>*k5kP4}L5xVE6fBG~U=9 zC5_$@UgJIA70b_kTc3eyf2yinMD_=JmfD?vQ@G2!4#Vf#C~_q2W7Roe)J(OG;{VS2 z?If*p3Vx<|EEMRRYLSpYZ>u(FgdU_NV7j?xjL(=Xy2Wd`sjeU|SCFfJmqBX6j<-v{ zB&&sSw~ZpEE&)b`3r8GV^h>9(?wI7N&b+>WN;xgt9o%gPzyqaKZZ0lYOjc4jLUED7 zydM57r^3Lk!<>c8|ku@^R;c{h(aF~J#ses_?;{aqsy_OJ3 z)xa!XI9lY24_;Ex53R%4Y;61rMrB7Nhz~t`xx)1=bUfmKxt71*Q9+2$5=T!kacdQg zu)M};DbJJNzs9oUCRaAiNCzo&q>lZ2itCx~%L+xfVX`rvJ_0U^kq=683Ap z=Ecmg^z`tvbvtny*L2*SUi-rEvO6DqJ3j3Y2vTjueYsm(;NHBX^hPR(bJljU)-@)_ zOqwd$t)r0hGM$4PC*1tPDEF8zh}sk{*K;Of@M~UbsSh_fx|h2N#(PR~ClGtq{VZS- z04019;)FVXomlflWTNP}nAte`ej94KsCqCwpr9Mo&GQFSU7NCLziWW(mRjv{*E1crr)uQz~>rq6eMq zKv;=_ESp>y1tHq7F{~1+vK;=#e9+UJ9Chxjylmffo%qFPOfRUjPLERk&~msvfzN@Y zR3}Hvt5FYk96LS8lXtrHTWeZZkY=WTwo$EFiO#4y0$~Z=n!YOw0X%KVCcDK4U6M_e z_8@a4rug%>g>y&Si+nkHQOks5(Ww96T@j3SI#PVnUxU&o6*$PB5O+8=X>yJzLY1K0 zlP?Z<%7Hkkfw5OaNdW&TQjSt{kj)EDBW?&aQXy!Kq+bs0u?s|>AWKtwwu`C)MY~Zf zW0a%GD7!Of1F64RC++%9SiS7CUddsi8}XnnV|O5m!--G=4+&N^PLM*52vD`NXIE;! zUKvj?8T1-kZ-Ii+{tZZjlD^BndYvK7eYX&6JioQ<5N;4j6*@P4J)!KkO^-#cFV4wJ zlF?%yet?*`oKM*B_4(krO`k-;nE_3KT(**iNJUISJR1XMPlLDna#Fz{LexKr&RS(_ zFrke7yp_q8p%AzS>-g;k!J2>tB;SmkC!d1Co-nZ8+hpOv_6yD;wo&%=Y{;F4BoUF{ zK3oXK1eQDxzU+iR3Z~(Tj{Fh$q5JJ#+FRfMs9UGRzaZ4G4D*-bmTeKiegV<1;9rE8 z_GM{FMKEH*S&erRp)hG`$ar;=#(;PP^5{<Cxx(|ZS)~<*(^e(n33Wd-cpOb z4Vd{5at77ljslqjHt~fHNksC!(q!vuXNPC4Pu;<*K$cwa=XDIH&OFBSs8H8O=&+BC zxZv6#B@dz8=!X%1=$uO4#68#r0V%vpNz?#^+1D_ z4(1y1u>29<^n)ttDE@TrqTw$=pY_6aNU-rwfndOee0KKYn=(T0LTuFwg>2JKmoIi zH76?v*jivqwlYe*x@ajOU}(sj4i!4kqerd88jR_<(2H`9J%7Um&I>O+=S9y$L1q8D zei!g51*7}2h_-lCr#%WXI2fh!m7_^PhWNF5_Ko5Dmj3mw#U8D6ZNW;{1ILzkRZEA@p$pwiXGcC|5Drde8k(qzy8_t zNA%ja8!ayY-CEd0+{))vwOHS0{r^^_|J0iQynAJ5V*MY2jO|}qm6w;{FLq|?WJbu$ z_7AE|i9y`l$_eN|$RKWI-~UB<*Ech_rKMs7(` z4b{Wf?ABkM>3-`z+N=4=q9>=PBR9GAgUk6JqV)dO1Es6GSW_nYZ(#Dtfy1pZvYf8& zr(-X~P6pMoy*r!x&0{J-Ujga7Mk0pZ8<}`G8gZr9^IDs$?baJmD!h@{_hXhJyUVo6 zR{%3YA+d`(dCQSJjZ9p2s>MHgCos18VbqsYP>lL^Bi0AHlY#Qc+`I$+R&p0N*}QUf z-e3laWV^k^txMsA6*6vOYLI!7b0`U`DQJNz(8Hi z(-W+{o7RV0pS6XN(1hA-Sa<`6p9VFeiY?_flDAwy?~+_Du_zWhf|8)Mnm-!OLcG#h z`71qVK(?>Yr+M1X>Ma9Wd$7Q=i!#D^;?jY$&vNi@{2Mpb@KC)DZ3B$fxHJ?dih# z0l`qhUK9;Xxc;lltJ~UmA6J$cUA>XbM*>L*SJli8fLYq0e=!qSUzT7ggf`(CxPnwZ z6D*;$d6wO*QeM8#JBr6`yC#GLfdfsbte|CrDE-1BR zJi0HRXSy(0of0Bgwmp05uogD>ajR?HY)!wW_80FtcluDB`uL~SQP2szAG6z7{YK=~^Uq1Kd+ z0)4&ih+c*)k{5igf5dG`6LwcMN0t|6*V2a`*R`$tOdaPr3Td$z==l4(X1ty_(GbZX51A|`=~?Z;}pph)AHFk^C#cz9#c=vBTil*rdB;d&j_ ztL&vVY>Q1M==O^6)YO8(A-`!-)b}ZCseS8pqlqmft6KKtM-ufRbcg*Snr`FMIWQRO zAg-FNrHm7;6Y7W5XvTBOWJh4)oRjdZPb3Pbe%2iG9^dg<7b7GPj!-NBsp2ML_frl;tfWN%oXu4S;5qVBRldx#FlGe}=m#zh8Ryn8Uem9I0-ch%Xr{LdGY08SR<)HDFyT3z z{M6~x8P|d-8RiX25FbMty@TC>n!cBY4?2^^1nM>hMW}7P;Bq)Ck{_~RWN?3HztW3k z4YR`>L{iLKs!jLm)|1l1^Bbye)9L&RFtEdxv_30F-!)aM44UIh8Y>jH4@^@A~>4e}(&a8;XjqKdbG$@iQ^u}?+F@x-RJ z)Y08m7<4#eo!1LSB?P$D6siV%Ty9pJ%6{Oh`{&DtikTchb3F0J*0rN3=WZPN$3{x) zOC1w?Y}4-#dw2cegg^Z*A9g*mM`CGq13+zB*F<@;g^&@lvM(T76)ok;y4sg58Oz;V^Dk)zFBO83ONq}t+wj}G*dvz&zH}O*z`kEO;phh7=SD1ar>g9es>7w#@pMo; z4R=!Q`w|*@3=FEdis@x7`&)#Oma+kV-CT9Fo-8Z+dr5q zCK@{$Fh0MNw{8BG~9}Hc>p7HVR?Eu!|;y5|)s<8t}*&KxTsK1{_LA)@TNX>NhKzQ&|Gvq88|K)yCdB=$=<^2eu( zq-{VK$Ai|QcLP8}TP|N~y zwJyzFM>gY{r)bfv&U*%+GMO&X*ipra+Xhrxbl6$47;%f3;rx0c$v6pFzI+y9xX!}2 z=cgbl@hMn(qvNrlSQ~$sc#$xPn&b7di zdZZHSFk6A|(R^RdSm_|3fUEEzM(1X3znen$;&gosqh*pD%sFIteR;y^4ywH5@=25` zH(o`MgBS6Axj6da3!t!FciY9a{NrWOx!=L)c>~yetu>M*H5ERR<2@u()@Y~XG}ss z1&ta5|N8S_DjLg1Z(pB93D>yQt4tI{=l)~{d2@*5*In{Y>D? zfKlocik@zxjTF`V%VD{s(>huU!ge4z_=9Sg`+NLi-QZ{D0|V z_J8n-|4)5fsb;CX#)wsSYZyHh4_nNvBM<}2DHeY>+`@; z&3$zy(2}_r!#EKUfO%|qPH}OoX}k0Ln#mvsgo$hl<3Hi~&RGOSb{`ZdB_2+56P$Q;`h~3t zp$HMISGy)t_Pn?ldiFWkR_g2dp#0_U6G-Wt;o%r1t=?BCr9!p7Or&_%7jZ6}5MN;| z8V^-%6YZv7&Ccwlyy|~N_WRXz2T%l(Vni zXugYSlBSl1>Cg@)DqfP`h|vlNdo=A;#YW!l&3x)rBgVd6$svAXWvMXb_irH*U^rwH zrP@fkU;ivzFlPnHe~-5k{%h(+^Q|JOY$G9ZtdLUdGK5o#zvM7{{O`!k%C55H%jLS$F^N+_3{!(XYb7NHK~ANGRn5&@6a*te_k|-N&y`Whb+@ zG$!jQgy)-dq{@%nQFV<38TD3GEzfF`fzyM2q^VZ1~Tuz{G>@( zM?qt8XJ()|&cH0e_0E9dz#>5tg(3uS1fguTkeNpmX+fOj!)hE#v+K}gqJLw?Ed*_o z-(TvbyW`f9F-l~H>unV9Mm{uD^mVSqaD1A!ifo?~jHh*qU3f!;w{v0-9=QAUfCT0kqK3RerC zEfgjQU?sr7WRqnJ+$^F>1nQ`2r}(FPYdKRGa!<6^4zwO(mCLj4K}>^zhMQ4j5{-f`-&taj_-p0L?X-gvwR5P3Q?C3kJFpX30v2O$-xs zzJX9@WJqW+h=JzSD5^g+IH+DMT}^xDNXIsea{d_DP^CgOV;aCz zp<2X}g7RvbJ^8X9lsM63e=JM`XmCtUwtK8zl z!%W*w4WD!e@?zf4F<;EHk<^jY(&NGFDMLPQPd2Wv!UxtG{i21r@--<tVxy?!1 zPvYlN!xQGyr;ke7#H4Z@Q1^zcnRQT;JvYqt(VkpcG$ ztKGgRKP2Zyah-&D_%KkhWHt#bbnW_1DL&9yJuoKdB0|KRkhPZcoxYc;7i$8)QE+U+V1Y&-J>Ve>< zuc%3Dl;*5_z>v{^84*xw>Jp70ad| zGB(Mi4LpZ2My`h|Xm4PsZkKFG*V&(;MG>D&x8p^yWu?ckMwO`ZD(&r( zJ}63%>s|NISJ~-hQqMKVO+C0n!}c|{cVkE`a6Au+6B5c+C$- z=kBd-;&$Pk7;8|t?|c|{Mkzq_CJA1P7qNM9Qj?PI_h{HtH?)bWTW;eao(1T((z zk3<(K!+I147}*KVoB*FY#oSf~P1BGxC969N*oO!HWGL`-@u$RX(QjHw)tP#KYWzDI zhD-`?QJLe@-Z&xIspzsIs<6DGkx1lJ1>rv5hYdl&%SdIE#4ZA4@`Jo{Xy!*&TMViy z?v_VF&Xje7gilIP+0EraHZpI^s5eVjfp7c1&AK+{he8Q4_4vx#lZI|mfchdTV3q?@ zp7?tiM4jevgORl~KNBCNKNa+=#ajX%mn9{d3#?K+z;oK1cj~!81^Vrw@_kTbdHzy% zsyfXUh1OOCl>gB+{zTcXi*@~t9IFtR$Ui)qH|dHPMTNyS_Wq zgyN6f?P;-h2@`aZ`IQj+*C_fxy_gYd6ROL<_S_=sbwqzsdvUx8l_ zag=sqs5n{4@DvN;4L02+eA%?iu<*ZI{{n@>A{0Qhn*8Nct? z%kgX67eVa})3~H1w72e&a9c)AY~2(Lf&4mZ7*_)Pq%H|$smx}Mc*?#Q%-E>a-0#LZ zV^BX~dl~Otj57jg$T~xfQiLN85lL4@?hH0B*wcOo7xua@A8clkz;J(J zM?#;dS7tR_^MRK3l8i9xI>IJic8;}deP^RgnHh>f;Z(fF88*7e>qAg$$O%!EgPWkuPxhaEbv&T!ACqEX%Zr;nljQewuH7Y4= z=*f>U2#PPAb>*gf(!xhyb@zR?bh-lgF?_PWtna>vt(+e2b9}F61nO*aUm>=?GfjNa z%zrS*K0_mQOH%PUDMAPk>bFJf_L#(TjtepkNPk3iR>682g9C`fu60V383g{M&ZSU2 zave!1W@)|k5~NHZzUoU*rW>L{XS9<0h%#1u8uy3v-yBpg4ig$KU%bK!^}-|>$o`Ml&JtUAI_D4aCNH$a>rdF6itUsQ0hr-zZ&3?@GU*PUvg!f-m6Z=2X2L7M@nEfB5)Bk@Q zRA04T7Xw^2#QyCboGT0+YM{UTxd#=cKx&7ICI}21L_ClFJIqmnD)_t0MO6ufj3x>c zl-!oHW4v`8%WIT@7^}%=ms1zM3$Dv(V06#0YfMKL!jvF%>Yr5yvegh@pz&D#aFhQi zJFu+B=GlLHJ<#Qta(iw8Mom?EF|y}$b^ba!95j09#RtGa3mdr-#U>&9we)d~Y(?{V zdzueMlH}Jx?`?};l?rLXpcq}H3Joaq1)S83X3VyazHD^HW11I;y0T(*`+8Z@HYd(oN|gGjB}KglA`ifYrCN;@x6s{7zXwa#$`hm94^}$MNr;&B9j9b` zd<{02YN#GQc45!dPmG_Gi3OjFKRYgJ@%xwL77hROZ`@KVL0Up|Q?Xi_r78bvR#Sy< zVfFg@Ra#a>hpi-;tA&;b2qRV%FnNDCJB zzK%r1T2vr!{6*KR4VCAF0o0;H-#5ZQ-D)e~G5~AP&qa1esiREVVNz7VXaKufiU&p- z{{zH3bwIM%E-I`b%}t;scYjFt#FXTI7q(h(hFF>PP6e} zMxpnKCsijGRsb${+}qL}*b8JH>Z0&NwMafM3wfrvo|~3DT8oezQ|{+NGood5BUkj4 z?o_@})AwP5@dZ!iTuKJ{bqSRwaQ1?8WZlLEhiof#vKuiKj282{VbLLFChynLwQZs> zxASimer$2hofy%AKy^V3=u7Gu(0pir!`{ImS`3M92bX6(*l5t{X z9LC~HYku2{C-bnuI8AU`6tz%c0g~Cf$gMKn7hnhksZnAV-vbUJ@oOHj*^LcM4kaS4nK0RBoekaIg;$vj1uGfz>j7$+b4d9Ad0 z5eP&x^WG~O)=KUgRGs;yGmS0eKBrK5^$k^rX zP?NE(9tmgBcL-H+^&v}0UGl#=xMdk=kiWE)F`Q7m`rRV$3e1j>Q?OC5pqKjWDOx)STdKTo_ltdjSrn0msenLKwA0O zakz9J^;S)V2A*zXBv{X`TiA@_8=j73W9jE?>prb-71a;p>bFSvWxc>2zVpB7`3Dt2 ztydY4uyA+PAf!-`Dv}b~n9A;#1a1E2xEvot-_qV~l$l4$6|dsMoN<@&kZHh&4*nzZ4rk)CS7_?%Bp0vB`n3H77Wo%DdUw(3aL@k+o6A^t&HJ^1tL!q$+n zKh^$h(-b9CZ_8k)b%~m4I9g`G`g+qibUe6$bG%7KnyL_93Dyf6G*__(b491^uz9jl z1IW^k7LEkNAF0UT#U_srZ%2zRA&a7L%FNU7U&=#=S|C*LTjwcyOcTE)chuVP##`-` zav!g;D9ga(Z8v!@-k+*zp4Z*+J_S%JMR0|28UMtJ9^Xni!GO5-ggy4>tqq`pDu(TQ zaR*0?R(o%P7S2}a2bC-&V^KhcEd>ttNVSJ1|u-NoRgIh{xhxV5v_?@y!_kAwzlnMeN}Z#zq^TR2$UP;9%Yn|>ed~jte;l_ zan-f-O`l-d-xi>({)wK{Pffue1Y@BG_-$#Wzz<^M%uR?YC<`Re81Q7&ET*7sS{GdF zxy$HVe98O{4*ilhMvJZxka<>S`s!IG*-?{D3#ap&r{t1Na#D{?LFYE%<;R~RPcKR) zM3{k+J2qfoZ_(}JfiJBZu`kK^*a8UX$_Q#h-UcmMg?2n=4auI!r;wj<79kV(oKtYm zC7tFR4=b2@GlGoc{-ABLb8(1gM~?F!i-1rcz<%xRt1QF00zxFmmo-LE5oJjuNM7*j`H5Ck&Dql1|(HICmBAxq2r zyOEdB4cbAe&_u(#lzF>_g+U?CCrj$cK@D%I9JnwBBGntm7q&qm*JsaA?RRgtGxMY% zUoFn+aNq7ukK`5Ie?Y1#6y#fP8Vh|9R5JA&NHz6mnHQGN{EamjGmQ=z6(LSjM=V=c z71#@izlGKYR^jVqu!_r36Fv*IJ|gWu730`>I;=O8l?l+?TGrOfq3!rHEk0nfVM>U% zci?gdN;xIc4Lk+$&f3Y%v;AM!XA+D$e<+S}C_^@dwY?rKytSk-xMx>ytBk^G;gQ4f zFa5kQsAC@{u9x9T|KQ)w1IVBV$@G43c0&k^MG;X=p=Q_a2QCZxoZTQpW3$}CjsXem zZymE^nbg25J#87FpM!E+Vt4A_Pj`*%->=8rzGsb zsX?sjVa`*v&HP zrw|8`PaD$r<5D`bBrwG0Xdmo!vK^cSQTHhs)Uk|7Sug-ASYvRKf_~ygB46QII7j=J zygb4Id{F6{q?E@c0Y=)%swo|laww98}B+3i}V zSrMkj0yle;^kQFQny^@Pr9*gwf?rS%bYxbY(qmfI%0weR*ICPCRMo~MtQMfj47fU5 z!>z~JSlt9a`-T=iqxg@{XWwVv8Sj6e4tw(QrAH&sr(*pwV9p-BeXs!N=oyZO9vc2& z5^A`0xF4m$#?4gUsDiVNE+?>N(lk9WeM$ zpy^OjVJ7Z8yV$CqTRGOr4$UbJ@y1MEw?jX$3>pu)=oUpAs>Wq&X&jfUV?~(aw!FNN zK^v*11-m(OvRfDTPhYNMy|A`e$#1p# z0ZKp&x~(Clvm72sn*LV>2256l&;3ecsDj48HSDY!KOdJ(U=Ny(A@93M%q_XvwfwHg z(jH*?TT2^kAjh{Ps;OZeti5oZel*nH%c4I=%04D|*z~(w8mY)ut3x~ZEk+)1Z<{i5=3Ka76xh~8mg*d-;nX(#$00Y9Y@oi;r3nl;O08#Ph?Y|+di z9isuGm5BCug0){TMDh2p26b>dfSJ*;y(K2M1!tF^YFkvH;O-2)UwnFDROzaBb18uu zCwdj!K~lO(g_r(vRUGkh__%-Iz8tC1Ho^L&tdHRP%AAnw;>CZ8~a<< zhN|_^{odZ)=LbGC%IBtJky8gJfdWQt3{|`ohLst&im6q>*Rl;%aI1!@M_Nu~Lsqve z`Ro1mPBtip7^cVbR_nt@FyPp?z*Dh^f(!fw%kcZaV91CynAp?%XQao#)7d(2hJFZY z(wf#^my#Nsl#au2rPr{jO#GSQdVRFUbXP14_9f!DpcE_}{74zpZZu~K9JR4#{!LX6 zA*W}2bC}hd3X$k~vQxs}&F?Y}MLt7HNi|lERd^!2z=8}yYY|}8vMDkH+CqwMpfS`U z_*#hc%X#{x7C9FQ0=Di43EZDcq+S@oNb~b%;96kOmE2+_7}lioqLXT(w6R!&ntNkO zV)Nez38%6Qb20Fi%5}a%`7GV*A_sj7o-1zz;g}EMtH6MJNmd3=HFzM@6AJr|BE0Av zj`VO82_P>%Qi~Z1M}dV-sMyk7+`eED_%dS%2UkteC(vXxt3?!;DA7lS1t&sVOrVyN zq`1I%Sj*201N@(pMsF|eE7Q4*JDJ4zLIN;>J&$ZPpn0}0Z6f>`B3pzEr1PEi0)1pg zQjS>g^_ZaZRpB!31Q0N7>%|JqAKy3`D_Mjmpj3P9p#5u>-we7C6;o=)aejT7OS$O^ z1q*dE#drxZ9tf!$z`CY?8)@&;ec*dVYBK#Kz=r;0i|{4+wBy!|&66`{lNzc!7J! zS5W61zi;dH0Hw!@56lI_v>$Vlh)YSx8X*w45w~)!(e6A)+7;9ruJLQTIJ=Qjy1Xsy z6M>fQCK3HzsJ4l|ZTL_Xi4~fKu%0W|+!{oe3);vQhQ-c6z>7?L?o*wU$=bt-KuhR> z4nl6axP1pgVo|I~)3FQQ_ShPc?aV}DDq##g9^qHk=Q8PG?rJ>1tWu&BJs5>R=1@*R z(x-(e0RlHo>Z_|1*+`9v^@|M@(P{rqJpAtZkw?X|SREes5f&eGfv?7N96ziI|Upe^h{aCdY z6d3yX4=(;n4$*Lv-cbSAF{RJZa94Dl1Pz_^gkJbYGwNJv?FfT**LEE%aKEkN^UCeL!KDQc7~w62`wyI$Vucca~1 z3t#U|*l2Qa;Rs$Z=rUl0z{ZywcnNaAR6*=t);R}yU zF#&JmkYs**o50C)kFD1hmy!U-E)06}76e-dw;1`YIoP3(DtVGLB`1FIqavb`Zeh{)n1>c|eF zb@la|vZ41!d3@^YBnW=$CaJ?b=&mL?!53icn*t#;TYv8+&(h}u<4$z&vK(NRCWxXG ze^cuK4o4p-1mt8n@Ack&%X5GEaBggW1I5y@D*c=3=D*o6M)rSsCpi8M8^-Y;v0?w1 zZuZ;$I(nbKpbY)i$s+=hw-2@u!JqutMAzFVAyXIUymYwXpv+EK3dkD%&-PVdHXw$!n#%;R8+g@ zOVIu7+U<7HErh2-^mp2xc?kiVv*tDD)q!x=?r9JznU4N<%-wt=$e zx@8L0!h^n3GLpX(oHc7RI~yZ!#ZKf2U$`G!2&GY>1;P$$nc=A?x}f;NXo1pTsium@ z#^Va~&Aky+OmWWy*E4%MY3ggxFl}>=i);R}8_)!3~rY)}%LCaA-ZJA$KE54A} z9B2bFt@U)<#pMc-0t~(kTRHMmQ{Nmx;1#2*y2Xz6Pu$Pj@6!Z3%df+y^yE2HpIq-6 z#_U32DlHJS&j&d(~^{JaKRv|#zd&9Hfz=@PjQ|tVsOpuTU4<^ zL*(*Fy&k@l5rQ?zi{*Fw6DXpnA8!B_TgSW4qfPJdd?1Vcxoy&5m@R^m;iUTy6*kAr znD2*VP;zLNo}0*beXx=BbO-*>zc6=g$j{IdbELJ!T&+ z*Dc5u=6q7=TAz#+Unx;Q!t~WoI&?Lad6&yK;L-!LD=V}>G_&99mc+J6gY56I0_i3_ z))}&1>w%6)*a~6d_#DPPVK(x6^=&;21UiPRY|RvL)@fpGn~&f()a)Y_C$Mzjb((Pd zjw5){fdpS6*4vB{z&Flt*d%25y+H;qXLN4}zO=7D(=py0I)>^kp-bFts3`x#TIeTnQI7#$!+pBuk^P2X;smVCZlKhFjtqmc)BX?Uy$) zm{)c|I}%py#++?Zxdi@T+RcMHB&@4kh36z=`P)eR?n)OB<~(nmF(_F{!a~!H-gJJI zr{n=CiQ%o)79)+JMSkAq=hX8%aenh>e>UOw+=Y_@uBK*U;AOE`i38;)3m$_IN~WB6 z5y3~Q^moD{-q;VMq?rp9#Zfd$F{Fc9d7(q=*?={j7c45*T;%{_2VP)^!3Yn*0f9Jh zbD$&*MqP(ESD)@pu%n{rl6dZv$K}MkK5}IhsszsE7#?Wl z@H|sX&AsZ4jXc|sqQRL^ZH-lHl1|E~$Tk=ru)|s6QHY3Ad;Hwc+I9DNHSIvm6fxdE ziWrmeoQJ3axgj)|Qd8%Q=rl-bDw*c276lmCEQt27cMHDUX4P657ZzC#VLLFcg|siJ z@!TN5`T9jtbgTWmR(IqUS0bi@e}v=yuy7B^Lt;U`7xrF15+|}tpiv4Qg>|;o%o38L z8C(z?cIdjR*#RH-eC5dm8o|e#`Yc0~FhKdDrzNzx(nUn3`of4);sdjWsXsx{Yzl`4 z{ML05C3_1L!OCj@0y*a2iL2d9(smL67cQ61J5_)%{bAI=Apg>dy+8$DW1B7GSw{D9 zt@5-!vm>@k3rl#$>+WoOV%6Yqahui~>+E?#ej3&LN04Pe;OWEEIg+E+ru2 zOF*(47^hUK&ULjQlx?u(Lzu#iOLU$2m#H&eoqtu!m6-*(Ye@=78{f86*0eJL;5h1X z)eroy>@R~=xZ$t$OWR@F^Ub%d(<3HGWu+Ao@4{T%lu%1D8<_{@X_+5_Dwq^0bG0w~1+O za`=W`2gs*XHdue%K^OAt_QCjKYPrzM69+|muF~1h2cr&TM92`mu?1tu?&sq=Ycdks z)vc^5b_nXsVfsj?SVtk)rItiT&jghfxU=_UhlhHJH0}t5Ey$fbhWu}E)l1Q&qYy+v zpbWU81(2V^SZ{74W@h~YHjJ=!Mm4Xm5M$s949qh&)PXWWa1ZHY{NiWpozk?l?gw-* zSZXS)xHRInB8Z!>}p5In7UWwliX-ayM+- zk^`NsnNHzA-nHht>wga{OijyuhlK-A=S`Ivwl0TPlM5#(%E;OD^k?LnC)U`s?w9WG zT2VvZA~F@8R~JBkMm7XiRJztp9Bc=J+?9 zFUNnz`Kqn|1v`+umeoq>G}rz9>~5vV{_L@f1eh7LhuTZeLhd= zh^E8rp_e@nnmsxHjjCB)ecp%KwJYqtV%Lt^irI>(t9#9HWc6ml;mtN+jaH-$)!Sb+ zFv8fei&T^uiiZJ&-CDA8?H#y2Arvz&Wzp?~h9apmjf;t!^5^JGPL;S5mxM~vZuknU z1#_+tA6lx_OmFjaXUfRaXX|#&^)reC94>sQSnhjv=knK!;?7Z#xcv+qOjo=t6 zy_`9{tdI@*hF}O`%2@`WEyGEZ_o3tTSQEN`j5)TB+Bd_8)rmjuTVyP)J4IZ1&jq0J zbM<11PRLM=Ex8uN_Dv9UONHBeKjcx@zt(A-givtI$((WKOfUueCPzDIr!+6iW;8;; z4@)Q<&7Razm~h)%@2n)s{?+7HXTl!n%Kjt?AOT{s9!(lvvf}wKyg@kp8Wf6GQ@MaPGx&jDm+0&QX zWV^4aa~xW}tuJ1@-C=O&KnsYJ;k+O0DCq@0g+U-<+!q9#VlgYj4usx}hu52hWctyl zdka>kxk}9u2Yccz>Gq^l&u;k|LEjfQ&bhF!g9Qg;eKf;d8fCM47<} z^U%0O8;CVpb<$~a`m-gJ3gl~yDGnpL0U4eRhj%hsa((TSfVivRNa@ky3G|kIP}c<~ z_-M4KD6gxE*XbpwswC*-8e825Rzs6D{_eDRaB0FDndQ)ZeVSh$GSu1U2osJLA9<(q z`3eJ5eowmoRdWaiCcpmz9L}H++|%uR;s*8z^Zh<^9pS2z-fmN>*20DE#yfE2UxpQ( z2YZqUtoJi(u=eg?hfbHSLZ9-h{LI*SNB^ykehENe+TNN?M6yXF!4A5gkav+u9Ncj| z4?5&*;saX(HZ|Mn@j1@*GBKD>a-Fj7wqHFh}Jo(6u?Edy{lP*3I#CnDozcr$C@$cbBB936nl$ z@mS76<7=B>GVKn;op4rOV+8}N#hKAS!IK<`&Q~#4vY-anq zdZL)8aXjx*4G_}5Bx%m;`>`kDiEq^)l`O3`n47*|E1vKR0VtJFaK#UF0tB+T)eopQ z*d^vPTTb{vUW9IK<|a{jNG_QKOA-cWrkznu8PN#S=+LDF>RFk%;LH6iH=$# z)@($*1vFMDw#an~MCE_uj*@?s*!UG>0lXx46hkq1((60w`oQtIHtP%ph81tSc%Xo~ z=n-QDaf6KHD%z&zm-_T#dxZ9Oaud{XLoBjZdTyd^W&NtseDFi)bM9yC>- zbMWA~&<$}*o&}2LDGzU@FrzkgSbI{z>?EvRgE$S(rynw4{Ehsvio;$avMVI^s(TDf zWKm5Pd&nBgd`UDRRSs<0YGV%T$y#ZN?YEy+(Rjr;m-Dac2F};k%Egk@(&K=?$oM&B zy00t#_Kw)ag@^iYo|6A!1Q}Tw|Miq`{u@S+^FLw)J2n6B73gpBnZYhdm6cXcG0o^z+pI*6x*(ls|fy-w1yEeM^kPRA&J_s_G5& zz0chA>(So$UU!m~3?l#w{oxqrE{9Rce}+4V_N95PD7Z zw-=ES5!~|4(Bt0T;UoKXUoLf|1INqh=K3{%uw4<1ibci{f7f?ALC43)_^!LqtzZrQ7daC3JGu2 z3kA_5tXH?n)|FZIN=2hEwhIl67k%p`bY*!KWrQmxv13xj=w2pWVJLCA#_mN76SYfBbD#{ToAMu zTV`t~md>rE*Yx{wx-ZA7fP8?_#9LQd2pQ=`>x7QnF3=RSScN{vi=(|iLOq$yj38UP z8Quejwqep^AFk+$hBd>9f>{4*<(?|)%GAO5UU3L?Vhx0zP*J3xfuxC zaCTq~=B}3<(LK3b!-{ItF6-bRQV>feLi`}i39Gjw7`PKAF`x)0ETH&aGCd`ff{ZPH z!(L&kuhZSy&z;A!aSeEsTv6!zVQr=_;5;TEK9!pRN_>};;{2q#7P$oeI@i*D8j=*H z`HDb>k+vKwOK6Oh&J?CM8xp2KQ_3osge^yFMoR|Q=Z|;R{C>H7hm1E%ypm>VpDr5_Nho7 zX5eY{^LL1ERLLuqWBeyRtX<-ms0ZaD4N&ph^d`e9s!)~Kezn7~l@HZY+5^)i2 z3K(aa3Ma`5wlBJEEt)de*6u`Fqc_zakbDYtGv1W0XXI}v$w|Kwl-}i*_(W+nLj*}@ z5c3p*B3_FJS8U=?kMGas?Py8iTsV>eXbyZY4N;R?goE{l)L^%ig!dU%WzDt9`t-te z(nKX&?{ev63Ds7B2d>6xEQ6A|(tX6{6QY-<1S)Q{ksD`Q+{p)@R_lCn|rHeT5Ge)6EGrH3W;*v3&~p+t(J;%jroIo=F4|KpDI zXULJr;Y887Sa!vAp(PMOcwBa~O|0^@A=<2THiclt0iqjB-9x3sYlO=Vx>y zn0z(f`7ih4>qZh1r47V2$uX2^VG#T$^Wj(y3K*fbNU?zGO#N1x<-??dc{|OTW%pj2Bu{ew^7BiPHH||{o5w=8Au1VCy`{g75mBYDa9*1{{69j=0QsH zFo@nqFHA;Rd#&cM(k@<$kn-juwB$EhHK!R=>|KeUf7Ye?a@6qBVqVnW+Ook^$=$9( zPnCjTY*n-Mi|HUQ*Kx_JaTDoMU%4ERRgMnVF7^#wTn-0ap@( zh1Nf|Om|dQEI`HuB{jZT9)a$H+mk>))R})jW0NenlrZ3|sm|e=2jo<<03>p7L&cNC zPHBE>xoB19(Hf@jcNlUxdwcK1RnNDzN(+{uZTc*@ZdF=2C?p<9)bah0BaDJXN)Ln* zfU%6nP0c^sd^{k)&?RTmftDqbAP3s+>Sj}{{q^n8)%x;wws&{dF1d|=7BNmh{;_w5 z^W9y;-w{Nh=9BSpw702}YWfj;$}xNsJjz|$I93Bngi)PlUEujQ26OL1Z8b4In=?2A z+jI!4XDotvmTP*~ZLtI}qlNqXnb7QFN5^DwqZ%dd&G|>31T2?RLs|1F(}=)~R8~Jx zQc7P+FvnXaLVfxnN=0#FLo2Ps%TNcDk5CJTn^bVF+9Xsiu(PoM&ZcTcQ?4{u;&EST zU?n|*ZS%U*CfU5;3(Zi-=wH{9*K=BQNBNY~P$(ZB6}31A4tFOo111NvnhWS5u!5~U z31mA)G0%@;&vpgVu=FR+i((hbU!O%3&;xe1LX#tt%x~z9pww!op-$VMC2JSU`Xw+6 zaDGR571rkmi-ImO3ivkzSzwAM8om&td)JbRti@wuzl_u+ZsD>Gg_Ag$AGVK3dk9=E?S8V4f3YVIKiZ;J?*Kn9G;C89k~ zit_~epz{yh=B#;dHrYfsU((0!sjMIV-e^W~d1y116|w+T?a-Ka`1--DNo2mXJ?zF$e`cKx$bL}6$K=rUa^f3JEMbp{elt|coa*Ls9Owd{ zr!}S5?FdNf8;yK2r{eo&)eX|G2Wz-^M45a{0 z*4O(anVsZ07$Ab9s_ct<# zILYR3c@lo;?Uu4Lc%XYDfmcyWc$3Nf2@hM{SurzhLtsOI?MReZ_QF*A(xovR7>jKi zypqq&;#H{&{6i3UUnkyGuYX&=jGYpdb@LwIH^gG#m!1gH(R?l)9?b4M&Ch<%XEYbj zZM|ve)H`Lfa{Wg;$D|`7am}*_?>B*_9!{8Wjql^`=e&~P|Gi=Sb8q;ESjEinKQ6JH z|AzMdOM3nXwD;s++8b3I>B_W%e@{w9LZM^zdHqL`5{gzRl;jzvN)oMTh?ivbfa&oS z+#jUx&W0MkV`2~}6-p&p(_<48(`+~ABl6x*(v^?b?a@k?`F6?Bq@bKp+Es!_=MWJx zY;#F6c`*#$XJAPd!E|z}zg8q8mUAoUF5WlD1x}j^X#mm>AveHJ9QRAt8g^!)eIjfZgn* zpNSSw{iEU({md9dc|3|p`9@=bE2gQ0M017mKVvlyW5g0r-n+#+t2T$%W84EtTEd== z&N?*cDwBm+WCK!;sGHdpC6Mt0OZxYZRne|0MQU$cmq*^hNy3Oiy!>UwCME6ktt?+~ z`gL_wv}5G0ERaxt`>43N@r`dC9mBpXyGAJdF-!!QNv63MMdW9?2SHX;mLFXcL^fAt z2YXWEN!`z!sB;!bI20Lv#Y7LS?_XYx%FDO!62N`);brA?IKF8KnPA?)o{|t3U#Gb9 z&=G9db#J`z*c=@@f$D3mU1YrT)y>8$6OB5yTc8oJY(CDbE~f^1RK}Au9w17X8%Qy4y5#SE6#&D1Lc~uK$K%klp%|g`v6+?<^JE zBs@Q0_{N|RN;tV7$fB#Gqke4$8}3{_4I#`3jtUnZgDq~1CHH7k#Gk37NRX4Jgbk(z za_KZUh|kbhe4ZQu6F97gSY2#Bz{r+ zrW89MqUgg*1Y;S({u^GPGCfApZ(U0J1~y>DrtMy6PzH` z&z!zGcpnP%I0!ekKV1+72lDD@sq4sZxMhK53p^pvkYYkTc(t+@1W(S0x@59{COq1G z$O@a^`#wy+AAr0Oa>)1}AVQX=QYvv}40qUVh2wUdk8N3U;n@d>Sr`!34bB+GCe|1Iqbg8%hB#Es6%Vh&U*~`^is{CzTcKh^0(YN+qP}nU(Wv8+2?I-|1b8{TDNnyw$>bT^xx?H&P-cYGZhLB8JSh~ z3e)?o|F_lp9DJvcom$r#|2peapbb~GKa&B{U!4`HR$D;8Q{-`kzUKuHtkE^-(NiPm zK$+*-#t7Bg)A=6z?Fpzb@SjvNdvF<;Gtn5dU+QZ|JK(b8tm)L z6y0F2XIh*m@x+$*eRR&)KOAuX2B}$C{+|}wKY-Ni{}o6r9YK%KO9v8<7Vz5R0$7cNhYy8(_+y9k1jCB90%YBzZ|4pe=p(bhl zt;==7ejp3Di~E|^U5UC&_@yhP2=q^E&j`H;)VvmpuBmpML=fH?fPKiRlhkJ`9YyMHSt4A)zoYhirdOY{K` z7L)yqo*d=lb5eM3_*I4%SKD4x{^PC(roL%&NpRlxxc-Ki`pAKN%y%1@*TK>b+M^JN zR|;jqzmeSS$qa@4FkFfJjbDmkD*rncLMoX_%2v2{%8}7b0H5bix=^J05PV3iJ-u_R zo#Ml{{j>%Qsjo9}W+_bStRm)KrvQdu(7u7i1WN!FHSygVLyZCu0qlwmCJ82jfOqqZx37iESo+$`nH)xOUDnCjza}S^;0GCo_72A+MRl= z*k7^GqLUjL*CKSf&DT@=O(oOCa*2@`g3P*;uEWUAO~n+JF3ApK{pt6GoB7z?%2q6H zT#QWSz|G_z2E~ylG(-36Cynm#Rd}JA8tO|GZ~RsJ%N>!PCwj? z;3=$beiGSL3`W*k*bgBZEFJlqhTbvFUm(;`*{9n}bUP}16l|80N#nCp*QN!9VC+It zCo{0W>v6FvDPP&we8+7wZd*>CI)%vqnFc5+C9f&|iF8~-pt=cokQ@%2jeZuRQ4l=B z0yNuE9n8@C!0#9tj|zbSY;w3AJ@tK|Q?MXHp!pz@$yVMP!+RD=N;WltVXkI=Rr^Fq zLo7acF3R&P!I?q64sz$?425s|!<)}w=6cNn>&ly8d;Uh)FhcEs7tl-X&lWHQQA=8wu~A% zJxu2?i@{P@$x53W4NGpP%Kh;?u{{LBH+ihkI7c?K&o|KOM`6epx3+s~$3dc1;keyl z*?PLVPHBt^m`rRLn<~PB zK;RJY7)0*tM8N84(Bvcd33LMF=O%8zRHIe*zD$VjJ0mT-G%1k$QQ;7M2$Nt2(KA%% zq}%f_vsB#j8idUFs(Se?4s4eQJbPF;k@h;xupnpE*P{ocig0|UfZL&PbV+E1kPS}4 zT)#amBkzR1h~|^f(ypG90|53smub@v-{nA$(^uhC`*gFE9QgN7HT(SMLoe;9nGc^HI-d!$h{3?XLOJ>S2SEfxyP`dPy&XZeWG=?*fhr7kbqXm3KnH#M zCBD6FMODw}vT2=c=s`!5ock9$>Hd$(k=Gb9Cr?U=*N(F1Yzs zyP~0spb@FoVUNEPj%D_~04b&rwT>URMPy45;2W5_o_~7y#IZ)IGQ=!ipcUhd7K&^U z`Ue}bv#Y9r6SfR={#@cpL96w(dvbY56E8#VPvy|1RCgcXFc|A{Ji9OT44sI;qw?(= z?cMQk6Z+7UGuNk_&($B8XYyZrn42;VR|QS%sVf(pY%fTWOhwy!Oso?fnUC3I0mO?O z1F<{oU4+C6^UmgJDQJE;|Ne>MT}1r@*NLI(&rs`fegrz(;u#;F4UGLV-|bzwscohG zKpk*0jx7=fJOLa86!qAVUO7UX<+9f9kR6FR39oenbnEbt`Vv&qmPa7C^GzJ^XTo=h^RZk1F4q`wpSg@) zcd=egiO7FGQuHj#Ov%uS3C4n|-d3@8c63}|FDgCS^G9LH`ILQiZ{&D$d9>~ARr~zg znA+aX-qvjFv>QC9IW{tJq5ck>#wLQDg_#4r5SO;FVsF&d@q+OkdBnM4rq6zK9hdg9 za)+ng)!gdpctJ+VpRdR9;YZ*VPJx-n5~0=QxdYjPpE}0m^l&zoMeBXt7mF;-EV;+q z;f8TY*_(mv+Ek6~xAixH)y>)Q?$COPwonQQEUj zC$J?EvrLIaufKetU7M^eU2v;0Y>ifL9>vJ0@p0}$Ke1wg^6hC8k-ay0@8xLX8;Vl( z(uC?QQ7(%5Gc||LJdV>WDetgUYL$9giO|W8q13bUyq|t^9hKBHgH(hz^{bNggd-wv zWz#!I4u4e+F2=m6c(JZJCt65h=BZLg@n_H>OPCfDmW)XX%E11%#AFXQ>6<=>mQ|Tn zgByAyxFp)=T)74rnLW+zfhSZ9!W{OLU=JOr2@(jmW)sEhj+fe%7j0$0i4h)I_^#*I z?b#G>R6vcckX@!~DDL4b%2ktnq37-mS) zhb!hQb`XWh!&y8s|)#} z*o*{+6Ivs@;(#P1_K#C!<|bU_^gUectE@=BfCNxtLMBOSP{k=oR%JXmP^yvH&JGS% z1`f8!F06F2wBGG|Cuy|bzTF95fj?W{ZEq)5%EqcE4T7Z=WZ<%)&job@i&%nDpyo}W zOS{Ech*8)E3j5YoCq9tduoy>W=OwVLzZ6#{*ho-Z5FQB#lRJ{Vy%HJXlo(dOb)3d;Q)pEbtW zFG(De_O&C30eokNN>^HHGu8x5u@cwO&eZhE_gmHD7OUnx41eIzu*op5qLr=``A60# zI=@s~Gde?$MA0^f$ia(O%HziOLvBBZqJ{DSDFVAtaS*~n@FOD~J)CSYhIHxRi0pNm zAyz@ics=hKzPD_D?_^2b96Y`%j2DDFcRS)qOKTR24W3H)HF!3yU}tj#{iS6b`2ho= zV$^A&_XvI*yS80j*2F1VBR((M71Zd@5w)FrA%beU-#f_)Lw&4;lg}-LL58;d6cATg zr|SFCJ|rgTguA!tY&6U;8!blzppxJbsuX1F;-Ot(dBy1l<6B zu5{6w);t+e^mszx0&r|f-DhVOOl%8Ca>3{oXcJq%p%HSNB#MKQ7*}uIzOm|T!zw{7 z1M9e;oHO{lQ}s2exigTkj|4{{3ncPt7YuFQ^^ieut)y5n)Eqd>)v04g8H0ykPz$B` zyH!`H!cQ9&+pzc-@#Q@#i9fe@O)`dsDzi!#5#WAjn&0f>*LMoprvNZahbcPj8t|t;NMNPG2(kJ2(r*H`(!l|Sv1BI9OiVM6W+*!mY5azO_f-Kuw3p*(+$k(&3&YG__4wZjON@#fkRt(S>-nQ57v4oi^e z?_^O?2~=P)a>T!9lk>cEO3VhH9%n&m3lwE~1HiP-%Wsl@SX-jdF$=>wyDap_fG5F~ ze8D=(li{LtV~sr_zX4 zu~N^rU%D3+X;lB#D2!lE$}wN@Txk^7$?`*kjBV1QM3gp&zKqm3m~zjFzaoaaT_pfD zlyp+OILS~AW14qmAmYYP8j6zg?YgC~^QQrEc{jMArX(w(0R4z}ak&|3bqpJ*$zBWW z+tiblzrQ1jdbqkAd|Y2`EMn02sP;+DoRl&A<`j10(ew-Gnd_MJVkFN4&6A&mdh;B?a>+L#2WGz#3y1C{zu&*1$54RQwMCr)3fL&H?>NzkBfQ%1y#kv{EBK zJL|cuKT?1c6;%qFRF_jQW>%I=xO|`8Vpcc$L}T-xd{qdwp(TtL-=zfx)J(owc5_$> z;HsIJG+yCSdx>}&;kaTMwB_@5WSioW0f1t=4f`?F6HHc|490z#%+>(mhN`)-&^BZ4 z^EYFW?R(DL2}pgj_(e&Wqs&^>)J1}(JbQ3qJe0|RACg}r2Yi42CMWwyy#2OJcn(TQ zD@V?09&7(eC2NK9R6(`GJi@q0UzSgH^5v%t&_N00P{9dnqGA>}g;|0P|8zg7X_`RF zSf=yIsIVomdqW&w*PTfZU`D&>`*i#gN8?ggEguEjw(|JieJE@Ppf#jb$spW)cI;(QDlQo>u4QwmTF$ zTv=%bNd=9>8J#CB0ms5%5nNHHbuemFpP3ETqu$+Hxc3!(K~&vXgrrSte{tCo^p_`| z-&!P%ghITNcKfY8_Y=KFGI$nlGB)iGAaqQI^CE@xlUq;Go22>TktiG6T&?ZlK7{;* z4C4!`2__WYBFw*tLMynZ0)KesT+a7u<)SURp?z1#z<=iO31IC!jqt_cCZVpdaZx!1 zMR4N(2JL;{76gt4rn7RRom0bI?R(UtrMBm$5-$q>kdTb2*=hRGImPs78StC1=-z5Q z`!9z!T_20lQ=ItlfGLW^BQG&QoM@a4cCn4q=Q*quc&WJR{L|Wic}=;~*z^)e=Z+LM z&mRX4>LOkmx>a5esba=&fgZ#rE_9vEh{~EZa$(ABgK`-7&Rz=Ti4D{nRh!X4^zO9B~{8iNL=Ajx+ zHo~>+b{4{S*n72j?C-D`Xl2p6keT&U)~Eo-8}ApmQzJ9oe_m1kb@BL@a7fSiZ~H<< z`u`LT8R`Ek;c!D^Eplxb`Jt{;zy??U7xKmv?5$x{L`1dt;#mqlEeM>(?l@hdka|AX z4$KM3+*G*Q{Is;k2 zLI2>vn0JTw8KV13W@^umaLRaTNbz5p^2VoBKSEnfjMMJ~usAd5;jLfEc49x#lrcrd zw}G{MJE+_GI=@HoHDoBjqegUp zDVOT{`&eRo#991)hxSERVhHaZ5WderQyLg(S~J>Hwd`SrFjls%8fs^*L(jE%aS)O2 zSZRt1G&SY3dKSUP{(479D?Jlfy_B!M@C!X_AuOZ&|Ra){AtC@keL_k!O4%A`N7~M2L@hL!w%*L&;Tuc%3xGY03en|ho z45nylr+A{5rx2uctud>z9(_Ed-8?DRO`maZ(qKh?^{d#GIWs?F1(oHi_t7^2T1y^_ z+Nh;o(psIuBD;P$)`UNg&p3pXclp3wS0n?u z3C&VN5V!v-Mo}6cNOu@uYk$0~&uL|0V)3Yq8dEt$c(jq*Lckn^8|Z*uYNFqI9lvWp zN=EkYJMbLtsV2;&D`^driDsb(%~j6(HmjO{*a}>$X`#FVfm121qrK_UR(swK>*NZK zit-v?z_v^;q^)yuWI1U1crATW54UckkFr$Q20=B*y1d=0BwQCIjI>a#M@=xr+x#CP zADxxzNFS{A&^*F^T|_DYK*ZVP)kF_c*iLuHj!)618$3w@l#6sN`;q;N^()3r9BlEkWgH-tY`Ql4bp2~;koc$~@&s|1 zU&cst$^0R+fEF}?%FW8sD)})5!3iyT2?7-M-8}b5viDN+q&K%EW_Lr9{5YBe=xg4% z;u(QS!AJ4p0*E?VywVZwpxg$vA{Vujkz4YD4~=wTa1Hji=v=1fN+9!WMVl)+s-l^()3DCTb?K@FDa_I|&#LwWr3 zt=j9=o&nQS>e52vY7#OeqYOZUKwF($i}_7DWt5r8Mn%8(vTQ2I4KJW+j4g$w17;1_ zosl%kitSh)I|ZGelU-QSGV3?ZsdNW|F9hZPJPF3rz0X1>o zcn?`fNM#yTh+<865pc)2B~z2^k>g+(7a~;RfBke%x1L*Sl_`nAcQo zhKuX#pwV9#Alp=Bp!xVFoZS=waW$J4*JI7sIaPlfTx@ufm3g@W^ zw*y{;8>&!a%svU`K-aAR7su5hJ^)^Tx)*TckS7|rrfw_!>t_f8MKKpN%_4w4DjyXL z$}7kZa^PCJpMBRRJA(7(!d4lqRwG!>HczCI8Gf<5`rFrO^ZVI~<#))9g=p-Jf$lH7 zrGqD1I@UyUZz#9LB)Sr5117H@#b`RnL~)+&-eWv1o@YOS57kxwMLEIlKpL+bgmTr>g8QrXFfDS0}5P>V@&AKex-IwZ&k zWC}G|t3^T;0?Q+{uA|Rwdx_AG_eBl%-uAoeG3GK}tj7q4B&;Br0c-&CYkx*uwK?Sh zRqe%Hm)HMAojpp+UwJVdQp;Q!YSGv8Pv-BoUbP@b0yz6Gucq2F4gQPFpyfNrj z$zk{(4xw4rz=mK#Rvg9b`H@0IBkS?>ee44bv_(}S!@n~Kcv-9iKS_-_@6C!FyHvj_ zQ~Qh{>LrHJG?xpd!WB z_qwE$6QGc7Uw$dicy#3~(}`=Fh7@etz#=n&7;mNAocxDY`Gs#bm(tNj=$+bhtwA8FB(z7T9 z#OI0JKXnHpokhDl;U{bf^_cDMHrQ7>Pr&2_-Nsqd{i@y>|)U--OJytoyK* zLCP#bu|mosjTa&ec|ZR-u-00^bq5`tg>=Xn&-7FDKG;^SRwmrQwc33!@O~o*uy);s z_)O}V1#q)r;5v5vn@0)uoV~83)$sJ_yP43tFH26e)jP(r=HBb}x}VoQvqcW(;Wx+c zN*5r*JJgQ+l+JKYo;?+YDulxks{K0N#@mEk&8HC@H$kKQ?MolR{6=%nQOP^ujXe{9 zO{kgcXB!H??^J%PndOjsi;eLRD3!*fO^3dMe9Sd(hxm7gCtycMbN_^4OnmKE_1!vc zVasnc^YO$Os|sl1Q_;r}U-!e@O0%IB(|U3w^!O^Y2FCoDFOI;&D-0v617sHIQHm?D z=9GA6%0ou#LrNBe%Q`sIP{kSDYfy`yxTaB^&)Ky2muY5~k&jtigC1umpKtJeYv>dI zP=Nn0*ucQX^#2s#{|PoQ(*L($1EMb-Qoz$^=r3D#cgyd~sekZ{P`|zIAX_rs^%usP z28w;3WapdqCd5x@hxYWbQkDi_lE$H0f#0WW^6A?DL%!85PA4ms= z|B7@dP#gOnH}#FP-(U`LXp4rMQAVf^$PP30KU!gQr_rcuV#HGNw=q9nv?s?q(5P3W zSJ?nQJJ&pu>`(l>RP3mdJfHhp2YNTvE^47JfnB40w;ygdm(IVFVj2GyXjNWeoPgKV z!+c6YAT9+Bq#?HLvMFt>J?MmWr`)ag6+9T<3`U7wd8z7CFsF0Uud3~2B((eZWaa1Qvg(<0|P%f-(E^}7d!iQKjs2K6Yz-n7{t4qVx+0y z!JE7<@@%9FoIO7i!Ab>&hp$$xyEhRf9WKv+8lI&fv+OHxRzEx>m{ujQOq2DX?0Q=2 zIWECJOt}1RsLGV)`D4mRh#V*D)k1@gfruoz>_)-f?TmQplD(e|Z!-fLV9oHwvlfAr z!RNx41Q095dN_y++NyUDg1pIWZtL$?z=K_ z{AH{Cl=4F_xJ0lfghFB{JPB(3B$+uUqlr;QRRW9rH3r}32Zs=o=*XJtZMYrcIP`N+ z$#+DnDq@?UH>#P+`0p^ncWAsrFM^_LFH42-ShJG*0FdmuW^dM7uW>OLX^L97d=(|U ztzQs6<-T5|c?rIi#tDSBO>ZTPd>Q(fPr@4oxIpFCd^;Csg53EcB}}mCt$g%hGa$Sm z1|I7RMvDy%5Ps_OMIsNk;*&+c>BSAcb@%%d_z~Qi2NFu@f2JakgoFvoLxG0BGAoz1^I@ zqV3W7g>G}x!N~uXp4OH}3K}B(jN;XyWq1T&XD&?KFzvU_$c)&>=2WGH>?eutOGonm zIjs_oJ2=1@YJT5xW?}(Xcw*XKuP5AI^Q^&Rc$$P|#OU|Xjv+D`Mpp8Gv_~EKE+*-Z zCYmf{r5lNVtd8pCEa0t6FKKpyqn6d9#R zAURWANzaE#^yCqO3-WhcMP3V6FetHl{{xtoas`W zUqU}Ys1^AoSJ~2`Ka@9YITis|6q_0H!5Jmc--u-2TtKgCC*~o}g^IajW-Ue~6^t>o zR1c4sghzp)?6tYINn#67(oyy@I#0{6wWN)K^00R*<3g;?pQW6y8K)iLNs-AI+3?T| zfnP{nR7F<|l}JkxN>bj@s7b34$AH|AwuRvkuL2^xQZoiRt?j)yreU=nY)aeeA9``e zTC%kRc#3#H6&-^d{+RDi9WgJ($^Jys1KD40SjJ?UIGiXMFKhbs^ioo@?Tc9)R9{5E zI@qiOYbjO)pQw%G;5it!q^Ds}oXIbJ>bqK3RXk$wKDr+a>4`afa&}efgWSwj1s4Bh zQ3@n!OOFZ5cQnXrnCrXeznWCr#oPqc_zb5Jk;9qH7V0pEh*h>t@uE1lv_@J%%_j|z ziL~4LQC}|pn*Bk)NQ8jEcp95{on#q-q_ZlZ*z{J~A})zk{{y425yUJ%I{`BZ{YA$Q zH%Q?YsJ>4q<;RMDA?v%o)Ow^*mNr6lrs*l4s?IOh_6k;=I>zLkODWGS9M6+?ERVQGyvf;?&Rn^#|$2Mmex@(Du=ZN%odI(`nh4uxYUj(HQuo$T>4 zHAOu)Wa z+hB8G;4V~DDlHHXU*M92TMt9r5207o)Y9z z43+j&m)elXXy}}pm@9K^j}BO>F4tev`&b1g4&%Su9$iG>b>f;GcS!i@`2J3BNc@r^ zP=6~*AR4iLPn$`%$+mc+T~z&f!x~ARw{7UO{mU|^6nvbbudcoR?c)4M6L^{L@P z20(3y{z&)-wuo5r|}#hm-?y!uq4{QZ;cFpmt1^6u=_%_2tpU$IQ_69 zN{)!E3TvftUZZN)#>#u;&+rRlfbdD>Tu((>t)(b!_kq0fAwLi>;nSDsn>&2tj|WNV z>)3GbmZla-YWrX*bnq>PBsAjV66_>N!M>x$mZY;*9dL{+(|klW;0#v(;i&F9ZWlwZ zN-V(eHXg(*Jvg6((!krlLp2A%&UKK%oYDU0=;4*;lrHp>cNfI)m~JydvgP%iSkng; zjAW4SS`QA$HQJ^7JqBU)qVySi6n7oe(;ivv$7wCjOJX4h`UeOc!r`hF=2Z##s(!uI z*mZRnkV>dAhORJlFH9_Ldm2SVK1K=N@=llth<~E8>)i9X^FrdOscKx74hA*CVfga6 z&Emu;0Ako$5(&P|)4tBymw_O>x^oUt1J6O7KyA|=BW|_+{I_?(2QseNr%sFC6fp=A zO1>joW9Z-*@Y4!ydEFR0ba$Fw$;q4$`vMjoiIP#waR}p6mxjb{S9Mk1YOD}!1tlNK ztS1bqZL(~PFXN|-fbeqpouv&hTM{A&RC~$vpNww+EJ4uw4+98=5*Z^zi94$Ay?&P# zN2?_*F<^jrv02+cr57qGqN}|=HpE9T{{pPgR3HQRg{hl4z&Elvlgat4E~v#2(R9Us zKL(m#F`&A)oLR?i_T?B{ZvJn%l>Z;N%%J2T_@LvQ`>^U7oMoY>`$a-53*YGF%hY0Op>QN@y2ChYJ!-31j&l*Mg7!#ch=5S_IZ1BL7&jc5)BMdH zXj4gYbxl6sdQZgY)*1Zuodh3yK05G&Z0JTa(G4$t!KnV5gs?S$rH|M8i!;0%mFhC| z^!fUTH$9IEpqW+bDH8k-1&8NRSzZ3MiGWMwnWt!%>VRF-3YwgiMis?1R{}+<7GpNA z@-jTh2&wdGaqr)ZV4;}Lj=oy$g(3yDnk*%FcsXJJxeY>DQ|v3 zKS<|FKDtPwD^hugkdJ!}=ssTL0UZYtMIn1Hw4KJ&QXgRBBR%F>;V;N0Dh@Mi5THqq zP7$a_t}3kT1w#$et?)Eu$k9NSBM4QV`Z`xuV?}v+T5MW^MHaxHtCh%lM%N3Zkf3>s z+$(k}@5KY-7=*fCuS$=}w8M*N)PpmkfU#odXNUSrDMMJ-uxLmzyqy6GFb7hyKi4mv z)Lr7ZK1%1Y2?hXVrmPtm@;rwD)07gkxS`y70_Gw))W#)2C@9(6(0(O`kRyKyHYNaq zH5H5CS{u>Q0e-cQ4OzRaY?n@z!vzIwWc@`f_!(?F{hX_~II33dV_b5|fK+Qn&Thpt zR|1NVQ8&PwUNBMD#c>wV&tY%hP(HPfh20~QbFuac92MYy$acT7cyPe-j7yho%4FU$ zS*FWl#0KxN*@}k!ocrK=_JrwuU4FLlXy>8Abqc4}$Za(Vl#*yCM7j!hK1Ln*RuWP?i<5uk2e(E@%ER|IV{P>gcTnLVCTHD zhD%f$0^DIIf)uK~&M~0yuv4z0U-$BC5WQCyzcI&hBTYWl*haR>e$I=W^h%1f_R-4K|3(+He+H3{dX)Gqe0A@sl)SfS{ zlD^4oEPzmupYfA@TM*=gr`8%4lV327I6P$`6M`f*Ls9j6C!;a-AfquQX(6*=?w-eec#C2u2ct32^q%p!e}u_+tju^a zr%0sn`1<#YPe;Qb3r!Co?c}7ExbMVnN~?s!7X_eNtBnU>JltfeU|kE?3`yy+aHcDJ zTjXELJ_Bl7m))=sJ;C8YTopluTPj^XAN*MxGAj0S9lG6veRl8}N&W{~i zfmlu12zDilxIj$DxVJ3#$F)%Sa+RE(i!i-&LHEOhWafM_WU^p{OAF5WzLDqg); zN4A1T#%UfaoPsTQ>e)a*E?HN!JWzLQh@Ar<(Q<=92oRyhC#)8srEc`V^V4N7e&vn^ zHC~UKXI&>eVZ6k`D?g482qgibCOsLKD1Ys#R=l+q;{^ zknNmf>5mbD+3{uT&GEF63`F4D9JdM9-|d`NlcKAOp0&N+818lK1zuo;fmjcF2}`(q zJVZQXaD0bD0jw~qk(LE@qvR* zWm0wQFmEoHl1PzKP(-8NP33>rOrD7-jS8{@2tvb6 z;ue2N1AzVYOr)PAE&cJ~@L2~NOf?NQH5V>lJYIAKh^z#CJfz6|S?=8mEfnFPq1cjy zj)l>Sz}%W}|H_}hL4hO_S&RqOS6+>opD^I=tK|RLnPtP3Lcv}oRq* z(5V@owWXV;S*$}hDXs`8%v;IqPse7`kXp%%S|Ccvgl4t{g zqwCo)H!Ul`QBwInBpM=ITu`g&VV7_Za9~qo9JxdsvbL&{lTnv5a2yh)M@k{t|&96KwDbaLK?i@l*ueX+LHo zpA7=bx5!P3okFq+HwOBhg4U`XYWrq&seaaE zt^n-XzP1X>gc2{EF6o#G++8=~6Ks@SRx3LOxZC%F7WcPp)#LkW%plLWYG7AM$-%<2 z?QOk-Kdv&}zJNK?k*faloBP+7^gkCvR<{2ev|{`R8iMh^q9LRs+x|6W_T&*DswS1* zG=xUk+E5=OcSH!0kMQvoK+1&D>Q}J0H}pSaR+I8c$`<;dl;w#=0i+>gV!)Uy6ejo` z1J(clw7Sm{LV;g>XdL6w{feW(=R>!cNQozLNB_y{06~KRdWFc|2u=hbB}RB`7SDqG zC&MqT1~%y_Ddld@5^hu8O_+Mj=2}u2%beA`r`R*l0~Rxf$;E=Z=+`&QAgjp^mL9=< z4`A{&p3Q&QlK*W`)3g0M!Gw|VANtdb|5bmwL*vhPj@XaMI$gA3Ui@2yH=nW=ozz1D zC-{E8y~apD=dqD+WpRZVjWi8)Sy!itm5I{`!9;%bPIqWfUkc;Vt>;$C%n)?Rv41n~ z&5?!U!_DcQ|7*>?!8gR-+0y!%z3d+&K~YG``lPx8>yXR#K14}P%34;IWQ}_&y=9@Z z@qRQKEAdNTcXs0aw7^kt36Cv<4tOuMmATMtQYlt~f%m4*nzyY)LU|MutLr0Y?dhU* zQT`5DsIOUoxLI&f@?)eRO}8LEzA(pat*P##_E8d6LtY{l z`r&njR_}MD!PDDAxix3kV?3%B77eN5&)#L;`3_#}3jg_$;}4qtX!;~kvwCmSTpf}e zLWIwbj`0#ol{Z8z{YQ%TRV~OOD{J@qhIi;#CEv>FM z$64#AiG_zQvis9ljHjhD?@k}Qt524f%hLdQ5i6a| z&QKXvbZ*y2uvq~>XAd+Qs7cxmw9|!tM@Wc4F-o4Izr7UuzCVfFHQFKO*NbA?Jw-pI znGj4T-mF}(P+^YZ!6{5+L3S2-g;KeuIuDh~A93=tc&rPKpZX-mdNMXvbUnO11o1iw zs^P=-jyMdzWF%X9n=gCufl>!3lewo7rGbEw%f%pCNnhjDGE~GK&VDNZ6mJO6`O6AmUl&5ro*Rht#siJ~Rd8}WRkLE(UO@?uxDEP#?x6Ga$ zkST+)VxZleJU_5=HpIp&+dQ)p>yw+y*y2=DtLvvu2uagZlm^<2+FXv4rjX|o1g;T8 zK^T43Zp1Fal=3*{CfZ>LLD~^q`@zNVi`XzBYeD@p><&Qo9;AgoL|}p;gs0Bj5}|OZ z!u+DbESnH1Y(9YJyTwN7h7_F`97Bb|F~e0MX6TC1C9t!KI!?ENc>uW+pH?fA`p>33 zXL-M3x2bxky{F^}_%iZ`7siB}EZ>3>oSVw?1-jstwfr(U3>I;==ecszb4Y)cODL|xl`kl148pax*7(i@Mib3$NA@?G2R`f&m4#R?YsWgDt> z#A7MjhVDwq(0dLTT;_10(3k*=0}eGlKT73LNlfCdhaKg?z0o z=QZUHxC7ArXve>gnfk{au5V;=kpvRaeG;j9$>mA04u;S1e$9bQ;>9jamZw9-Jz&`p z!e{p2K%TvRf*uc~NEtvGGYNvJ8N#Z`1f(qtylqQv4ze6iaO= zo{Y_2n>1htepR%vGuVT@4Jv_~w|*L1&J+wCVcK-|{B@foE>{6%_<`sOzkZ1uvxZv> zVpH5btAnG;)2-PCtPQ?>&kQz!OTb>D$l4Pl>ipJLviB~XUXg<9@K^>UBbTkA(@z+b z0`FY!Zz+f)P5@dcN-iy9an0p)Jf8Z27VkjbcPTgO}R@nW5SJm3_rqI0tyn zwDVjX#({5Bo?DLmuM*;fTOzIp;O~!~V1%Cnv0Lt$QDs$Y)-`r@tAdXKg(+ISotGLE zlCOG^3V!UT_a3HZInxD329Vb|ppy!jT?~N={Q1q&K>KU#9+|6DXVnN&Q|s%jS#NSS z;HOOJ($5Xa*C=c;-YFae4&4vS9tE)c(Jc^bN4Y=!zHl^MKbSdGH9UYHjOCwhLyggl zJ9y=%!-=A^X2UqDdSht{gK#?BPbaUh*i5#9euH}dD22damKO>0_{;v66>(y5AZOo) zqOQ7tNzn7=5R4WpGC|pDd;_gK8&f{|Mt9f9qD0)oZ8d|2LoCO zK=Qhy^&E`-m_KakZ81QiV3%#q8kS5)9-{(u7R>?vM{rHieRE?_YoU$z_HjJXV!GV? zI>WsAgE8t4{HfW_lBTv})mS{BY7%VC*sM#2mF>;^;OI5C#UeQg=E_T94@QtYVIYlwL90iZ>MMz$7`qE zD?q`bpdpq)j2w+DVti#;u3+(RO2j4?j-fP^Mbl+vI{#Ex=zJ{$%bpA5rbs^`f<8KPMyM$XMKC6PpY~wYi+F|B!k- zK?O;@QR{BeUjsd=Ues<529at&k0IiL@uSsAnq$;%b)4Wnsuqnp13~GW+Ecd_d+?{= zB+)uxK1)hm5YB|iANxEb72oFdmabf!25hAZejJ(1L8Vi{Rz1U+Gvz#UN;V;r0@yw_ zn(8l4n88agP+xvV#NOa-CjvGr;xBn zHXuKnaMrWFfZw(_=Ki6^|6l5Yf&Kr1P?-J!yI}gSu#1jAmftaj-(kT7$JT87k{9^7 zPag%AJpGkxP!nNgo{jZx+x98+toptLO>bOzPDzmLnx&&mn&d!G^CYdSf z9T_#gQ)WA7APYZzr~$F{R$+qP}n&W>$6*|BZgwr$(C`KP=7 zbNW3@XO zZdKA{V>~<_@7%U3g2#BO*^%y2u}wsh(RIJyFHKEc+~y_+KW`T5y%Ks2JLge5o;6(D z^uXXjX<+2tHr$5Oq@w=8`?wCxsIb-Z!9(ZUyePVDwhNh|4Gxz37}0x)MDO=V)4fID zwGR%lzJHwa(zQmL8mO*dbIp0yyA7V7F4kMo>DiLHg38NG)p0r%a`H3;XsuD%R%tR1Dtvqe?#Q{eD&5SJQhjCv|gf(saoNd#s49c6B{L z>n_RZV8Ph9q`MoqaoydLfzqwdxM97rcu~&Rj?$<18c~1dI&4kQI0CO`;;2S4!7w%J zbVPa$15?DEZQpRkHmpN{>f>9t-hB4~vk_o0=4>gQ1yDA>Q zwlXwCE`-uea|hDi`l^lX;s|tYgy)|>Gk*)4&5x}UT7n7GzO<`dE6yJtfzkxDcVyp) zFgC^-zH5V*4N=PZp;gzgA!LGQ@8?^E%)y{d%y|bL>Bm5_jB;j4Ir==>c)np2U=0jz zl{=7D>;jen)D=7Zr|9~Gr-w$=Otw12{j5>i3o3lB6%iz)K$wr7lu8?d<1wAXg^A3_ zb=>mN2eT0Tk>)I%(XGq7(2TgWs;LcZ0yNi~eY(zH@ZAZ#hOG!o>IU|91rZj!kn#Lg zWcI2+_F>v0`wjpsAb!3HIG%9r`Y(}kULE%>t0*G9xj;#xX=7voHlQwMS#NGG#JRfZ zMGrWxjpU_n!t2pY2pQ1=n7v=eOd%zx+Hv%OPYY9J?Ep40_HN&XzMUnzl3i4ENS{Nc zCul@<1+&N#39vh37_OR(|&a2y{gi0Ue}GubtmQ=E>hUhB`1?YqpfSnS~=DTZLv)bkLb9APDF2Z+99& z=mWgFw)33s69eD_w=_AB01-Ii5uuYSTrz5z_#Z$VDwZNfRd>^pRkU`j2`yUjy35|(LkU+PILAp1l7b7PGcL~Se=QPp7}7UeCTqv_U? zR)YHsZGBTGQS;qfDX_BwUYe+xSoYJ(wHb%z1mu|21;A-eC{y^n7hC1Jj~$tO|18!0 z=nALGugi&!BtOJhQ#9k)N^~}zD1=4>0@*nh5n}Nl6+GstBjcIY5SHg6PHVO=pW}pb zW8)Mv-7Tuc7-bGu6Y;fU43*#vAG)oOOB{+E*KOMWGG~Pa9w2*JlB|{(M$O>g&(u6op&>0WSAtgEgT~RnS$`Y<`tuUrD-~}E05ka4f&&st z7sOO@VLM+M_5w?EDKL;jYcjc&0fzcMj^#=&(Pa@;antN7?Z5b^GgSyhO$GG^)sOO) zfAmcpQkj17DhI%LFuai*R}|mg#>COaJdfI_jlJ{)AIK;jT}8&DS_}((81yjL>M*;W zof{Vm^!Sr73o_t?T3ntZo`F=3$L!4CENi=M^aLs}e{pi2aCCU%2MmaE-gR8iKCxZ8 zRUeo$ieM!|o6_XK{2rPDIe#l^S8$rNv3&>!_3Ae=2R9%>tYs-3;jHDhTjHbwrta&B zgPLxxZSmkU`iqf+geUcXOPo|ujy7SFetpDb0g8%5914Z<_mX?d-J#f+9}r0M1O@bM z743=h{ATi(^4Sg1)RNFG6lz}Tivgv@0iPheehQg6L7NzdL=lqb2j)|ONN>bTjBgO? zxK)@>C=kR+D)g)6Hj3XN?>UlL>ImvH90t}2gIKc~U>m{)zKXOw#9ifsx$Gipm_pT- z<-$6*l`Cytf0ZU~Jmwyb*!GHPE1WQ3wEN$7C6jeIeJJ1WNpqe#Pm|&@hm{?XUBGlED9zZ+FSxl^_b5 z$GTi9`>pl|l{paig}{0?p|FXFaMx)a(N~6~8=*s)$lN{%X9j``pYf(ayy)L{af-uH z*;BI&Sqrb0Rgdga80_!zMUe4@8+|RI!?$b1(L+v0zOo0PWf|AZ%`Dp3lRSeoLtT^| zDpa?vCEQR2F6YJhl2L3^0aML|#3!BPPPuMF`NEnrE#UIjUl?INqVUgU9q4VIgRhG< zKXB=60h+>yU|BIxogjCZxNi5Uge(vMCX0x!l@Vc_KD}txe$VieUuW4%-S0iRXj%5| zun0N}9yf#-JCyh&y%Ip0*||EbPzZ))!&}W(kqvL~UqP8f_@KB3Qh7;-`Y`Zr@9OLJ z+i&?-iQe|)xBZ<9=>h*a663ryK&8+lWeE-jMO1aRo(^}%yD1oJ6>atx`vLk)H`EWe z?-P)Z_Ls?XM`ViHm#5E^msD>u3_IGg|H2b;H5)R9+bc8Rw%z#h;Z}Bh-ln|RCgY_k zSiZ0X)T19pTR1aeXjKytboRw$sZlWF>v6G14m;@h+yN3Bm(%?sg@8oZDexOm(fN4{ zq{(IN4iq$CYd4(#2G5t!t8WS9*zQfvF7=X}ZF%Thf(|lQYPD@miI|Th52{~L$xYJe zjwCkgZb0}0_f5m?un(GDnKi^SV5I(tXKlvIV=K%Q&^*AKK@L}f^_LVjleXq!~y;EnMtsfH@wiLj_*fH zp-fOgWl!b0h|*2_C>vA+v>diFt4vz|l;ruWNCT*f7yu1@i#p}P@xyMZoKknJ#*{D? zK&n6x2hSY!idAm@L1kl#{vomDzNehbXE=i+x ZF8jYYau%$;uTf2K?|1C)R?&w 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

Y~xccqPx=HfMkSCE3C5tzfUgf&nm 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 +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; + + /* ... 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 & Key Range & Rounds \\ + \hline Blowfish & blowfish\_desc & 8 & 8 $\ldots$ 56 & 16 \\ + \hline X-Tea & xtea\_desc & 8 & 16 & 32 \\ + \hline RC2 & rc2\_desc & 8 & 8 $\ldots$ 128 & 16 \\ + \hline RC5-32/12/b & rc5\_desc & 8 & 8 $\ldots$ 128 & 12 $\ldots$ 24 \\ + \hline RC6-32/20/b & rc6\_desc & 16 & 8 $\ldots$ 128 & 20 \\ + \hline SAFER+ & saferp\_desc &16 & 16, 24, 32 & 8, 12, 16 \\ + \hline Safer K64 & safer\_k64\_desc & 8 & 8 & 6 $\ldots$ 13 \\ + \hline Safer SK64 & safer\_sk64\_desc & 8 & 8 & 6 $\ldots$ 13 \\ + \hline Safer K128 & safer\_k128\_desc & 8 & 16 & 6 $\ldots$ 13 \\ + \hline Safer SK128 & safer\_sk128\_desc & 8 & 16 & 6 $\ldots$ 13 \\ + \hline AES & aes\_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 $\ldots$ 16 & 12, 16 \\ + \hline Noekeon & noekeon\_desc & 16 & 16 & 16 \\ + \hline Skipjack & skipjack\_desc & 8 & 10 & 32 \\ + \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. + +\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 +five of the modes will return {\bf CRYPT\_OK} on success from the encrypt or decrypt functions. + +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} + +\section{Encrypt and Authenticate Modes} + +\subsection{EAX Mode} +LibTomCrypt provides support for a mode called EAX\footnote{See +M. Bellare, P. Rogaway, D. Wagner, A Conventional Authenticated-Encryption Mode.} in a manner similar to the +way it was intended to be used. + +First a short description of what EAX mode is before I explain how to use it. EAX is a mode that requires a cipher, +CTR and OMAC support and provides encryption and authentication. It is initialized with a random ``nonce'' that can +be shared publicly as well as a ``header'' which can be fixed and public as well as a random secret symmetric key. + +The ``header'' data is meant to be meta-data associated with a stream that isn't private (e.g. protocol messages). It can +be added at anytime during an EAX stream and is part of the authentication tag. That is, changes in the meta-data can +be detected by an invalid output tag. + +The mode can then process plaintext producing ciphertext as well as compute a partial checksum. The actual checksum +called a ``tag'' is only emitted when the message is finished. In the interim though the user can process any arbitrary +sized message block to send to the recipient as ciphertext. This makes the EAX mode especially suited for streaming modes +of operation. + +The mode is initialized with the following function. +\begin{verbatim} +int eax_init(eax_state *eax, int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, unsigned long noncelen, + const unsigned char *header, unsigned long headerlen); +\end{verbatim} + +Where ``eax'' is the EAX state. ``cipher'' is the index of the desired cipher in the descriptor table. +``key'' is the shared secret symmetric key of length ``keylen''. ``nonce'' is the random public string of +length ``noncelen''. ``header'' is the random (or fixed or \textbf{NULL}) header for the message of length +``headerlen''. + +When this function completes ``eax'' will be initialized such that you can now either have data decrypted or +encrypted in EAX mode. Note that if ``headerlen'' is zero you may pass ``header'' as \textbf{NULL}. It will still +initialize the EAX ``H'' value to the correct value. + +To encrypt or decrypt data in a streaming mode use the following. +\begin{verbatim} +int eax_encrypt(eax_state *eax, const unsigned char *pt, + unsigned char *ct, unsigned long length); + +int eax_decrypt(eax_state *eax, const unsigned char *ct, + unsigned char *pt, unsigned long length); +\end{verbatim} +The function ``eax\_encrypt'' will encrypt the bytes in ``pt'' of ``length'' bytes and store the ciphertext in +``ct''. Note that ``ct'' and ``pt'' may be the same region in memory. This function will also send the ciphertext +through the OMAC function. The function ``eax\_decrypt'' decrypts ``ct'' and stores it in ``pt''. This also allows +``pt'' and ``ct'' to be the same region in memory. + +Note that both of these functions allow you to send the data in any granularity but the order is important. While +the eax\_init() function allows you to add initial header data to the stream you can also add header data during the +EAX stream with the following. + +Also note that you cannot both encrypt or decrypt with the same ``eax'' context. For bi-directional communication you +will need to initialize two EAX contexts (preferably with different headers and nonces). + +\begin{verbatim} +int eax_addheader(eax_state *eax, + const unsigned char *header, unsigned long length); +\end{verbatim} + +This will add the ``length'' bytes from ``header'' to the given ``eax'' stream. Once the message is finished the +``tag'' (checksum) may be computed with the following function. + +\begin{verbatim} +int eax_done(eax_state *eax, + unsigned char *tag, unsigned long *taglen); +\end{verbatim} +This will terminate the EAX state ``eax'' and store upto ``taglen'' bytes of the message tag in ``tag''. The function +then stores how many bytes of the tag were written out back into ``taglen''. + +The EAX mode code can be tested to ensure it matches the test vectors by calling the following function. +\begin{verbatim} +int eax_test(void); +\end{verbatim} +This requires that the AES (or Rijndael) block cipher be registered with the cipher\_descriptor table first. + +\subsection{OCB Mode} +LibTomCrypt provides support for a mode called OCB\footnote{See +P. Rogaway, M. Bellare, J. Black, T. Krovetz, ``OCB: A Block Cipher Mode of Operation for Efficient Authenticated Encryption''.} +in a mode somewhat similar to as it was meant to be used. + +OCB is an encryption protocol that simultaneously provides authentication. It is slightly faster to use than EAX mode +but is less flexible. Let's review how to initialize an OCB context. + +\begin{verbatim} +int ocb_init(ocb_state *ocb, int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *nonce); +\end{verbatim} + +This will initialize the ``ocb'' context using cipher descriptor ``cipher''. It will use a ``key'' of length ``keylen'' +and the random ``nonce''. Note that ``nonce'' must be a random (public) string the same length as the block ciphers +block size (e.g. 16 for AES). + +This mode has no ``Associated Data'' like EAX mode does which means you cannot authenticate metadata along with the stream. +To encrypt or decrypt data use the following. + +\begin{verbatim} +int ocb_encrypt(ocb_state *ocb, const unsigned char *pt, unsigned char *ct); +int ocb_decrypt(ocb_state *ocb, const unsigned char *ct, unsigned char *pt); +\end{verbatim} + +This will encrypt (or decrypt for the latter) a fixed length of data from ``pt'' to ``ct'' (vice versa for the latter). +They assume that ``pt'' and ``ct'' are the same size as the block cipher's block size. Note that you cannot call +both functions given a single ``ocb'' state. For bi-directional communication you will have to initialize two ``ocb'' +states (with different nonces). Also ``pt'' and ``ct'' may point to the same location in memory. + +When you are finished encrypting the message you call the following function to compute the tag. + +\begin{verbatim} +int ocb_done_encrypt(ocb_state *ocb, + const unsigned char *pt, unsigned long ptlen, + unsigned char *ct, + unsigned char *tag, unsigned long *taglen); +\end{verbatim} + +This will terminate an encrypt stream ``ocb''. If you have trailing bytes of plaintext that will not complete a block +you can pass them here. This will also encrypt the ``ptlen'' bytes in ``pt'' and store them in ``ct''. It will also +store upto ``taglen'' bytes of the tag into ``tag''. + +Note that ``ptlen'' must be less than or equal to the block size of block cipher chosen. Also note that if you have +an input message equal to the length of the block size then you pass the data here (not to ocb\_encrypt()) only. + +To terminate a decrypt stream and compared the tag you call the following. + +\begin{verbatim} +int ocb_done_decrypt(ocb_state *ocb, + const unsigned char *ct, unsigned long ctlen, + unsigned char *pt, + const unsigned char *tag, unsigned long taglen, + int *res); +\end{verbatim} + +Similarly to the previous function you can pass trailing message bytes into this function. This will compute the +tag of the message (internally) and then compare it against the ``taglen'' bytes of ``tag'' provided. By default +``res'' is set to zero. If all ``taglen'' bytes of ``tag'' can be verified then ``res'' is set to one (authenticated +message). + +To make life simpler the following two functions are provided for memory bound OCB. + +\begin{verbatim} +int ocb_encrypt_authenticate_memory(int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, + const unsigned char *pt, unsigned long ptlen, + unsigned char *ct, + unsigned char *tag, unsigned long *taglen); +\end{verbatim} + +This will OCB encrypt the message ``pt'' of length ``ptlen'' and store the ciphertext in ``ct''. The length ``ptlen'' +can be any arbitrary length. + +\begin{verbatim} +int ocb_decrypt_verify_memory(int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, + const unsigned char *ct, unsigned long ctlen, + unsigned char *pt, + const unsigned char *tag, unsigned long taglen, + int *res); +\end{verbatim} + +Similarly this will OCB decrypt and compare the internally computed tag against the tag provided. ``res'' is set +appropriately. + + + +\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} +int 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} +int 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 in out[0..15] */ + 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 *); + int (*process)(hash_state *, const unsigned char *, unsigned long); + int (*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} + +The ``hash'' parameter is the location in the descriptor table of the hash (\textit{e.g. the return of find\_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 hash to the end of file and not reset +the file position when finished. + +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 WHIRLPOOL & whirlpool\_desc & 64 \\ + \hline SHA-512 & sha512\_desc & 64 \\ + \hline SHA-384 & sha384\_desc & 48 \\ + \hline SHA-256 & sha256\_desc & 32 \\ + \hline SHA-224 & sha224\_desc & 28 \\ + \hline TIGER-192 & tiger\_desc & 24 \\ + \hline SHA-1 & sha1\_desc & 20 \\ + \hline RIPEMD-160 & rmd160\_desc & 20 \\ + \hline RIPEMD-128 & rmd128\_desc & 16 \\ + \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 \textbf{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. + +\chapter{Message Authentication Codes} +\section{HMAC Protocol} +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 *hashOut, + unsigned long *outlen); +\end{verbatim} +``hmac'' is the HMAC state you are working with. ``hashOut'' is the array of octets where the HMAC code should be stored. You must +set ``outlen'' to the size of the destination buffer before calling this function. It is updated with the length of the HMAC code +produced (depending on which hash was picked). If ``outlen'' is less than the size of the message digest (and ultimately +the HMAC code) then the HMAC code is truncated as per FIPS-198 specifications (e.g. take the first ``outlen'' bytes). + +There are two utility functions provided to make using HMACs easier todo. They accept the key and information about the +message (file pointer, address in memory) and produce the HMAC result in one shot. These are useful if you want to avoid +calling the three step process yourself. + +\begin{verbatim} +int hmac_memory(int hash, const unsigned char *key, unsigned long keylen, + const unsigned char *data, unsigned long len, + unsigned char *dst, unsigned long *dstlen); +\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'' and the length in ``dstlen''. The value of ``dstlen'' must be set +to the size of the destination buffer before calling this function. 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, unsigned long *dstlen); +\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 of length ``keylen''. ``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]; + unsigned long dstlen; + + /* 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...) */ + dstlen = sizeof(dst); + if ((errno = hmac_done(&hmac, dst, &dstlen)) != CRYPT_OK) { + printf("Error finishing hmac: %s\n", error_to_string(errno)); + return -1; + } + printf("The hmac is %lu bytes long\n", dstlen); + + /* return */ + return 0; +} +\end{verbatim} +\end{small} + +\section{OMAC Support} +OMAC\footnote{\url{http://crypt.cis.ibaraki.ac.jp/omac/omac.html}}, which stands for \textit{One-Key CBC MAC} is an +algorithm which produces a Message Authentication Code (MAC) using only a block cipher such as AES. From an API +standpoint the OMAC routines work much like the HMAC routines do. Instead in this case a cipher is used instead of a hash. + +To start an OMAC state you call + +\begin{verbatim} +int omac_init(omac_state *omac, int cipher, + const unsigned char *key, unsigned long keylen); +\end{verbatim} +The ``omac'' variable is the state for the OMAC algorithm. ``cipher'' is the index into the cipher\_descriptor table +of the cipher\footnote{The cipher must have a 64 or 128 bit block size. Such as CAST5, Blowfish, DES, AES, Twofish, etc.} you +wish to use. ``key'' and ``keylen'' are the keys used to authenticate the data. + +To send data through the algorithm call +\begin{verbatim} +int omac_process(omac_state *state, + const unsigned char *buf, unsigned long len); +\end{verbatim} +This will send ``len'' bytes from ``buf'' through the active OMAC state ``state''. Returns \textbf{CRYPT\_OK} if the +function succeeds. The function is not sensitive to the granularity of the data. For example, + +\begin{verbatim} +omac_process(&mystate, "hello", 5); +omac_process(&mystate, " world", 6); +\end{verbatim} + +Would produce the same result as, + +\begin{verbatim} +omac_process(&mystate, "hello world", 11); +\end{verbatim} + +When you are done processing the message you can call the following to compute the message tag. + +\begin{verbatim} +int omac_done(omac_state *state, + unsigned char *out, unsigned long *outlen); +\end{verbatim} +Which will terminate the OMAC and output the \textit{tag} (MAC) to ``out''. Note that unlike the HMAC and other code +``outlen'' can be smaller than the default MAC size (for instance AES would make a 16-byte tag). Part of the OMAC +specification states that the output may be truncated. So if you pass in $outlen = 5$ and use AES as your cipher than +the output MAC code will only be five bytes long. If ``outlen'' is larger than the default size it is set to the default +size to show how many bytes were actually used. + +Similar to the HMAC code the file and memory functions are also provided. To OMAC a buffer of memory in one shot use the +following function. + +\begin{verbatim} +int omac_memory(int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *msg, unsigned long msglen, + unsigned char *out, unsigned long *outlen); +\end{verbatim} +This will compute the OMAC of ``msglen'' bytes of ``msg'' using the key ``key'' of length ``keylen'' bytes and the cipher +specified by the ``cipher'''th entry in the cipher\_descriptor table. It will store the MAC in ``out'' with the same +rules as omac\_done. + +To OMAC a file use +\begin{verbatim} +int omac_file(int cipher, + const unsigned char *key, unsigned long keylen, + const char *filename, + unsigned char *out, unsigned long *outlen); +\end{verbatim} + +Which will OMAC the entire contents of the file specified by ``filename'' using the key ``key'' of length ``keylen'' bytes +and the cipher specified by the ``cipher'''th entry in the cipher\_descriptor table. It will store the MAC in ``out'' with +the same rules as omac\_done. + +To test if the OMAC code is working there is the following function: +\begin{verbatim} +int omac_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 +OMAC system is given below. + +\begin{small} +\begin{verbatim} +#include +int main(void) +{ + int idx, err; + omac_state omac; + unsigned char key[16], dst[MAXBLOCKSIZE]; + unsigned long dstlen; + + /* register Rijndael */ + if (register_cipher(&rijndael_desc) == -1) { + printf("Error registering Rijndael\n"); + return -1; + } + + /* get index of Rijndael in cipher descriptor table */ + idx = find_cipher("rijndael"); + + /* we would make up our symmetric key in "key[]" here */ + + /* start the OMAC */ + if ((err = omac_init(&omac, idx, key, 16)) != CRYPT_OK) { + printf("Error setting up omac: %s\n", error_to_string(err)); + return -1; + } + + /* process a few octets */ + if((err = omac_process(&omac, "hello", 5) != CRYPT_OK) { + printf("Error processing omac: %s\n", error_to_string(err)); + return -1; + } + + /* get result (presumably to use it somehow...) */ + dstlen = sizeof(dst); + if ((err = omac_done(&omac, dst, &dstlen)) != CRYPT_OK) { + printf("Error finishing omac: %s\n", error_to_string(err)); + return -1; + } + printf("The omac is %lu bytes long\n", dstlen); + + /* return */ + return 0; +} +\end{verbatim} +\end{small} + +\section{PMAC Support} +The PMAC\footnote{J.Black, P.Rogaway, ``A Block--Cipher Mode of Operation for Parallelizable Message Authentication''} +protocol is another MAC algorithm that relies solely on a symmetric-key block cipher. It uses essentially the same +API as the provided OMAC code. + +A PMAC state is initialized with the following. + +\begin{verbatim} +int pmac_init(pmac_state *pmac, int cipher, + const unsigned char *key, unsigned long keylen); +\end{verbatim} +Which initializes the ``pmac'' state with the given ``cipher'' and ``key'' of length ``keylen'' bytes. The chosen cipher +must have a 64 or 128 bit block size (e.x. AES). + +To MAC data simply send it through the process function. + +\begin{verbatim} +int pmac_process(pmac_state *state, + const unsigned char *buf, unsigned long len); +\end{verbatim} +This will process ``len'' bytes of ``buf'' in the given ``state''. The function is not sensitive to the granularity of the +data. For example, + +\begin{verbatim} +pmac_process(&mystate, "hello", 5); +pmac_process(&mystate, " world", 6); +\end{verbatim} + +Would produce the same result as, + +\begin{verbatim} +pmac_process(&mystate, "hello world", 11); +\end{verbatim} + +When a complete message has been processed the following function can be called to compute the message tag. + +\begin{verbatim} +int pmac_done(pmac_state *state, + unsigned char *out, unsigned long *outlen); +\end{verbatim} +This will store upto ``outlen'' bytes of the tag for the given ``state'' into ``out''. Note that if ``outlen'' is larger +than the size of the tag it is set to the amount of bytes stored in ``out''. + +Similar to the PMAC code the file and memory functions are also provided. To PMAC a buffer of memory in one shot use the +following function. + +\begin{verbatim} +int pmac_memory(int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *msg, unsigned long msglen, + unsigned char *out, unsigned long *outlen); +\end{verbatim} +This will compute the PMAC of ``msglen'' bytes of ``msg'' using the key ``key'' of length ``keylen'' bytes and the cipher +specified by the ``cipher'''th entry in the cipher\_descriptor table. It will store the MAC in ``out'' with the same +rules as omac\_done. + +To PMAC a file use +\begin{verbatim} +int pmac_file(int cipher, + const unsigned char *key, unsigned long keylen, + const char *filename, + unsigned char *out, unsigned long *outlen); +\end{verbatim} + +Which will PMAC the entire contents of the file specified by ``filename'' using the key ``key'' of length ``keylen'' bytes +and the cipher specified by the ``cipher'''th entry in the cipher\_descriptor table. It will store the MAC in ``out'' with +the same rules as omac\_done. + +To test if the PMAC code is working there is the following function: +\begin{verbatim} +int pmac_test(void); +\end{verbatim} +Which returns {\bf CRYPT\_OK} if the code passes otherwise it returns an error code. + + +\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 err; + + /* start it */ + if ((err = yarrow_start(&prng)) != CRYPT_OK) { + printf("Start error: %s\n", error_to_string(err)); + } + /* add entropy */ + if ((err = yarrow_add_entropy("hello world", 11, &prng)) != CRYPT_OK) { + printf("Add_entropy error: %s\n", error_to_string(err)); + } + /* ready and read */ + if ((err = yarrow_ready(&prng)) != CRYPT_OK) { + printf("Ready error: %s\n", error_to_string(err)); + } + 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 err; + + if ((err = rc4_start(&prng)) != CRYPT_OK) { + printf("RC4 init error: %s\n", error_to_string(err)); + exit(-1); + } + + /* use ``key'' as the key */ + if ((err = rc4_add_entropy("key", 3, &prng)) != CRYPT_OK) { + printf("RC4 add entropy error: %s\n", error_to_string(err)); + exit(-1); + } + + /* setup RC4 for use */ + if ((err = rc4_ready(&prng)) != CRYPT_OK) { + printf("RC4 ready error: %s\n", error_to_string(err)); + 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 err; + + /* register yarrow */ + if (register_prng(&yarrow_desc) == -1) { + printf("Error registering Yarrow\n"); + return -1; + } + + /* setup the PRNG */ + if ((err = rng_make_prng(128, find_prng("yarrow"), &prng, NULL)) != CRYPT_OK) { + printf("Error setting up PRNG, %s\n", error_to_string(err)); + return -1; + } + + /* make a 192-bit ECC key */ + if ((err = ecc_make_key(&prng, find_prng("yarrow"), 24, &mykey)) != CRYPT_OK) { + printf("Error making key: %s\n", error_to_string(err)); + 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 err; + + /* register SPRNG */ + if (register_prng(&sprng_desc) == -1) { + printf("Error registering SPRNG\n"); + return -1; + } + + /* make a 192-bit ECC key */ + if ((err = ecc_make_key(NULL, find_prng("sprng"), 24, &mykey)) != CRYPT_OK) { + printf("Error making key: %s\n", error_to_string(err)); + return -1; + } + return 0; +} +\end{verbatim} +\end{small} + +\chapter{RSA Public Key Cryptography} +\textbf{Note: } \textit{This chapter on PKCS \#1 RSA will replace the older chapter on RSA (The current chapter nine) in subsequent +releases of the library. Users are encouraged to stop using the LibTomCrypt style padding functions.} + +\section{PKCS \#1 Encryption} + +PKCS \#1 RSA Encryption amounts to OAEP padding of the input message followed by the modular exponentiation. As far as this portion of +the library is concerned we are only dealing with th OAEP padding of the message. + +\subsection{OAEP Encoding} + +\begin{alltt} +int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, + const unsigned char *lparam, unsigned long lparamlen, + unsigned long modulus_bitlen, int hash_idx, + int prng_idx, prng_state *prng, + unsigned char *out, unsigned long *outlen); +\end{alltt} + +This accepts ``msg'' as input of length ``msglen'' which will be OAEP padded. The ``lparam'' variable is an additional system specific +tag that can be applied to the encoding. This is useful to identify which system encoded the message. If no variance is desired then +``lparam'' can be set to \textbf{NULL}. + +OAEP encoding requires the length of the modulus in bits in order to calculate the size of the output. This is passed as the parameter +``modulus\_bitlen''. ``hash\_idx'' is the index into the hash descriptor table of the hash desired. PKCS \#1 allows any hash to be +used but both the encoder and decoder must use the same hash in order for this to succeed. The size of hash output affects the maximum + sized input message. ``prng\_idx'' and ``prng'' are the random number generator arguments required to randomize the padding process. +The padded message is stored in ``out'' along with the length in ``outlen''. + +If $h$ is the length of the hash and $m$ the length of the modulus (both in octets) then the maximum payload for ``msg'' is +$m - 2h - 2$. For example, with a $1024$--bit RSA key and SHA--1 as the hash the maximum payload is $86$ bytes. + +Note that when the message is padded it still has not been RSA encrypted. You must pass the output of this function to +rsa\_exptmod() to encrypt it. + +\subsection{OAEP Decoding} + +\begin{alltt} +int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, + const unsigned char *lparam, unsigned long lparamlen, + unsigned long modulus_bitlen, int hash_idx, + unsigned char *out, unsigned long *outlen); +\end{alltt} + +This function decodes an OAEP encoded message and outputs the original message that was passed to the OAEP encoder. ``msg'' is the +output of pkcs\_1\_oaep\_encode() of length ``msglen''. ``lparam'' is the same system variable passed to the OAEP encoder. If it does not +match what was used during encoding this function will not decode the packet. ``modulus\_bitlen'' is the size of the RSA modulus in bits +and must match what was used during encoding. Similarly the ``hash\_idx'' index into the hash descriptor table must match what was used +during encoding. + +If the function succeeds it decodes the OAEP encoded message into ``out'' of length ``outlen''. + +\section{PKCS \#1 Digital Signatures} + +\subsection{PSS Encoding} +PSS encoding is the second half of the PKCS \#1 standard which is padding to be applied to messages that are signed. + +\begin{alltt} +int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, + unsigned long saltlen, int hash_idx, + int prng_idx, prng_state *prng, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen); +\end{alltt} + +This function assumes the message to be PSS encoded has previously been hashed. The input hash ``msghash'' is of length +``msghashlen''. PSS allows a variable length random salt (it can be zero length) to be introduced in the signature process. +``hash\_idx'' is the index into the hash descriptor table of the hash to use. ``prng\_idx'' and ``prng'' are the random +number generator information required for the salt. + +Similar to OAEP encoding ``modulus\_bitlen'' is the size of the RSA modulus. It limits the size of the salt. If $m$ is the length +of the modulus $h$ the length of the hash output (in octets) then there can be $m - h - 2$ bytes of salt. + +This function does not actually sign the data it merely pads the hash of a message so that it can be processed by rsa\_exptmod(). + +\subsection{PSS Decoding} + +To decode a PSS encoded signature block you have to use the following. + +\begin{alltt} +int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, + const unsigned char *sig, unsigned long siglen, + unsigned long saltlen, int hash_idx, + unsigned long modulus_bitlen, int *res); +\end{alltt} +This will decode the PSS encoded message in ``sig'' of length ``siglen'' and compare it to values in ``msghash'' of length +``msghashlen''. If the block is a valid PSS block and the decoded hash equals the hash supplied ``res'' is set to non--zero. Otherwise, +it is set to zero. The rest of the parameters are as in the PSS encode call. + +It's important to use the same ``saltlen'' and hash for both encoding and decoding as otherwise the procedure will not work. + +\chapter{Password Based Cryptography} +\section{PKCS \#5} +In order to securely handle user passwords for the purposes of creating session keys and chaining IVs the PKCS \#5 was drafted. PKCS \#5 +is made up of two algorithms, Algorithm One and Algorithm Two. Algorithm One is the older fairly limited algorithm which has been implemented +for completeness. Algorithm Two is a bit more modern and more flexible to work with. + +\section{Algorithm One} +Algorithm One accepts as input a password, an 8--byte salt and an iteration counter. The iteration counter is meant to act as delay for +people trying to brute force guess the password. The higher the iteration counter the longer the delay. This algorithm also requires a hash +algorithm and produces an output no longer than the output of the hash. + +\begin{alltt} +int pkcs_5_alg1(const unsigned char *password, unsigned long password_len, + const unsigned char *salt, + int iteration_count, int hash_idx, + unsigned char *out, unsigned long *outlen) +\end{alltt} +Where ``password'' is the users password. Since the algorithm allows binary passwords you must also specify the length in ``password\_len''. +The ``salt'' is a fixed size 8--byte array which should be random for each user and session. The ``iteration\_count'' is the delay desired +on the password. The ``hash\_idx'' is the index of the hash you wish to use in the descriptor table. + +The output of length upto ``outlen'' is stored in ``out''. If ``outlen'' is initially larger than the size of the hash functions output +it is set to the number of bytes stored. If it is smaller than not all of the hash output is stored in ``out''. + +\section{Algorithm Two} + +Algorithm Two is the recommended algorithm for this task. It allows variable length salts and can produce outputs larger than the +hash functions output. As such it can easily be used to derive session keys for ciphers and MACs as well initial vectors as required +from a single password and invokation of this algorithm. + +\begin{alltt} +int pkcs_5_alg2(const unsigned char *password, unsigned long password_len, + const unsigned char *salt, unsigned long salt_len, + int iteration_count, int hash_idx, + unsigned char *out, unsigned long *outlen) +\end{alltt} +Where ``password'' is the users password. Since the algorithm allows binary passwords you must also specify the length in ``password\_len''. +The ``salt'' is an array of size ``salt\_len''. It should be random for each user and session. The ``iteration\_count'' is the delay desired +on the password. The ``hash\_idx'' is the index of the hash you wish to use in the descriptor table. The output of length upto +``outlen'' is stored in ``out''. + +\begin{alltt} +/* demo to show how to make session state material from a password */ +#include +int main(void) +\{ + unsigned char password[100], salt[100], + cipher_key[16], cipher_iv[16], + mac_key[16], outbuf[48]; + int err, hash_idx; + unsigned long outlen, password_len, salt_len; + + /* register hash and get it's idx .... */ + + /* get users password and make up a salt ... */ + + /* create the material (100 iterations in algorithm) */ + outlen = sizeof(outbuf); + if ((err = pkcs_5_alg2(password, password_len, salt, salt_len, + 100, hash_idx, outbuf, &outlen)) != CRYPT_OK) \{ + /* error handle */ + \} + + /* now extract it */ + memcpy(cipher_key, outbuf, 16); + memcpy(cipher_iv, outbuf+16, 16); + memcpy(mac_key, outbuf+32, 16); + + /* use material (recall to store the salt in the output) */ +\} +\end{alltt} + +\chapter{RSA Routines} + +\textbf{Note: } \textit{This chapter has been marked for removal. In particular any function that uses the LibTomCrypt style +RSA padding (e.g. rsa\_pad() rsa\_signpad()) will be removed in the v0.96 release cycle. The functions like rsa\_make\_key() and +rsa\_exptmod() will stay but may be slightly modified. } + +\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 (\textit{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 in the format PKCS specifies, 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). + +Note that this function does not perform padding on the input (as per PKCS). So if you send in ``0000001'' you will +get ``01'' back (when you do the opposite operation). Make sure you pad properly which usually involves setting the msb to +a non-zero value. + +\section{Packet Routines} +To encrypt or decrypt a symmetric key using RSA the following functions are provided. The idea is that you make up +a random symmetric key and use that to encode your message. By RSA encrypting the symmetric key you can send it to a +recipient who can RSA decrypt it and symmetrically decrypt the message. +\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); +\end{verbatim} +This function is used to RSA encrypt a symmetric to share with another user. The symmetric key and its length are +passed as ``inkey'' and ``inlen'' respectively. The symmetric key is limited to a range of 8 to 32 bytes +(\textit{64 to 256 bits}). The RSA encrypted packet is stored in ``outkey'' and will be of length ``outlen'' bytes. The +value of ``outlen'' must be originally set to the size of the output buffer. + +\begin{verbatim} +int rsa_decrypt_key(const unsigned char *in, unsigned long inlen, + unsigned char *outkey, unsigned long *keylen, + rsa_key *key); +\end{verbatim} + +This function will decrypt an RSA packet to retrieve the original symmetric key encrypted with rsa\_encrypt\_key(). +Similarly to sign or verify a hash of a message the following two messages are provided. The idea is to hash your message +then use these functions to RSA sign the hash. +\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, unsigned long siglen, + const unsigned char *hash, int *stat, rsa_key *key); +\end{verbatim} +For ``rsa\_sign\_hash'' the input is intended to be the hash of a message the user wants to sign. The output is the +RSA signed packet which ``rsa\_verify\_hash'' can verify. For the verification function ``sig'' is the RSA signature +and ``hash'' is the hash of the message. The integer ``stat'' is set to non-zero if the signature is valid or zero +otherwise. + +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, unsigned long inlen, 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. This means to encrypt or sign +a message of N bytes 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 the +internal RSA routines directly 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. 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. Or to be simple just make 2048-bit or larger +keys. None of the hashes will have problems with such key sizes. + +\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 96 to 512 bytes which correspond +to key sizes of 768 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 768 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. + +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, unsigned long inlen, 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, err, inlen; + dh_key mykey, theirkey; + + /* make up our private key */ + if ((err = dh_make_key(prng, wprng, 128, &mykey)) != CRYPT_OK) { + return err; + } + + /* export our key as public */ + x = sizeof(buf); + if ((err = dh_export(buf, &x, PK_PUBLIC, &mykey)) != CRYPT_OK) { + res = err; + 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 ((inlen = recv(sock, buf2, sizeof(buf2), 0)) <= 0) { + res = CRYPT_ERROR; + goto done2; + } + } else { + /* mode >0 so we send second */ + if ((inlen = 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 ((err = dh_import(buf2, inlen, &theirkey)) != CRYPT_OK) { + res = err; + goto done2; + } + + /* make shared secret */ + x = sizeof(buf); + if ((err = dh_shared_secret(&mykey, &theirkey, buf, &x)) != CRYPT_OK) { + res = err; + goto done; + } + + /* hash it */ + len = 16; /* default is MD5 so "key" must be at least 16 bytes long */ + if ((err = hash_memory(find_hash("md5"), buf, x, key, &len)) != CRYPT_OK) { + res = err; + 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} +Similar to the RSA related functions there are functions to encrypt or decrypt symmetric keys using the DH public key +algorithms. +\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 long inlen, + 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. + +Similar to the RSA system you can sign and verify a hash of a message. +\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, unsigned long siglen, + const unsigned char *hash, unsigned long hashlen, + int *stat, dh_key *key); +\end{verbatim} + +The ``dh\_sign\_hash'' function signs the message hash in ``in'' of length ``inlen'' and forms a DH packet in ``out''. +The ``dh\_verify\_hash'' function verifies the DH signature in ``sig'' against the hash in ``hash''. It sets ``stat'' +to non-zero if the signature passes or zero if it fails. + +\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, unsigned long inlen, 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} +Similar to the RSA API there are two functions which encrypt and decrypt symmetric keys using the ECC public key +algorithms. +\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 long inlen, + unsigned char *outkey, unsigned long *keylen, + ecc_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 ``ecc\_encrypt\_key()''. The hash chosen must produce a message digest at least as large +as the symmetric key you are trying to share. + +There are also functions to sign and verify the hash of a message. +\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, unsigned long siglen, + const unsigned char *hash, unsigned long hashlen, + int *stat, ecc_key *key); +\end{verbatim} + +The ``ecc\_sign\_hash'' function signs the message hash in ``in'' of length ``inlen'' and forms a ECC packet in ``out''. +The ``ecc\_verify\_hash'' function verifies the ECC signature in ``sig'' against the hash in ``hash''. It sets ``stat'' +to non-zero if the signature passes or zero if it fails. + + +\section{ECC Keysizes} +With ECC if you try and sign a hash that is bigger than your ECC key you can run into problems. The math will still work +and in effect the signature will still work. With ECC keys the strength of the signature is limited by the size of +the hash or the size of they key, whichever is smaller. For example, if you sign with SHA256 and a ECC-160 key in effect +you have 160-bits of security (e.g. as if you signed with SHA-1). + +The library will not warn you if you make this mistake so it is important to check yourself before using the +signatures. + +\chapter{Digital Signature Algorithm} +\section{Introduction} +The Digital Signature Algorithm (or DSA) is a variant of the ElGamal Signature scheme which has been modified to +reduce the bandwidth of a signature. For example, to have ``80-bits of security'' with ElGamal you need a group of +order at least 1024-bits. With DSA you need a group of order at least 160-bits. By comparison the ElGamal signature +would require at least 256 bytes where as the DSA signature would require only at least 40 bytes. + +The API for the DSA is essentially the same as the other PK algorithms. Except in the case of DSA no encryption or +decryption routines are provided. + +\section{Key Generation} +To make a DSA key you must call the following function +\begin{verbatim} +int dsa_make_key(prng_state *prng, int wprng, + int group_size, int modulus_size, + dsa_key *key); +\end{verbatim} +The variable ``prng'' is an active PRNG state and ``wprng'' the index to the descriptor. ``group\_size'' and +``modulus\_size'' control the difficulty of forging a signature. Both parameters are in bytes. The larger the +``group\_size'' the more difficult a forgery becomes upto a limit. The value of $group\_size$ is limited by +$15 < group\_size < 1024$ and $modulus\_size - group\_size < 512$. Suggested values for the pairs are as follows. + +\begin{center} +\begin{tabular}{|c|c|c|} +\hline \textbf{Bits of Security} & \textbf{group\_size} & \textbf{modulus\_size} \\ +\hline 80 & 20 & 128 \\ +\hline 120 & 30 & 256 \\ +\hline 140 & 35 & 384 \\ +\hline 160 & 40 & 512 \\ +\hline +\end{tabular} +\end{center} + +When you are finished with a DSA key you can call the following function to free the memory used. +\begin{verbatim} +void dsa_free(dsa_key *key); +\end{verbatim} + +\section{Key Verification} +Each DSA key is composed of the following variables. + +\begin{enumerate} + \item $q$ a small prime of magnitude $256^{group\_size}$. + \item $p = qr + 1$ a large prime of magnitude $256^{modulus\_size}$ where $r$ is a random even integer. + \item $g = h^r \mbox{ (mod }p\mbox{)}$ a generator of order $q$ modulo $p$. $h$ can be any non-trivial random + value. For this library they start at $h = 2$ and step until $g$ is not $1$. + \item $x$ a random secret (the secret key) in the range $1 < x < q$ + \item $y = g^x \mbox{ (mod }p\mbox{)}$ the public key. +\end{enumerate} + +A DSA key is considered valid if it passes all of the following tests. + +\begin{enumerate} + \item $q$ must be prime. + \item $p$ must be prime. + \item $g$ cannot be one of $\lbrace -1, 0, 1 \rbrace$ (modulo $p$). + \item $g$ must be less than $p$. + \item $(p-1) \equiv 0 \mbox{ (mod }q\mbox{)}$. + \item $g^q \equiv 1 \mbox{ (mod }p\mbox{)}$. + \item $1 < y < p - 1$ + \item $y^q \equiv 1 \mbox{ (mod }p\mbox{)}$. +\end{enumerate} + +Tests one and two ensure that the values will at least form a field which is required for the signatures to +function. Tests three and four ensure that the generator $g$ is not set to a trivial value which would make signature +forgery easier. Test five ensures that $q$ divides the order of multiplicative sub-group of $\Z/p\Z$. Test six +ensures that the generator actually generates a prime order group. Tests seven and eight ensure that the public key +is within range and belongs to a group of prime order. Note that test eight does not prove that $g$ generated $y$ only +that $y$ belongs to a multiplicative sub-group of order $q$. + +The following function will perform these tests. + +\begin{verbatim} +int dsa_verify_key(dsa_key *key, int *stat); +\end{verbatim} + +This will test ``key'' and store the result in ``stat''. If the result is $stat = 0$ the DSA key failed one of the tests +and should not be used at all. If the result is $stat = 1$ the DSA key is valid (as far as valid mathematics are concerned). + + + +\section{Signatures} +To generate a DSA signature call the following function + +\begin{verbatim} +int dsa_sign_hash(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, dsa_key *key); +\end{verbatim} + +Which will sign the data in ``in'' of length ``inlen'' bytes. The signature is stored in ``out'' and the size +of the signature in ``outlen''. If the signature is longer than the size you initially specify in ``outlen'' nothing +is stored and the function returns an error code. The DSA ``key'' must be of the \textbf{PK\_PRIVATE} persuasion. + +To verify a hash created with that function use the following function + +\begin{verbatim} +int dsa_verify_hash(const unsigned char *sig, unsigned long siglen, + const unsigned char *hash, unsigned long inlen, + int *stat, dsa_key *key); +\end{verbatim} +Which will verify the data in ``hash'' of length ``inlen'' against the signature stored in ``sig'' of length ``siglen''. +It will set ``stat'' to $1$ if the signature is valid, otherwise it sets ``stat'' to $0$. + +\section{Import and Export} + +To export a DSA key so that it can be transported use the following function +\begin{verbatim} +int dsa_export(unsigned char *out, unsigned long *outlen, + int type, + dsa_key *key); +\end{verbatim} +This will export the DSA ``key'' to the buffer ``out'' and set the length in ``outlen'' (which must have been previously +initialized to the maximum buffer size). The ``type`` variable may be either \textbf{PK\_PRIVATE} or \textbf{PK\_PUBLIC} +depending on whether you want to export a private or public copy of the DSA key. + +To import an exported DSA key use the following function + +\begin{verbatim} +int dsa_import(const unsigned char *in, unsigned long inlen, + dsa_key *key); +\end{verbatim} + +This will import the DSA key from the buffer ``in'' of length ``inlen'' to the ``key''. If the process fails the function +will automatically free all of the heap allocated in the process (you don't have to call dsa\_free()). + +\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 err; + + /* make a new list */ + if ((err = kr_init(&kr)) != CRYPT_OK) { + printf("kr_init: %s\n", error_to_string(err)); + exit(-1); + } + + /* add a key to it */ + register_prng(&sprng_desc); + if ((err = 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(err)); + exit(-1); + } + + /* export the first key */ + len = sizeof(buf); + if ((err = kr_export(kr, kr->ID, PK_PRIVATE, buf, &len)) != CRYPT_OK) { + printf("kr_export: %s\n", error_to_string(err)); + 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 LibTomMath which is a multiple precision integer library written by the +author of LibTomCrypt. LibTomMath is a trivial to use ANSI C compatible large integer library which is free +for all uses and is distributed freely. + +At the heart of all the functions is the data type ``mp\_int'' (defined in tommath.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 +LibTomMath 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} + +The functions also 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} + +\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.). LibTomMath 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 eight 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 )^{8} = 2^{-16}$. In practice the probability of error is in fact much lower than that. + +When making random primes the trial division step is in fact an optimized implementation of ``Implementation of Fast RSA Key Generation on Smart Cards''\footnote{Chenghuai Lu, Andre L. M. dos Santos and Francisco R. Pimentel}. +In essence a table of machine-word sized residues are kept of a candidate modulo a set of primes. When the candiate +is rejected and ultimately incremented to test the next number the residues are updated without using multi-word precision +math operations. As a result the routine can scan ahead to the next number required for testing with very little work +involved. + +In the event that 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 LibTomMath library 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 256$). 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 Configure Script} +There are also options you can specify from the configure script or ``mycrypt\_config.h''. + +\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{SMALL\_CODE} +When this is defined some of the code such as the Rijndael and SAFER+ ciphers are replaced with smaller code variants. +These variants are slower but can save quite a bit of code space. + +\end{document} diff --git a/crypt_argchk.c b/crypt_argchk.c new file mode 100644 index 0000000..3bb73a0 --- /dev/null +++ b/crypt_argchk.c @@ -0,0 +1,21 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" +#include + +#if (ARGTYPE == 0) +void crypt_argchk(char *v, char *s, int d) +{ + fprintf(stderr, "_ARGCHK '%s' failure on line %d of file %s\n", + v, d, s); + (void)raise(SIGABRT); +} +#endif diff --git a/crypt_cipher_descriptor.c b/crypt_cipher_descriptor.c new file mode 100644 index 0000000..d103ea0 --- /dev/null +++ b/crypt_cipher_descriptor.c @@ -0,0 +1,18 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +struct _cipher_descriptor cipher_descriptor[TAB_SIZE] = { +{ 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 } }; + diff --git a/crypt_cipher_is_valid.c b/crypt_cipher_is_valid.c new file mode 100644 index 0000000..8b0c448 --- /dev/null +++ b/crypt_cipher_is_valid.c @@ -0,0 +1,19 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int cipher_is_valid(int idx) +{ + if (idx < 0 || idx >= TAB_SIZE || cipher_descriptor[idx].name == NULL) { + return CRYPT_INVALID_CIPHER; + } + return CRYPT_OK; +} diff --git a/crypt_find_cipher.c b/crypt_find_cipher.c new file mode 100644 index 0000000..0aa88c7 --- /dev/null +++ b/crypt_find_cipher.c @@ -0,0 +1,24 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int find_cipher(const char *name) +{ + int x; + _ARGCHK(name != NULL); + for (x = 0; x < TAB_SIZE; x++) { + if (cipher_descriptor[x].name != NULL && !strcmp(cipher_descriptor[x].name, name)) { + return x; + } + } + return -1; +} + diff --git a/crypt_find_cipher_any.c b/crypt_find_cipher_any.c new file mode 100644 index 0000000..81c33be --- /dev/null +++ b/crypt_find_cipher_any.c @@ -0,0 +1,32 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +/* 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; x < TAB_SIZE; x++) { + if (cipher_descriptor[x].name == NULL) { + continue; + } + if (blocklen <= (int)cipher_descriptor[x].block_length && keylen <= (int)cipher_descriptor[x].max_key_length) { + return x; + } + } + return -1; +} diff --git a/crypt_find_cipher_id.c b/crypt_find_cipher_id.c new file mode 100644 index 0000000..91b19d5 --- /dev/null +++ b/crypt_find_cipher_id.c @@ -0,0 +1,22 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int find_cipher_id(unsigned char ID) +{ + int x; + for (x = 0; x < TAB_SIZE; x++) { + if (cipher_descriptor[x].ID == ID) { + return (cipher_descriptor[x].name == NULL) ? -1 : x; + } + } + return -1; +} diff --git a/crypt_find_hash.c b/crypt_find_hash.c new file mode 100644 index 0000000..1422233 --- /dev/null +++ b/crypt_find_hash.c @@ -0,0 +1,23 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int find_hash(const char *name) +{ + int x; + _ARGCHK(name != NULL); + for (x = 0; x < TAB_SIZE; x++) { + if (hash_descriptor[x].name != NULL && strcmp(hash_descriptor[x].name, name) == 0) { + return x; + } + } + return -1; +} diff --git a/crypt_find_hash_any.c b/crypt_find_hash_any.c new file mode 100644 index 0000000..5b35252 --- /dev/null +++ b/crypt_find_hash_any.c @@ -0,0 +1,34 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +/* return first hash with at least [amount over] digestlen bytes of output */ +int find_hash_any(const char *name, int digestlen) +{ + int x, y, z; + _ARGCHK(name != NULL); + + x = find_hash(name); + if (x != -1) return x; + + y = MAXBLOCKSIZE+1; + z = -1; + for (x = 0; x < TAB_SIZE; x++) { + if (hash_descriptor[x].name == NULL) { + continue; + } + if ((int)hash_descriptor[x].hashsize >= digestlen && (int)hash_descriptor[x].hashsize < y) { + z = x; + y = hash_descriptor[x].hashsize; + } + } + return z; +} diff --git a/crypt_find_hash_id.c b/crypt_find_hash_id.c new file mode 100644 index 0000000..ff04aea --- /dev/null +++ b/crypt_find_hash_id.c @@ -0,0 +1,22 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int find_hash_id(unsigned char ID) +{ + int x; + for (x = 0; x < TAB_SIZE; x++) { + if (hash_descriptor[x].ID == ID) { + return (hash_descriptor[x].name == NULL) ? -1 : x; + } + } + return -1; +} diff --git a/crypt_find_prng.c b/crypt_find_prng.c new file mode 100644 index 0000000..7fc4e45 --- /dev/null +++ b/crypt_find_prng.c @@ -0,0 +1,24 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int find_prng(const char *name) +{ + int x; + _ARGCHK(name != NULL); + for (x = 0; x < TAB_SIZE; x++) { + if ((prng_descriptor[x].name != NULL) && strcmp(prng_descriptor[x].name, name) == 0) { + return x; + } + } + return -1; +} + diff --git a/crypt_hash_descriptor.c b/crypt_hash_descriptor.c new file mode 100644 index 0000000..5234863 --- /dev/null +++ b/crypt_hash_descriptor.c @@ -0,0 +1,17 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +struct _hash_descriptor hash_descriptor[TAB_SIZE] = { +{ 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 } }; diff --git a/crypt_hash_is_valid.c b/crypt_hash_is_valid.c new file mode 100644 index 0000000..b924e59 --- /dev/null +++ b/crypt_hash_is_valid.c @@ -0,0 +1,19 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int hash_is_valid(int idx) +{ + if (idx < 0 || idx >= TAB_SIZE || hash_descriptor[idx].name == NULL) { + return CRYPT_INVALID_HASH; + } + return CRYPT_OK; +} diff --git a/crypt_prng_descriptor.c b/crypt_prng_descriptor.c new file mode 100644 index 0000000..85f3ead --- /dev/null +++ b/crypt_prng_descriptor.c @@ -0,0 +1,18 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +struct _prng_descriptor prng_descriptor[TAB_SIZE] = { +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL }, +{ NULL, NULL, NULL, NULL, NULL } }; + diff --git a/crypt_prng_is_valid.c b/crypt_prng_is_valid.c new file mode 100644 index 0000000..cc66bc2 --- /dev/null +++ b/crypt_prng_is_valid.c @@ -0,0 +1,19 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int prng_is_valid(int idx) +{ + if (idx < 0 || idx >= TAB_SIZE || prng_descriptor[idx].name == NULL) { + return CRYPT_INVALID_PRNG; + } + return CRYPT_OK; +} diff --git a/crypt_register_cipher.c b/crypt_register_cipher.c new file mode 100644 index 0000000..5fb0dcb --- /dev/null +++ b/crypt_register_cipher.c @@ -0,0 +1,36 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int register_cipher(const struct _cipher_descriptor *cipher) +{ + int x; + + _ARGCHK(cipher != NULL); + + /* is it already registered? */ + for (x = 0; x < TAB_SIZE; x++) { + if (cipher_descriptor[x].name != NULL && cipher_descriptor[x].ID == cipher->ID) { + return x; + } + } + + /* find a blank spot */ + for (x = 0; x < TAB_SIZE; x++) { + if (cipher_descriptor[x].name == NULL) { + memcpy(&cipher_descriptor[x], cipher, sizeof(struct _cipher_descriptor)); + return x; + } + } + + /* no spot */ + return -1; +} diff --git a/crypt_register_hash.c b/crypt_register_hash.c new file mode 100644 index 0000000..7603693 --- /dev/null +++ b/crypt_register_hash.c @@ -0,0 +1,36 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int register_hash(const struct _hash_descriptor *hash) +{ + int x; + + _ARGCHK(hash != NULL); + + /* is it already registered? */ + for (x = 0; x < TAB_SIZE; x++) { + if (memcmp(&hash_descriptor[x], hash, sizeof(struct _hash_descriptor)) == 0) { + return x; + } + } + + /* find a blank spot */ + for (x = 0; x < TAB_SIZE; x++) { + if (hash_descriptor[x].name == NULL) { + memcpy(&hash_descriptor[x], hash, sizeof(struct _hash_descriptor)); + return x; + } + } + + /* no spot */ + return -1; +} diff --git a/crypt_register_prng.c b/crypt_register_prng.c new file mode 100644 index 0000000..1b14a33 --- /dev/null +++ b/crypt_register_prng.c @@ -0,0 +1,36 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int register_prng(const struct _prng_descriptor *prng) +{ + int x; + + _ARGCHK(prng != NULL); + + /* is it already registered? */ + for (x = 0; x < TAB_SIZE; x++) { + if (memcmp(&prng_descriptor[x], prng, sizeof(struct _prng_descriptor)) == 0) { + return x; + } + } + + /* find a blank spot */ + for (x = 0; x < TAB_SIZE; x++) { + if (prng_descriptor[x].name == NULL) { + memcpy(&prng_descriptor[x], prng, sizeof(struct _prng_descriptor)); + return x; + } + } + + /* no spot */ + return -1; +} diff --git a/crypt_unregister_cipher.c b/crypt_unregister_cipher.c new file mode 100644 index 0000000..6321daf --- /dev/null +++ b/crypt_unregister_cipher.c @@ -0,0 +1,28 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int unregister_cipher(const struct _cipher_descriptor *cipher) +{ + int x; + + _ARGCHK(cipher != NULL); + + /* is it already registered? */ + for (x = 0; x < TAB_SIZE; x++) { + if (memcmp(&cipher_descriptor[x], cipher, sizeof(struct _cipher_descriptor)) == 0) { + cipher_descriptor[x].name = NULL; + cipher_descriptor[x].ID = 255; + return CRYPT_OK; + } + } + return CRYPT_ERROR; +} diff --git a/crypt_unregister_hash.c b/crypt_unregister_hash.c new file mode 100644 index 0000000..fcdca5f --- /dev/null +++ b/crypt_unregister_hash.c @@ -0,0 +1,27 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int unregister_hash(const struct _hash_descriptor *hash) +{ + int x; + + _ARGCHK(hash != NULL); + + /* is it already registered? */ + for (x = 0; x < TAB_SIZE; x++) { + if (memcmp(&hash_descriptor[x], hash, sizeof(struct _hash_descriptor)) == 0) { + hash_descriptor[x].name = NULL; + return CRYPT_OK; + } + } + return CRYPT_ERROR; +} diff --git a/crypt_unregister_prng.c b/crypt_unregister_prng.c new file mode 100644 index 0000000..c315338 --- /dev/null +++ b/crypt_unregister_prng.c @@ -0,0 +1,27 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int unregister_prng(const struct _prng_descriptor *prng) +{ + int x; + + _ARGCHK(prng != NULL); + + /* is it already registered? */ + for (x = 0; x < TAB_SIZE; x++) { + if (memcmp(&prng_descriptor[x], prng, sizeof(struct _prng_descriptor)) != 0) { + prng_descriptor[x].name = NULL; + return CRYPT_OK; + } + } + return CRYPT_ERROR; +} diff --git a/ctr_decrypt.c b/ctr_decrypt.c new file mode 100644 index 0000000..dce3a39 --- /dev/null +++ b/ctr_decrypt.c @@ -0,0 +1,25 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef CTR + +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/ctr_encrypt.c b/ctr_encrypt.c new file mode 100644 index 0000000..476de38 --- /dev/null +++ b/ctr_encrypt.c @@ -0,0 +1,64 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef CTR + +int ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CTR *ctr) +{ + int x, err; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(ctr != NULL); + + if ((err = cipher_is_valid(ctr->cipher)) != CRYPT_OK) { + return err; + } + + /* is blocklen/padlen valid? */ + if (ctr->blocklen < 0 || ctr->blocklen > (int)sizeof(ctr->ctr) || + ctr->padlen < 0 || ctr->padlen > (int)sizeof(ctr->pad)) { + return CRYPT_INVALID_ARG; + } + + while (len-- > 0) { + /* is the pad empty? */ + if (ctr->padlen == ctr->blocklen) { + /* increment counter */ + if (ctr->mode == 0) { + /* little-endian */ + for (x = 0; x < ctr->blocklen; x++) { + ctr->ctr[x] = (ctr->ctr[x] + (unsigned char)1) & (unsigned char)255; + if (ctr->ctr[x] != (unsigned char)0) { + break; + } + } + } else { + /* big-endian */ + for (x = ctr->blocklen-1; x >= 0; x--) { + ctr->ctr[x] = (ctr->ctr[x] + (unsigned char)1) & (unsigned char)255; + if (ctr->ctr[x] != (unsigned char)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; +} + +#endif diff --git a/ctr_start.c b/ctr_start.c new file mode 100644 index 0000000..f752b65 --- /dev/null +++ b/ctr_start.c @@ -0,0 +1,46 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#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, err; + + _ARGCHK(count != NULL); + _ARGCHK(key != NULL); + _ARGCHK(ctr != NULL); + + /* bad param? */ + if ((err = cipher_is_valid(cipher)) != CRYPT_OK) { + return err; + } + + /* setup cipher */ + if ((err = cipher_descriptor[cipher].setup(key, keylen, num_rounds, &ctr->key)) != CRYPT_OK) { + return err; + } + + /* copy ctr */ + ctr->blocklen = cipher_descriptor[cipher].block_length; + ctr->cipher = cipher; + ctr->padlen = 0; + ctr->mode = 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; +} + +#endif diff --git a/demos/encrypt.c b/demos/encrypt.c new file mode 100644 index 0000000..5320c21 --- /dev/null +++ b/demos/encrypt.c @@ -0,0 +1,231 @@ +/* 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; + +int usage(char *name) +{ + int x; + + printf("Usage: %s [-d](ecrypt) cipher infile outfile\nCiphers:\n", name); + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + printf("%s\n",cipher_descriptor[x].name); + } + exit(1); +} + +void register_algs(void) +{ + int x; + +#ifdef RIJNDAEL + register_cipher (&aes_desc); +#endif +#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 TWOFISH + register_cipher (&twofish_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 RC2 + register_cipher (&rc2_desc); +#endif +#ifdef DES + register_cipher (&des_desc); + register_cipher (&des3_desc); +#endif +#ifdef CAST5 + register_cipher (&cast5_desc); +#endif +#ifdef NOEKEON + register_cipher (&noekeon_desc); +#endif +#ifdef SKIPJACK + register_cipher (&skipjack_desc); +#endif + + 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(argv[0]); + } + + 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((char *)tmpkey,sizeof(tmpkey), stdin); + outlen = sizeof(key); + if ((errno = hash_memory(hash_idx,tmpkey,strlen((char *)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..e0269b3 --- /dev/null +++ b/demos/hashsum.c @@ -0,0 +1,106 @@ +/* + * 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) +{ +#ifdef TIGER + register_hash (&tiger_desc); +#endif +#ifdef MD2 + register_hash (&md2_desc); +#endif +#ifdef MD4 + register_hash (&md4_desc); +#endif +#ifdef MD5 + register_hash (&md5_desc); +#endif +#ifdef SHA1 + register_hash (&sha1_desc); +#endif +#ifdef SHA224 + register_hash (&sha224_desc); +#endif +#ifdef SHA256 + register_hash (&sha256_desc); +#endif +#ifdef SHA384 + register_hash (&sha384_desc); +#endif +#ifdef SHA512 + register_hash (&sha512_desc); +#endif +#ifdef RIPEMD128 + register_hash (&rmd128_desc); +#endif +#ifdef RIPEMD160 + register_hash (&rmd160_desc); +#endif +#ifdef WHIRLPOOL + register_hash (&whirlpool_desc); +#endif + +} diff --git a/demos/small.c b/demos/small.c new file mode 100644 index 0000000..e45f3a6 --- /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(&sha256_desc); + return 0; +} diff --git a/demos/test.c b/demos/test.c new file mode 100644 index 0000000..6d1df5a --- /dev/null +++ b/demos/test.c @@ -0,0 +1,1982 @@ +/* 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 + +int errnum; + + +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"); + exit (-1); + } + 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"); + exit (-1); + } + + L = 0x12345678UL; + STORE32H (L, &buf[0]); + L = 0; + LOAD32H (L, &buf[0]); + if (L != 0x12345678UL) { + printf ("LOAD/STORE32 High don't work, %08lx\n", L); + exit (-1); + } + 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"); + exit (-1); + } +} + +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: %4d to %4d, Block Size: %3d, Default # of rounds: %2d\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 ((errnum = cipher_descriptor[x].test ()) != CRYPT_OK) { + printf (" **failed** Reason: %s\n", error_to_string (errnum)); + exit (-1); + } 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 ((errnum = + cbc_start (find_cipher ("blowfish"), IV, key, 16, 0, + &cbc)) != CRYPT_OK) { + printf ("CBC Setup: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errnum = cbc_encrypt (blk + 8 * x, ct + 8 * x, &cbc)) != CRYPT_OK) { + printf ("CBC encrypt: %s\n", error_to_string (errnum)); + exit (-1); + } + } + + 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 ((errnum = + cbc_start (find_cipher ("blowfish"), IV, key, 16, 0, + &cbc)) != CRYPT_OK) { + printf ("CBC Setup: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errnum = cbc_decrypt (ct + 8 * x, blk + 8 * x, &cbc)) != CRYPT_OK) { + printf ("CBC decrypt: %s\n", error_to_string (errnum)); + exit (-1); + } + } + + + /* 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"); + exit (-1); + } 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 ((errnum = + ofb_start (find_cipher ("cast5"), IV, key, 16, 0, &ofb)) != CRYPT_OK) { + printf ("OFB Setup: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errnum = ofb_encrypt (blk + 8 * x, ct + 8 * x, 8, &ofb)) != CRYPT_OK) { + printf ("OFB encrypt: %s\n", error_to_string (errnum)); + exit (-1); + } + } + + 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 ((errnum = + ofb_start (find_cipher ("cast5"), IV, key, 16, 0, &ofb)) != CRYPT_OK) { + printf ("OFB setup: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errnum = ofb_decrypt (ct + 8 * x, blk + 8 * x, 8, &ofb)) != CRYPT_OK) { + printf ("OFB decrypt: %s\n", error_to_string (errnum)); + exit (-1); + } + } + + /* print output */ + for (x = y = 0; x < 32; x++) + if (blk[x] != x) + y = 1; + printf (" %s\n", y ? "failed" : "passed"); + if (y) + exit (-1); +} +#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 ((errnum = + cfb_start (find_cipher ("blowfish"), IV, key, 16, 0, + &cfb)) != CRYPT_OK) { + printf ("CFB setup: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errnum = cfb_encrypt (blk + 8 * x, ct + 8 * x, 8, &cfb)) != CRYPT_OK) { + printf ("CFB encrypt: %s\n", error_to_string (errnum)); + exit (-1); + } + } + + 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 ((errnum = + cfb_start (find_cipher ("blowfish"), IV, key, 16, 0, + &cfb)) != CRYPT_OK) { + printf ("CFB Setup: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errnum = cfb_decrypt (ct + 8 * x, blk + 8 * x, 8, &cfb)) != CRYPT_OK) { + printf ("CFB decrypt: %s\n", error_to_string (errnum)); + exit (-1); + } + } + + /* print output */ + for (x = y = 0; x < 32; x++) + if (blk[x] != x) + y = 1; + printf (" %s\n", y ? "failed" : "passed"); + if (y) + exit (-1); +} +#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 ((errnum = + ctr_start (find_cipher ("xtea"), count, key, 16, 0, + &ctr)) != CRYPT_OK) { + printf ("CTR Setup: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* now lets encode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errnum = ctr_encrypt (blk + 8 * x, ct + 8 * x, 8, &ctr)) != CRYPT_OK) { + printf ("CTR encrypt: %s\n", error_to_string (errnum)); + exit (-1); + } + } + + 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 ((errnum = + ctr_start (find_cipher ("xtea"), count, key, 16, 0, + &ctr)) != CRYPT_OK) { + printf ("CTR Setup: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* now lets decode 32 bytes */ + for (x = 0; x < 4; x++) { + if ((errnum = ctr_decrypt (ct + 8 * x, blk + 8 * x, 8, &ctr)) != CRYPT_OK) { + printf ("CTR decrypt: %s\n", error_to_string (errnum)); + exit (-1); + } + } + + /* print output */ + for (x = y = 0; x < 32; x++) + if (blk[x] != x) + y = 1; + printf (" %s\n", y ? "failed" : "passed"); + if (y) + exit (-1); + + /* 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 ((errnum = hash_descriptor[x].test ()) != CRYPT_OK) { + printf ("**failed** Reason: %s\n", error_to_string (errnum)); + exit(-1); + } 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 ((errnum = + rsa_pad (in, 16, out, &y, find_prng ("yarrow"), &prng)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* depad the message to get the original content */ + memset (in, 0, sizeof (in)); + x = 100; + if ((errnum = rsa_depad (out, y, in, &x)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* check outcome */ + printf ("rsa_pad: "); + if (x != 16) { + printf ("Failed. Wrong size.\n"); + exit (-1); + } + for (x = 0; x < 16; x++) + if (in[x] != x) { + printf ("Failed. Expected %02lx and got %02x.\n", x, in[x]); + exit (-1); + } + printf ("passed.\n"); +} +void +rsa_test (void) +{ + unsigned char in[520], out[520]; + unsigned long x, y, z, limit; + int stat; + rsa_key key; + clock_t t; + + /* ---- SINGLE ENCRYPT ---- */ + /* encrypt a short 8 byte string */ + if ((errnum = + rsa_make_key (&prng, find_prng ("yarrow"), 1024 / 8, 65537, + &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + for (x = 0; x < 8; x++) + in[x] = (unsigned char) (x + 1); + y = sizeof (in); + if ((errnum = rsa_exptmod (in, 8, out, &y, PK_PUBLIC, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* decrypt it */ + zeromem (in, sizeof (in)); + x = sizeof (out); + if ((errnum = rsa_exptmod (out, y, in, &x, PK_PRIVATE, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* 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]); + exit (-1); + } + printf ("passed.\n"); + + /* test the rsa_encrypt_key functions */ + for (x = 0; x < 16; x++) + in[x] = x; + y = sizeof (out); + if ((errnum = + rsa_encrypt_key (in, 16, out, &y, &prng, find_prng ("yarrow"), + &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + zeromem (in, sizeof (in)); + x = sizeof (in); + if ((errnum = rsa_decrypt_key (out, y, in, &x, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + printf ("RSA en/de crypt key routines: "); + if (x != 16) { + printf ("Failed (length)\n"); + exit (-1); + } + for (x = 0; x < 16; x++) + if (in[x] != x) { + printf ("Failed (contents)\n"); + exit (-1); + } + printf ("Passed\n"); + + /* test sign_hash functions */ + for (x = 0; x < 16; x++) + in[x] = x; + x = sizeof (in); + if ((errnum = rsa_sign_hash (in, 16, out, &x, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + printf ("RSA signed hash: %lu bytes\n", x); + if ((errnum = rsa_verify_hash (out, x, in, &stat, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + printf ("Verify hash: %s, ", stat ? "passed" : "failed"); + in[0] ^= 1; + if ((errnum = rsa_verify_hash (out, x, in, &stat, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + printf ("%s\n", (!stat) ? "passed" : "failed"); + if (stat) + exit (-1); + rsa_free (&key); + + /* make a RSA key */ +#ifdef SONY_PS2_NOPE + limit = 1024; +#else + limit = 2048; +#endif + + { + int tt; + + for (z = 1024; z <= limit; z += 512) { + t = XCLOCK (); + for (tt = 0; tt < 3; tt++) { + if ((errnum = rsa_make_key (&prng, find_prng ("yarrow"), z / 8, 65537, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* check modulus size */ + if (mp_unsigned_bin_size(&key.N) != (int)(z/8)) { + printf("\nRSA key supposed to be %lu bits but was %d bits\n", z, mp_count_bits(&key.N)); + exit(EXIT_FAILURE); + } + + if (tt < 2) { + rsa_free (&key); + } + } + t = XCLOCK () - t; + printf ("Took %.0f ms to make a %ld-bit RSA key.\n", 1000.0 * (((double) t / 3.0) / (double) XCLOCKS_PER_SEC), z); + + /* time encryption */ + t = XCLOCK (); + + for (tt = 0; tt < 20; tt++) { + y = sizeof (in); + if ((errnum = rsa_exptmod (in, 8, out, &y, PK_PUBLIC, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + } + t = XCLOCK () - t; + printf ("Took %.0f ms to encrypt with a %ld-bit RSA key.\n", + 1000.0 * (((double) t / 20.0) / (double) XCLOCKS_PER_SEC), z); + + /* time decryption */ + t = XCLOCK (); + for (tt = 0; tt < 20; tt++) { + x = sizeof (out); + if ((errnum = rsa_exptmod (out, y, in, &x, PK_PRIVATE, &key)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + } + t = XCLOCK () - t; + printf ("Took %.0f ms to decrypt with a %ld-bit RSA key.\n", + 1000.0 * (((double) t / 20.0) / (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 (errnum)); + exit (-1); + } + 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 (errnum)); + exit (-1); + } + printf (" decoded %ld bytes to %ld bytes\n", x, y); + for (x = 0; x < 16; x++) + if (buf[0][x] != x) { + printf (" **failed**\n"); + exit (-1); + } + 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 < (5 * 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); + 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 += 32; + } + 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 < 3 * XCLOCKS_PER_SEC) { + DO256; + y1 += 256; + } + t1 = XCLOCK () - t1; + + func = cipher_descriptor[x].ecb_decrypt; + y2 = 0; + t2 = XCLOCK (); + while (XCLOCK () - t2 < 3 * 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; + + printf("Testing builting DH parameters...."); fflush(stdout); + if ((errnum = dh_test()) != CRYPT_OK) { + printf("DH Error: %s\n", error_to_string(errnum)); + exit(-1); + } + printf("Passed.\n"); + + dh_sizes (&low, &high); + printf ("DH Keys from %d to %d supported.\n", low * 8, high * 8); + + /* make up two keys */ + if ((errnum = + dh_make_key (&prng, find_prng ("yarrow"), 96, &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + if ((errnum = + dh_make_key (&prng, find_prng ("yarrow"), 96, &userb)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* make the shared secret */ + x = 4096; + if ((errnum = dh_shared_secret (&usera, &userb, buf[0], &x)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + + y = 4096; + if ((errnum = dh_shared_secret (&userb, &usera, buf[1], &y)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + if (y != x) { + printf ("DH Shared keys are not same size.\n"); + exit (-1); + } + if (memcmp (buf[0], buf[1], x)) { + printf ("DH Shared keys not same contents.\n"); + exit (-1); + } + + /* now export userb */ + y = 4096; + if ((errnum = dh_export (buf[1], &y, PK_PUBLIC, &userb)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + dh_free (&userb); + + /* import and make the shared secret again */ + if ((errnum = dh_import (buf[1], y, &userb)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + z = 4096; + if ((errnum = dh_shared_secret (&usera, &userb, buf[2], &z)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + + printf ("DH routines: "); + if (z != x) { + printf ("failed. Size don't match?\n"); + exit (-1); + } + if (memcmp (buf[0], buf[2], x)) { + printf ("Failed. Content didn't match.\n"); + exit (-1); + } + printf ("Passed\n"); + dh_free (&usera); + dh_free (&userb); + +/* time stuff */ + { + static int sizes[] = { 96, 128, 160, 192, 224, 256, 320, 384, 512 }; + int ii, tt; + + for (ii = 0; ii < (int) (sizeof (sizes) / sizeof (sizes[0])); ii++) { + t1 = XCLOCK (); + for (tt = 0; tt < 25; tt++) { + dh_make_key (&prng, find_prng ("yarrow"), sizes[ii], &usera); + dh_free (&usera); + } + t1 = XCLOCK () - t1; + printf ("Make dh-%d key took %f msec\n", sizes[ii] * 8, + 1000.0 * (((double) t1 / 25.0) / (double) XCLOCKS_PER_SEC)); + } + } + +/* test encrypt_key */ + dh_make_key (&prng, find_prng ("yarrow"), 128, &usera); + for (x = 0; x < 16; x++) + buf[0][x] = x; + y = sizeof (buf[1]); + if ((errnum = + 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 (errnum)); + exit (-1); + } + zeromem (buf[0], sizeof (buf[0])); + x = sizeof (buf[0]); + if ((errnum = dh_decrypt_key (buf[1], y, buf[0], &x, &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + printf ("DH en/de crypt key routines: "); + if (x != 16) { + printf ("Failed (length)\n"); + exit (-1); + } + for (x = 0; x < 16; x++) + if (buf[0][x] != x) { + printf ("Failed (contents)\n"); + exit (-1); + } + printf ("Passed (size %lu)\n", y); + +/* test sign_hash */ + for (x = 0; x < 16; x++) + buf[0][x] = x; + x = sizeof (buf[1]); + if ((errnum = + dh_sign_hash (buf[0], 16, buf[1], &x, &prng, find_prng ("yarrow"), + &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + if ((errnum = dh_verify_hash (buf[1], x, buf[0], 16, &stat, &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + buf[0][0] ^= 1; + if ((errnum = dh_verify_hash (buf[1], x, buf[0], 16, &stat2, &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + printf ("dh_sign/verify_hash: %s (%d,%d), %lu\n", + ((stat == 1) + && (stat2 == 0)) ? "passed" : "failed", stat, stat2, x); + 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 ((errnum = + rng_make_prng (128, find_prng ("yarrow"), &prng, + &callback)) != CRYPT_OK) { + printf (" starting yarrow error: %s\n", error_to_string (errnum)); + 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 ((errnum = ecc_test ()) != CRYPT_OK) { + printf ("ecc Error: %s\n", error_to_string (errnum)); + exit (-1); + } + + ecc_sizes (&low, &high); + printf ("ecc Keys from %d to %d supported.\n", low * 8, high * 8); + + /* make up two keys */ + if ((errnum = + ecc_make_key (&prng, find_prng ("yarrow"), 24, &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + if ((errnum = + ecc_make_key (&prng, find_prng ("yarrow"), 24, &userb)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* make the shared secret */ + x = 4096; + if ((errnum = ecc_shared_secret (&usera, &userb, buf[0], &x)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + + y = 4096; + if ((errnum = ecc_shared_secret (&userb, &usera, buf[1], &y)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + + if (y != x) { + printf ("ecc Shared keys are not same size.\n"); + exit (-1); + } + + if (memcmp (buf[0], buf[1], x)) { + printf ("ecc Shared keys not same contents.\n"); + exit (-1); + } + + /* now export userb */ + y = 4096; + if ((errnum = ecc_export (buf[1], &y, PK_PUBLIC, &userb)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + ecc_free (&userb); + printf ("ECC-192 export took %ld bytes\n", y); + + /* import and make the shared secret again */ + if ((errnum = ecc_import (buf[1], y, &userb)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + + z = 4096; + if ((errnum = ecc_shared_secret (&usera, &userb, buf[2], &z)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + + printf ("ecc routines: "); + if (z != x) { + printf ("failed. Size don't match?\n"); + exit (-1); + } + if (memcmp (buf[0], buf[2], x)) { + printf ("Failed. Content didn't match.\n"); + exit (-1); + } + printf ("Passed\n"); + ecc_free (&usera); + ecc_free (&userb); + +/* time stuff */ + { + static int sizes[] = { 20, 24, 28, 32, 48, 65 }; + int ii, tt; + + for (ii = 0; ii < (int) (sizeof (sizes) / sizeof (sizes[0])); ii++) { + t1 = XCLOCK (); + for (tt = 0; tt < 10; tt++) { + if ((errnum = + ecc_make_key (&prng, find_prng ("yarrow"), sizes[ii], + &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + ecc_free (&usera); + } + t1 = XCLOCK () - t1; + printf ("Make ECC-%d key took %f msec\n", sizes[ii] * 8, + 1000.0 * (((double) t1 / 10.0) / (double) XCLOCKS_PER_SEC)); + } + } + +/* test encrypt_key */ + ecc_make_key (&prng, find_prng ("yarrow"), 20, &usera); + for (x = 0; x < 32; x++) + buf[0][x] = x; + y = sizeof (buf[1]); + if ((errnum = + ecc_encrypt_key (buf[0], 32, buf[1], &y, &prng, find_prng ("yarrow"), + find_hash ("sha256"), &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + zeromem (buf[0], sizeof (buf[0])); + x = sizeof (buf[0]); + if ((errnum = ecc_decrypt_key (buf[1], y, buf[0], &x, &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + printf ("ECC en/de crypt key routines: "); + if (x != 32) { + printf ("Failed (length)\n"); + exit (-1); + } + for (x = 0; x < 32; x++) + if (buf[0][x] != x) { + printf ("Failed (contents)\n"); + exit (-1); + } + printf ("Passed (size: %lu)\n", y); +/* test sign_hash */ + for (x = 0; x < 16; x++) + buf[0][x] = x; + x = sizeof (buf[1]); + if ((errnum = + ecc_sign_hash (buf[0], 16, buf[1], &x, &prng, find_prng ("yarrow"), + &usera)) != CRYPT_OK) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + printf("Signature size: %lu\n", x); + if (ecc_verify_hash (buf[1], x, buf[0], 16, &stat, &usera)) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + buf[0][0] ^= 1; + if (ecc_verify_hash (buf[1], x, buf[0], 16, &stat2, &usera)) { + printf ("Error: %s\n", error_to_string (errnum)); + exit (-1); + } + 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) +{ + char buf[1024]; + mp_int a; + int x; + + /* make a 1024 bit prime */ + mp_init (&a); + rand_prime (&a, 128*8, &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 RIJNDAEL + register_cipher (&aes_desc); +#endif +#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 TWOFISH + register_cipher (&twofish_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 RC2 + register_cipher (&rc2_desc); +#endif +#ifdef DES + register_cipher (&des_desc); + register_cipher (&des3_desc); +#endif +#ifdef CAST5 + register_cipher (&cast5_desc); +#endif +#ifdef NOEKEON + register_cipher (&noekeon_desc); +#endif +#ifdef SKIPJACK + register_cipher (&skipjack_desc); +#endif + register_cipher (&null_desc); + +#ifdef TIGER + register_hash (&tiger_desc); +#endif +#ifdef MD2 + register_hash (&md2_desc); +#endif +#ifdef MD4 + register_hash (&md4_desc); +#endif +#ifdef MD5 + register_hash (&md5_desc); +#endif +#ifdef SHA1 + register_hash (&sha1_desc); +#endif +#ifdef SHA256 + register_hash (&sha256_desc); +#endif +#ifdef SHA224 + register_hash (&sha224_desc); +#endif +#ifdef SHA384 + register_hash (&sha384_desc); +#endif +#ifdef SHA512 + register_hash (&sha512_desc); +#endif +#ifdef RIPEMD128 + register_hash (&rmd128_desc); +#endif +#ifdef RIPEMD160 + register_hash (&rmd160_desc); +#endif +#ifdef WHIRLPOOL + register_hash (&whirlpool_desc); +#endif + +#ifdef YARROW + register_prng (&yarrow_desc); +#endif +#ifdef SPRNG + register_prng (&sprng_desc); +#endif +} + +#ifdef KR +void +kr_display (pk_key * kr) +{ + static const char *sys[] = { "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, + sys[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 ((errnum = kr_init (kr)) != CRYPT_OK) { + printf ("KR init error %s\n", error_to_string (errnum)); + exit (-1); + } + + /* make a DH key */ + printf ("KR: Making DH key...\n"); + if ((errnum = + 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 (errnum)); + exit (-1); + } + + /* make a ECC key */ + printf ("KR: Making ECC key...\n"); + if ((errnum = + kr_make_key (*kr, &prng, find_prng ("yarrow"), ECC_KEY, 20, "ecckey", + "ecc@ecc.ecc", "ecckey one")) != CRYPT_OK) { + printf ("Make key error: %s\n", error_to_string (errnum)); + exit (-1); + } + + /* make a RSA key */ + printf ("KR: Making RSA key...\n"); + if ((errnum = + 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 (errnum)); + 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 ((errnum = kr_export (kr, kr->ID, kr->key_type, buf, &len)) != CRYPT_OK) { + printf ("Error exporting key %d, %s\n", i, error_to_string (errnum)); + exit (-1); + } + printf ("Exported key was: %lu bytes\n", len); + if ((errnum = kr_del (&kr, kr->ID)) != CRYPT_OK) { + printf ("Error deleting key %d, %s\n", i, error_to_string (errnum)); + exit (-1); + } + kr_display (kr); + if ((errnum = kr_import (kr, buf, len)) != CRYPT_OK) { + printf ("Error importing key %d, %s\n", i, error_to_string (errnum)); + exit (-1); + } + kr_display (kr); + } + + for (i = 0; i < 3; i++) { + len = sizeof (buf); + if ((errnum = kr_export (kr, kr->ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) { + printf ("Error exporting key %d, %s\n", i, error_to_string (errnum)); + exit (-1); + } + printf ("Exported key was: %lu bytes\n", len); + if ((errnum = kr_del (&kr, kr->ID)) != CRYPT_OK) { + printf ("Error deleting key %d, %s\n", i, error_to_string (errnum)); + exit (-1); + } + kr_display (kr); + if ((errnum = kr_import (kr, buf, len)) != CRYPT_OK) { + printf ("Error importing key %d, %s\n", i, error_to_string (errnum)); + exit (-1); + } + kr_display (kr); + } + + if ((errnum = kr_clear (&kr)) != CRYPT_OK) { + printf ("Error clearing ring: %s\n", error_to_string (errnum)); + exit (-1); + } + + +/* TEST output to file */ +#ifndef NO_FILE + + if ((errnum = kr_init (&kr)) != CRYPT_OK) { + printf ("KR init error %s\n", error_to_string (errnum)); + exit (-1); + } + kr_test_makekeys (&kr); + + /* save to file */ + f = fopen ("ring.dat", "wb"); + if ((errnum = kr_save (kr, f, NULL)) != CRYPT_OK) { + printf ("kr_save error %s\n", error_to_string (errnum)); + exit (-1); + } + fclose (f); + + /* delete and load */ + if ((errnum = kr_clear (&kr)) != CRYPT_OK) { + printf ("clear error: %s\n", error_to_string (errnum)); + exit (-1); + } + + f = fopen ("ring.dat", "rb"); + if ((errnum = kr_load (&kr, f, NULL)) != CRYPT_OK) { + printf ("kr_load error %s\n", error_to_string (errnum)); + exit (-1); + } + fclose (f); + remove ("ring.dat"); + printf ("After load and save...\n"); + kr_display (kr); + + if ((errnum = kr_clear (&kr)) != CRYPT_OK) { + printf ("clear error: %s\n", error_to_string (errnum)); + exit (-1); + } +#endif + +/* test the packet encryption/sign stuff */ + for (i = 0; i < 32; 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 ((errnum = + 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 (errnum)); + exit (-1); + } + len = sizeof (buf3); + if ((errnum = kr_decrypt_key (kr, buf2, buf3, &len)) != CRYPT_OK) { + printf ("decrypt error, %d, %s\n", i, error_to_string (errnum)); + 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 ((errnum = + kr_sign_hash (kr, _kr->ID, buf, 32, buf2, &len, &prng, + find_prng ("yarrow"))) != CRYPT_OK) { + printf ("kr_sign_hash failed, %i, %s\n", i, error_to_string (errnum)); + exit (-1); + } + printf ("kr_sign_hash: "); + if ((errnum = kr_verify_hash (kr, buf2, buf, 32, &stat)) != CRYPT_OK) { + printf ("kr_sign_hash failed, %i, %s\n", i, error_to_string (errnum)); + exit (-1); + } + printf ("%s, ", stat ? "passed" : "failed"); + buf[15] ^= 1; + if ((errnum = kr_verify_hash (kr, buf2, buf, 32, &stat)) != CRYPT_OK) { + printf ("kr_sign_hash failed, %i, %s\n", i, error_to_string (errnum)); + exit (-1); + } + printf ("%s\n", (!stat) ? "passed" : "failed"); + buf[15] ^= 1; + + len = sizeof (buf); + if ((errnum = + 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 ((errnum = kr_export (kr, kr->ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) { + printf ("Error exporting key %d, %s\n", i, error_to_string (errnum)); + exit (-1); + } + + /* check boundaries */ + memset (buf + len, 0, sizeof (buf) - len); + + len = sizeof (buf2); + if ((errnum = kr_export (kr, kr->ID, PK_PRIVATE, buf2, &len)) != CRYPT_OK) { + printf ("Error exporting key %s\n", error_to_string (errnum)); + 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 ((errnum = kr_import (kr, buf, len)) != CRYPT_OK) { + printf ("Error importing key %s\n", error_to_string (errnum)); + exit (-1); + } + kr_display (kr); + + /* now encrypt a buffer */ + for (i = 0; i < 16; i++) + buf[i] = i; + len = sizeof (buf3); + if ((errnum = + 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 (errnum)); + exit (-1); + } + + /* now delete the key and import the private one */ + kr_clear (&kr); + kr_init (&kr); + kr_display (kr); + if ((errnum = kr_import (kr, buf2, len)) != CRYPT_OK) { + printf ("Error importing key %s\n", error_to_string (errnum)); + exit (-1); + } + kr_display (kr); + + /* now decrypt */ + len = sizeof (buf2); + if ((errnum = kr_decrypt_key (kr, buf3, buf2, &len)) != CRYPT_OK) { + printf ("decrypt error, %s\n", error_to_string (errnum)); + 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); +} +#endif + +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_FILE_NOTFOUND); + + 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); +} + + +void dsa_tests(void) +{ + unsigned char msg[16], out[1024], out2[1024]; + unsigned long x, y; + int err, stat1, stat2; + dsa_key key, key2; + + /* make a random key */ + if ((err = dsa_make_key(&prng, find_prng("yarrow"), 20, 128, &key)) != CRYPT_OK) { + printf("Error making DSA key: %s\n", error_to_string(err)); + exit(-1); + } + printf("DSA Key Made\n"); + + /* verify it */ + if ((err = dsa_verify_key(&key, &stat1)) != CRYPT_OK) { + printf("Error verifying DSA key: %s\n", error_to_string(err)); + exit(-1); + } + printf("DSA key verification: %s\n", stat1 == 1 ? "passed" : "failed"); + if (stat1 == 0) exit(-1); + + /* sign the message */ + x = sizeof(out); + if ((err = dsa_sign_hash(msg, sizeof(msg), out, &x, &prng, find_prng("yarrow"), &key)) != CRYPT_OK) { + printf("Error signing with DSA key: %s\n", error_to_string(err)); + exit(-1); + } + printf("DSA 160/1024 signature is %lu bytes long\n", x); + + /* verify it once */ + if ((err = dsa_verify_hash(out, x, msg, sizeof(msg), &stat1, &key)) != CRYPT_OK) { + printf("Error verifying with DSA key 1: %s\n", error_to_string(err)); + exit(-1); + } + + /* Modify and verify again */ + msg[0] ^= 1; + if ((err = dsa_verify_hash(out, x, msg, sizeof(msg), &stat2, &key)) != CRYPT_OK) { + printf("Error verifying with DSA key 2: %s\n", error_to_string(err)); + exit(-1); + } + msg[0] ^= 1; + printf("DSA Verification: %d, %d, %s\n", stat1, stat2, (stat1 == 1 && stat2 == 0) ? "passed" : "failed"); + if (!(stat1 == 1 && stat2 == 0)) exit(-1); + + /* test exporting it */ + x = sizeof(out2); + if ((err = dsa_export(out2, &x, PK_PRIVATE, &key)) != CRYPT_OK) { + printf("Error export PK_PRIVATE DSA key: %s\n", error_to_string(err)); + exit(-1); + } + printf("Exported PK_PRIVATE DSA key in %lu bytes\n", x); + if ((err = dsa_import(out2, x, &key2)) != CRYPT_OK) { + printf("Error importing PK_PRIVATE DSA key: %s\n", error_to_string(err)); + exit(-1); + } + /* verify a signature with it */ + if ((err = dsa_verify_hash(out, x, msg, sizeof(msg), &stat1, &key2)) != CRYPT_OK) { + printf("Error verifying with DSA key 3: %s\n", error_to_string(err)); + exit(-1); + } + printf("PRIVATE Import Test: %s\n", stat1 == 1 ? "passed" : "failed"); + if (stat1 == 0) exit(-1); + dsa_free(&key2); + + /* export as public now */ + x = sizeof(out2); + if ((err = dsa_export(out2, &x, PK_PUBLIC, &key)) != CRYPT_OK) { + printf("Error export PK_PUBLIC DSA key: %s\n", error_to_string(err)); + exit(-1); + } + printf("Exported PK_PUBLIC DSA key in %lu bytes\n", x); + if ((err = dsa_import(out2, x, &key2)) != CRYPT_OK) { + printf("Error importing PK_PUBLIC DSA key: %s\n", error_to_string(err)); + exit(-1); + } + /* verify a signature with it */ + if ((err = dsa_verify_hash(out, x, msg, sizeof(msg), &stat1, &key2)) != CRYPT_OK) { + printf("Error verifying with DSA key 4: %s\n", error_to_string(err)); + exit(-1); + } + printf("PUBLIC Import Test: %s\n", stat1 == 1 ? "passed" : "failed"); + if (stat1 == 0) exit(-1); + + dsa_free(&key2); + dsa_free(&key); +} + +#ifdef PKCS_1 +void pkcs1_test(void) +{ + unsigned char buf[3][128]; + int err, res1, res2, res3, prng_idx, hash_idx; + unsigned long x, y, l1, l2, l3, i1, i2; + + /* get hash/prng */ + hash_idx = find_hash("sha1"); + prng_idx = find_prng("yarrow"); + + /* do many tests */ + for (x = 0; x < 10000; x++) { + zeromem(buf, sizeof(buf)); + + /* make a dummy message (of random length) */ + l3 = (rand() & 31) + 8; + for (y = 0; y < l3; y++) buf[0][y] = rand() & 255; + + /* encode it */ + l1 = sizeof(buf[1]); + if ((err = pkcs_1_oaep_encode(buf[0], l3, NULL, 0, 1024, hash_idx, prng_idx, &prng, buf[1], &l1)) != CRYPT_OK) { + printf("OAEP encode: %s\n", error_to_string(err)); + exit(-1); + } + + /* decode it */ + l2 = sizeof(buf[2]); + if ((err = pkcs_1_oaep_decode(buf[1], l1, NULL, 0, 1024, hash_idx, buf[2], &l2)) != CRYPT_OK) { + printf("OAEP decode: %s\n", error_to_string(err)); + exit(-1); + } + + if (l2 != l3 || memcmp(buf[2], buf[0], l3) != 0) { + printf("Outsize == %lu, should have been %lu, msg contents follow.\n", l2, l3); + printf("ORIGINAL:\n"); + for (x = 0; x < l3; x++) { + printf("%02x ", buf[0][x]); + } + printf("\nRESULT:\n"); + for (x = 0; x < l2; x++) { + printf("%02x ", buf[2][x]); + } + printf("\n\n"); + exit(-1); + } + + /* test PSS */ + l1 = sizeof(buf[1]); + if ((err = pkcs_1_pss_encode(buf[0], l3, l3>>2, hash_idx, prng_idx, &prng, 1024, buf[1], &l1)) != CRYPT_OK) { + printf("PSS encode: %s\n", error_to_string(err)); + exit(-1); + } + + if ((err = pkcs_1_pss_decode(buf[0], l3, buf[1], l1, l3>>2, hash_idx, 1024, &res1)) != CRYPT_OK) { + printf("PSS decode1: %s\n", error_to_string(err)); + exit(-1); + } + + buf[0][i1 = abs(rand()) % l3] ^= 1; + if ((err = pkcs_1_pss_decode(buf[0], l3, buf[1], l1, l3>>2, hash_idx, 1024, &res2)) != CRYPT_OK) { + printf("PSS decode2: %s\n", error_to_string(err)); + exit(-1); + } + + buf[0][i1] ^= 1; + buf[1][i2 = abs(rand()) % l1] ^= 1; + if ((err = pkcs_1_pss_decode(buf[0], l3, buf[1], l1, l3>>2, hash_idx, 1024, &res3)) != CRYPT_OK) { + printf("PSS decode3: %s\n", error_to_string(err)); + exit(-1); + } + + if (!(res1 == 1 && res2 == 0 && res3 == 0)) { + printf("PSS failed: %d, %d, %d, %lu\n", res1, res2, res3, l3); + exit(-1); + } + } + printf("PKCS #1: Passed\n"); +} + +#endif /* PKCS_1 */ + +int +main (void) +{ +#ifdef SONY_PS2 + TIMER_Init (); +#endif + srand(time(NULL)); + + register_all_algs (); + + if ((errnum = yarrow_start (&prng)) != CRYPT_OK) { + printf ("yarrow_start: %s\n", error_to_string (errnum)); + } + if ((errnum = yarrow_add_entropy ((unsigned char *)"hello", 5, &prng)) != CRYPT_OK) { + printf ("yarrow_add_entropy: %s\n", error_to_string (errnum)); + } + if ((errnum = yarrow_ready (&prng)) != CRYPT_OK) { + printf ("yarrow_ready: %s\n", error_to_string (errnum)); + } + + printf (crypt_build_settings); + test_errs (); + +#ifdef HMAC + printf ("HMAC: %s\n", hmac_test () == CRYPT_OK ? "passed" : "failed"); + if (hmac_test() != CRYPT_OK) exit(EXIT_FAILURE); +#endif + +#ifdef OMAC + printf ("OMAC: %s\n", omac_test () == CRYPT_OK ? "passed" : "failed"); + if (omac_test() != CRYPT_OK) exit(EXIT_FAILURE); +#endif + +#ifdef PMAC + printf ("PMAC: %s\n", pmac_test () == CRYPT_OK ? "passed" : "failed"); + if (pmac_test() != CRYPT_OK) exit(EXIT_FAILURE); +#endif + +#ifdef EAX_MODE + printf ("EAX : %s\n", eax_test () == CRYPT_OK ? "passed" : "failed"); + if (eax_test() != CRYPT_OK) exit(EXIT_FAILURE); +#endif + +#ifdef OCB_MODE + printf ("OCB : %s\n", ocb_test () == CRYPT_OK ? "passed" : "failed"); + if (ocb_test() != CRYPT_OK) exit(EXIT_FAILURE); +#endif + + store_tests (); + cipher_tests (); + hash_tests (); + +#ifdef PKCS_1 + pkcs1_test(); +#endif + + ecb_tests (); + cbc_tests (); + ctr_tests (); + ofb_tests (); + cfb_tests (); + + rng_tests (); + test_prime(); + +#ifdef KR + kr_test (); +#endif + dsa_tests(); + 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/tv_gen.c b/demos/tv_gen.c new file mode 100644 index 0000000..cf75d3b --- /dev/null +++ b/demos/tv_gen.c @@ -0,0 +1,492 @@ +#include + +void reg_algs(void) +{ +#ifdef RIJNDAEL + register_cipher (&aes_desc); +#endif +#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 TWOFISH + register_cipher (&twofish_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 RC2 + register_cipher (&rc2_desc); +#endif +#ifdef DES + register_cipher (&des_desc); + register_cipher (&des3_desc); +#endif +#ifdef CAST5 + register_cipher (&cast5_desc); +#endif +#ifdef NOEKEON + register_cipher (&noekeon_desc); +#endif +#ifdef SKIPJACK + register_cipher (&skipjack_desc); +#endif + +#ifdef TIGER + register_hash (&tiger_desc); +#endif +#ifdef MD2 + register_hash (&md2_desc); +#endif +#ifdef MD4 + register_hash (&md4_desc); +#endif +#ifdef MD5 + register_hash (&md5_desc); +#endif +#ifdef SHA1 + register_hash (&sha1_desc); +#endif +#ifdef SHA224 + register_hash (&sha224_desc); +#endif +#ifdef SHA256 + register_hash (&sha256_desc); +#endif +#ifdef SHA384 + register_hash (&sha384_desc); +#endif +#ifdef SHA512 + register_hash (&sha512_desc); +#endif +#ifdef RIPEMD128 + register_hash (&rmd128_desc); +#endif +#ifdef RIPEMD160 + register_hash (&rmd160_desc); +#endif +#ifdef WHIRLPOOL + register_hash (&whirlpool_desc); +#endif +} + +void hash_gen(void) +{ + unsigned char md[MAXBLOCKSIZE], buf[MAXBLOCKSIZE*2+2]; + unsigned long outlen, x, y, z; + FILE *out; + + out = fopen("hash_tv.txt", "w"); + + fprintf(out, "Hash Test Vectors:\n\nThese are the hashes of nn bytes '00 01 02 03 .. (nn-1)'\n\n"); + for (x = 0; hash_descriptor[x].name != NULL; x++) { + fprintf(out, "Hash: %s\n", hash_descriptor[x].name); + + for (y = 0; y <= (hash_descriptor[x].blocksize * 2); y++) { + for (z = 0; z < y; z++) { + buf[z] = (unsigned char)(z & 255); + } + outlen = sizeof(md); + hash_memory(x, buf, y, md, &outlen); + fprintf(out, "%3lu: ", y); + for (z = 0; z < outlen; z++) { + fprintf(out, "%02X", md[z]); + } + fprintf(out, "\n"); + } + fprintf(out, "\n"); + } + fclose(out); +} + +void cipher_gen(void) +{ + unsigned char key[MAXBLOCKSIZE], pt[MAXBLOCKSIZE]; + unsigned long x, y, z, w; + int kl, lastkl; + FILE *out; + symmetric_key skey; + + out = fopen("cipher_tv.txt", "w"); + + fprintf(out, +"Cipher Test Vectors\n\nThese are test encryptions with key of nn bytes '00 01 02 03 .. (nn-1)' and original PT of the same style.\n" +"The output of step N is used as the key and plaintext for step N+1 (key bytes repeated as required to fill the key)\n\n"); + + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + fprintf(out, "Cipher: %s\n", cipher_descriptor[x].name); + + /* three modes, smallest, medium, large keys */ + lastkl = 10000; + for (y = 0; y < 3; y++) { + switch (y) { + case 0: kl = cipher_descriptor[x].min_key_length; break; + case 1: kl = (cipher_descriptor[x].min_key_length + cipher_descriptor[x].max_key_length)/2; break; + case 2: kl = cipher_descriptor[x].max_key_length; break; + } + cipher_descriptor[x].keysize(&kl); + if (kl == lastkl) break; + lastkl = kl; + fprintf(out, "Key Size: %d bytes\n", kl); + + for (z = 0; (int)z < kl; z++) { + key[z] = (unsigned char)z; + } + cipher_descriptor[x].setup(key, kl, 0, &skey); + + for (z = 0; (int)z < cipher_descriptor[x].block_length; z++) { + pt[z] = (unsigned char)z; + } + for (w = 0; w < 50; w++) { + cipher_descriptor[x].ecb_encrypt(pt, pt, &skey); + fprintf(out, "%2lu: ", w); + for (z = 0; (int)z < cipher_descriptor[x].block_length; z++) { + fprintf(out, "%02X", pt[z]); + } + fprintf(out, "\n"); + + /* reschedule a new key */ + for (z = 0; z < (unsigned long)kl; z++) { + key[z] = pt[z % cipher_descriptor[x].block_length]; + } + cipher_descriptor[x].setup(key, kl, 0, &skey); + } + fprintf(out, "\n"); + } + fprintf(out, "\n"); + } + fclose(out); +} + +void hmac_gen(void) +{ + unsigned char key[MAXBLOCKSIZE], output[MAXBLOCKSIZE], input[MAXBLOCKSIZE*2+2]; + int x, y, z, kl, err; + FILE *out; + unsigned long len; + + out = fopen("hmac_tv.txt", "w"); + + fprintf(out, +"HMAC Tests. In these tests messages of N bytes long (00,01,02,...,NN-1) are HMACed. The initial key is\n" +"of the same format (the same length as the HASH output size). The HMAC key in step N+1 is the HMAC output of\n" +"step N.\n\n"); + + for (x = 0; hash_descriptor[x].name != NULL; x++) { + fprintf(out, "HMAC-%s\n", hash_descriptor[x].name); + + /* initial key */ + for (y = 0; y < (int)hash_descriptor[x].hashsize; y++) { + key[y] = (y&255); + } + + for (y = 0; y <= (int)(hash_descriptor[x].blocksize * 2); y++) { + for (z = 0; z < y; z++) { + input[z] = (unsigned char)(z & 255); + } + len = sizeof(output); + if ((err = hmac_memory(x, key, hash_descriptor[x].hashsize, input, y, output, &len)) != CRYPT_OK) { + printf("Error hmacing: %s\n", error_to_string(err)); + exit(EXIT_FAILURE); + } + fprintf(out, "%3d: ", y); + for (z = 0; z <(int) len; z++) { + fprintf(out, "%02X", output[z]); + } + fprintf(out, "\n"); + + /* forward the key */ + memcpy(key, output, hash_descriptor[x].hashsize); + } + fprintf(out, "\n"); + } + fclose(out); +} + +void omac_gen(void) +{ + unsigned char key[MAXBLOCKSIZE], output[MAXBLOCKSIZE], input[MAXBLOCKSIZE*2+2]; + int err, x, y, z, kl; + FILE *out; + unsigned long len; + + out = fopen("omac_tv.txt", "w"); + + fprintf(out, +"OMAC Tests. In these tests messages of N bytes long (00,01,02,...,NN-1) are OMAC'ed. The initial key is\n" +"of the same format (length specified per cipher). The OMAC key in step N+1 is the OMAC output of\n" +"step N (repeated as required to fill the array).\n\n"); + + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + kl = cipher_descriptor[x].block_length; + + /* skip ciphers which do not have 64 or 128 bit block sizes */ + if (kl != 8 && kl != 16) continue; + + if (cipher_descriptor[x].keysize(&kl) != CRYPT_OK) { + kl = cipher_descriptor[x].max_key_length; + } + fprintf(out, "OMAC-%s (%d byte key)\n", cipher_descriptor[x].name, kl); + + /* initial key/block */ + for (y = 0; y < kl; y++) { + key[y] = (y & 255); + } + + for (y = 0; y <= (int)(cipher_descriptor[x].block_length*2); y++) { + for (z = 0; z < y; z++) { + input[z] = (unsigned char)(z & 255); + } + len = sizeof(output); + if ((err = omac_memory(x, key, kl, input, y, output, &len)) != CRYPT_OK) { + printf("Error omacing: %s\n", error_to_string(err)); + exit(EXIT_FAILURE); + } + fprintf(out, "%3d: ", y); + for (z = 0; z <(int)len; z++) { + fprintf(out, "%02X", output[z]); + } + fprintf(out, "\n"); + + /* forward the key */ + for (z = 0; z < kl; z++) { + key[z] = output[z % len]; + } + } + fprintf(out, "\n"); + } + fclose(out); +} + +void pmac_gen(void) +{ + unsigned char key[MAXBLOCKSIZE], output[MAXBLOCKSIZE], input[MAXBLOCKSIZE*2+2]; + int err, x, y, z, kl; + FILE *out; + unsigned long len; + + out = fopen("pmac_tv.txt", "w"); + + fprintf(out, +"PMAC Tests. In these tests messages of N bytes long (00,01,02,...,NN-1) are OMAC'ed. The initial key is\n" +"of the same format (length specified per cipher). The OMAC key in step N+1 is the OMAC output of\n" +"step N (repeated as required to fill the array).\n\n"); + + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + kl = cipher_descriptor[x].block_length; + + /* skip ciphers which do not have 64 or 128 bit block sizes */ + if (kl != 8 && kl != 16) continue; + + if (cipher_descriptor[x].keysize(&kl) != CRYPT_OK) { + kl = cipher_descriptor[x].max_key_length; + } + fprintf(out, "PMAC-%s (%d byte key)\n", cipher_descriptor[x].name, kl); + + /* initial key/block */ + for (y = 0; y < kl; y++) { + key[y] = (y & 255); + } + + for (y = 0; y <= (int)(cipher_descriptor[x].block_length*2); y++) { + for (z = 0; z < y; z++) { + input[z] = (unsigned char)(z & 255); + } + len = sizeof(output); + if ((err = pmac_memory(x, key, kl, input, y, output, &len)) != CRYPT_OK) { + printf("Error omacing: %s\n", error_to_string(err)); + exit(EXIT_FAILURE); + } + fprintf(out, "%3d: ", y); + for (z = 0; z <(int)len; z++) { + fprintf(out, "%02X", output[z]); + } + fprintf(out, "\n"); + + /* forward the key */ + for (z = 0; z < kl; z++) { + key[z] = output[z % len]; + } + } + fprintf(out, "\n"); + } + fclose(out); +} + +void eax_gen(void) +{ + int err, kl, x, y1, z; + FILE *out; + unsigned char key[MAXBLOCKSIZE], nonce[MAXBLOCKSIZE*2], header[MAXBLOCKSIZE*2], + plaintext[MAXBLOCKSIZE*2], tag[MAXBLOCKSIZE]; + unsigned long len; + + out = fopen("eax_tv.txt", "w"); + fprintf(out, "EAX Test Vectors. Uses the 00010203...NN-1 pattern for header/nonce/plaintext/key. The outputs\n" + "are of the form ciphertext,tag for a given NN. The key for step N>1 is the tag of the previous\n" + "step repeated sufficiently.\n\n"); + + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + kl = cipher_descriptor[x].block_length; + + /* skip ciphers which do not have 64 or 128 bit block sizes */ + if (kl != 8 && kl != 16) continue; + + if (cipher_descriptor[x].keysize(&kl) != CRYPT_OK) { + kl = cipher_descriptor[x].max_key_length; + } + fprintf(out, "EAX-%s (%d byte key)\n", cipher_descriptor[x].name, kl); + + /* the key */ + for (z = 0; z < kl; z++) { + key[z] = (z & 255); + } + + for (y1 = 0; y1 <= (int)(cipher_descriptor[x].block_length*2); y1++){ + for (z = 0; z < y1; z++) { + plaintext[z] = (unsigned char)(z & 255); + nonce[z] = (unsigned char)(z & 255); + header[z] = (unsigned char)(z & 255); + } + len = sizeof(tag); + if ((err = eax_encrypt_authenticate_memory(x, key, kl, nonce, y1, header, y1, plaintext, y1, plaintext, tag, &len)) != CRYPT_OK) { + printf("Error EAX'ing: %s\n", error_to_string(err)); + exit(EXIT_FAILURE); + } + fprintf(out, "%3d: ", y1); + for (z = 0; z < y1; z++) { + fprintf(out, "%02X", plaintext[z]); + } + fprintf(out, ", "); + for (z = 0; z <(int)len; z++) { + fprintf(out, "%02X", tag[z]); + } + fprintf(out, "\n"); + + /* forward the key */ + for (z = 0; z < kl; z++) { + key[z] = tag[z % len]; + } + } + fprintf(out, "\n"); + } + fclose(out); +} + +void ocb_gen(void) +{ + int err, kl, x, y1, z; + FILE *out; + unsigned char key[MAXBLOCKSIZE], nonce[MAXBLOCKSIZE*2], + plaintext[MAXBLOCKSIZE*2], tag[MAXBLOCKSIZE]; + unsigned long len; + + out = fopen("ocb_tv.txt", "w"); + fprintf(out, "OCB Test Vectors. Uses the 00010203...NN-1 pattern for nonce/plaintext/key. The outputs\n" + "are of the form ciphertext,tag for a given NN. The key for step N>1 is the tag of the previous\n" + "step repeated sufficiently. The nonce is fixed throughout.\n\n"); + + for (x = 0; cipher_descriptor[x].name != NULL; x++) { + kl = cipher_descriptor[x].block_length; + + /* skip ciphers which do not have 64 or 128 bit block sizes */ + if (kl != 8 && kl != 16) continue; + + if (cipher_descriptor[x].keysize(&kl) != CRYPT_OK) { + kl = cipher_descriptor[x].max_key_length; + } + fprintf(out, "OCB-%s (%d byte key)\n", cipher_descriptor[x].name, kl); + + /* the key */ + for (z = 0; z < kl; z++) { + key[z] = (z & 255); + } + + /* fixed nonce */ + for (z = 0; z < cipher_descriptor[x].block_length; z++) { + nonce[z] = z; + } + + for (y1 = 0; y1 <= (int)(cipher_descriptor[x].block_length*2); y1++){ + for (z = 0; z < y1; z++) { + plaintext[z] = (unsigned char)(z & 255); + } + len = sizeof(tag); + if ((err = ocb_encrypt_authenticate_memory(x, key, kl, nonce, plaintext, y1, plaintext, tag, &len)) != CRYPT_OK) { + printf("Error OCB'ing: %s\n", error_to_string(err)); + exit(EXIT_FAILURE); + } + fprintf(out, "%3d: ", y1); + for (z = 0; z < y1; z++) { + fprintf(out, "%02X", plaintext[z]); + } + fprintf(out, ", "); + for (z = 0; z <(int)len; z++) { + fprintf(out, "%02X", tag[z]); + } + fprintf(out, "\n"); + + /* forward the key */ + for (z = 0; z < kl; z++) { + key[z] = tag[z % len]; + } + } + fprintf(out, "\n"); + } + fclose(out); +} + +void base64_gen(void) +{ + FILE *out; + unsigned char dst[256], src[32]; + unsigned long x, y, len; + + out = fopen("base64_tv.txt", "w"); + fprintf(out, "Base64 vectors. These are the base64 encodings of the strings 00,01,02...NN-1\n\n"); + for (x = 0; x <= 32; x++) { + for (y = 0; y < x; y++) { + src[y] = y; + } + len = sizeof(dst); + base64_encode(src, x, dst, &len); + fprintf(out, "%2lu: %s\n", x, dst); + } + fclose(out); +} + +int main(void) +{ + reg_algs(); + printf("Generating hash vectors..."); fflush(stdout); hash_gen(); printf("done\n"); + printf("Generating cipher vectors..."); fflush(stdout); cipher_gen(); printf("done\n"); + printf("Generating HMAC vectors..."); fflush(stdout); hmac_gen(); printf("done\n"); + printf("Generating OMAC vectors..."); fflush(stdout); omac_gen(); printf("done\n"); + printf("Generating PMAC vectors..."); fflush(stdout); pmac_gen(); printf("done\n"); + printf("Generating EAX vectors..."); fflush(stdout); eax_gen(); printf("done\n"); + printf("Generating OCB vectors..."); fflush(stdout); ocb_gen(); printf("done\n"); + printf("Generating BASE64 vectors..."); fflush(stdout); base64_gen(); printf("done\n"); + return 0; +} + + + + + + + + diff --git a/demos/x86_prof.c b/demos/x86_prof.c new file mode 100644 index 0000000..e968554 --- /dev/null +++ b/demos/x86_prof.c @@ -0,0 +1,358 @@ +#include + +#define KTIMES 25 +#define TIMES 100000 + +struct list { + int id; + unsigned long spd1, spd2, avg; +} results[100]; + +int no_results; + +int sorter(const void *a, const void *b) +{ + const struct list *A, *B; + A = a; + B = b; + if (A->avg < B->avg) return -1; + if (A->avg > B->avg) return 1; + return 0; +} + +void tally_results(int type) +{ + int x; + + // qsort the results + qsort(results, no_results, sizeof(struct list), &sorter); + + printf("\n"); + if (type == 0) { + for (x = 0; x < no_results; x++) { + printf("%-20s: Schedule at %6lu\n", cipher_descriptor[results[x].id].name, (unsigned long)results[x].spd1); + } + } else if (type == 1) { + for (x = 0; x < no_results; x++) { + printf + ("%-20s: Encrypt at %5lu, Decrypt at %5lu\n", cipher_descriptor[results[x].id].name, results[x].spd1, results[x].spd2); + } + } else { + for (x = 0; x < no_results; x++) { + printf + ("%-20s: Process at %5lu\n", hash_descriptor[results[x].id].name, results[x].spd1 / 1000); + } + } +} + + + + +/* RDTSC from Scott Duplichan */ +static ulong64 rdtsc (void) + { + #if defined __GNUC__ + #ifdef __i386__ + ulong64 a; + __asm__ __volatile__ ("rdtsc ":"=A" (a)); + return a; + #else /* gcc-IA64 version */ + unsigned long result; + __asm__ __volatile__("mov %0=ar.itc" : "=r"(result) :: "memory"); + while (__builtin_expect ((int) result == -1, 0)) + __asm__ __volatile__("mov %0=ar.itc" : "=r"(result) :: "memory"); + return result; + #endif + + // Microsoft and Intel Windows compilers + #elif defined _M_IX86 + __asm rdtsc + #elif defined _M_AMD64 + return __rdtsc (); + #elif defined _M_IA64 + #if defined __INTEL_COMPILER + #include + #endif + return __getReg (3116); + #else + #error need rdtsc function for this build + #endif + } + +ulong64 timer, skew = 0; +prng_state prng; + +void t_start(void) +{ + timer = rdtsc(); +} + +ulong64 t_read(void) +{ + return rdtsc() - timer; +} + +void init_timer(void) +{ + ulong64 c1, c2, t1, t2, t3; + unsigned long y1; + + c1 = c2 = (ulong64)-1; + for (y1 = 0; y1 < TIMES*100; y1++) { + t_start(); + t1 = t_read(); + t3 = t_read(); + t2 = t_read() - t1; + + c1 = (c1 > t1) ? t1 : c1; + c2 = (c2 > t2) ? t2 : c2; + } + skew = c2 - c1; + printf("Clock Skew: %lu\n", (unsigned long)skew); +} + +void reg_algs(void) +{ +#ifdef RIJNDAEL + register_cipher (&aes_desc); +#endif +#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 TWOFISH + register_cipher (&twofish_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 RC2 + register_cipher (&rc2_desc); +#endif +#ifdef DES + register_cipher (&des_desc); + register_cipher (&des3_desc); +#endif +#ifdef CAST5 + register_cipher (&cast5_desc); +#endif +#ifdef NOEKEON + register_cipher (&noekeon_desc); +#endif +#ifdef SKIPJACK + register_cipher (&skipjack_desc); +#endif + +#ifdef TIGER + register_hash (&tiger_desc); +#endif +#ifdef MD2 + register_hash (&md2_desc); +#endif +#ifdef MD4 + register_hash (&md4_desc); +#endif +#ifdef MD5 + register_hash (&md5_desc); +#endif +#ifdef SHA1 + register_hash (&sha1_desc); +#endif +#ifdef SHA224 + register_hash (&sha224_desc); +#endif +#ifdef SHA256 + register_hash (&sha256_desc); +#endif +#ifdef SHA384 + register_hash (&sha384_desc); +#endif +#ifdef SHA512 + register_hash (&sha512_desc); +#endif +#ifdef RIPEMD128 + register_hash (&rmd128_desc); +#endif +#ifdef RIPEMD160 + register_hash (&rmd160_desc); +#endif +#ifdef WHIRLPOOL + register_hash (&whirlpool_desc); +#endif + +register_prng(&yarrow_desc); +rng_make_prng(128, find_prng("yarrow"), &prng, NULL); +} + +int time_keysched(void) +{ + unsigned long x, i, y1; + ulong64 t1, c1; + symmetric_key skey; + int kl; + int (*func) (const unsigned char *, int , int , symmetric_key *); + unsigned char key[MAXBLOCKSIZE]; + + printf ("\n\nKey Schedule Time Trials for the Symmetric Ciphers:\n(Times are cycles per key)\n"); + no_results = 0; + for (x = 0; cipher_descriptor[x].name != NULL; x++) { +#define DO1(k) func(k, kl, 0, &skey); + + func = cipher_descriptor[x].setup; + kl = cipher_descriptor[x].min_key_length; + c1 = (ulong64)-1; + for (y1 = 0; y1 < KTIMES; y1++) { + yarrow_read(key, kl, &prng); + t_start(); + DO1(key); + t1 = t_read(); + c1 = (t1 > c1) ? c1 : t1; + } + t1 = c1 - skew; + results[no_results].spd1 = results[no_results].avg = t1; + results[no_results++].id = x; + printf("."); fflush(stdout); + +#undef DO1 + } + tally_results(0); + + return 0; +} + +int time_cipher(void) +{ + unsigned long x, y1; + ulong64 t1, t2, c1, c2, a1, a2; + symmetric_key skey; + void (*func) (const unsigned char *, unsigned char *, symmetric_key *); + unsigned char key[MAXBLOCKSIZE], pt[MAXBLOCKSIZE]; + + + printf ("\n\nECB Time Trials for the Symmetric Ciphers:\n"); + no_results = 0; + 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 + + func = cipher_descriptor[x].ecb_encrypt; + c1 = c2 = (ulong64)-1; + for (y1 = 0; y1 < TIMES; y1++) { + t_start(); + DO1; + t1 = t_read(); + DO2; + t2 = t_read(); + t2 -= t1; + + c1 = (t1 > c1 ? c1 : t1); + c2 = (t2 > c2 ? c2 : t2); + } + a1 = c2 - c1 - skew; + + + func = cipher_descriptor[x].ecb_decrypt; + c1 = c2 = (ulong64)-1; + for (y1 = 0; y1 < TIMES; y1++) { + t_start(); + DO1; + t1 = t_read(); + DO2; + t2 = t_read(); + t2 -= t1; + + c1 = (t1 > c1 ? c1 : t1); + c2 = (t2 > c2 ? c2 : t2); + } + a2 = c2 - c1 - skew; + + results[no_results].id = x; + results[no_results].spd1 = a1/cipher_descriptor[x].block_length; + results[no_results].spd2 = a2/cipher_descriptor[x].block_length;; + results[no_results].avg = (results[no_results].spd1 + results[no_results].spd2+1)/2; + ++no_results; + printf("."); fflush(stdout); + +#undef DO2 +#undef DO1 + } + tally_results(1); + + return 0; +} + +int time_hash(void) +{ + unsigned long x, y1, len; + ulong64 t1, t2, c1, c2; + hash_state md; + int (*func)(hash_state *, const unsigned char *, unsigned long); + unsigned char pt[MAXBLOCKSIZE]; + + + printf ("\n\nHASH Time Trials for:\n"); + no_results = 0; + for (x = 0; hash_descriptor[x].name != NULL; x++) { + hash_descriptor[x].init(&md); + +#define DO1 func(&md,pt,len); +#define DO2 DO1 DO1 + + func = hash_descriptor[x].process; + len = hash_descriptor[x].blocksize; + + c1 = c2 = (ulong64)-1; + for (y1 = 0; y1 < TIMES; y1++) { + t_start(); + DO1; + t1 = t_read(); + DO2; + t2 = t_read() - t1; + c1 = (t1 > c1) ? c1 : t1; + c2 = (t2 > c2) ? c2 : t2; + } + t1 = c2 - c1 - skew; + t1 = ((t1 * CONST64(1000))) / ((ulong64)hash_descriptor[x].blocksize); + results[no_results].id = x; + results[no_results].spd1 = results[no_results].avg = t1; + ++no_results; + printf("."); fflush(stdout); +#undef DO2 +#undef DO1 + } + tally_results(2); + + return 0; +} + +int main(void) +{ + reg_algs(); + + printf("Timings for ciphers and hashes. Times are listed as cycles per byte processed.\n\n"); + +// init_timer(); + time_cipher(); + time_keysched(); + time_hash(); + + return EXIT_SUCCESS; +} + diff --git a/des.c b/des.c new file mode 100644 index 0000000..090c594 --- /dev/null +++ b/des.c @@ -0,0 +1,1813 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* 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 ulong32 bytebit[8] = +{ + 0200, 0100, 040, 020, 010, 04, 02, 01 +}; + +static const ulong32 bigbyte[24] = +{ + 0x800000UL, 0x400000UL, 0x200000UL, 0x100000UL, + 0x80000UL, 0x40000UL, 0x20000UL, 0x10000UL, + 0x8000UL, 0x4000UL, 0x2000UL, 0x1000UL, + 0x800UL, 0x400UL, 0x200UL, 0x100UL, + 0x80UL, 0x40UL, 0x20UL, 0x10UL, + 0x8UL, 0x4UL, 0x2UL, 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 ulong32 SP1[64] = +{ + 0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL, + 0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL, + 0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL, + 0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL, + 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL, + 0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL, + 0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL, + 0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL, + 0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL, + 0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL, + 0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL, + 0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL, + 0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL, + 0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL, + 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL, + 0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL +}; + +static const ulong32 SP2[64] = +{ + 0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL, + 0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL, + 0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL, + 0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL, + 0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL, + 0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL, + 0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL, + 0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL, + 0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL, + 0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL, + 0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL, + 0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL, + 0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL, + 0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL, + 0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL, + 0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL +}; + +static const ulong32 SP3[64] = +{ + 0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL, + 0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL, + 0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL, + 0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL, + 0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL, + 0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL, + 0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL, + 0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL, + 0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL, + 0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL, + 0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL, + 0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL, + 0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL, + 0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL, + 0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL, + 0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL +}; + +static const ulong32 SP4[64] = +{ + 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, + 0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL, + 0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL, + 0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL, + 0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL, + 0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL, + 0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL, + 0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL, + 0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL, + 0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL, + 0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL, + 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, + 0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL, + 0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL, + 0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL, + 0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL +}; + +static const ulong32 SP5[64] = +{ + 0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL, + 0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL, + 0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL, + 0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL, + 0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL, + 0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL, + 0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL, + 0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL, + 0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL, + 0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL, + 0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL, + 0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL, + 0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL, + 0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL, + 0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL, + 0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL +}; + +static const ulong32 SP6[64] = +{ + 0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL, + 0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL, + 0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL, + 0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, + 0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL, + 0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL, + 0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL, + 0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL, + 0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL, + 0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL, + 0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, + 0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL, + 0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL, + 0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL, + 0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL, + 0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL +}; + +static const ulong32 SP7[64] = +{ + 0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL, + 0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL, + 0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL, + 0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL, + 0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL, + 0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL, + 0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL, + 0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL, + 0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL, + 0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL, + 0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL, + 0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL, + 0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL, + 0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL, + 0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL, + 0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL +}; + +static const ulong32 SP8[64] = +{ + 0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL, + 0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL, + 0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL, + 0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL, + 0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL, + 0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL, + 0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL, + 0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL, + 0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL, + 0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL, + 0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL, + 0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL, + 0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL, + 0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL, + 0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL, + 0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL +}; + +#ifndef SMALL_CODE + +static const ulong64 des_ip[8][256] = { + +{ CONST64(0x0000000000000000), CONST64(0x0000001000000000), CONST64(0x0000000000000010), CONST64(0x0000001000000010), + CONST64(0x0000100000000000), CONST64(0x0000101000000000), CONST64(0x0000100000000010), CONST64(0x0000101000000010), + CONST64(0x0000000000001000), CONST64(0x0000001000001000), CONST64(0x0000000000001010), CONST64(0x0000001000001010), + CONST64(0x0000100000001000), CONST64(0x0000101000001000), CONST64(0x0000100000001010), CONST64(0x0000101000001010), + CONST64(0x0010000000000000), CONST64(0x0010001000000000), CONST64(0x0010000000000010), CONST64(0x0010001000000010), + CONST64(0x0010100000000000), CONST64(0x0010101000000000), CONST64(0x0010100000000010), CONST64(0x0010101000000010), + CONST64(0x0010000000001000), CONST64(0x0010001000001000), CONST64(0x0010000000001010), CONST64(0x0010001000001010), + CONST64(0x0010100000001000), CONST64(0x0010101000001000), CONST64(0x0010100000001010), CONST64(0x0010101000001010), + CONST64(0x0000000000100000), CONST64(0x0000001000100000), CONST64(0x0000000000100010), CONST64(0x0000001000100010), + CONST64(0x0000100000100000), CONST64(0x0000101000100000), CONST64(0x0000100000100010), CONST64(0x0000101000100010), + CONST64(0x0000000000101000), CONST64(0x0000001000101000), CONST64(0x0000000000101010), CONST64(0x0000001000101010), + CONST64(0x0000100000101000), CONST64(0x0000101000101000), CONST64(0x0000100000101010), CONST64(0x0000101000101010), + CONST64(0x0010000000100000), CONST64(0x0010001000100000), CONST64(0x0010000000100010), CONST64(0x0010001000100010), + CONST64(0x0010100000100000), CONST64(0x0010101000100000), CONST64(0x0010100000100010), CONST64(0x0010101000100010), + CONST64(0x0010000000101000), CONST64(0x0010001000101000), CONST64(0x0010000000101010), CONST64(0x0010001000101010), + CONST64(0x0010100000101000), CONST64(0x0010101000101000), CONST64(0x0010100000101010), CONST64(0x0010101000101010), + CONST64(0x1000000000000000), CONST64(0x1000001000000000), CONST64(0x1000000000000010), CONST64(0x1000001000000010), + CONST64(0x1000100000000000), CONST64(0x1000101000000000), CONST64(0x1000100000000010), CONST64(0x1000101000000010), + CONST64(0x1000000000001000), CONST64(0x1000001000001000), CONST64(0x1000000000001010), CONST64(0x1000001000001010), + CONST64(0x1000100000001000), CONST64(0x1000101000001000), CONST64(0x1000100000001010), CONST64(0x1000101000001010), + CONST64(0x1010000000000000), CONST64(0x1010001000000000), CONST64(0x1010000000000010), CONST64(0x1010001000000010), + CONST64(0x1010100000000000), CONST64(0x1010101000000000), CONST64(0x1010100000000010), CONST64(0x1010101000000010), + CONST64(0x1010000000001000), CONST64(0x1010001000001000), CONST64(0x1010000000001010), CONST64(0x1010001000001010), + CONST64(0x1010100000001000), CONST64(0x1010101000001000), CONST64(0x1010100000001010), CONST64(0x1010101000001010), + CONST64(0x1000000000100000), CONST64(0x1000001000100000), CONST64(0x1000000000100010), CONST64(0x1000001000100010), + CONST64(0x1000100000100000), CONST64(0x1000101000100000), CONST64(0x1000100000100010), CONST64(0x1000101000100010), + CONST64(0x1000000000101000), CONST64(0x1000001000101000), CONST64(0x1000000000101010), CONST64(0x1000001000101010), + CONST64(0x1000100000101000), CONST64(0x1000101000101000), CONST64(0x1000100000101010), CONST64(0x1000101000101010), + CONST64(0x1010000000100000), CONST64(0x1010001000100000), CONST64(0x1010000000100010), CONST64(0x1010001000100010), + CONST64(0x1010100000100000), CONST64(0x1010101000100000), CONST64(0x1010100000100010), CONST64(0x1010101000100010), + CONST64(0x1010000000101000), CONST64(0x1010001000101000), CONST64(0x1010000000101010), CONST64(0x1010001000101010), + CONST64(0x1010100000101000), CONST64(0x1010101000101000), CONST64(0x1010100000101010), CONST64(0x1010101000101010), + CONST64(0x0000000010000000), CONST64(0x0000001010000000), CONST64(0x0000000010000010), CONST64(0x0000001010000010), + CONST64(0x0000100010000000), CONST64(0x0000101010000000), CONST64(0x0000100010000010), CONST64(0x0000101010000010), + CONST64(0x0000000010001000), CONST64(0x0000001010001000), CONST64(0x0000000010001010), CONST64(0x0000001010001010), + CONST64(0x0000100010001000), CONST64(0x0000101010001000), CONST64(0x0000100010001010), CONST64(0x0000101010001010), + CONST64(0x0010000010000000), CONST64(0x0010001010000000), CONST64(0x0010000010000010), CONST64(0x0010001010000010), + CONST64(0x0010100010000000), CONST64(0x0010101010000000), CONST64(0x0010100010000010), CONST64(0x0010101010000010), + CONST64(0x0010000010001000), CONST64(0x0010001010001000), CONST64(0x0010000010001010), CONST64(0x0010001010001010), + CONST64(0x0010100010001000), CONST64(0x0010101010001000), CONST64(0x0010100010001010), CONST64(0x0010101010001010), + CONST64(0x0000000010100000), CONST64(0x0000001010100000), CONST64(0x0000000010100010), CONST64(0x0000001010100010), + CONST64(0x0000100010100000), CONST64(0x0000101010100000), CONST64(0x0000100010100010), CONST64(0x0000101010100010), + CONST64(0x0000000010101000), CONST64(0x0000001010101000), CONST64(0x0000000010101010), CONST64(0x0000001010101010), + CONST64(0x0000100010101000), CONST64(0x0000101010101000), CONST64(0x0000100010101010), CONST64(0x0000101010101010), + CONST64(0x0010000010100000), CONST64(0x0010001010100000), CONST64(0x0010000010100010), CONST64(0x0010001010100010), + CONST64(0x0010100010100000), CONST64(0x0010101010100000), CONST64(0x0010100010100010), CONST64(0x0010101010100010), + CONST64(0x0010000010101000), CONST64(0x0010001010101000), CONST64(0x0010000010101010), CONST64(0x0010001010101010), + CONST64(0x0010100010101000), CONST64(0x0010101010101000), CONST64(0x0010100010101010), CONST64(0x0010101010101010), + CONST64(0x1000000010000000), CONST64(0x1000001010000000), CONST64(0x1000000010000010), CONST64(0x1000001010000010), + CONST64(0x1000100010000000), CONST64(0x1000101010000000), CONST64(0x1000100010000010), CONST64(0x1000101010000010), + CONST64(0x1000000010001000), CONST64(0x1000001010001000), CONST64(0x1000000010001010), CONST64(0x1000001010001010), + CONST64(0x1000100010001000), CONST64(0x1000101010001000), CONST64(0x1000100010001010), CONST64(0x1000101010001010), + CONST64(0x1010000010000000), CONST64(0x1010001010000000), CONST64(0x1010000010000010), CONST64(0x1010001010000010), + CONST64(0x1010100010000000), CONST64(0x1010101010000000), CONST64(0x1010100010000010), CONST64(0x1010101010000010), + CONST64(0x1010000010001000), CONST64(0x1010001010001000), CONST64(0x1010000010001010), CONST64(0x1010001010001010), + CONST64(0x1010100010001000), CONST64(0x1010101010001000), CONST64(0x1010100010001010), CONST64(0x1010101010001010), + CONST64(0x1000000010100000), CONST64(0x1000001010100000), CONST64(0x1000000010100010), CONST64(0x1000001010100010), + CONST64(0x1000100010100000), CONST64(0x1000101010100000), CONST64(0x1000100010100010), CONST64(0x1000101010100010), + CONST64(0x1000000010101000), CONST64(0x1000001010101000), CONST64(0x1000000010101010), CONST64(0x1000001010101010), + CONST64(0x1000100010101000), CONST64(0x1000101010101000), CONST64(0x1000100010101010), CONST64(0x1000101010101010), + CONST64(0x1010000010100000), CONST64(0x1010001010100000), CONST64(0x1010000010100010), CONST64(0x1010001010100010), + CONST64(0x1010100010100000), CONST64(0x1010101010100000), CONST64(0x1010100010100010), CONST64(0x1010101010100010), + CONST64(0x1010000010101000), CONST64(0x1010001010101000), CONST64(0x1010000010101010), CONST64(0x1010001010101010), + CONST64(0x1010100010101000), CONST64(0x1010101010101000), CONST64(0x1010100010101010), CONST64(0x1010101010101010) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000000800000000), CONST64(0x0000000000000008), CONST64(0x0000000800000008), + CONST64(0x0000080000000000), CONST64(0x0000080800000000), CONST64(0x0000080000000008), CONST64(0x0000080800000008), + CONST64(0x0000000000000800), CONST64(0x0000000800000800), CONST64(0x0000000000000808), CONST64(0x0000000800000808), + CONST64(0x0000080000000800), CONST64(0x0000080800000800), CONST64(0x0000080000000808), CONST64(0x0000080800000808), + CONST64(0x0008000000000000), CONST64(0x0008000800000000), CONST64(0x0008000000000008), CONST64(0x0008000800000008), + CONST64(0x0008080000000000), CONST64(0x0008080800000000), CONST64(0x0008080000000008), CONST64(0x0008080800000008), + CONST64(0x0008000000000800), CONST64(0x0008000800000800), CONST64(0x0008000000000808), CONST64(0x0008000800000808), + CONST64(0x0008080000000800), CONST64(0x0008080800000800), CONST64(0x0008080000000808), CONST64(0x0008080800000808), + CONST64(0x0000000000080000), CONST64(0x0000000800080000), CONST64(0x0000000000080008), CONST64(0x0000000800080008), + CONST64(0x0000080000080000), CONST64(0x0000080800080000), CONST64(0x0000080000080008), CONST64(0x0000080800080008), + CONST64(0x0000000000080800), CONST64(0x0000000800080800), CONST64(0x0000000000080808), CONST64(0x0000000800080808), + CONST64(0x0000080000080800), CONST64(0x0000080800080800), CONST64(0x0000080000080808), CONST64(0x0000080800080808), + CONST64(0x0008000000080000), CONST64(0x0008000800080000), CONST64(0x0008000000080008), CONST64(0x0008000800080008), + CONST64(0x0008080000080000), CONST64(0x0008080800080000), CONST64(0x0008080000080008), CONST64(0x0008080800080008), + CONST64(0x0008000000080800), CONST64(0x0008000800080800), CONST64(0x0008000000080808), CONST64(0x0008000800080808), + CONST64(0x0008080000080800), CONST64(0x0008080800080800), CONST64(0x0008080000080808), CONST64(0x0008080800080808), + CONST64(0x0800000000000000), CONST64(0x0800000800000000), CONST64(0x0800000000000008), CONST64(0x0800000800000008), + CONST64(0x0800080000000000), CONST64(0x0800080800000000), CONST64(0x0800080000000008), CONST64(0x0800080800000008), + CONST64(0x0800000000000800), CONST64(0x0800000800000800), CONST64(0x0800000000000808), CONST64(0x0800000800000808), + CONST64(0x0800080000000800), CONST64(0x0800080800000800), CONST64(0x0800080000000808), CONST64(0x0800080800000808), + CONST64(0x0808000000000000), CONST64(0x0808000800000000), CONST64(0x0808000000000008), CONST64(0x0808000800000008), + CONST64(0x0808080000000000), CONST64(0x0808080800000000), CONST64(0x0808080000000008), CONST64(0x0808080800000008), + CONST64(0x0808000000000800), CONST64(0x0808000800000800), CONST64(0x0808000000000808), CONST64(0x0808000800000808), + CONST64(0x0808080000000800), CONST64(0x0808080800000800), CONST64(0x0808080000000808), CONST64(0x0808080800000808), + CONST64(0x0800000000080000), CONST64(0x0800000800080000), CONST64(0x0800000000080008), CONST64(0x0800000800080008), + CONST64(0x0800080000080000), CONST64(0x0800080800080000), CONST64(0x0800080000080008), CONST64(0x0800080800080008), + CONST64(0x0800000000080800), CONST64(0x0800000800080800), CONST64(0x0800000000080808), CONST64(0x0800000800080808), + CONST64(0x0800080000080800), CONST64(0x0800080800080800), CONST64(0x0800080000080808), CONST64(0x0800080800080808), + CONST64(0x0808000000080000), CONST64(0x0808000800080000), CONST64(0x0808000000080008), CONST64(0x0808000800080008), + CONST64(0x0808080000080000), CONST64(0x0808080800080000), CONST64(0x0808080000080008), CONST64(0x0808080800080008), + CONST64(0x0808000000080800), CONST64(0x0808000800080800), CONST64(0x0808000000080808), CONST64(0x0808000800080808), + CONST64(0x0808080000080800), CONST64(0x0808080800080800), CONST64(0x0808080000080808), CONST64(0x0808080800080808), + CONST64(0x0000000008000000), CONST64(0x0000000808000000), CONST64(0x0000000008000008), CONST64(0x0000000808000008), + CONST64(0x0000080008000000), CONST64(0x0000080808000000), CONST64(0x0000080008000008), CONST64(0x0000080808000008), + CONST64(0x0000000008000800), CONST64(0x0000000808000800), CONST64(0x0000000008000808), CONST64(0x0000000808000808), + CONST64(0x0000080008000800), CONST64(0x0000080808000800), CONST64(0x0000080008000808), CONST64(0x0000080808000808), + CONST64(0x0008000008000000), CONST64(0x0008000808000000), CONST64(0x0008000008000008), CONST64(0x0008000808000008), + CONST64(0x0008080008000000), CONST64(0x0008080808000000), CONST64(0x0008080008000008), CONST64(0x0008080808000008), + CONST64(0x0008000008000800), CONST64(0x0008000808000800), CONST64(0x0008000008000808), CONST64(0x0008000808000808), + CONST64(0x0008080008000800), CONST64(0x0008080808000800), CONST64(0x0008080008000808), CONST64(0x0008080808000808), + CONST64(0x0000000008080000), CONST64(0x0000000808080000), CONST64(0x0000000008080008), CONST64(0x0000000808080008), + CONST64(0x0000080008080000), CONST64(0x0000080808080000), CONST64(0x0000080008080008), CONST64(0x0000080808080008), + CONST64(0x0000000008080800), CONST64(0x0000000808080800), CONST64(0x0000000008080808), CONST64(0x0000000808080808), + CONST64(0x0000080008080800), CONST64(0x0000080808080800), CONST64(0x0000080008080808), CONST64(0x0000080808080808), + CONST64(0x0008000008080000), CONST64(0x0008000808080000), CONST64(0x0008000008080008), CONST64(0x0008000808080008), + CONST64(0x0008080008080000), CONST64(0x0008080808080000), CONST64(0x0008080008080008), CONST64(0x0008080808080008), + CONST64(0x0008000008080800), CONST64(0x0008000808080800), CONST64(0x0008000008080808), CONST64(0x0008000808080808), + CONST64(0x0008080008080800), CONST64(0x0008080808080800), CONST64(0x0008080008080808), CONST64(0x0008080808080808), + CONST64(0x0800000008000000), CONST64(0x0800000808000000), CONST64(0x0800000008000008), CONST64(0x0800000808000008), + CONST64(0x0800080008000000), CONST64(0x0800080808000000), CONST64(0x0800080008000008), CONST64(0x0800080808000008), + CONST64(0x0800000008000800), CONST64(0x0800000808000800), CONST64(0x0800000008000808), CONST64(0x0800000808000808), + CONST64(0x0800080008000800), CONST64(0x0800080808000800), CONST64(0x0800080008000808), CONST64(0x0800080808000808), + CONST64(0x0808000008000000), CONST64(0x0808000808000000), CONST64(0x0808000008000008), CONST64(0x0808000808000008), + CONST64(0x0808080008000000), CONST64(0x0808080808000000), CONST64(0x0808080008000008), CONST64(0x0808080808000008), + CONST64(0x0808000008000800), CONST64(0x0808000808000800), CONST64(0x0808000008000808), CONST64(0x0808000808000808), + CONST64(0x0808080008000800), CONST64(0x0808080808000800), CONST64(0x0808080008000808), CONST64(0x0808080808000808), + CONST64(0x0800000008080000), CONST64(0x0800000808080000), CONST64(0x0800000008080008), CONST64(0x0800000808080008), + CONST64(0x0800080008080000), CONST64(0x0800080808080000), CONST64(0x0800080008080008), CONST64(0x0800080808080008), + CONST64(0x0800000008080800), CONST64(0x0800000808080800), CONST64(0x0800000008080808), CONST64(0x0800000808080808), + CONST64(0x0800080008080800), CONST64(0x0800080808080800), CONST64(0x0800080008080808), CONST64(0x0800080808080808), + CONST64(0x0808000008080000), CONST64(0x0808000808080000), CONST64(0x0808000008080008), CONST64(0x0808000808080008), + CONST64(0x0808080008080000), CONST64(0x0808080808080000), CONST64(0x0808080008080008), CONST64(0x0808080808080008), + CONST64(0x0808000008080800), CONST64(0x0808000808080800), CONST64(0x0808000008080808), CONST64(0x0808000808080808), + CONST64(0x0808080008080800), CONST64(0x0808080808080800), CONST64(0x0808080008080808), CONST64(0x0808080808080808) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000000400000000), CONST64(0x0000000000000004), CONST64(0x0000000400000004), + CONST64(0x0000040000000000), CONST64(0x0000040400000000), CONST64(0x0000040000000004), CONST64(0x0000040400000004), + CONST64(0x0000000000000400), CONST64(0x0000000400000400), CONST64(0x0000000000000404), CONST64(0x0000000400000404), + CONST64(0x0000040000000400), CONST64(0x0000040400000400), CONST64(0x0000040000000404), CONST64(0x0000040400000404), + CONST64(0x0004000000000000), CONST64(0x0004000400000000), CONST64(0x0004000000000004), CONST64(0x0004000400000004), + CONST64(0x0004040000000000), CONST64(0x0004040400000000), CONST64(0x0004040000000004), CONST64(0x0004040400000004), + CONST64(0x0004000000000400), CONST64(0x0004000400000400), CONST64(0x0004000000000404), CONST64(0x0004000400000404), + CONST64(0x0004040000000400), CONST64(0x0004040400000400), CONST64(0x0004040000000404), CONST64(0x0004040400000404), + CONST64(0x0000000000040000), CONST64(0x0000000400040000), CONST64(0x0000000000040004), CONST64(0x0000000400040004), + CONST64(0x0000040000040000), CONST64(0x0000040400040000), CONST64(0x0000040000040004), CONST64(0x0000040400040004), + CONST64(0x0000000000040400), CONST64(0x0000000400040400), CONST64(0x0000000000040404), CONST64(0x0000000400040404), + CONST64(0x0000040000040400), CONST64(0x0000040400040400), CONST64(0x0000040000040404), CONST64(0x0000040400040404), + CONST64(0x0004000000040000), CONST64(0x0004000400040000), CONST64(0x0004000000040004), CONST64(0x0004000400040004), + CONST64(0x0004040000040000), CONST64(0x0004040400040000), CONST64(0x0004040000040004), CONST64(0x0004040400040004), + CONST64(0x0004000000040400), CONST64(0x0004000400040400), CONST64(0x0004000000040404), CONST64(0x0004000400040404), + CONST64(0x0004040000040400), CONST64(0x0004040400040400), CONST64(0x0004040000040404), CONST64(0x0004040400040404), + CONST64(0x0400000000000000), CONST64(0x0400000400000000), CONST64(0x0400000000000004), CONST64(0x0400000400000004), + CONST64(0x0400040000000000), CONST64(0x0400040400000000), CONST64(0x0400040000000004), CONST64(0x0400040400000004), + CONST64(0x0400000000000400), CONST64(0x0400000400000400), CONST64(0x0400000000000404), CONST64(0x0400000400000404), + CONST64(0x0400040000000400), CONST64(0x0400040400000400), CONST64(0x0400040000000404), CONST64(0x0400040400000404), + CONST64(0x0404000000000000), CONST64(0x0404000400000000), CONST64(0x0404000000000004), CONST64(0x0404000400000004), + CONST64(0x0404040000000000), CONST64(0x0404040400000000), CONST64(0x0404040000000004), CONST64(0x0404040400000004), + CONST64(0x0404000000000400), CONST64(0x0404000400000400), CONST64(0x0404000000000404), CONST64(0x0404000400000404), + CONST64(0x0404040000000400), CONST64(0x0404040400000400), CONST64(0x0404040000000404), CONST64(0x0404040400000404), + CONST64(0x0400000000040000), CONST64(0x0400000400040000), CONST64(0x0400000000040004), CONST64(0x0400000400040004), + CONST64(0x0400040000040000), CONST64(0x0400040400040000), CONST64(0x0400040000040004), CONST64(0x0400040400040004), + CONST64(0x0400000000040400), CONST64(0x0400000400040400), CONST64(0x0400000000040404), CONST64(0x0400000400040404), + CONST64(0x0400040000040400), CONST64(0x0400040400040400), CONST64(0x0400040000040404), CONST64(0x0400040400040404), + CONST64(0x0404000000040000), CONST64(0x0404000400040000), CONST64(0x0404000000040004), CONST64(0x0404000400040004), + CONST64(0x0404040000040000), CONST64(0x0404040400040000), CONST64(0x0404040000040004), CONST64(0x0404040400040004), + CONST64(0x0404000000040400), CONST64(0x0404000400040400), CONST64(0x0404000000040404), CONST64(0x0404000400040404), + CONST64(0x0404040000040400), CONST64(0x0404040400040400), CONST64(0x0404040000040404), CONST64(0x0404040400040404), + CONST64(0x0000000004000000), CONST64(0x0000000404000000), CONST64(0x0000000004000004), CONST64(0x0000000404000004), + CONST64(0x0000040004000000), CONST64(0x0000040404000000), CONST64(0x0000040004000004), CONST64(0x0000040404000004), + CONST64(0x0000000004000400), CONST64(0x0000000404000400), CONST64(0x0000000004000404), CONST64(0x0000000404000404), + CONST64(0x0000040004000400), CONST64(0x0000040404000400), CONST64(0x0000040004000404), CONST64(0x0000040404000404), + CONST64(0x0004000004000000), CONST64(0x0004000404000000), CONST64(0x0004000004000004), CONST64(0x0004000404000004), + CONST64(0x0004040004000000), CONST64(0x0004040404000000), CONST64(0x0004040004000004), CONST64(0x0004040404000004), + CONST64(0x0004000004000400), CONST64(0x0004000404000400), CONST64(0x0004000004000404), CONST64(0x0004000404000404), + CONST64(0x0004040004000400), CONST64(0x0004040404000400), CONST64(0x0004040004000404), CONST64(0x0004040404000404), + CONST64(0x0000000004040000), CONST64(0x0000000404040000), CONST64(0x0000000004040004), CONST64(0x0000000404040004), + CONST64(0x0000040004040000), CONST64(0x0000040404040000), CONST64(0x0000040004040004), CONST64(0x0000040404040004), + CONST64(0x0000000004040400), CONST64(0x0000000404040400), CONST64(0x0000000004040404), CONST64(0x0000000404040404), + CONST64(0x0000040004040400), CONST64(0x0000040404040400), CONST64(0x0000040004040404), CONST64(0x0000040404040404), + CONST64(0x0004000004040000), CONST64(0x0004000404040000), CONST64(0x0004000004040004), CONST64(0x0004000404040004), + CONST64(0x0004040004040000), CONST64(0x0004040404040000), CONST64(0x0004040004040004), CONST64(0x0004040404040004), + CONST64(0x0004000004040400), CONST64(0x0004000404040400), CONST64(0x0004000004040404), CONST64(0x0004000404040404), + CONST64(0x0004040004040400), CONST64(0x0004040404040400), CONST64(0x0004040004040404), CONST64(0x0004040404040404), + CONST64(0x0400000004000000), CONST64(0x0400000404000000), CONST64(0x0400000004000004), CONST64(0x0400000404000004), + CONST64(0x0400040004000000), CONST64(0x0400040404000000), CONST64(0x0400040004000004), CONST64(0x0400040404000004), + CONST64(0x0400000004000400), CONST64(0x0400000404000400), CONST64(0x0400000004000404), CONST64(0x0400000404000404), + CONST64(0x0400040004000400), CONST64(0x0400040404000400), CONST64(0x0400040004000404), CONST64(0x0400040404000404), + CONST64(0x0404000004000000), CONST64(0x0404000404000000), CONST64(0x0404000004000004), CONST64(0x0404000404000004), + CONST64(0x0404040004000000), CONST64(0x0404040404000000), CONST64(0x0404040004000004), CONST64(0x0404040404000004), + CONST64(0x0404000004000400), CONST64(0x0404000404000400), CONST64(0x0404000004000404), CONST64(0x0404000404000404), + CONST64(0x0404040004000400), CONST64(0x0404040404000400), CONST64(0x0404040004000404), CONST64(0x0404040404000404), + CONST64(0x0400000004040000), CONST64(0x0400000404040000), CONST64(0x0400000004040004), CONST64(0x0400000404040004), + CONST64(0x0400040004040000), CONST64(0x0400040404040000), CONST64(0x0400040004040004), CONST64(0x0400040404040004), + CONST64(0x0400000004040400), CONST64(0x0400000404040400), CONST64(0x0400000004040404), CONST64(0x0400000404040404), + CONST64(0x0400040004040400), CONST64(0x0400040404040400), CONST64(0x0400040004040404), CONST64(0x0400040404040404), + CONST64(0x0404000004040000), CONST64(0x0404000404040000), CONST64(0x0404000004040004), CONST64(0x0404000404040004), + CONST64(0x0404040004040000), CONST64(0x0404040404040000), CONST64(0x0404040004040004), CONST64(0x0404040404040004), + CONST64(0x0404000004040400), CONST64(0x0404000404040400), CONST64(0x0404000004040404), CONST64(0x0404000404040404), + CONST64(0x0404040004040400), CONST64(0x0404040404040400), CONST64(0x0404040004040404), CONST64(0x0404040404040404) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000000200000000), CONST64(0x0000000000000002), CONST64(0x0000000200000002), + CONST64(0x0000020000000000), CONST64(0x0000020200000000), CONST64(0x0000020000000002), CONST64(0x0000020200000002), + CONST64(0x0000000000000200), CONST64(0x0000000200000200), CONST64(0x0000000000000202), CONST64(0x0000000200000202), + CONST64(0x0000020000000200), CONST64(0x0000020200000200), CONST64(0x0000020000000202), CONST64(0x0000020200000202), + CONST64(0x0002000000000000), CONST64(0x0002000200000000), CONST64(0x0002000000000002), CONST64(0x0002000200000002), + CONST64(0x0002020000000000), CONST64(0x0002020200000000), CONST64(0x0002020000000002), CONST64(0x0002020200000002), + CONST64(0x0002000000000200), CONST64(0x0002000200000200), CONST64(0x0002000000000202), CONST64(0x0002000200000202), + CONST64(0x0002020000000200), CONST64(0x0002020200000200), CONST64(0x0002020000000202), CONST64(0x0002020200000202), + CONST64(0x0000000000020000), CONST64(0x0000000200020000), CONST64(0x0000000000020002), CONST64(0x0000000200020002), + CONST64(0x0000020000020000), CONST64(0x0000020200020000), CONST64(0x0000020000020002), CONST64(0x0000020200020002), + CONST64(0x0000000000020200), CONST64(0x0000000200020200), CONST64(0x0000000000020202), CONST64(0x0000000200020202), + CONST64(0x0000020000020200), CONST64(0x0000020200020200), CONST64(0x0000020000020202), CONST64(0x0000020200020202), + CONST64(0x0002000000020000), CONST64(0x0002000200020000), CONST64(0x0002000000020002), CONST64(0x0002000200020002), + CONST64(0x0002020000020000), CONST64(0x0002020200020000), CONST64(0x0002020000020002), CONST64(0x0002020200020002), + CONST64(0x0002000000020200), CONST64(0x0002000200020200), CONST64(0x0002000000020202), CONST64(0x0002000200020202), + CONST64(0x0002020000020200), CONST64(0x0002020200020200), CONST64(0x0002020000020202), CONST64(0x0002020200020202), + CONST64(0x0200000000000000), CONST64(0x0200000200000000), CONST64(0x0200000000000002), CONST64(0x0200000200000002), + CONST64(0x0200020000000000), CONST64(0x0200020200000000), CONST64(0x0200020000000002), CONST64(0x0200020200000002), + CONST64(0x0200000000000200), CONST64(0x0200000200000200), CONST64(0x0200000000000202), CONST64(0x0200000200000202), + CONST64(0x0200020000000200), CONST64(0x0200020200000200), CONST64(0x0200020000000202), CONST64(0x0200020200000202), + CONST64(0x0202000000000000), CONST64(0x0202000200000000), CONST64(0x0202000000000002), CONST64(0x0202000200000002), + CONST64(0x0202020000000000), CONST64(0x0202020200000000), CONST64(0x0202020000000002), CONST64(0x0202020200000002), + CONST64(0x0202000000000200), CONST64(0x0202000200000200), CONST64(0x0202000000000202), CONST64(0x0202000200000202), + CONST64(0x0202020000000200), CONST64(0x0202020200000200), CONST64(0x0202020000000202), CONST64(0x0202020200000202), + CONST64(0x0200000000020000), CONST64(0x0200000200020000), CONST64(0x0200000000020002), CONST64(0x0200000200020002), + CONST64(0x0200020000020000), CONST64(0x0200020200020000), CONST64(0x0200020000020002), CONST64(0x0200020200020002), + CONST64(0x0200000000020200), CONST64(0x0200000200020200), CONST64(0x0200000000020202), CONST64(0x0200000200020202), + CONST64(0x0200020000020200), CONST64(0x0200020200020200), CONST64(0x0200020000020202), CONST64(0x0200020200020202), + CONST64(0x0202000000020000), CONST64(0x0202000200020000), CONST64(0x0202000000020002), CONST64(0x0202000200020002), + CONST64(0x0202020000020000), CONST64(0x0202020200020000), CONST64(0x0202020000020002), CONST64(0x0202020200020002), + CONST64(0x0202000000020200), CONST64(0x0202000200020200), CONST64(0x0202000000020202), CONST64(0x0202000200020202), + CONST64(0x0202020000020200), CONST64(0x0202020200020200), CONST64(0x0202020000020202), CONST64(0x0202020200020202), + CONST64(0x0000000002000000), CONST64(0x0000000202000000), CONST64(0x0000000002000002), CONST64(0x0000000202000002), + CONST64(0x0000020002000000), CONST64(0x0000020202000000), CONST64(0x0000020002000002), CONST64(0x0000020202000002), + CONST64(0x0000000002000200), CONST64(0x0000000202000200), CONST64(0x0000000002000202), CONST64(0x0000000202000202), + CONST64(0x0000020002000200), CONST64(0x0000020202000200), CONST64(0x0000020002000202), CONST64(0x0000020202000202), + CONST64(0x0002000002000000), CONST64(0x0002000202000000), CONST64(0x0002000002000002), CONST64(0x0002000202000002), + CONST64(0x0002020002000000), CONST64(0x0002020202000000), CONST64(0x0002020002000002), CONST64(0x0002020202000002), + CONST64(0x0002000002000200), CONST64(0x0002000202000200), CONST64(0x0002000002000202), CONST64(0x0002000202000202), + CONST64(0x0002020002000200), CONST64(0x0002020202000200), CONST64(0x0002020002000202), CONST64(0x0002020202000202), + CONST64(0x0000000002020000), CONST64(0x0000000202020000), CONST64(0x0000000002020002), CONST64(0x0000000202020002), + CONST64(0x0000020002020000), CONST64(0x0000020202020000), CONST64(0x0000020002020002), CONST64(0x0000020202020002), + CONST64(0x0000000002020200), CONST64(0x0000000202020200), CONST64(0x0000000002020202), CONST64(0x0000000202020202), + CONST64(0x0000020002020200), CONST64(0x0000020202020200), CONST64(0x0000020002020202), CONST64(0x0000020202020202), + CONST64(0x0002000002020000), CONST64(0x0002000202020000), CONST64(0x0002000002020002), CONST64(0x0002000202020002), + CONST64(0x0002020002020000), CONST64(0x0002020202020000), CONST64(0x0002020002020002), CONST64(0x0002020202020002), + CONST64(0x0002000002020200), CONST64(0x0002000202020200), CONST64(0x0002000002020202), CONST64(0x0002000202020202), + CONST64(0x0002020002020200), CONST64(0x0002020202020200), CONST64(0x0002020002020202), CONST64(0x0002020202020202), + CONST64(0x0200000002000000), CONST64(0x0200000202000000), CONST64(0x0200000002000002), CONST64(0x0200000202000002), + CONST64(0x0200020002000000), CONST64(0x0200020202000000), CONST64(0x0200020002000002), CONST64(0x0200020202000002), + CONST64(0x0200000002000200), CONST64(0x0200000202000200), CONST64(0x0200000002000202), CONST64(0x0200000202000202), + CONST64(0x0200020002000200), CONST64(0x0200020202000200), CONST64(0x0200020002000202), CONST64(0x0200020202000202), + CONST64(0x0202000002000000), CONST64(0x0202000202000000), CONST64(0x0202000002000002), CONST64(0x0202000202000002), + CONST64(0x0202020002000000), CONST64(0x0202020202000000), CONST64(0x0202020002000002), CONST64(0x0202020202000002), + CONST64(0x0202000002000200), CONST64(0x0202000202000200), CONST64(0x0202000002000202), CONST64(0x0202000202000202), + CONST64(0x0202020002000200), CONST64(0x0202020202000200), CONST64(0x0202020002000202), CONST64(0x0202020202000202), + CONST64(0x0200000002020000), CONST64(0x0200000202020000), CONST64(0x0200000002020002), CONST64(0x0200000202020002), + CONST64(0x0200020002020000), CONST64(0x0200020202020000), CONST64(0x0200020002020002), CONST64(0x0200020202020002), + CONST64(0x0200000002020200), CONST64(0x0200000202020200), CONST64(0x0200000002020202), CONST64(0x0200000202020202), + CONST64(0x0200020002020200), CONST64(0x0200020202020200), CONST64(0x0200020002020202), CONST64(0x0200020202020202), + CONST64(0x0202000002020000), CONST64(0x0202000202020000), CONST64(0x0202000002020002), CONST64(0x0202000202020002), + CONST64(0x0202020002020000), CONST64(0x0202020202020000), CONST64(0x0202020002020002), CONST64(0x0202020202020002), + CONST64(0x0202000002020200), CONST64(0x0202000202020200), CONST64(0x0202000002020202), CONST64(0x0202000202020202), + CONST64(0x0202020002020200), CONST64(0x0202020202020200), CONST64(0x0202020002020202), CONST64(0x0202020202020202) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000010000000000), CONST64(0x0000000000000100), CONST64(0x0000010000000100), + CONST64(0x0001000000000000), CONST64(0x0001010000000000), CONST64(0x0001000000000100), CONST64(0x0001010000000100), + CONST64(0x0000000000010000), CONST64(0x0000010000010000), CONST64(0x0000000000010100), CONST64(0x0000010000010100), + CONST64(0x0001000000010000), CONST64(0x0001010000010000), CONST64(0x0001000000010100), CONST64(0x0001010000010100), + CONST64(0x0100000000000000), CONST64(0x0100010000000000), CONST64(0x0100000000000100), CONST64(0x0100010000000100), + CONST64(0x0101000000000000), CONST64(0x0101010000000000), CONST64(0x0101000000000100), CONST64(0x0101010000000100), + CONST64(0x0100000000010000), CONST64(0x0100010000010000), CONST64(0x0100000000010100), CONST64(0x0100010000010100), + CONST64(0x0101000000010000), CONST64(0x0101010000010000), CONST64(0x0101000000010100), CONST64(0x0101010000010100), + CONST64(0x0000000001000000), CONST64(0x0000010001000000), CONST64(0x0000000001000100), CONST64(0x0000010001000100), + CONST64(0x0001000001000000), CONST64(0x0001010001000000), CONST64(0x0001000001000100), CONST64(0x0001010001000100), + CONST64(0x0000000001010000), CONST64(0x0000010001010000), CONST64(0x0000000001010100), CONST64(0x0000010001010100), + CONST64(0x0001000001010000), CONST64(0x0001010001010000), CONST64(0x0001000001010100), CONST64(0x0001010001010100), + CONST64(0x0100000001000000), CONST64(0x0100010001000000), CONST64(0x0100000001000100), CONST64(0x0100010001000100), + CONST64(0x0101000001000000), CONST64(0x0101010001000000), CONST64(0x0101000001000100), CONST64(0x0101010001000100), + CONST64(0x0100000001010000), CONST64(0x0100010001010000), CONST64(0x0100000001010100), CONST64(0x0100010001010100), + CONST64(0x0101000001010000), CONST64(0x0101010001010000), CONST64(0x0101000001010100), CONST64(0x0101010001010100), + CONST64(0x0000000100000000), CONST64(0x0000010100000000), CONST64(0x0000000100000100), CONST64(0x0000010100000100), + CONST64(0x0001000100000000), CONST64(0x0001010100000000), CONST64(0x0001000100000100), CONST64(0x0001010100000100), + CONST64(0x0000000100010000), CONST64(0x0000010100010000), CONST64(0x0000000100010100), CONST64(0x0000010100010100), + CONST64(0x0001000100010000), CONST64(0x0001010100010000), CONST64(0x0001000100010100), CONST64(0x0001010100010100), + CONST64(0x0100000100000000), CONST64(0x0100010100000000), CONST64(0x0100000100000100), CONST64(0x0100010100000100), + CONST64(0x0101000100000000), CONST64(0x0101010100000000), CONST64(0x0101000100000100), CONST64(0x0101010100000100), + CONST64(0x0100000100010000), CONST64(0x0100010100010000), CONST64(0x0100000100010100), CONST64(0x0100010100010100), + CONST64(0x0101000100010000), CONST64(0x0101010100010000), CONST64(0x0101000100010100), CONST64(0x0101010100010100), + CONST64(0x0000000101000000), CONST64(0x0000010101000000), CONST64(0x0000000101000100), CONST64(0x0000010101000100), + CONST64(0x0001000101000000), CONST64(0x0001010101000000), CONST64(0x0001000101000100), CONST64(0x0001010101000100), + CONST64(0x0000000101010000), CONST64(0x0000010101010000), CONST64(0x0000000101010100), CONST64(0x0000010101010100), + CONST64(0x0001000101010000), CONST64(0x0001010101010000), CONST64(0x0001000101010100), CONST64(0x0001010101010100), + CONST64(0x0100000101000000), CONST64(0x0100010101000000), CONST64(0x0100000101000100), CONST64(0x0100010101000100), + CONST64(0x0101000101000000), CONST64(0x0101010101000000), CONST64(0x0101000101000100), CONST64(0x0101010101000100), + CONST64(0x0100000101010000), CONST64(0x0100010101010000), CONST64(0x0100000101010100), CONST64(0x0100010101010100), + CONST64(0x0101000101010000), CONST64(0x0101010101010000), CONST64(0x0101000101010100), CONST64(0x0101010101010100), + CONST64(0x0000000000000001), CONST64(0x0000010000000001), CONST64(0x0000000000000101), CONST64(0x0000010000000101), + CONST64(0x0001000000000001), CONST64(0x0001010000000001), CONST64(0x0001000000000101), CONST64(0x0001010000000101), + CONST64(0x0000000000010001), CONST64(0x0000010000010001), CONST64(0x0000000000010101), CONST64(0x0000010000010101), + CONST64(0x0001000000010001), CONST64(0x0001010000010001), CONST64(0x0001000000010101), CONST64(0x0001010000010101), + CONST64(0x0100000000000001), CONST64(0x0100010000000001), CONST64(0x0100000000000101), CONST64(0x0100010000000101), + CONST64(0x0101000000000001), CONST64(0x0101010000000001), CONST64(0x0101000000000101), CONST64(0x0101010000000101), + CONST64(0x0100000000010001), CONST64(0x0100010000010001), CONST64(0x0100000000010101), CONST64(0x0100010000010101), + CONST64(0x0101000000010001), CONST64(0x0101010000010001), CONST64(0x0101000000010101), CONST64(0x0101010000010101), + CONST64(0x0000000001000001), CONST64(0x0000010001000001), CONST64(0x0000000001000101), CONST64(0x0000010001000101), + CONST64(0x0001000001000001), CONST64(0x0001010001000001), CONST64(0x0001000001000101), CONST64(0x0001010001000101), + CONST64(0x0000000001010001), CONST64(0x0000010001010001), CONST64(0x0000000001010101), CONST64(0x0000010001010101), + CONST64(0x0001000001010001), CONST64(0x0001010001010001), CONST64(0x0001000001010101), CONST64(0x0001010001010101), + CONST64(0x0100000001000001), CONST64(0x0100010001000001), CONST64(0x0100000001000101), CONST64(0x0100010001000101), + CONST64(0x0101000001000001), CONST64(0x0101010001000001), CONST64(0x0101000001000101), CONST64(0x0101010001000101), + CONST64(0x0100000001010001), CONST64(0x0100010001010001), CONST64(0x0100000001010101), CONST64(0x0100010001010101), + CONST64(0x0101000001010001), CONST64(0x0101010001010001), CONST64(0x0101000001010101), CONST64(0x0101010001010101), + CONST64(0x0000000100000001), CONST64(0x0000010100000001), CONST64(0x0000000100000101), CONST64(0x0000010100000101), + CONST64(0x0001000100000001), CONST64(0x0001010100000001), CONST64(0x0001000100000101), CONST64(0x0001010100000101), + CONST64(0x0000000100010001), CONST64(0x0000010100010001), CONST64(0x0000000100010101), CONST64(0x0000010100010101), + CONST64(0x0001000100010001), CONST64(0x0001010100010001), CONST64(0x0001000100010101), CONST64(0x0001010100010101), + CONST64(0x0100000100000001), CONST64(0x0100010100000001), CONST64(0x0100000100000101), CONST64(0x0100010100000101), + CONST64(0x0101000100000001), CONST64(0x0101010100000001), CONST64(0x0101000100000101), CONST64(0x0101010100000101), + CONST64(0x0100000100010001), CONST64(0x0100010100010001), CONST64(0x0100000100010101), CONST64(0x0100010100010101), + CONST64(0x0101000100010001), CONST64(0x0101010100010001), CONST64(0x0101000100010101), CONST64(0x0101010100010101), + CONST64(0x0000000101000001), CONST64(0x0000010101000001), CONST64(0x0000000101000101), CONST64(0x0000010101000101), + CONST64(0x0001000101000001), CONST64(0x0001010101000001), CONST64(0x0001000101000101), CONST64(0x0001010101000101), + CONST64(0x0000000101010001), CONST64(0x0000010101010001), CONST64(0x0000000101010101), CONST64(0x0000010101010101), + CONST64(0x0001000101010001), CONST64(0x0001010101010001), CONST64(0x0001000101010101), CONST64(0x0001010101010101), + CONST64(0x0100000101000001), CONST64(0x0100010101000001), CONST64(0x0100000101000101), CONST64(0x0100010101000101), + CONST64(0x0101000101000001), CONST64(0x0101010101000001), CONST64(0x0101000101000101), CONST64(0x0101010101000101), + CONST64(0x0100000101010001), CONST64(0x0100010101010001), CONST64(0x0100000101010101), CONST64(0x0100010101010101), + CONST64(0x0101000101010001), CONST64(0x0101010101010001), CONST64(0x0101000101010101), CONST64(0x0101010101010101) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000008000000000), CONST64(0x0000000000000080), CONST64(0x0000008000000080), + CONST64(0x0000800000000000), CONST64(0x0000808000000000), CONST64(0x0000800000000080), CONST64(0x0000808000000080), + CONST64(0x0000000000008000), CONST64(0x0000008000008000), CONST64(0x0000000000008080), CONST64(0x0000008000008080), + CONST64(0x0000800000008000), CONST64(0x0000808000008000), CONST64(0x0000800000008080), CONST64(0x0000808000008080), + CONST64(0x0080000000000000), CONST64(0x0080008000000000), CONST64(0x0080000000000080), CONST64(0x0080008000000080), + CONST64(0x0080800000000000), CONST64(0x0080808000000000), CONST64(0x0080800000000080), CONST64(0x0080808000000080), + CONST64(0x0080000000008000), CONST64(0x0080008000008000), CONST64(0x0080000000008080), CONST64(0x0080008000008080), + CONST64(0x0080800000008000), CONST64(0x0080808000008000), CONST64(0x0080800000008080), CONST64(0x0080808000008080), + CONST64(0x0000000000800000), CONST64(0x0000008000800000), CONST64(0x0000000000800080), CONST64(0x0000008000800080), + CONST64(0x0000800000800000), CONST64(0x0000808000800000), CONST64(0x0000800000800080), CONST64(0x0000808000800080), + CONST64(0x0000000000808000), CONST64(0x0000008000808000), CONST64(0x0000000000808080), CONST64(0x0000008000808080), + CONST64(0x0000800000808000), CONST64(0x0000808000808000), CONST64(0x0000800000808080), CONST64(0x0000808000808080), + CONST64(0x0080000000800000), CONST64(0x0080008000800000), CONST64(0x0080000000800080), CONST64(0x0080008000800080), + CONST64(0x0080800000800000), CONST64(0x0080808000800000), CONST64(0x0080800000800080), CONST64(0x0080808000800080), + CONST64(0x0080000000808000), CONST64(0x0080008000808000), CONST64(0x0080000000808080), CONST64(0x0080008000808080), + CONST64(0x0080800000808000), CONST64(0x0080808000808000), CONST64(0x0080800000808080), CONST64(0x0080808000808080), + CONST64(0x8000000000000000), CONST64(0x8000008000000000), CONST64(0x8000000000000080), CONST64(0x8000008000000080), + CONST64(0x8000800000000000), CONST64(0x8000808000000000), CONST64(0x8000800000000080), CONST64(0x8000808000000080), + CONST64(0x8000000000008000), CONST64(0x8000008000008000), CONST64(0x8000000000008080), CONST64(0x8000008000008080), + CONST64(0x8000800000008000), CONST64(0x8000808000008000), CONST64(0x8000800000008080), CONST64(0x8000808000008080), + CONST64(0x8080000000000000), CONST64(0x8080008000000000), CONST64(0x8080000000000080), CONST64(0x8080008000000080), + CONST64(0x8080800000000000), CONST64(0x8080808000000000), CONST64(0x8080800000000080), CONST64(0x8080808000000080), + CONST64(0x8080000000008000), CONST64(0x8080008000008000), CONST64(0x8080000000008080), CONST64(0x8080008000008080), + CONST64(0x8080800000008000), CONST64(0x8080808000008000), CONST64(0x8080800000008080), CONST64(0x8080808000008080), + CONST64(0x8000000000800000), CONST64(0x8000008000800000), CONST64(0x8000000000800080), CONST64(0x8000008000800080), + CONST64(0x8000800000800000), CONST64(0x8000808000800000), CONST64(0x8000800000800080), CONST64(0x8000808000800080), + CONST64(0x8000000000808000), CONST64(0x8000008000808000), CONST64(0x8000000000808080), CONST64(0x8000008000808080), + CONST64(0x8000800000808000), CONST64(0x8000808000808000), CONST64(0x8000800000808080), CONST64(0x8000808000808080), + CONST64(0x8080000000800000), CONST64(0x8080008000800000), CONST64(0x8080000000800080), CONST64(0x8080008000800080), + CONST64(0x8080800000800000), CONST64(0x8080808000800000), CONST64(0x8080800000800080), CONST64(0x8080808000800080), + CONST64(0x8080000000808000), CONST64(0x8080008000808000), CONST64(0x8080000000808080), CONST64(0x8080008000808080), + CONST64(0x8080800000808000), CONST64(0x8080808000808000), CONST64(0x8080800000808080), CONST64(0x8080808000808080), + CONST64(0x0000000080000000), CONST64(0x0000008080000000), CONST64(0x0000000080000080), CONST64(0x0000008080000080), + CONST64(0x0000800080000000), CONST64(0x0000808080000000), CONST64(0x0000800080000080), CONST64(0x0000808080000080), + CONST64(0x0000000080008000), CONST64(0x0000008080008000), CONST64(0x0000000080008080), CONST64(0x0000008080008080), + CONST64(0x0000800080008000), CONST64(0x0000808080008000), CONST64(0x0000800080008080), CONST64(0x0000808080008080), + CONST64(0x0080000080000000), CONST64(0x0080008080000000), CONST64(0x0080000080000080), CONST64(0x0080008080000080), + CONST64(0x0080800080000000), CONST64(0x0080808080000000), CONST64(0x0080800080000080), CONST64(0x0080808080000080), + CONST64(0x0080000080008000), CONST64(0x0080008080008000), CONST64(0x0080000080008080), CONST64(0x0080008080008080), + CONST64(0x0080800080008000), CONST64(0x0080808080008000), CONST64(0x0080800080008080), CONST64(0x0080808080008080), + CONST64(0x0000000080800000), CONST64(0x0000008080800000), CONST64(0x0000000080800080), CONST64(0x0000008080800080), + CONST64(0x0000800080800000), CONST64(0x0000808080800000), CONST64(0x0000800080800080), CONST64(0x0000808080800080), + CONST64(0x0000000080808000), CONST64(0x0000008080808000), CONST64(0x0000000080808080), CONST64(0x0000008080808080), + CONST64(0x0000800080808000), CONST64(0x0000808080808000), CONST64(0x0000800080808080), CONST64(0x0000808080808080), + CONST64(0x0080000080800000), CONST64(0x0080008080800000), CONST64(0x0080000080800080), CONST64(0x0080008080800080), + CONST64(0x0080800080800000), CONST64(0x0080808080800000), CONST64(0x0080800080800080), CONST64(0x0080808080800080), + CONST64(0x0080000080808000), CONST64(0x0080008080808000), CONST64(0x0080000080808080), CONST64(0x0080008080808080), + CONST64(0x0080800080808000), CONST64(0x0080808080808000), CONST64(0x0080800080808080), CONST64(0x0080808080808080), + CONST64(0x8000000080000000), CONST64(0x8000008080000000), CONST64(0x8000000080000080), CONST64(0x8000008080000080), + CONST64(0x8000800080000000), CONST64(0x8000808080000000), CONST64(0x8000800080000080), CONST64(0x8000808080000080), + CONST64(0x8000000080008000), CONST64(0x8000008080008000), CONST64(0x8000000080008080), CONST64(0x8000008080008080), + CONST64(0x8000800080008000), CONST64(0x8000808080008000), CONST64(0x8000800080008080), CONST64(0x8000808080008080), + CONST64(0x8080000080000000), CONST64(0x8080008080000000), CONST64(0x8080000080000080), CONST64(0x8080008080000080), + CONST64(0x8080800080000000), CONST64(0x8080808080000000), CONST64(0x8080800080000080), CONST64(0x8080808080000080), + CONST64(0x8080000080008000), CONST64(0x8080008080008000), CONST64(0x8080000080008080), CONST64(0x8080008080008080), + CONST64(0x8080800080008000), CONST64(0x8080808080008000), CONST64(0x8080800080008080), CONST64(0x8080808080008080), + CONST64(0x8000000080800000), CONST64(0x8000008080800000), CONST64(0x8000000080800080), CONST64(0x8000008080800080), + CONST64(0x8000800080800000), CONST64(0x8000808080800000), CONST64(0x8000800080800080), CONST64(0x8000808080800080), + CONST64(0x8000000080808000), CONST64(0x8000008080808000), CONST64(0x8000000080808080), CONST64(0x8000008080808080), + CONST64(0x8000800080808000), CONST64(0x8000808080808000), CONST64(0x8000800080808080), CONST64(0x8000808080808080), + CONST64(0x8080000080800000), CONST64(0x8080008080800000), CONST64(0x8080000080800080), CONST64(0x8080008080800080), + CONST64(0x8080800080800000), CONST64(0x8080808080800000), CONST64(0x8080800080800080), CONST64(0x8080808080800080), + CONST64(0x8080000080808000), CONST64(0x8080008080808000), CONST64(0x8080000080808080), CONST64(0x8080008080808080), + CONST64(0x8080800080808000), CONST64(0x8080808080808000), CONST64(0x8080800080808080), CONST64(0x8080808080808080) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000004000000000), CONST64(0x0000000000000040), CONST64(0x0000004000000040), + CONST64(0x0000400000000000), CONST64(0x0000404000000000), CONST64(0x0000400000000040), CONST64(0x0000404000000040), + CONST64(0x0000000000004000), CONST64(0x0000004000004000), CONST64(0x0000000000004040), CONST64(0x0000004000004040), + CONST64(0x0000400000004000), CONST64(0x0000404000004000), CONST64(0x0000400000004040), CONST64(0x0000404000004040), + CONST64(0x0040000000000000), CONST64(0x0040004000000000), CONST64(0x0040000000000040), CONST64(0x0040004000000040), + CONST64(0x0040400000000000), CONST64(0x0040404000000000), CONST64(0x0040400000000040), CONST64(0x0040404000000040), + CONST64(0x0040000000004000), CONST64(0x0040004000004000), CONST64(0x0040000000004040), CONST64(0x0040004000004040), + CONST64(0x0040400000004000), CONST64(0x0040404000004000), CONST64(0x0040400000004040), CONST64(0x0040404000004040), + CONST64(0x0000000000400000), CONST64(0x0000004000400000), CONST64(0x0000000000400040), CONST64(0x0000004000400040), + CONST64(0x0000400000400000), CONST64(0x0000404000400000), CONST64(0x0000400000400040), CONST64(0x0000404000400040), + CONST64(0x0000000000404000), CONST64(0x0000004000404000), CONST64(0x0000000000404040), CONST64(0x0000004000404040), + CONST64(0x0000400000404000), CONST64(0x0000404000404000), CONST64(0x0000400000404040), CONST64(0x0000404000404040), + CONST64(0x0040000000400000), CONST64(0x0040004000400000), CONST64(0x0040000000400040), CONST64(0x0040004000400040), + CONST64(0x0040400000400000), CONST64(0x0040404000400000), CONST64(0x0040400000400040), CONST64(0x0040404000400040), + CONST64(0x0040000000404000), CONST64(0x0040004000404000), CONST64(0x0040000000404040), CONST64(0x0040004000404040), + CONST64(0x0040400000404000), CONST64(0x0040404000404000), CONST64(0x0040400000404040), CONST64(0x0040404000404040), + CONST64(0x4000000000000000), CONST64(0x4000004000000000), CONST64(0x4000000000000040), CONST64(0x4000004000000040), + CONST64(0x4000400000000000), CONST64(0x4000404000000000), CONST64(0x4000400000000040), CONST64(0x4000404000000040), + CONST64(0x4000000000004000), CONST64(0x4000004000004000), CONST64(0x4000000000004040), CONST64(0x4000004000004040), + CONST64(0x4000400000004000), CONST64(0x4000404000004000), CONST64(0x4000400000004040), CONST64(0x4000404000004040), + CONST64(0x4040000000000000), CONST64(0x4040004000000000), CONST64(0x4040000000000040), CONST64(0x4040004000000040), + CONST64(0x4040400000000000), CONST64(0x4040404000000000), CONST64(0x4040400000000040), CONST64(0x4040404000000040), + CONST64(0x4040000000004000), CONST64(0x4040004000004000), CONST64(0x4040000000004040), CONST64(0x4040004000004040), + CONST64(0x4040400000004000), CONST64(0x4040404000004000), CONST64(0x4040400000004040), CONST64(0x4040404000004040), + CONST64(0x4000000000400000), CONST64(0x4000004000400000), CONST64(0x4000000000400040), CONST64(0x4000004000400040), + CONST64(0x4000400000400000), CONST64(0x4000404000400000), CONST64(0x4000400000400040), CONST64(0x4000404000400040), + CONST64(0x4000000000404000), CONST64(0x4000004000404000), CONST64(0x4000000000404040), CONST64(0x4000004000404040), + CONST64(0x4000400000404000), CONST64(0x4000404000404000), CONST64(0x4000400000404040), CONST64(0x4000404000404040), + CONST64(0x4040000000400000), CONST64(0x4040004000400000), CONST64(0x4040000000400040), CONST64(0x4040004000400040), + CONST64(0x4040400000400000), CONST64(0x4040404000400000), CONST64(0x4040400000400040), CONST64(0x4040404000400040), + CONST64(0x4040000000404000), CONST64(0x4040004000404000), CONST64(0x4040000000404040), CONST64(0x4040004000404040), + CONST64(0x4040400000404000), CONST64(0x4040404000404000), CONST64(0x4040400000404040), CONST64(0x4040404000404040), + CONST64(0x0000000040000000), CONST64(0x0000004040000000), CONST64(0x0000000040000040), CONST64(0x0000004040000040), + CONST64(0x0000400040000000), CONST64(0x0000404040000000), CONST64(0x0000400040000040), CONST64(0x0000404040000040), + CONST64(0x0000000040004000), CONST64(0x0000004040004000), CONST64(0x0000000040004040), CONST64(0x0000004040004040), + CONST64(0x0000400040004000), CONST64(0x0000404040004000), CONST64(0x0000400040004040), CONST64(0x0000404040004040), + CONST64(0x0040000040000000), CONST64(0x0040004040000000), CONST64(0x0040000040000040), CONST64(0x0040004040000040), + CONST64(0x0040400040000000), CONST64(0x0040404040000000), CONST64(0x0040400040000040), CONST64(0x0040404040000040), + CONST64(0x0040000040004000), CONST64(0x0040004040004000), CONST64(0x0040000040004040), CONST64(0x0040004040004040), + CONST64(0x0040400040004000), CONST64(0x0040404040004000), CONST64(0x0040400040004040), CONST64(0x0040404040004040), + CONST64(0x0000000040400000), CONST64(0x0000004040400000), CONST64(0x0000000040400040), CONST64(0x0000004040400040), + CONST64(0x0000400040400000), CONST64(0x0000404040400000), CONST64(0x0000400040400040), CONST64(0x0000404040400040), + CONST64(0x0000000040404000), CONST64(0x0000004040404000), CONST64(0x0000000040404040), CONST64(0x0000004040404040), + CONST64(0x0000400040404000), CONST64(0x0000404040404000), CONST64(0x0000400040404040), CONST64(0x0000404040404040), + CONST64(0x0040000040400000), CONST64(0x0040004040400000), CONST64(0x0040000040400040), CONST64(0x0040004040400040), + CONST64(0x0040400040400000), CONST64(0x0040404040400000), CONST64(0x0040400040400040), CONST64(0x0040404040400040), + CONST64(0x0040000040404000), CONST64(0x0040004040404000), CONST64(0x0040000040404040), CONST64(0x0040004040404040), + CONST64(0x0040400040404000), CONST64(0x0040404040404000), CONST64(0x0040400040404040), CONST64(0x0040404040404040), + CONST64(0x4000000040000000), CONST64(0x4000004040000000), CONST64(0x4000000040000040), CONST64(0x4000004040000040), + CONST64(0x4000400040000000), CONST64(0x4000404040000000), CONST64(0x4000400040000040), CONST64(0x4000404040000040), + CONST64(0x4000000040004000), CONST64(0x4000004040004000), CONST64(0x4000000040004040), CONST64(0x4000004040004040), + CONST64(0x4000400040004000), CONST64(0x4000404040004000), CONST64(0x4000400040004040), CONST64(0x4000404040004040), + CONST64(0x4040000040000000), CONST64(0x4040004040000000), CONST64(0x4040000040000040), CONST64(0x4040004040000040), + CONST64(0x4040400040000000), CONST64(0x4040404040000000), CONST64(0x4040400040000040), CONST64(0x4040404040000040), + CONST64(0x4040000040004000), CONST64(0x4040004040004000), CONST64(0x4040000040004040), CONST64(0x4040004040004040), + CONST64(0x4040400040004000), CONST64(0x4040404040004000), CONST64(0x4040400040004040), CONST64(0x4040404040004040), + CONST64(0x4000000040400000), CONST64(0x4000004040400000), CONST64(0x4000000040400040), CONST64(0x4000004040400040), + CONST64(0x4000400040400000), CONST64(0x4000404040400000), CONST64(0x4000400040400040), CONST64(0x4000404040400040), + CONST64(0x4000000040404000), CONST64(0x4000004040404000), CONST64(0x4000000040404040), CONST64(0x4000004040404040), + CONST64(0x4000400040404000), CONST64(0x4000404040404000), CONST64(0x4000400040404040), CONST64(0x4000404040404040), + CONST64(0x4040000040400000), CONST64(0x4040004040400000), CONST64(0x4040000040400040), CONST64(0x4040004040400040), + CONST64(0x4040400040400000), CONST64(0x4040404040400000), CONST64(0x4040400040400040), CONST64(0x4040404040400040), + CONST64(0x4040000040404000), CONST64(0x4040004040404000), CONST64(0x4040000040404040), CONST64(0x4040004040404040), + CONST64(0x4040400040404000), CONST64(0x4040404040404000), CONST64(0x4040400040404040), CONST64(0x4040404040404040) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000002000000000), CONST64(0x0000000000000020), CONST64(0x0000002000000020), + CONST64(0x0000200000000000), CONST64(0x0000202000000000), CONST64(0x0000200000000020), CONST64(0x0000202000000020), + CONST64(0x0000000000002000), CONST64(0x0000002000002000), CONST64(0x0000000000002020), CONST64(0x0000002000002020), + CONST64(0x0000200000002000), CONST64(0x0000202000002000), CONST64(0x0000200000002020), CONST64(0x0000202000002020), + CONST64(0x0020000000000000), CONST64(0x0020002000000000), CONST64(0x0020000000000020), CONST64(0x0020002000000020), + CONST64(0x0020200000000000), CONST64(0x0020202000000000), CONST64(0x0020200000000020), CONST64(0x0020202000000020), + CONST64(0x0020000000002000), CONST64(0x0020002000002000), CONST64(0x0020000000002020), CONST64(0x0020002000002020), + CONST64(0x0020200000002000), CONST64(0x0020202000002000), CONST64(0x0020200000002020), CONST64(0x0020202000002020), + CONST64(0x0000000000200000), CONST64(0x0000002000200000), CONST64(0x0000000000200020), CONST64(0x0000002000200020), + CONST64(0x0000200000200000), CONST64(0x0000202000200000), CONST64(0x0000200000200020), CONST64(0x0000202000200020), + CONST64(0x0000000000202000), CONST64(0x0000002000202000), CONST64(0x0000000000202020), CONST64(0x0000002000202020), + CONST64(0x0000200000202000), CONST64(0x0000202000202000), CONST64(0x0000200000202020), CONST64(0x0000202000202020), + CONST64(0x0020000000200000), CONST64(0x0020002000200000), CONST64(0x0020000000200020), CONST64(0x0020002000200020), + CONST64(0x0020200000200000), CONST64(0x0020202000200000), CONST64(0x0020200000200020), CONST64(0x0020202000200020), + CONST64(0x0020000000202000), CONST64(0x0020002000202000), CONST64(0x0020000000202020), CONST64(0x0020002000202020), + CONST64(0x0020200000202000), CONST64(0x0020202000202000), CONST64(0x0020200000202020), CONST64(0x0020202000202020), + CONST64(0x2000000000000000), CONST64(0x2000002000000000), CONST64(0x2000000000000020), CONST64(0x2000002000000020), + CONST64(0x2000200000000000), CONST64(0x2000202000000000), CONST64(0x2000200000000020), CONST64(0x2000202000000020), + CONST64(0x2000000000002000), CONST64(0x2000002000002000), CONST64(0x2000000000002020), CONST64(0x2000002000002020), + CONST64(0x2000200000002000), CONST64(0x2000202000002000), CONST64(0x2000200000002020), CONST64(0x2000202000002020), + CONST64(0x2020000000000000), CONST64(0x2020002000000000), CONST64(0x2020000000000020), CONST64(0x2020002000000020), + CONST64(0x2020200000000000), CONST64(0x2020202000000000), CONST64(0x2020200000000020), CONST64(0x2020202000000020), + CONST64(0x2020000000002000), CONST64(0x2020002000002000), CONST64(0x2020000000002020), CONST64(0x2020002000002020), + CONST64(0x2020200000002000), CONST64(0x2020202000002000), CONST64(0x2020200000002020), CONST64(0x2020202000002020), + CONST64(0x2000000000200000), CONST64(0x2000002000200000), CONST64(0x2000000000200020), CONST64(0x2000002000200020), + CONST64(0x2000200000200000), CONST64(0x2000202000200000), CONST64(0x2000200000200020), CONST64(0x2000202000200020), + CONST64(0x2000000000202000), CONST64(0x2000002000202000), CONST64(0x2000000000202020), CONST64(0x2000002000202020), + CONST64(0x2000200000202000), CONST64(0x2000202000202000), CONST64(0x2000200000202020), CONST64(0x2000202000202020), + CONST64(0x2020000000200000), CONST64(0x2020002000200000), CONST64(0x2020000000200020), CONST64(0x2020002000200020), + CONST64(0x2020200000200000), CONST64(0x2020202000200000), CONST64(0x2020200000200020), CONST64(0x2020202000200020), + CONST64(0x2020000000202000), CONST64(0x2020002000202000), CONST64(0x2020000000202020), CONST64(0x2020002000202020), + CONST64(0x2020200000202000), CONST64(0x2020202000202000), CONST64(0x2020200000202020), CONST64(0x2020202000202020), + CONST64(0x0000000020000000), CONST64(0x0000002020000000), CONST64(0x0000000020000020), CONST64(0x0000002020000020), + CONST64(0x0000200020000000), CONST64(0x0000202020000000), CONST64(0x0000200020000020), CONST64(0x0000202020000020), + CONST64(0x0000000020002000), CONST64(0x0000002020002000), CONST64(0x0000000020002020), CONST64(0x0000002020002020), + CONST64(0x0000200020002000), CONST64(0x0000202020002000), CONST64(0x0000200020002020), CONST64(0x0000202020002020), + CONST64(0x0020000020000000), CONST64(0x0020002020000000), CONST64(0x0020000020000020), CONST64(0x0020002020000020), + CONST64(0x0020200020000000), CONST64(0x0020202020000000), CONST64(0x0020200020000020), CONST64(0x0020202020000020), + CONST64(0x0020000020002000), CONST64(0x0020002020002000), CONST64(0x0020000020002020), CONST64(0x0020002020002020), + CONST64(0x0020200020002000), CONST64(0x0020202020002000), CONST64(0x0020200020002020), CONST64(0x0020202020002020), + CONST64(0x0000000020200000), CONST64(0x0000002020200000), CONST64(0x0000000020200020), CONST64(0x0000002020200020), + CONST64(0x0000200020200000), CONST64(0x0000202020200000), CONST64(0x0000200020200020), CONST64(0x0000202020200020), + CONST64(0x0000000020202000), CONST64(0x0000002020202000), CONST64(0x0000000020202020), CONST64(0x0000002020202020), + CONST64(0x0000200020202000), CONST64(0x0000202020202000), CONST64(0x0000200020202020), CONST64(0x0000202020202020), + CONST64(0x0020000020200000), CONST64(0x0020002020200000), CONST64(0x0020000020200020), CONST64(0x0020002020200020), + CONST64(0x0020200020200000), CONST64(0x0020202020200000), CONST64(0x0020200020200020), CONST64(0x0020202020200020), + CONST64(0x0020000020202000), CONST64(0x0020002020202000), CONST64(0x0020000020202020), CONST64(0x0020002020202020), + CONST64(0x0020200020202000), CONST64(0x0020202020202000), CONST64(0x0020200020202020), CONST64(0x0020202020202020), + CONST64(0x2000000020000000), CONST64(0x2000002020000000), CONST64(0x2000000020000020), CONST64(0x2000002020000020), + CONST64(0x2000200020000000), CONST64(0x2000202020000000), CONST64(0x2000200020000020), CONST64(0x2000202020000020), + CONST64(0x2000000020002000), CONST64(0x2000002020002000), CONST64(0x2000000020002020), CONST64(0x2000002020002020), + CONST64(0x2000200020002000), CONST64(0x2000202020002000), CONST64(0x2000200020002020), CONST64(0x2000202020002020), + CONST64(0x2020000020000000), CONST64(0x2020002020000000), CONST64(0x2020000020000020), CONST64(0x2020002020000020), + CONST64(0x2020200020000000), CONST64(0x2020202020000000), CONST64(0x2020200020000020), CONST64(0x2020202020000020), + CONST64(0x2020000020002000), CONST64(0x2020002020002000), CONST64(0x2020000020002020), CONST64(0x2020002020002020), + CONST64(0x2020200020002000), CONST64(0x2020202020002000), CONST64(0x2020200020002020), CONST64(0x2020202020002020), + CONST64(0x2000000020200000), CONST64(0x2000002020200000), CONST64(0x2000000020200020), CONST64(0x2000002020200020), + CONST64(0x2000200020200000), CONST64(0x2000202020200000), CONST64(0x2000200020200020), CONST64(0x2000202020200020), + CONST64(0x2000000020202000), CONST64(0x2000002020202000), CONST64(0x2000000020202020), CONST64(0x2000002020202020), + CONST64(0x2000200020202000), CONST64(0x2000202020202000), CONST64(0x2000200020202020), CONST64(0x2000202020202020), + CONST64(0x2020000020200000), CONST64(0x2020002020200000), CONST64(0x2020000020200020), CONST64(0x2020002020200020), + CONST64(0x2020200020200000), CONST64(0x2020202020200000), CONST64(0x2020200020200020), CONST64(0x2020202020200020), + CONST64(0x2020000020202000), CONST64(0x2020002020202000), CONST64(0x2020000020202020), CONST64(0x2020002020202020), + CONST64(0x2020200020202000), CONST64(0x2020202020202000), CONST64(0x2020200020202020), CONST64(0x2020202020202020) + }}; + +static const ulong64 des_fp[8][256] = { + +{ CONST64(0x0000000000000000), CONST64(0x0000008000000000), CONST64(0x0000000002000000), CONST64(0x0000008002000000), + CONST64(0x0000000000020000), CONST64(0x0000008000020000), CONST64(0x0000000002020000), CONST64(0x0000008002020000), + CONST64(0x0000000000000200), CONST64(0x0000008000000200), CONST64(0x0000000002000200), CONST64(0x0000008002000200), + CONST64(0x0000000000020200), CONST64(0x0000008000020200), CONST64(0x0000000002020200), CONST64(0x0000008002020200), + CONST64(0x0000000000000002), CONST64(0x0000008000000002), CONST64(0x0000000002000002), CONST64(0x0000008002000002), + CONST64(0x0000000000020002), CONST64(0x0000008000020002), CONST64(0x0000000002020002), CONST64(0x0000008002020002), + CONST64(0x0000000000000202), CONST64(0x0000008000000202), CONST64(0x0000000002000202), CONST64(0x0000008002000202), + CONST64(0x0000000000020202), CONST64(0x0000008000020202), CONST64(0x0000000002020202), CONST64(0x0000008002020202), + CONST64(0x0200000000000000), CONST64(0x0200008000000000), CONST64(0x0200000002000000), CONST64(0x0200008002000000), + CONST64(0x0200000000020000), CONST64(0x0200008000020000), CONST64(0x0200000002020000), CONST64(0x0200008002020000), + CONST64(0x0200000000000200), CONST64(0x0200008000000200), CONST64(0x0200000002000200), CONST64(0x0200008002000200), + CONST64(0x0200000000020200), CONST64(0x0200008000020200), CONST64(0x0200000002020200), CONST64(0x0200008002020200), + CONST64(0x0200000000000002), CONST64(0x0200008000000002), CONST64(0x0200000002000002), CONST64(0x0200008002000002), + CONST64(0x0200000000020002), CONST64(0x0200008000020002), CONST64(0x0200000002020002), CONST64(0x0200008002020002), + CONST64(0x0200000000000202), CONST64(0x0200008000000202), CONST64(0x0200000002000202), CONST64(0x0200008002000202), + CONST64(0x0200000000020202), CONST64(0x0200008000020202), CONST64(0x0200000002020202), CONST64(0x0200008002020202), + CONST64(0x0002000000000000), CONST64(0x0002008000000000), CONST64(0x0002000002000000), CONST64(0x0002008002000000), + CONST64(0x0002000000020000), CONST64(0x0002008000020000), CONST64(0x0002000002020000), CONST64(0x0002008002020000), + CONST64(0x0002000000000200), CONST64(0x0002008000000200), CONST64(0x0002000002000200), CONST64(0x0002008002000200), + CONST64(0x0002000000020200), CONST64(0x0002008000020200), CONST64(0x0002000002020200), CONST64(0x0002008002020200), + CONST64(0x0002000000000002), CONST64(0x0002008000000002), CONST64(0x0002000002000002), CONST64(0x0002008002000002), + CONST64(0x0002000000020002), CONST64(0x0002008000020002), CONST64(0x0002000002020002), CONST64(0x0002008002020002), + CONST64(0x0002000000000202), CONST64(0x0002008000000202), CONST64(0x0002000002000202), CONST64(0x0002008002000202), + CONST64(0x0002000000020202), CONST64(0x0002008000020202), CONST64(0x0002000002020202), CONST64(0x0002008002020202), + CONST64(0x0202000000000000), CONST64(0x0202008000000000), CONST64(0x0202000002000000), CONST64(0x0202008002000000), + CONST64(0x0202000000020000), CONST64(0x0202008000020000), CONST64(0x0202000002020000), CONST64(0x0202008002020000), + CONST64(0x0202000000000200), CONST64(0x0202008000000200), CONST64(0x0202000002000200), CONST64(0x0202008002000200), + CONST64(0x0202000000020200), CONST64(0x0202008000020200), CONST64(0x0202000002020200), CONST64(0x0202008002020200), + CONST64(0x0202000000000002), CONST64(0x0202008000000002), CONST64(0x0202000002000002), CONST64(0x0202008002000002), + CONST64(0x0202000000020002), CONST64(0x0202008000020002), CONST64(0x0202000002020002), CONST64(0x0202008002020002), + CONST64(0x0202000000000202), CONST64(0x0202008000000202), CONST64(0x0202000002000202), CONST64(0x0202008002000202), + CONST64(0x0202000000020202), CONST64(0x0202008000020202), CONST64(0x0202000002020202), CONST64(0x0202008002020202), + CONST64(0x0000020000000000), CONST64(0x0000028000000000), CONST64(0x0000020002000000), CONST64(0x0000028002000000), + CONST64(0x0000020000020000), CONST64(0x0000028000020000), CONST64(0x0000020002020000), CONST64(0x0000028002020000), + CONST64(0x0000020000000200), CONST64(0x0000028000000200), CONST64(0x0000020002000200), CONST64(0x0000028002000200), + CONST64(0x0000020000020200), CONST64(0x0000028000020200), CONST64(0x0000020002020200), CONST64(0x0000028002020200), + CONST64(0x0000020000000002), CONST64(0x0000028000000002), CONST64(0x0000020002000002), CONST64(0x0000028002000002), + CONST64(0x0000020000020002), CONST64(0x0000028000020002), CONST64(0x0000020002020002), CONST64(0x0000028002020002), + CONST64(0x0000020000000202), CONST64(0x0000028000000202), CONST64(0x0000020002000202), CONST64(0x0000028002000202), + CONST64(0x0000020000020202), CONST64(0x0000028000020202), CONST64(0x0000020002020202), CONST64(0x0000028002020202), + CONST64(0x0200020000000000), CONST64(0x0200028000000000), CONST64(0x0200020002000000), CONST64(0x0200028002000000), + CONST64(0x0200020000020000), CONST64(0x0200028000020000), CONST64(0x0200020002020000), CONST64(0x0200028002020000), + CONST64(0x0200020000000200), CONST64(0x0200028000000200), CONST64(0x0200020002000200), CONST64(0x0200028002000200), + CONST64(0x0200020000020200), CONST64(0x0200028000020200), CONST64(0x0200020002020200), CONST64(0x0200028002020200), + CONST64(0x0200020000000002), CONST64(0x0200028000000002), CONST64(0x0200020002000002), CONST64(0x0200028002000002), + CONST64(0x0200020000020002), CONST64(0x0200028000020002), CONST64(0x0200020002020002), CONST64(0x0200028002020002), + CONST64(0x0200020000000202), CONST64(0x0200028000000202), CONST64(0x0200020002000202), CONST64(0x0200028002000202), + CONST64(0x0200020000020202), CONST64(0x0200028000020202), CONST64(0x0200020002020202), CONST64(0x0200028002020202), + CONST64(0x0002020000000000), CONST64(0x0002028000000000), CONST64(0x0002020002000000), CONST64(0x0002028002000000), + CONST64(0x0002020000020000), CONST64(0x0002028000020000), CONST64(0x0002020002020000), CONST64(0x0002028002020000), + CONST64(0x0002020000000200), CONST64(0x0002028000000200), CONST64(0x0002020002000200), CONST64(0x0002028002000200), + CONST64(0x0002020000020200), CONST64(0x0002028000020200), CONST64(0x0002020002020200), CONST64(0x0002028002020200), + CONST64(0x0002020000000002), CONST64(0x0002028000000002), CONST64(0x0002020002000002), CONST64(0x0002028002000002), + CONST64(0x0002020000020002), CONST64(0x0002028000020002), CONST64(0x0002020002020002), CONST64(0x0002028002020002), + CONST64(0x0002020000000202), CONST64(0x0002028000000202), CONST64(0x0002020002000202), CONST64(0x0002028002000202), + CONST64(0x0002020000020202), CONST64(0x0002028000020202), CONST64(0x0002020002020202), CONST64(0x0002028002020202), + CONST64(0x0202020000000000), CONST64(0x0202028000000000), CONST64(0x0202020002000000), CONST64(0x0202028002000000), + CONST64(0x0202020000020000), CONST64(0x0202028000020000), CONST64(0x0202020002020000), CONST64(0x0202028002020000), + CONST64(0x0202020000000200), CONST64(0x0202028000000200), CONST64(0x0202020002000200), CONST64(0x0202028002000200), + CONST64(0x0202020000020200), CONST64(0x0202028000020200), CONST64(0x0202020002020200), CONST64(0x0202028002020200), + CONST64(0x0202020000000002), CONST64(0x0202028000000002), CONST64(0x0202020002000002), CONST64(0x0202028002000002), + CONST64(0x0202020000020002), CONST64(0x0202028000020002), CONST64(0x0202020002020002), CONST64(0x0202028002020002), + CONST64(0x0202020000000202), CONST64(0x0202028000000202), CONST64(0x0202020002000202), CONST64(0x0202028002000202), + CONST64(0x0202020000020202), CONST64(0x0202028000020202), CONST64(0x0202020002020202), CONST64(0x0202028002020202) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000000200000000), CONST64(0x0000000008000000), CONST64(0x0000000208000000), + CONST64(0x0000000000080000), CONST64(0x0000000200080000), CONST64(0x0000000008080000), CONST64(0x0000000208080000), + CONST64(0x0000000000000800), CONST64(0x0000000200000800), CONST64(0x0000000008000800), CONST64(0x0000000208000800), + CONST64(0x0000000000080800), CONST64(0x0000000200080800), CONST64(0x0000000008080800), CONST64(0x0000000208080800), + CONST64(0x0000000000000008), CONST64(0x0000000200000008), CONST64(0x0000000008000008), CONST64(0x0000000208000008), + CONST64(0x0000000000080008), CONST64(0x0000000200080008), CONST64(0x0000000008080008), CONST64(0x0000000208080008), + CONST64(0x0000000000000808), CONST64(0x0000000200000808), CONST64(0x0000000008000808), CONST64(0x0000000208000808), + CONST64(0x0000000000080808), CONST64(0x0000000200080808), CONST64(0x0000000008080808), CONST64(0x0000000208080808), + CONST64(0x0800000000000000), CONST64(0x0800000200000000), CONST64(0x0800000008000000), CONST64(0x0800000208000000), + CONST64(0x0800000000080000), CONST64(0x0800000200080000), CONST64(0x0800000008080000), CONST64(0x0800000208080000), + CONST64(0x0800000000000800), CONST64(0x0800000200000800), CONST64(0x0800000008000800), CONST64(0x0800000208000800), + CONST64(0x0800000000080800), CONST64(0x0800000200080800), CONST64(0x0800000008080800), CONST64(0x0800000208080800), + CONST64(0x0800000000000008), CONST64(0x0800000200000008), CONST64(0x0800000008000008), CONST64(0x0800000208000008), + CONST64(0x0800000000080008), CONST64(0x0800000200080008), CONST64(0x0800000008080008), CONST64(0x0800000208080008), + CONST64(0x0800000000000808), CONST64(0x0800000200000808), CONST64(0x0800000008000808), CONST64(0x0800000208000808), + CONST64(0x0800000000080808), CONST64(0x0800000200080808), CONST64(0x0800000008080808), CONST64(0x0800000208080808), + CONST64(0x0008000000000000), CONST64(0x0008000200000000), CONST64(0x0008000008000000), CONST64(0x0008000208000000), + CONST64(0x0008000000080000), CONST64(0x0008000200080000), CONST64(0x0008000008080000), CONST64(0x0008000208080000), + CONST64(0x0008000000000800), CONST64(0x0008000200000800), CONST64(0x0008000008000800), CONST64(0x0008000208000800), + CONST64(0x0008000000080800), CONST64(0x0008000200080800), CONST64(0x0008000008080800), CONST64(0x0008000208080800), + CONST64(0x0008000000000008), CONST64(0x0008000200000008), CONST64(0x0008000008000008), CONST64(0x0008000208000008), + CONST64(0x0008000000080008), CONST64(0x0008000200080008), CONST64(0x0008000008080008), CONST64(0x0008000208080008), + CONST64(0x0008000000000808), CONST64(0x0008000200000808), CONST64(0x0008000008000808), CONST64(0x0008000208000808), + CONST64(0x0008000000080808), CONST64(0x0008000200080808), CONST64(0x0008000008080808), CONST64(0x0008000208080808), + CONST64(0x0808000000000000), CONST64(0x0808000200000000), CONST64(0x0808000008000000), CONST64(0x0808000208000000), + CONST64(0x0808000000080000), CONST64(0x0808000200080000), CONST64(0x0808000008080000), CONST64(0x0808000208080000), + CONST64(0x0808000000000800), CONST64(0x0808000200000800), CONST64(0x0808000008000800), CONST64(0x0808000208000800), + CONST64(0x0808000000080800), CONST64(0x0808000200080800), CONST64(0x0808000008080800), CONST64(0x0808000208080800), + CONST64(0x0808000000000008), CONST64(0x0808000200000008), CONST64(0x0808000008000008), CONST64(0x0808000208000008), + CONST64(0x0808000000080008), CONST64(0x0808000200080008), CONST64(0x0808000008080008), CONST64(0x0808000208080008), + CONST64(0x0808000000000808), CONST64(0x0808000200000808), CONST64(0x0808000008000808), CONST64(0x0808000208000808), + CONST64(0x0808000000080808), CONST64(0x0808000200080808), CONST64(0x0808000008080808), CONST64(0x0808000208080808), + CONST64(0x0000080000000000), CONST64(0x0000080200000000), CONST64(0x0000080008000000), CONST64(0x0000080208000000), + CONST64(0x0000080000080000), CONST64(0x0000080200080000), CONST64(0x0000080008080000), CONST64(0x0000080208080000), + CONST64(0x0000080000000800), CONST64(0x0000080200000800), CONST64(0x0000080008000800), CONST64(0x0000080208000800), + CONST64(0x0000080000080800), CONST64(0x0000080200080800), CONST64(0x0000080008080800), CONST64(0x0000080208080800), + CONST64(0x0000080000000008), CONST64(0x0000080200000008), CONST64(0x0000080008000008), CONST64(0x0000080208000008), + CONST64(0x0000080000080008), CONST64(0x0000080200080008), CONST64(0x0000080008080008), CONST64(0x0000080208080008), + CONST64(0x0000080000000808), CONST64(0x0000080200000808), CONST64(0x0000080008000808), CONST64(0x0000080208000808), + CONST64(0x0000080000080808), CONST64(0x0000080200080808), CONST64(0x0000080008080808), CONST64(0x0000080208080808), + CONST64(0x0800080000000000), CONST64(0x0800080200000000), CONST64(0x0800080008000000), CONST64(0x0800080208000000), + CONST64(0x0800080000080000), CONST64(0x0800080200080000), CONST64(0x0800080008080000), CONST64(0x0800080208080000), + CONST64(0x0800080000000800), CONST64(0x0800080200000800), CONST64(0x0800080008000800), CONST64(0x0800080208000800), + CONST64(0x0800080000080800), CONST64(0x0800080200080800), CONST64(0x0800080008080800), CONST64(0x0800080208080800), + CONST64(0x0800080000000008), CONST64(0x0800080200000008), CONST64(0x0800080008000008), CONST64(0x0800080208000008), + CONST64(0x0800080000080008), CONST64(0x0800080200080008), CONST64(0x0800080008080008), CONST64(0x0800080208080008), + CONST64(0x0800080000000808), CONST64(0x0800080200000808), CONST64(0x0800080008000808), CONST64(0x0800080208000808), + CONST64(0x0800080000080808), CONST64(0x0800080200080808), CONST64(0x0800080008080808), CONST64(0x0800080208080808), + CONST64(0x0008080000000000), CONST64(0x0008080200000000), CONST64(0x0008080008000000), CONST64(0x0008080208000000), + CONST64(0x0008080000080000), CONST64(0x0008080200080000), CONST64(0x0008080008080000), CONST64(0x0008080208080000), + CONST64(0x0008080000000800), CONST64(0x0008080200000800), CONST64(0x0008080008000800), CONST64(0x0008080208000800), + CONST64(0x0008080000080800), CONST64(0x0008080200080800), CONST64(0x0008080008080800), CONST64(0x0008080208080800), + CONST64(0x0008080000000008), CONST64(0x0008080200000008), CONST64(0x0008080008000008), CONST64(0x0008080208000008), + CONST64(0x0008080000080008), CONST64(0x0008080200080008), CONST64(0x0008080008080008), CONST64(0x0008080208080008), + CONST64(0x0008080000000808), CONST64(0x0008080200000808), CONST64(0x0008080008000808), CONST64(0x0008080208000808), + CONST64(0x0008080000080808), CONST64(0x0008080200080808), CONST64(0x0008080008080808), CONST64(0x0008080208080808), + CONST64(0x0808080000000000), CONST64(0x0808080200000000), CONST64(0x0808080008000000), CONST64(0x0808080208000000), + CONST64(0x0808080000080000), CONST64(0x0808080200080000), CONST64(0x0808080008080000), CONST64(0x0808080208080000), + CONST64(0x0808080000000800), CONST64(0x0808080200000800), CONST64(0x0808080008000800), CONST64(0x0808080208000800), + CONST64(0x0808080000080800), CONST64(0x0808080200080800), CONST64(0x0808080008080800), CONST64(0x0808080208080800), + CONST64(0x0808080000000008), CONST64(0x0808080200000008), CONST64(0x0808080008000008), CONST64(0x0808080208000008), + CONST64(0x0808080000080008), CONST64(0x0808080200080008), CONST64(0x0808080008080008), CONST64(0x0808080208080008), + CONST64(0x0808080000000808), CONST64(0x0808080200000808), CONST64(0x0808080008000808), CONST64(0x0808080208000808), + CONST64(0x0808080000080808), CONST64(0x0808080200080808), CONST64(0x0808080008080808), CONST64(0x0808080208080808) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000000800000000), CONST64(0x0000000020000000), CONST64(0x0000000820000000), + CONST64(0x0000000000200000), CONST64(0x0000000800200000), CONST64(0x0000000020200000), CONST64(0x0000000820200000), + CONST64(0x0000000000002000), CONST64(0x0000000800002000), CONST64(0x0000000020002000), CONST64(0x0000000820002000), + CONST64(0x0000000000202000), CONST64(0x0000000800202000), CONST64(0x0000000020202000), CONST64(0x0000000820202000), + CONST64(0x0000000000000020), CONST64(0x0000000800000020), CONST64(0x0000000020000020), CONST64(0x0000000820000020), + CONST64(0x0000000000200020), CONST64(0x0000000800200020), CONST64(0x0000000020200020), CONST64(0x0000000820200020), + CONST64(0x0000000000002020), CONST64(0x0000000800002020), CONST64(0x0000000020002020), CONST64(0x0000000820002020), + CONST64(0x0000000000202020), CONST64(0x0000000800202020), CONST64(0x0000000020202020), CONST64(0x0000000820202020), + CONST64(0x2000000000000000), CONST64(0x2000000800000000), CONST64(0x2000000020000000), CONST64(0x2000000820000000), + CONST64(0x2000000000200000), CONST64(0x2000000800200000), CONST64(0x2000000020200000), CONST64(0x2000000820200000), + CONST64(0x2000000000002000), CONST64(0x2000000800002000), CONST64(0x2000000020002000), CONST64(0x2000000820002000), + CONST64(0x2000000000202000), CONST64(0x2000000800202000), CONST64(0x2000000020202000), CONST64(0x2000000820202000), + CONST64(0x2000000000000020), CONST64(0x2000000800000020), CONST64(0x2000000020000020), CONST64(0x2000000820000020), + CONST64(0x2000000000200020), CONST64(0x2000000800200020), CONST64(0x2000000020200020), CONST64(0x2000000820200020), + CONST64(0x2000000000002020), CONST64(0x2000000800002020), CONST64(0x2000000020002020), CONST64(0x2000000820002020), + CONST64(0x2000000000202020), CONST64(0x2000000800202020), CONST64(0x2000000020202020), CONST64(0x2000000820202020), + CONST64(0x0020000000000000), CONST64(0x0020000800000000), CONST64(0x0020000020000000), CONST64(0x0020000820000000), + CONST64(0x0020000000200000), CONST64(0x0020000800200000), CONST64(0x0020000020200000), CONST64(0x0020000820200000), + CONST64(0x0020000000002000), CONST64(0x0020000800002000), CONST64(0x0020000020002000), CONST64(0x0020000820002000), + CONST64(0x0020000000202000), CONST64(0x0020000800202000), CONST64(0x0020000020202000), CONST64(0x0020000820202000), + CONST64(0x0020000000000020), CONST64(0x0020000800000020), CONST64(0x0020000020000020), CONST64(0x0020000820000020), + CONST64(0x0020000000200020), CONST64(0x0020000800200020), CONST64(0x0020000020200020), CONST64(0x0020000820200020), + CONST64(0x0020000000002020), CONST64(0x0020000800002020), CONST64(0x0020000020002020), CONST64(0x0020000820002020), + CONST64(0x0020000000202020), CONST64(0x0020000800202020), CONST64(0x0020000020202020), CONST64(0x0020000820202020), + CONST64(0x2020000000000000), CONST64(0x2020000800000000), CONST64(0x2020000020000000), CONST64(0x2020000820000000), + CONST64(0x2020000000200000), CONST64(0x2020000800200000), CONST64(0x2020000020200000), CONST64(0x2020000820200000), + CONST64(0x2020000000002000), CONST64(0x2020000800002000), CONST64(0x2020000020002000), CONST64(0x2020000820002000), + CONST64(0x2020000000202000), CONST64(0x2020000800202000), CONST64(0x2020000020202000), CONST64(0x2020000820202000), + CONST64(0x2020000000000020), CONST64(0x2020000800000020), CONST64(0x2020000020000020), CONST64(0x2020000820000020), + CONST64(0x2020000000200020), CONST64(0x2020000800200020), CONST64(0x2020000020200020), CONST64(0x2020000820200020), + CONST64(0x2020000000002020), CONST64(0x2020000800002020), CONST64(0x2020000020002020), CONST64(0x2020000820002020), + CONST64(0x2020000000202020), CONST64(0x2020000800202020), CONST64(0x2020000020202020), CONST64(0x2020000820202020), + CONST64(0x0000200000000000), CONST64(0x0000200800000000), CONST64(0x0000200020000000), CONST64(0x0000200820000000), + CONST64(0x0000200000200000), CONST64(0x0000200800200000), CONST64(0x0000200020200000), CONST64(0x0000200820200000), + CONST64(0x0000200000002000), CONST64(0x0000200800002000), CONST64(0x0000200020002000), CONST64(0x0000200820002000), + CONST64(0x0000200000202000), CONST64(0x0000200800202000), CONST64(0x0000200020202000), CONST64(0x0000200820202000), + CONST64(0x0000200000000020), CONST64(0x0000200800000020), CONST64(0x0000200020000020), CONST64(0x0000200820000020), + CONST64(0x0000200000200020), CONST64(0x0000200800200020), CONST64(0x0000200020200020), CONST64(0x0000200820200020), + CONST64(0x0000200000002020), CONST64(0x0000200800002020), CONST64(0x0000200020002020), CONST64(0x0000200820002020), + CONST64(0x0000200000202020), CONST64(0x0000200800202020), CONST64(0x0000200020202020), CONST64(0x0000200820202020), + CONST64(0x2000200000000000), CONST64(0x2000200800000000), CONST64(0x2000200020000000), CONST64(0x2000200820000000), + CONST64(0x2000200000200000), CONST64(0x2000200800200000), CONST64(0x2000200020200000), CONST64(0x2000200820200000), + CONST64(0x2000200000002000), CONST64(0x2000200800002000), CONST64(0x2000200020002000), CONST64(0x2000200820002000), + CONST64(0x2000200000202000), CONST64(0x2000200800202000), CONST64(0x2000200020202000), CONST64(0x2000200820202000), + CONST64(0x2000200000000020), CONST64(0x2000200800000020), CONST64(0x2000200020000020), CONST64(0x2000200820000020), + CONST64(0x2000200000200020), CONST64(0x2000200800200020), CONST64(0x2000200020200020), CONST64(0x2000200820200020), + CONST64(0x2000200000002020), CONST64(0x2000200800002020), CONST64(0x2000200020002020), CONST64(0x2000200820002020), + CONST64(0x2000200000202020), CONST64(0x2000200800202020), CONST64(0x2000200020202020), CONST64(0x2000200820202020), + CONST64(0x0020200000000000), CONST64(0x0020200800000000), CONST64(0x0020200020000000), CONST64(0x0020200820000000), + CONST64(0x0020200000200000), CONST64(0x0020200800200000), CONST64(0x0020200020200000), CONST64(0x0020200820200000), + CONST64(0x0020200000002000), CONST64(0x0020200800002000), CONST64(0x0020200020002000), CONST64(0x0020200820002000), + CONST64(0x0020200000202000), CONST64(0x0020200800202000), CONST64(0x0020200020202000), CONST64(0x0020200820202000), + CONST64(0x0020200000000020), CONST64(0x0020200800000020), CONST64(0x0020200020000020), CONST64(0x0020200820000020), + CONST64(0x0020200000200020), CONST64(0x0020200800200020), CONST64(0x0020200020200020), CONST64(0x0020200820200020), + CONST64(0x0020200000002020), CONST64(0x0020200800002020), CONST64(0x0020200020002020), CONST64(0x0020200820002020), + CONST64(0x0020200000202020), CONST64(0x0020200800202020), CONST64(0x0020200020202020), CONST64(0x0020200820202020), + CONST64(0x2020200000000000), CONST64(0x2020200800000000), CONST64(0x2020200020000000), CONST64(0x2020200820000000), + CONST64(0x2020200000200000), CONST64(0x2020200800200000), CONST64(0x2020200020200000), CONST64(0x2020200820200000), + CONST64(0x2020200000002000), CONST64(0x2020200800002000), CONST64(0x2020200020002000), CONST64(0x2020200820002000), + CONST64(0x2020200000202000), CONST64(0x2020200800202000), CONST64(0x2020200020202000), CONST64(0x2020200820202000), + CONST64(0x2020200000000020), CONST64(0x2020200800000020), CONST64(0x2020200020000020), CONST64(0x2020200820000020), + CONST64(0x2020200000200020), CONST64(0x2020200800200020), CONST64(0x2020200020200020), CONST64(0x2020200820200020), + CONST64(0x2020200000002020), CONST64(0x2020200800002020), CONST64(0x2020200020002020), CONST64(0x2020200820002020), + CONST64(0x2020200000202020), CONST64(0x2020200800202020), CONST64(0x2020200020202020), CONST64(0x2020200820202020) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000002000000000), CONST64(0x0000000080000000), CONST64(0x0000002080000000), + CONST64(0x0000000000800000), CONST64(0x0000002000800000), CONST64(0x0000000080800000), CONST64(0x0000002080800000), + CONST64(0x0000000000008000), CONST64(0x0000002000008000), CONST64(0x0000000080008000), CONST64(0x0000002080008000), + CONST64(0x0000000000808000), CONST64(0x0000002000808000), CONST64(0x0000000080808000), CONST64(0x0000002080808000), + CONST64(0x0000000000000080), CONST64(0x0000002000000080), CONST64(0x0000000080000080), CONST64(0x0000002080000080), + CONST64(0x0000000000800080), CONST64(0x0000002000800080), CONST64(0x0000000080800080), CONST64(0x0000002080800080), + CONST64(0x0000000000008080), CONST64(0x0000002000008080), CONST64(0x0000000080008080), CONST64(0x0000002080008080), + CONST64(0x0000000000808080), CONST64(0x0000002000808080), CONST64(0x0000000080808080), CONST64(0x0000002080808080), + CONST64(0x8000000000000000), CONST64(0x8000002000000000), CONST64(0x8000000080000000), CONST64(0x8000002080000000), + CONST64(0x8000000000800000), CONST64(0x8000002000800000), CONST64(0x8000000080800000), CONST64(0x8000002080800000), + CONST64(0x8000000000008000), CONST64(0x8000002000008000), CONST64(0x8000000080008000), CONST64(0x8000002080008000), + CONST64(0x8000000000808000), CONST64(0x8000002000808000), CONST64(0x8000000080808000), CONST64(0x8000002080808000), + CONST64(0x8000000000000080), CONST64(0x8000002000000080), CONST64(0x8000000080000080), CONST64(0x8000002080000080), + CONST64(0x8000000000800080), CONST64(0x8000002000800080), CONST64(0x8000000080800080), CONST64(0x8000002080800080), + CONST64(0x8000000000008080), CONST64(0x8000002000008080), CONST64(0x8000000080008080), CONST64(0x8000002080008080), + CONST64(0x8000000000808080), CONST64(0x8000002000808080), CONST64(0x8000000080808080), CONST64(0x8000002080808080), + CONST64(0x0080000000000000), CONST64(0x0080002000000000), CONST64(0x0080000080000000), CONST64(0x0080002080000000), + CONST64(0x0080000000800000), CONST64(0x0080002000800000), CONST64(0x0080000080800000), CONST64(0x0080002080800000), + CONST64(0x0080000000008000), CONST64(0x0080002000008000), CONST64(0x0080000080008000), CONST64(0x0080002080008000), + CONST64(0x0080000000808000), CONST64(0x0080002000808000), CONST64(0x0080000080808000), CONST64(0x0080002080808000), + CONST64(0x0080000000000080), CONST64(0x0080002000000080), CONST64(0x0080000080000080), CONST64(0x0080002080000080), + CONST64(0x0080000000800080), CONST64(0x0080002000800080), CONST64(0x0080000080800080), CONST64(0x0080002080800080), + CONST64(0x0080000000008080), CONST64(0x0080002000008080), CONST64(0x0080000080008080), CONST64(0x0080002080008080), + CONST64(0x0080000000808080), CONST64(0x0080002000808080), CONST64(0x0080000080808080), CONST64(0x0080002080808080), + CONST64(0x8080000000000000), CONST64(0x8080002000000000), CONST64(0x8080000080000000), CONST64(0x8080002080000000), + CONST64(0x8080000000800000), CONST64(0x8080002000800000), CONST64(0x8080000080800000), CONST64(0x8080002080800000), + CONST64(0x8080000000008000), CONST64(0x8080002000008000), CONST64(0x8080000080008000), CONST64(0x8080002080008000), + CONST64(0x8080000000808000), CONST64(0x8080002000808000), CONST64(0x8080000080808000), CONST64(0x8080002080808000), + CONST64(0x8080000000000080), CONST64(0x8080002000000080), CONST64(0x8080000080000080), CONST64(0x8080002080000080), + CONST64(0x8080000000800080), CONST64(0x8080002000800080), CONST64(0x8080000080800080), CONST64(0x8080002080800080), + CONST64(0x8080000000008080), CONST64(0x8080002000008080), CONST64(0x8080000080008080), CONST64(0x8080002080008080), + CONST64(0x8080000000808080), CONST64(0x8080002000808080), CONST64(0x8080000080808080), CONST64(0x8080002080808080), + CONST64(0x0000800000000000), CONST64(0x0000802000000000), CONST64(0x0000800080000000), CONST64(0x0000802080000000), + CONST64(0x0000800000800000), CONST64(0x0000802000800000), CONST64(0x0000800080800000), CONST64(0x0000802080800000), + CONST64(0x0000800000008000), CONST64(0x0000802000008000), CONST64(0x0000800080008000), CONST64(0x0000802080008000), + CONST64(0x0000800000808000), CONST64(0x0000802000808000), CONST64(0x0000800080808000), CONST64(0x0000802080808000), + CONST64(0x0000800000000080), CONST64(0x0000802000000080), CONST64(0x0000800080000080), CONST64(0x0000802080000080), + CONST64(0x0000800000800080), CONST64(0x0000802000800080), CONST64(0x0000800080800080), CONST64(0x0000802080800080), + CONST64(0x0000800000008080), CONST64(0x0000802000008080), CONST64(0x0000800080008080), CONST64(0x0000802080008080), + CONST64(0x0000800000808080), CONST64(0x0000802000808080), CONST64(0x0000800080808080), CONST64(0x0000802080808080), + CONST64(0x8000800000000000), CONST64(0x8000802000000000), CONST64(0x8000800080000000), CONST64(0x8000802080000000), + CONST64(0x8000800000800000), CONST64(0x8000802000800000), CONST64(0x8000800080800000), CONST64(0x8000802080800000), + CONST64(0x8000800000008000), CONST64(0x8000802000008000), CONST64(0x8000800080008000), CONST64(0x8000802080008000), + CONST64(0x8000800000808000), CONST64(0x8000802000808000), CONST64(0x8000800080808000), CONST64(0x8000802080808000), + CONST64(0x8000800000000080), CONST64(0x8000802000000080), CONST64(0x8000800080000080), CONST64(0x8000802080000080), + CONST64(0x8000800000800080), CONST64(0x8000802000800080), CONST64(0x8000800080800080), CONST64(0x8000802080800080), + CONST64(0x8000800000008080), CONST64(0x8000802000008080), CONST64(0x8000800080008080), CONST64(0x8000802080008080), + CONST64(0x8000800000808080), CONST64(0x8000802000808080), CONST64(0x8000800080808080), CONST64(0x8000802080808080), + CONST64(0x0080800000000000), CONST64(0x0080802000000000), CONST64(0x0080800080000000), CONST64(0x0080802080000000), + CONST64(0x0080800000800000), CONST64(0x0080802000800000), CONST64(0x0080800080800000), CONST64(0x0080802080800000), + CONST64(0x0080800000008000), CONST64(0x0080802000008000), CONST64(0x0080800080008000), CONST64(0x0080802080008000), + CONST64(0x0080800000808000), CONST64(0x0080802000808000), CONST64(0x0080800080808000), CONST64(0x0080802080808000), + CONST64(0x0080800000000080), CONST64(0x0080802000000080), CONST64(0x0080800080000080), CONST64(0x0080802080000080), + CONST64(0x0080800000800080), CONST64(0x0080802000800080), CONST64(0x0080800080800080), CONST64(0x0080802080800080), + CONST64(0x0080800000008080), CONST64(0x0080802000008080), CONST64(0x0080800080008080), CONST64(0x0080802080008080), + CONST64(0x0080800000808080), CONST64(0x0080802000808080), CONST64(0x0080800080808080), CONST64(0x0080802080808080), + CONST64(0x8080800000000000), CONST64(0x8080802000000000), CONST64(0x8080800080000000), CONST64(0x8080802080000000), + CONST64(0x8080800000800000), CONST64(0x8080802000800000), CONST64(0x8080800080800000), CONST64(0x8080802080800000), + CONST64(0x8080800000008000), CONST64(0x8080802000008000), CONST64(0x8080800080008000), CONST64(0x8080802080008000), + CONST64(0x8080800000808000), CONST64(0x8080802000808000), CONST64(0x8080800080808000), CONST64(0x8080802080808000), + CONST64(0x8080800000000080), CONST64(0x8080802000000080), CONST64(0x8080800080000080), CONST64(0x8080802080000080), + CONST64(0x8080800000800080), CONST64(0x8080802000800080), CONST64(0x8080800080800080), CONST64(0x8080802080800080), + CONST64(0x8080800000008080), CONST64(0x8080802000008080), CONST64(0x8080800080008080), CONST64(0x8080802080008080), + CONST64(0x8080800000808080), CONST64(0x8080802000808080), CONST64(0x8080800080808080), CONST64(0x8080802080808080) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000004000000000), CONST64(0x0000000001000000), CONST64(0x0000004001000000), + CONST64(0x0000000000010000), CONST64(0x0000004000010000), CONST64(0x0000000001010000), CONST64(0x0000004001010000), + CONST64(0x0000000000000100), CONST64(0x0000004000000100), CONST64(0x0000000001000100), CONST64(0x0000004001000100), + CONST64(0x0000000000010100), CONST64(0x0000004000010100), CONST64(0x0000000001010100), CONST64(0x0000004001010100), + CONST64(0x0000000000000001), CONST64(0x0000004000000001), CONST64(0x0000000001000001), CONST64(0x0000004001000001), + CONST64(0x0000000000010001), CONST64(0x0000004000010001), CONST64(0x0000000001010001), CONST64(0x0000004001010001), + CONST64(0x0000000000000101), CONST64(0x0000004000000101), CONST64(0x0000000001000101), CONST64(0x0000004001000101), + CONST64(0x0000000000010101), CONST64(0x0000004000010101), CONST64(0x0000000001010101), CONST64(0x0000004001010101), + CONST64(0x0100000000000000), CONST64(0x0100004000000000), CONST64(0x0100000001000000), CONST64(0x0100004001000000), + CONST64(0x0100000000010000), CONST64(0x0100004000010000), CONST64(0x0100000001010000), CONST64(0x0100004001010000), + CONST64(0x0100000000000100), CONST64(0x0100004000000100), CONST64(0x0100000001000100), CONST64(0x0100004001000100), + CONST64(0x0100000000010100), CONST64(0x0100004000010100), CONST64(0x0100000001010100), CONST64(0x0100004001010100), + CONST64(0x0100000000000001), CONST64(0x0100004000000001), CONST64(0x0100000001000001), CONST64(0x0100004001000001), + CONST64(0x0100000000010001), CONST64(0x0100004000010001), CONST64(0x0100000001010001), CONST64(0x0100004001010001), + CONST64(0x0100000000000101), CONST64(0x0100004000000101), CONST64(0x0100000001000101), CONST64(0x0100004001000101), + CONST64(0x0100000000010101), CONST64(0x0100004000010101), CONST64(0x0100000001010101), CONST64(0x0100004001010101), + CONST64(0x0001000000000000), CONST64(0x0001004000000000), CONST64(0x0001000001000000), CONST64(0x0001004001000000), + CONST64(0x0001000000010000), CONST64(0x0001004000010000), CONST64(0x0001000001010000), CONST64(0x0001004001010000), + CONST64(0x0001000000000100), CONST64(0x0001004000000100), CONST64(0x0001000001000100), CONST64(0x0001004001000100), + CONST64(0x0001000000010100), CONST64(0x0001004000010100), CONST64(0x0001000001010100), CONST64(0x0001004001010100), + CONST64(0x0001000000000001), CONST64(0x0001004000000001), CONST64(0x0001000001000001), CONST64(0x0001004001000001), + CONST64(0x0001000000010001), CONST64(0x0001004000010001), CONST64(0x0001000001010001), CONST64(0x0001004001010001), + CONST64(0x0001000000000101), CONST64(0x0001004000000101), CONST64(0x0001000001000101), CONST64(0x0001004001000101), + CONST64(0x0001000000010101), CONST64(0x0001004000010101), CONST64(0x0001000001010101), CONST64(0x0001004001010101), + CONST64(0x0101000000000000), CONST64(0x0101004000000000), CONST64(0x0101000001000000), CONST64(0x0101004001000000), + CONST64(0x0101000000010000), CONST64(0x0101004000010000), CONST64(0x0101000001010000), CONST64(0x0101004001010000), + CONST64(0x0101000000000100), CONST64(0x0101004000000100), CONST64(0x0101000001000100), CONST64(0x0101004001000100), + CONST64(0x0101000000010100), CONST64(0x0101004000010100), CONST64(0x0101000001010100), CONST64(0x0101004001010100), + CONST64(0x0101000000000001), CONST64(0x0101004000000001), CONST64(0x0101000001000001), CONST64(0x0101004001000001), + CONST64(0x0101000000010001), CONST64(0x0101004000010001), CONST64(0x0101000001010001), CONST64(0x0101004001010001), + CONST64(0x0101000000000101), CONST64(0x0101004000000101), CONST64(0x0101000001000101), CONST64(0x0101004001000101), + CONST64(0x0101000000010101), CONST64(0x0101004000010101), CONST64(0x0101000001010101), CONST64(0x0101004001010101), + CONST64(0x0000010000000000), CONST64(0x0000014000000000), CONST64(0x0000010001000000), CONST64(0x0000014001000000), + CONST64(0x0000010000010000), CONST64(0x0000014000010000), CONST64(0x0000010001010000), CONST64(0x0000014001010000), + CONST64(0x0000010000000100), CONST64(0x0000014000000100), CONST64(0x0000010001000100), CONST64(0x0000014001000100), + CONST64(0x0000010000010100), CONST64(0x0000014000010100), CONST64(0x0000010001010100), CONST64(0x0000014001010100), + CONST64(0x0000010000000001), CONST64(0x0000014000000001), CONST64(0x0000010001000001), CONST64(0x0000014001000001), + CONST64(0x0000010000010001), CONST64(0x0000014000010001), CONST64(0x0000010001010001), CONST64(0x0000014001010001), + CONST64(0x0000010000000101), CONST64(0x0000014000000101), CONST64(0x0000010001000101), CONST64(0x0000014001000101), + CONST64(0x0000010000010101), CONST64(0x0000014000010101), CONST64(0x0000010001010101), CONST64(0x0000014001010101), + CONST64(0x0100010000000000), CONST64(0x0100014000000000), CONST64(0x0100010001000000), CONST64(0x0100014001000000), + CONST64(0x0100010000010000), CONST64(0x0100014000010000), CONST64(0x0100010001010000), CONST64(0x0100014001010000), + CONST64(0x0100010000000100), CONST64(0x0100014000000100), CONST64(0x0100010001000100), CONST64(0x0100014001000100), + CONST64(0x0100010000010100), CONST64(0x0100014000010100), CONST64(0x0100010001010100), CONST64(0x0100014001010100), + CONST64(0x0100010000000001), CONST64(0x0100014000000001), CONST64(0x0100010001000001), CONST64(0x0100014001000001), + CONST64(0x0100010000010001), CONST64(0x0100014000010001), CONST64(0x0100010001010001), CONST64(0x0100014001010001), + CONST64(0x0100010000000101), CONST64(0x0100014000000101), CONST64(0x0100010001000101), CONST64(0x0100014001000101), + CONST64(0x0100010000010101), CONST64(0x0100014000010101), CONST64(0x0100010001010101), CONST64(0x0100014001010101), + CONST64(0x0001010000000000), CONST64(0x0001014000000000), CONST64(0x0001010001000000), CONST64(0x0001014001000000), + CONST64(0x0001010000010000), CONST64(0x0001014000010000), CONST64(0x0001010001010000), CONST64(0x0001014001010000), + CONST64(0x0001010000000100), CONST64(0x0001014000000100), CONST64(0x0001010001000100), CONST64(0x0001014001000100), + CONST64(0x0001010000010100), CONST64(0x0001014000010100), CONST64(0x0001010001010100), CONST64(0x0001014001010100), + CONST64(0x0001010000000001), CONST64(0x0001014000000001), CONST64(0x0001010001000001), CONST64(0x0001014001000001), + CONST64(0x0001010000010001), CONST64(0x0001014000010001), CONST64(0x0001010001010001), CONST64(0x0001014001010001), + CONST64(0x0001010000000101), CONST64(0x0001014000000101), CONST64(0x0001010001000101), CONST64(0x0001014001000101), + CONST64(0x0001010000010101), CONST64(0x0001014000010101), CONST64(0x0001010001010101), CONST64(0x0001014001010101), + CONST64(0x0101010000000000), CONST64(0x0101014000000000), CONST64(0x0101010001000000), CONST64(0x0101014001000000), + CONST64(0x0101010000010000), CONST64(0x0101014000010000), CONST64(0x0101010001010000), CONST64(0x0101014001010000), + CONST64(0x0101010000000100), CONST64(0x0101014000000100), CONST64(0x0101010001000100), CONST64(0x0101014001000100), + CONST64(0x0101010000010100), CONST64(0x0101014000010100), CONST64(0x0101010001010100), CONST64(0x0101014001010100), + CONST64(0x0101010000000001), CONST64(0x0101014000000001), CONST64(0x0101010001000001), CONST64(0x0101014001000001), + CONST64(0x0101010000010001), CONST64(0x0101014000010001), CONST64(0x0101010001010001), CONST64(0x0101014001010001), + CONST64(0x0101010000000101), CONST64(0x0101014000000101), CONST64(0x0101010001000101), CONST64(0x0101014001000101), + CONST64(0x0101010000010101), CONST64(0x0101014000010101), CONST64(0x0101010001010101), CONST64(0x0101014001010101) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000000100000000), CONST64(0x0000000004000000), CONST64(0x0000000104000000), + CONST64(0x0000000000040000), CONST64(0x0000000100040000), CONST64(0x0000000004040000), CONST64(0x0000000104040000), + CONST64(0x0000000000000400), CONST64(0x0000000100000400), CONST64(0x0000000004000400), CONST64(0x0000000104000400), + CONST64(0x0000000000040400), CONST64(0x0000000100040400), CONST64(0x0000000004040400), CONST64(0x0000000104040400), + CONST64(0x0000000000000004), CONST64(0x0000000100000004), CONST64(0x0000000004000004), CONST64(0x0000000104000004), + CONST64(0x0000000000040004), CONST64(0x0000000100040004), CONST64(0x0000000004040004), CONST64(0x0000000104040004), + CONST64(0x0000000000000404), CONST64(0x0000000100000404), CONST64(0x0000000004000404), CONST64(0x0000000104000404), + CONST64(0x0000000000040404), CONST64(0x0000000100040404), CONST64(0x0000000004040404), CONST64(0x0000000104040404), + CONST64(0x0400000000000000), CONST64(0x0400000100000000), CONST64(0x0400000004000000), CONST64(0x0400000104000000), + CONST64(0x0400000000040000), CONST64(0x0400000100040000), CONST64(0x0400000004040000), CONST64(0x0400000104040000), + CONST64(0x0400000000000400), CONST64(0x0400000100000400), CONST64(0x0400000004000400), CONST64(0x0400000104000400), + CONST64(0x0400000000040400), CONST64(0x0400000100040400), CONST64(0x0400000004040400), CONST64(0x0400000104040400), + CONST64(0x0400000000000004), CONST64(0x0400000100000004), CONST64(0x0400000004000004), CONST64(0x0400000104000004), + CONST64(0x0400000000040004), CONST64(0x0400000100040004), CONST64(0x0400000004040004), CONST64(0x0400000104040004), + CONST64(0x0400000000000404), CONST64(0x0400000100000404), CONST64(0x0400000004000404), CONST64(0x0400000104000404), + CONST64(0x0400000000040404), CONST64(0x0400000100040404), CONST64(0x0400000004040404), CONST64(0x0400000104040404), + CONST64(0x0004000000000000), CONST64(0x0004000100000000), CONST64(0x0004000004000000), CONST64(0x0004000104000000), + CONST64(0x0004000000040000), CONST64(0x0004000100040000), CONST64(0x0004000004040000), CONST64(0x0004000104040000), + CONST64(0x0004000000000400), CONST64(0x0004000100000400), CONST64(0x0004000004000400), CONST64(0x0004000104000400), + CONST64(0x0004000000040400), CONST64(0x0004000100040400), CONST64(0x0004000004040400), CONST64(0x0004000104040400), + CONST64(0x0004000000000004), CONST64(0x0004000100000004), CONST64(0x0004000004000004), CONST64(0x0004000104000004), + CONST64(0x0004000000040004), CONST64(0x0004000100040004), CONST64(0x0004000004040004), CONST64(0x0004000104040004), + CONST64(0x0004000000000404), CONST64(0x0004000100000404), CONST64(0x0004000004000404), CONST64(0x0004000104000404), + CONST64(0x0004000000040404), CONST64(0x0004000100040404), CONST64(0x0004000004040404), CONST64(0x0004000104040404), + CONST64(0x0404000000000000), CONST64(0x0404000100000000), CONST64(0x0404000004000000), CONST64(0x0404000104000000), + CONST64(0x0404000000040000), CONST64(0x0404000100040000), CONST64(0x0404000004040000), CONST64(0x0404000104040000), + CONST64(0x0404000000000400), CONST64(0x0404000100000400), CONST64(0x0404000004000400), CONST64(0x0404000104000400), + CONST64(0x0404000000040400), CONST64(0x0404000100040400), CONST64(0x0404000004040400), CONST64(0x0404000104040400), + CONST64(0x0404000000000004), CONST64(0x0404000100000004), CONST64(0x0404000004000004), CONST64(0x0404000104000004), + CONST64(0x0404000000040004), CONST64(0x0404000100040004), CONST64(0x0404000004040004), CONST64(0x0404000104040004), + CONST64(0x0404000000000404), CONST64(0x0404000100000404), CONST64(0x0404000004000404), CONST64(0x0404000104000404), + CONST64(0x0404000000040404), CONST64(0x0404000100040404), CONST64(0x0404000004040404), CONST64(0x0404000104040404), + CONST64(0x0000040000000000), CONST64(0x0000040100000000), CONST64(0x0000040004000000), CONST64(0x0000040104000000), + CONST64(0x0000040000040000), CONST64(0x0000040100040000), CONST64(0x0000040004040000), CONST64(0x0000040104040000), + CONST64(0x0000040000000400), CONST64(0x0000040100000400), CONST64(0x0000040004000400), CONST64(0x0000040104000400), + CONST64(0x0000040000040400), CONST64(0x0000040100040400), CONST64(0x0000040004040400), CONST64(0x0000040104040400), + CONST64(0x0000040000000004), CONST64(0x0000040100000004), CONST64(0x0000040004000004), CONST64(0x0000040104000004), + CONST64(0x0000040000040004), CONST64(0x0000040100040004), CONST64(0x0000040004040004), CONST64(0x0000040104040004), + CONST64(0x0000040000000404), CONST64(0x0000040100000404), CONST64(0x0000040004000404), CONST64(0x0000040104000404), + CONST64(0x0000040000040404), CONST64(0x0000040100040404), CONST64(0x0000040004040404), CONST64(0x0000040104040404), + CONST64(0x0400040000000000), CONST64(0x0400040100000000), CONST64(0x0400040004000000), CONST64(0x0400040104000000), + CONST64(0x0400040000040000), CONST64(0x0400040100040000), CONST64(0x0400040004040000), CONST64(0x0400040104040000), + CONST64(0x0400040000000400), CONST64(0x0400040100000400), CONST64(0x0400040004000400), CONST64(0x0400040104000400), + CONST64(0x0400040000040400), CONST64(0x0400040100040400), CONST64(0x0400040004040400), CONST64(0x0400040104040400), + CONST64(0x0400040000000004), CONST64(0x0400040100000004), CONST64(0x0400040004000004), CONST64(0x0400040104000004), + CONST64(0x0400040000040004), CONST64(0x0400040100040004), CONST64(0x0400040004040004), CONST64(0x0400040104040004), + CONST64(0x0400040000000404), CONST64(0x0400040100000404), CONST64(0x0400040004000404), CONST64(0x0400040104000404), + CONST64(0x0400040000040404), CONST64(0x0400040100040404), CONST64(0x0400040004040404), CONST64(0x0400040104040404), + CONST64(0x0004040000000000), CONST64(0x0004040100000000), CONST64(0x0004040004000000), CONST64(0x0004040104000000), + CONST64(0x0004040000040000), CONST64(0x0004040100040000), CONST64(0x0004040004040000), CONST64(0x0004040104040000), + CONST64(0x0004040000000400), CONST64(0x0004040100000400), CONST64(0x0004040004000400), CONST64(0x0004040104000400), + CONST64(0x0004040000040400), CONST64(0x0004040100040400), CONST64(0x0004040004040400), CONST64(0x0004040104040400), + CONST64(0x0004040000000004), CONST64(0x0004040100000004), CONST64(0x0004040004000004), CONST64(0x0004040104000004), + CONST64(0x0004040000040004), CONST64(0x0004040100040004), CONST64(0x0004040004040004), CONST64(0x0004040104040004), + CONST64(0x0004040000000404), CONST64(0x0004040100000404), CONST64(0x0004040004000404), CONST64(0x0004040104000404), + CONST64(0x0004040000040404), CONST64(0x0004040100040404), CONST64(0x0004040004040404), CONST64(0x0004040104040404), + CONST64(0x0404040000000000), CONST64(0x0404040100000000), CONST64(0x0404040004000000), CONST64(0x0404040104000000), + CONST64(0x0404040000040000), CONST64(0x0404040100040000), CONST64(0x0404040004040000), CONST64(0x0404040104040000), + CONST64(0x0404040000000400), CONST64(0x0404040100000400), CONST64(0x0404040004000400), CONST64(0x0404040104000400), + CONST64(0x0404040000040400), CONST64(0x0404040100040400), CONST64(0x0404040004040400), CONST64(0x0404040104040400), + CONST64(0x0404040000000004), CONST64(0x0404040100000004), CONST64(0x0404040004000004), CONST64(0x0404040104000004), + CONST64(0x0404040000040004), CONST64(0x0404040100040004), CONST64(0x0404040004040004), CONST64(0x0404040104040004), + CONST64(0x0404040000000404), CONST64(0x0404040100000404), CONST64(0x0404040004000404), CONST64(0x0404040104000404), + CONST64(0x0404040000040404), CONST64(0x0404040100040404), CONST64(0x0404040004040404), CONST64(0x0404040104040404) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000000400000000), CONST64(0x0000000010000000), CONST64(0x0000000410000000), + CONST64(0x0000000000100000), CONST64(0x0000000400100000), CONST64(0x0000000010100000), CONST64(0x0000000410100000), + CONST64(0x0000000000001000), CONST64(0x0000000400001000), CONST64(0x0000000010001000), CONST64(0x0000000410001000), + CONST64(0x0000000000101000), CONST64(0x0000000400101000), CONST64(0x0000000010101000), CONST64(0x0000000410101000), + CONST64(0x0000000000000010), CONST64(0x0000000400000010), CONST64(0x0000000010000010), CONST64(0x0000000410000010), + CONST64(0x0000000000100010), CONST64(0x0000000400100010), CONST64(0x0000000010100010), CONST64(0x0000000410100010), + CONST64(0x0000000000001010), CONST64(0x0000000400001010), CONST64(0x0000000010001010), CONST64(0x0000000410001010), + CONST64(0x0000000000101010), CONST64(0x0000000400101010), CONST64(0x0000000010101010), CONST64(0x0000000410101010), + CONST64(0x1000000000000000), CONST64(0x1000000400000000), CONST64(0x1000000010000000), CONST64(0x1000000410000000), + CONST64(0x1000000000100000), CONST64(0x1000000400100000), CONST64(0x1000000010100000), CONST64(0x1000000410100000), + CONST64(0x1000000000001000), CONST64(0x1000000400001000), CONST64(0x1000000010001000), CONST64(0x1000000410001000), + CONST64(0x1000000000101000), CONST64(0x1000000400101000), CONST64(0x1000000010101000), CONST64(0x1000000410101000), + CONST64(0x1000000000000010), CONST64(0x1000000400000010), CONST64(0x1000000010000010), CONST64(0x1000000410000010), + CONST64(0x1000000000100010), CONST64(0x1000000400100010), CONST64(0x1000000010100010), CONST64(0x1000000410100010), + CONST64(0x1000000000001010), CONST64(0x1000000400001010), CONST64(0x1000000010001010), CONST64(0x1000000410001010), + CONST64(0x1000000000101010), CONST64(0x1000000400101010), CONST64(0x1000000010101010), CONST64(0x1000000410101010), + CONST64(0x0010000000000000), CONST64(0x0010000400000000), CONST64(0x0010000010000000), CONST64(0x0010000410000000), + CONST64(0x0010000000100000), CONST64(0x0010000400100000), CONST64(0x0010000010100000), CONST64(0x0010000410100000), + CONST64(0x0010000000001000), CONST64(0x0010000400001000), CONST64(0x0010000010001000), CONST64(0x0010000410001000), + CONST64(0x0010000000101000), CONST64(0x0010000400101000), CONST64(0x0010000010101000), CONST64(0x0010000410101000), + CONST64(0x0010000000000010), CONST64(0x0010000400000010), CONST64(0x0010000010000010), CONST64(0x0010000410000010), + CONST64(0x0010000000100010), CONST64(0x0010000400100010), CONST64(0x0010000010100010), CONST64(0x0010000410100010), + CONST64(0x0010000000001010), CONST64(0x0010000400001010), CONST64(0x0010000010001010), CONST64(0x0010000410001010), + CONST64(0x0010000000101010), CONST64(0x0010000400101010), CONST64(0x0010000010101010), CONST64(0x0010000410101010), + CONST64(0x1010000000000000), CONST64(0x1010000400000000), CONST64(0x1010000010000000), CONST64(0x1010000410000000), + CONST64(0x1010000000100000), CONST64(0x1010000400100000), CONST64(0x1010000010100000), CONST64(0x1010000410100000), + CONST64(0x1010000000001000), CONST64(0x1010000400001000), CONST64(0x1010000010001000), CONST64(0x1010000410001000), + CONST64(0x1010000000101000), CONST64(0x1010000400101000), CONST64(0x1010000010101000), CONST64(0x1010000410101000), + CONST64(0x1010000000000010), CONST64(0x1010000400000010), CONST64(0x1010000010000010), CONST64(0x1010000410000010), + CONST64(0x1010000000100010), CONST64(0x1010000400100010), CONST64(0x1010000010100010), CONST64(0x1010000410100010), + CONST64(0x1010000000001010), CONST64(0x1010000400001010), CONST64(0x1010000010001010), CONST64(0x1010000410001010), + CONST64(0x1010000000101010), CONST64(0x1010000400101010), CONST64(0x1010000010101010), CONST64(0x1010000410101010), + CONST64(0x0000100000000000), CONST64(0x0000100400000000), CONST64(0x0000100010000000), CONST64(0x0000100410000000), + CONST64(0x0000100000100000), CONST64(0x0000100400100000), CONST64(0x0000100010100000), CONST64(0x0000100410100000), + CONST64(0x0000100000001000), CONST64(0x0000100400001000), CONST64(0x0000100010001000), CONST64(0x0000100410001000), + CONST64(0x0000100000101000), CONST64(0x0000100400101000), CONST64(0x0000100010101000), CONST64(0x0000100410101000), + CONST64(0x0000100000000010), CONST64(0x0000100400000010), CONST64(0x0000100010000010), CONST64(0x0000100410000010), + CONST64(0x0000100000100010), CONST64(0x0000100400100010), CONST64(0x0000100010100010), CONST64(0x0000100410100010), + CONST64(0x0000100000001010), CONST64(0x0000100400001010), CONST64(0x0000100010001010), CONST64(0x0000100410001010), + CONST64(0x0000100000101010), CONST64(0x0000100400101010), CONST64(0x0000100010101010), CONST64(0x0000100410101010), + CONST64(0x1000100000000000), CONST64(0x1000100400000000), CONST64(0x1000100010000000), CONST64(0x1000100410000000), + CONST64(0x1000100000100000), CONST64(0x1000100400100000), CONST64(0x1000100010100000), CONST64(0x1000100410100000), + CONST64(0x1000100000001000), CONST64(0x1000100400001000), CONST64(0x1000100010001000), CONST64(0x1000100410001000), + CONST64(0x1000100000101000), CONST64(0x1000100400101000), CONST64(0x1000100010101000), CONST64(0x1000100410101000), + CONST64(0x1000100000000010), CONST64(0x1000100400000010), CONST64(0x1000100010000010), CONST64(0x1000100410000010), + CONST64(0x1000100000100010), CONST64(0x1000100400100010), CONST64(0x1000100010100010), CONST64(0x1000100410100010), + CONST64(0x1000100000001010), CONST64(0x1000100400001010), CONST64(0x1000100010001010), CONST64(0x1000100410001010), + CONST64(0x1000100000101010), CONST64(0x1000100400101010), CONST64(0x1000100010101010), CONST64(0x1000100410101010), + CONST64(0x0010100000000000), CONST64(0x0010100400000000), CONST64(0x0010100010000000), CONST64(0x0010100410000000), + CONST64(0x0010100000100000), CONST64(0x0010100400100000), CONST64(0x0010100010100000), CONST64(0x0010100410100000), + CONST64(0x0010100000001000), CONST64(0x0010100400001000), CONST64(0x0010100010001000), CONST64(0x0010100410001000), + CONST64(0x0010100000101000), CONST64(0x0010100400101000), CONST64(0x0010100010101000), CONST64(0x0010100410101000), + CONST64(0x0010100000000010), CONST64(0x0010100400000010), CONST64(0x0010100010000010), CONST64(0x0010100410000010), + CONST64(0x0010100000100010), CONST64(0x0010100400100010), CONST64(0x0010100010100010), CONST64(0x0010100410100010), + CONST64(0x0010100000001010), CONST64(0x0010100400001010), CONST64(0x0010100010001010), CONST64(0x0010100410001010), + CONST64(0x0010100000101010), CONST64(0x0010100400101010), CONST64(0x0010100010101010), CONST64(0x0010100410101010), + CONST64(0x1010100000000000), CONST64(0x1010100400000000), CONST64(0x1010100010000000), CONST64(0x1010100410000000), + CONST64(0x1010100000100000), CONST64(0x1010100400100000), CONST64(0x1010100010100000), CONST64(0x1010100410100000), + CONST64(0x1010100000001000), CONST64(0x1010100400001000), CONST64(0x1010100010001000), CONST64(0x1010100410001000), + CONST64(0x1010100000101000), CONST64(0x1010100400101000), CONST64(0x1010100010101000), CONST64(0x1010100410101000), + CONST64(0x1010100000000010), CONST64(0x1010100400000010), CONST64(0x1010100010000010), CONST64(0x1010100410000010), + CONST64(0x1010100000100010), CONST64(0x1010100400100010), CONST64(0x1010100010100010), CONST64(0x1010100410100010), + CONST64(0x1010100000001010), CONST64(0x1010100400001010), CONST64(0x1010100010001010), CONST64(0x1010100410001010), + CONST64(0x1010100000101010), CONST64(0x1010100400101010), CONST64(0x1010100010101010), CONST64(0x1010100410101010) + }, +{ CONST64(0x0000000000000000), CONST64(0x0000001000000000), CONST64(0x0000000040000000), CONST64(0x0000001040000000), + CONST64(0x0000000000400000), CONST64(0x0000001000400000), CONST64(0x0000000040400000), CONST64(0x0000001040400000), + CONST64(0x0000000000004000), CONST64(0x0000001000004000), CONST64(0x0000000040004000), CONST64(0x0000001040004000), + CONST64(0x0000000000404000), CONST64(0x0000001000404000), CONST64(0x0000000040404000), CONST64(0x0000001040404000), + CONST64(0x0000000000000040), CONST64(0x0000001000000040), CONST64(0x0000000040000040), CONST64(0x0000001040000040), + CONST64(0x0000000000400040), CONST64(0x0000001000400040), CONST64(0x0000000040400040), CONST64(0x0000001040400040), + CONST64(0x0000000000004040), CONST64(0x0000001000004040), CONST64(0x0000000040004040), CONST64(0x0000001040004040), + CONST64(0x0000000000404040), CONST64(0x0000001000404040), CONST64(0x0000000040404040), CONST64(0x0000001040404040), + CONST64(0x4000000000000000), CONST64(0x4000001000000000), CONST64(0x4000000040000000), CONST64(0x4000001040000000), + CONST64(0x4000000000400000), CONST64(0x4000001000400000), CONST64(0x4000000040400000), CONST64(0x4000001040400000), + CONST64(0x4000000000004000), CONST64(0x4000001000004000), CONST64(0x4000000040004000), CONST64(0x4000001040004000), + CONST64(0x4000000000404000), CONST64(0x4000001000404000), CONST64(0x4000000040404000), CONST64(0x4000001040404000), + CONST64(0x4000000000000040), CONST64(0x4000001000000040), CONST64(0x4000000040000040), CONST64(0x4000001040000040), + CONST64(0x4000000000400040), CONST64(0x4000001000400040), CONST64(0x4000000040400040), CONST64(0x4000001040400040), + CONST64(0x4000000000004040), CONST64(0x4000001000004040), CONST64(0x4000000040004040), CONST64(0x4000001040004040), + CONST64(0x4000000000404040), CONST64(0x4000001000404040), CONST64(0x4000000040404040), CONST64(0x4000001040404040), + CONST64(0x0040000000000000), CONST64(0x0040001000000000), CONST64(0x0040000040000000), CONST64(0x0040001040000000), + CONST64(0x0040000000400000), CONST64(0x0040001000400000), CONST64(0x0040000040400000), CONST64(0x0040001040400000), + CONST64(0x0040000000004000), CONST64(0x0040001000004000), CONST64(0x0040000040004000), CONST64(0x0040001040004000), + CONST64(0x0040000000404000), CONST64(0x0040001000404000), CONST64(0x0040000040404000), CONST64(0x0040001040404000), + CONST64(0x0040000000000040), CONST64(0x0040001000000040), CONST64(0x0040000040000040), CONST64(0x0040001040000040), + CONST64(0x0040000000400040), CONST64(0x0040001000400040), CONST64(0x0040000040400040), CONST64(0x0040001040400040), + CONST64(0x0040000000004040), CONST64(0x0040001000004040), CONST64(0x0040000040004040), CONST64(0x0040001040004040), + CONST64(0x0040000000404040), CONST64(0x0040001000404040), CONST64(0x0040000040404040), CONST64(0x0040001040404040), + CONST64(0x4040000000000000), CONST64(0x4040001000000000), CONST64(0x4040000040000000), CONST64(0x4040001040000000), + CONST64(0x4040000000400000), CONST64(0x4040001000400000), CONST64(0x4040000040400000), CONST64(0x4040001040400000), + CONST64(0x4040000000004000), CONST64(0x4040001000004000), CONST64(0x4040000040004000), CONST64(0x4040001040004000), + CONST64(0x4040000000404000), CONST64(0x4040001000404000), CONST64(0x4040000040404000), CONST64(0x4040001040404000), + CONST64(0x4040000000000040), CONST64(0x4040001000000040), CONST64(0x4040000040000040), CONST64(0x4040001040000040), + CONST64(0x4040000000400040), CONST64(0x4040001000400040), CONST64(0x4040000040400040), CONST64(0x4040001040400040), + CONST64(0x4040000000004040), CONST64(0x4040001000004040), CONST64(0x4040000040004040), CONST64(0x4040001040004040), + CONST64(0x4040000000404040), CONST64(0x4040001000404040), CONST64(0x4040000040404040), CONST64(0x4040001040404040), + CONST64(0x0000400000000000), CONST64(0x0000401000000000), CONST64(0x0000400040000000), CONST64(0x0000401040000000), + CONST64(0x0000400000400000), CONST64(0x0000401000400000), CONST64(0x0000400040400000), CONST64(0x0000401040400000), + CONST64(0x0000400000004000), CONST64(0x0000401000004000), CONST64(0x0000400040004000), CONST64(0x0000401040004000), + CONST64(0x0000400000404000), CONST64(0x0000401000404000), CONST64(0x0000400040404000), CONST64(0x0000401040404000), + CONST64(0x0000400000000040), CONST64(0x0000401000000040), CONST64(0x0000400040000040), CONST64(0x0000401040000040), + CONST64(0x0000400000400040), CONST64(0x0000401000400040), CONST64(0x0000400040400040), CONST64(0x0000401040400040), + CONST64(0x0000400000004040), CONST64(0x0000401000004040), CONST64(0x0000400040004040), CONST64(0x0000401040004040), + CONST64(0x0000400000404040), CONST64(0x0000401000404040), CONST64(0x0000400040404040), CONST64(0x0000401040404040), + CONST64(0x4000400000000000), CONST64(0x4000401000000000), CONST64(0x4000400040000000), CONST64(0x4000401040000000), + CONST64(0x4000400000400000), CONST64(0x4000401000400000), CONST64(0x4000400040400000), CONST64(0x4000401040400000), + CONST64(0x4000400000004000), CONST64(0x4000401000004000), CONST64(0x4000400040004000), CONST64(0x4000401040004000), + CONST64(0x4000400000404000), CONST64(0x4000401000404000), CONST64(0x4000400040404000), CONST64(0x4000401040404000), + CONST64(0x4000400000000040), CONST64(0x4000401000000040), CONST64(0x4000400040000040), CONST64(0x4000401040000040), + CONST64(0x4000400000400040), CONST64(0x4000401000400040), CONST64(0x4000400040400040), CONST64(0x4000401040400040), + CONST64(0x4000400000004040), CONST64(0x4000401000004040), CONST64(0x4000400040004040), CONST64(0x4000401040004040), + CONST64(0x4000400000404040), CONST64(0x4000401000404040), CONST64(0x4000400040404040), CONST64(0x4000401040404040), + CONST64(0x0040400000000000), CONST64(0x0040401000000000), CONST64(0x0040400040000000), CONST64(0x0040401040000000), + CONST64(0x0040400000400000), CONST64(0x0040401000400000), CONST64(0x0040400040400000), CONST64(0x0040401040400000), + CONST64(0x0040400000004000), CONST64(0x0040401000004000), CONST64(0x0040400040004000), CONST64(0x0040401040004000), + CONST64(0x0040400000404000), CONST64(0x0040401000404000), CONST64(0x0040400040404000), CONST64(0x0040401040404000), + CONST64(0x0040400000000040), CONST64(0x0040401000000040), CONST64(0x0040400040000040), CONST64(0x0040401040000040), + CONST64(0x0040400000400040), CONST64(0x0040401000400040), CONST64(0x0040400040400040), CONST64(0x0040401040400040), + CONST64(0x0040400000004040), CONST64(0x0040401000004040), CONST64(0x0040400040004040), CONST64(0x0040401040004040), + CONST64(0x0040400000404040), CONST64(0x0040401000404040), CONST64(0x0040400040404040), CONST64(0x0040401040404040), + CONST64(0x4040400000000000), CONST64(0x4040401000000000), CONST64(0x4040400040000000), CONST64(0x4040401040000000), + CONST64(0x4040400000400000), CONST64(0x4040401000400000), CONST64(0x4040400040400000), CONST64(0x4040401040400000), + CONST64(0x4040400000004000), CONST64(0x4040401000004000), CONST64(0x4040400040004000), CONST64(0x4040401040004000), + CONST64(0x4040400000404000), CONST64(0x4040401000404000), CONST64(0x4040400040404000), CONST64(0x4040401040404000), + CONST64(0x4040400000000040), CONST64(0x4040401000000040), CONST64(0x4040400040000040), CONST64(0x4040401040000040), + CONST64(0x4040400000400040), CONST64(0x4040401000400040), CONST64(0x4040400040400040), CONST64(0x4040401040400040), + CONST64(0x4040400000004040), CONST64(0x4040401000004040), CONST64(0x4040400040004040), CONST64(0x4040401040004040), + CONST64(0x4040400000404040), CONST64(0x4040401000404040), CONST64(0x4040400040404040), CONST64(0x4040401040404040) + }}; + +#endif + + +static void cookey(const ulong32 *raw1, ulong32 *keyout); + +#ifdef CLEAN_STACK +void _deskey(const unsigned char *key, short edf, ulong32 *keyout) +#else +void deskey(const unsigned char *key, short edf, ulong32 *keyout) +#endif +{ + ulong32 i, j, l, m, n, kn[32]; + unsigned char pc1m[56], pcr[56]; + + for (j=0; j < 56; j++) { + l = (ulong32)pc1[j]; + m = l & 7; + pc1m[j] = (unsigned char)((key[l >> 3U] & bytebit[m]) == 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 + (ulong32)totrot[i]; + if (l < 28) { + pcr[j] = pc1m[l]; + } else { + pcr[j] = pc1m[l - 28]; + } + } + for (/*j = 28*/; j < 56; j++) { + l = j + (ulong32)totrot[i]; + if (l < 56) { + pcr[j] = pc1m[l]; + } else { + pcr[j] = pc1m[l - 28]; + } + } + for (j=0; j < 24; j++) { + if ((int)pcr[(int)pc2[j]] != 0) { + kn[m] |= bigbyte[j]; + } + if ((int)pcr[(int)pc2[j+24]] != 0) { + kn[n] |= bigbyte[j]; + } + } + } + + cookey(kn, keyout); +} + +#ifdef CLEAN_STACK +void deskey(const unsigned char *key, short edf, ulong32 *keyout) +{ + _deskey(key, edf, keyout); + burn_stack(sizeof(int)*5 + sizeof(ulong32)*32 + sizeof(unsigned char)*112); +} +#endif + +#ifdef CLEAN_STACK +static void _cookey(const ulong32 *raw1, ulong32 *keyout) +#else +static void cookey(const ulong32 *raw1, ulong32 *keyout) +#endif +{ + ulong32 *cook; + const ulong32 *raw0; + ulong32 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 ulong32 *raw1, ulong32 *keyout) +{ + _cookey(raw1, keyout); + burn_stack(sizeof(ulong32 *) * 2 + sizeof(ulong32)*32 + sizeof(int)); +} +#endif + +#ifndef CLEAN_STACK +static void desfunc(ulong32 *block, const ulong32 *keys) +#else +static void _desfunc(ulong32 *block, const ulong32 *keys) +#endif +{ + ulong32 work, right, leftt; + int round; + + leftt = block[0]; + right = block[1]; + +#ifdef SMALL_CODE + 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 = ROL(right, 1); + work = (leftt ^ right) & 0xaaaaaaaaL; + + leftt ^= work; + right ^= work; + leftt = ROL(leftt, 1); +#else + { + ulong64 tmp; + tmp = des_ip[0][byte(leftt, 0)] ^ + des_ip[1][byte(leftt, 1)] ^ + des_ip[2][byte(leftt, 2)] ^ + des_ip[3][byte(leftt, 3)] ^ + des_ip[4][byte(right, 0)] ^ + des_ip[5][byte(right, 1)] ^ + des_ip[6][byte(right, 2)] ^ + des_ip[7][byte(right, 3)]; + leftt = (ulong32)(tmp >> 32); + right = (ulong32)(tmp & 0xFFFFFFFFUL); + } +#endif + + for (round = 0; round < 8; round++) { + work = ROR(right, 4) ^ *keys++; + leftt ^= SP7[work & 0x3fL] + ^ SP5[(work >> 8) & 0x3fL] + ^ SP3[(work >> 16) & 0x3fL] + ^ SP1[(work >> 24) & 0x3fL]; + work = right ^ *keys++; + leftt ^= SP8[ work & 0x3fL] + ^ SP6[(work >> 8) & 0x3fL] + ^ SP4[(work >> 16) & 0x3fL] + ^ SP2[(work >> 24) & 0x3fL]; + + work = ROR(leftt, 4) ^ *keys++; + right ^= SP7[ work & 0x3fL] + ^ SP5[(work >> 8) & 0x3fL] + ^ SP3[(work >> 16) & 0x3fL] + ^ SP1[(work >> 24) & 0x3fL]; + work = leftt ^ *keys++; + right ^= SP8[ work & 0x3fL] + ^ SP6[(work >> 8) & 0x3fL] + ^ SP4[(work >> 16) & 0x3fL] + ^ SP2[(work >> 24) & 0x3fL]; + } + +#ifdef SMALL_CODE + right = ROR(right, 1); + work = (leftt ^ right) & 0xaaaaaaaaL; + leftt ^= work; + right ^= work; + leftt = ROR(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); +#else + { + ulong64 tmp; + tmp = des_fp[0][byte(leftt, 0)] ^ + des_fp[1][byte(leftt, 1)] ^ + des_fp[2][byte(leftt, 2)] ^ + des_fp[3][byte(leftt, 3)] ^ + des_fp[4][byte(right, 0)] ^ + des_fp[5][byte(right, 1)] ^ + des_fp[6][byte(right, 2)] ^ + des_fp[7][byte(right, 3)]; + leftt = (ulong32)(tmp >> 32); + right = (ulong32)(tmp & 0xFFFFFFFFUL); + } +#endif + + block[0] = right; + block[1] = leftt; +} + +#ifdef CLEAN_STACK +static void desfunc(ulong32 *block, const ulong32 *keys) +{ + _desfunc(block, keys); + burn_stack(sizeof(ulong32) * 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) +{ + ulong32 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) +{ + ulong32 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) +{ + ulong32 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) +{ + ulong32 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) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + int err; + 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, y; + unsigned char tmp[8]; + symmetric_key des; + + for(i=0; i < (int)(sizeof(cases)/sizeof(cases[0])); i++) + { + if ((err = des_setup(cases[i].key, 8, 0, &des)) != CRYPT_OK) { + return err; + } + if (cases[i].mode != 0) { + des_ecb_encrypt(cases[i].txt, tmp, &des); + } else { + des_ecb_decrypt(cases[i].txt, tmp, &des); + } + + if (memcmp(cases[i].out, tmp, sizeof(tmp)) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + + /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ + for (y = 0; y < 8; y++) tmp[y] = 0; + for (y = 0; y < 1000; y++) des_ecb_encrypt(tmp, tmp, &des); + for (y = 0; y < 1000; y++) des_ecb_decrypt(tmp, tmp, &des); + for (y = 0; y < 8; y++) if (tmp[y] != 0) return CRYPT_FAIL_TESTVECTOR; +} + + return CRYPT_OK; + #endif +} + +int des3_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + unsigned char key[24], pt[8], ct[8], tmp[8]; + symmetric_key skey; + int x, err; + + if ((err = des_test()) != CRYPT_OK) { + return err; + } + + for (x = 0; x < 8; x++) { + pt[x] = x; + } + + for (x = 0; x < 24; x++) { + key[x] = x; + } + + if ((err = des3_setup(key, 24, 0, &skey)) != CRYPT_OK) { + return err; + } + + des3_ecb_encrypt(pt, ct, &skey); + des3_ecb_decrypt(ct, tmp, &skey); + + if (memcmp(pt, tmp, 8) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + + return CRYPT_OK; + #endif +} + +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..8cf5632 --- /dev/null +++ b/dh.c @@ -0,0 +1,452 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef MDH + +/* This holds the key settings. ***MUST*** be organized by size from smallest to largest. */ +static const struct { + int size; + char *name, *base, *prime; +} sets[] = { +#ifdef DH768 +{ + 96, + "DH-768", + "4", + "F///////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "//////m3wvV" +}, +#endif +#ifdef DH1024 +{ + 128, + "DH-1024", + "4", + "F///////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////m3C47" +}, +#endif +#ifdef DH1280 +{ + 160, + "DH-1280", + "4", + "F///////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "//////////////////////////////m4kSN" +}, +#endif +#ifdef DH1536 +{ + 192, + "DH-1536", + "4", + "F///////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////m5uqd" +}, +#endif +#ifdef DH1792 +{ + 224, + "DH-1792", + "4", + "F///////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "//////////////////////////////////////////////////////mT/sd" +}, +#endif +#ifdef DH2048 +{ + 256, + "DH-2048", + "4", + "3///////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "/////////////////////////////////////////m8MPh" +}, +#endif +#ifdef DH2560 +{ + 320, + "DH-2560", + "4", + "3///////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "/////mKFpF" +}, +#endif +#ifdef DH3072 +{ + 384, + "DH-3072", + "4", + "3///////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "/////////////////////////////m32nN" +}, +#endif +#ifdef DH4096 +{ + 512, + "DH-4096", + "4", + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////" + "/////////////////////m8pOF" +}, +#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, err, primality; + + if ((err = mp_init_multi(&p, &g, &tmp, NULL)) != MP_OKAY) { goto error; } + + for (x = 0; sets[x].size != 0; x++) { +#if 0 + printf("dh_test():testing size %d-bits\n", sets[x].size * 8); +#endif + if ((err = mp_read_radix(&g,(char *)sets[x].base, 64)) != MP_OKAY) { goto error; } + if ((err = mp_read_radix(&p,(char *)sets[x].prime, 64)) != MP_OKAY) { goto error; } + + /* ensure p is prime */ + if ((err = is_prime(&p, &primality)) != CRYPT_OK) { goto done; } + if (primality == 0) { + err = CRYPT_FAIL_TESTVECTOR; + goto done; + } + + if ((err = mp_sub_d(&p, 1, &tmp)) != MP_OKAY) { goto error; } + if ((err = mp_div_2(&tmp, &tmp)) != MP_OKAY) { goto error; } + + /* ensure (p-1)/2 is prime */ + if ((err = is_prime(&tmp, &primality)) != CRYPT_OK) { goto done; } + if (primality == 0) { + err = CRYPT_FAIL_TESTVECTOR; + goto done; + } + + /* now see if g^((p-1)/2) mod p is in fact 1 */ + if ((err = mp_exptmod(&g, &tmp, &p, &tmp)) != MP_OKAY) { goto error; } + if (mp_cmp_d(&tmp, 1)) { + err = CRYPT_FAIL_TESTVECTOR; + goto done; + } + } + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); +done: + mp_clear_multi(&tmp, &g, &p, NULL); + return err; +} + +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 != 0; 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) == 1) { + 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[512]; + unsigned long x; + mp_int p, g; + int err; + + _ARGCHK(key != NULL); + + /* good prng? */ + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + /* find key size */ + for (x = 0; (keysize > sets[x].size) && (sets[x].size != 0); 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 */ + if (prng_descriptor[wprng].read(buf, keysize, prng) != (unsigned long)keysize) { + return CRYPT_ERROR_READPRNG; + } + + /* init parameters */ + if ((err = mp_init_multi(&g, &p, &key->x, &key->y, NULL)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + if ((err = mp_read_radix(&g, sets[key->idx].base, 64)) != MP_OKAY) { goto error; } + if ((err = mp_read_radix(&p, sets[key->idx].prime, 64)) != MP_OKAY) { goto error; } + + /* load the x value */ + if ((err = mp_read_unsigned_bin(&key->x, buf, keysize)) != MP_OKAY) { goto error; } + if ((err = mp_exptmod(&g, &key->x, &p, &key->y)) != MP_OKAY) { goto error; } + key->type = PK_PRIVATE; + + if ((err = mp_shrink(&key->x)) != MP_OKAY) { goto error; } + if ((err = mp_shrink(&key->y)) != MP_OKAY) { goto error; } + + /* free up ram */ + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); + mp_clear_multi(&key->x, &key->y, NULL); +done: + mp_clear_multi(&p, &g, NULL); + zeromem(buf, sizeof(buf)); + return err; +} + +void dh_free(dh_key *key) +{ + _ARGCHK(key != NULL); + mp_clear_multi(&key->x, &key->y, NULL); +} + +int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key) +{ + unsigned long y, z; + int err; + + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* can we store the static header? */ + if (*outlen < (PACKET_SIZE + 2)) { + return CRYPT_BUFFER_OVERFLOW; + } + + if (type == PK_PRIVATE && key->type != PK_PRIVATE) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* header */ + y = PACKET_SIZE; + + /* header */ + out[y++] = type; + out[y++] = (unsigned char)(sets[key->idx].size / 8); + + /* export y */ + OUTPUT_BIGNUM(&key->y, out, y, z); + + if (type == PK_PRIVATE) { + /* export x */ + OUTPUT_BIGNUM(&key->x, out, y, z); + } + + /* store header */ + packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_KEY); + + /* store len */ + *outlen = y; + return CRYPT_OK; +} + +int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key) +{ + unsigned long x, y, s; + int err; + + _ARGCHK(in != NULL); + _ARGCHK(key != NULL); + + /* make sure valid length */ + if ((2+PACKET_SIZE) > inlen) { + return CRYPT_INVALID_PACKET; + } + + /* check type byte */ + if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_KEY)) != CRYPT_OK) { + return err; + } + + /* init */ + if ((err = mp_init_multi(&key->x, &key->y, NULL)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + + /* advance past packet header */ + y = PACKET_SIZE; + + /* key type, e.g. private, public */ + key->type = (int)in[y++]; + + /* key size in bytes */ + s = (unsigned long)in[y++] * 8; + + for (x = 0; (s > (unsigned long)sets[x].size) && (sets[x].size != 0); x++); + if (sets[x].size == 0) { + err = CRYPT_INVALID_KEYSIZE; + goto error; + } + key->idx = (int)x; + + /* type check both values */ + if ((key->type != PK_PUBLIC) && (key->type != PK_PRIVATE)) { + err = CRYPT_PK_TYPE_MISMATCH; + goto error; + } + + /* is the key idx valid? */ + if (is_valid_idx(key->idx) != 1) { + err = CRYPT_PK_TYPE_MISMATCH; + goto error; + } + + /* load public value g^x mod p*/ + INPUT_BIGNUM(&key->y, in, x, y, inlen); + + if (key->type == PK_PRIVATE) { + INPUT_BIGNUM(&key->x, in, x, y, inlen); + } + + /* eliminate private key if public */ + if (key->type == PK_PUBLIC) { + mp_clear(&key->x); + } + + return CRYPT_OK; +error: + mp_clear_multi(&key->y, &key->x, NULL); + return err; +} + +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 err; + + _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 ((err = mp_init_multi(&tmp, &p, NULL)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + + if ((err = mp_read_radix(&p, (char *)sets[private_key->idx].prime, 64)) != MP_OKAY) { goto error; } + if ((err = mp_exptmod(&public_key->y, &private_key->x, &p, &tmp)) != MP_OKAY) { goto error; } + + /* enough space for output? */ + x = (unsigned long)mp_unsigned_bin_size(&tmp); + if (*outlen < x) { + err = CRYPT_BUFFER_OVERFLOW; + goto done; + } + if ((err = mp_to_unsigned_bin(&tmp, out)) != MP_OKAY) { goto error; } + *outlen = x; + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); +done: + mp_clear_multi(&p, &tmp, NULL); + return err; +} + +#include "dh_sys.c" + +#endif + diff --git a/dh_sys.c b/dh_sys.c new file mode 100644 index 0000000..fb05aa3 --- /dev/null +++ b/dh_sys.c @@ -0,0 +1,399 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +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[768], dh_shared[768], skey[MAXBLOCKSIZE]; + dh_key pubkey; + unsigned long x, y, z, hashsize, pubkeysize; + int err; + + _ARGCHK(inkey != NULL); + _ARGCHK(out != NULL); + _ARGCHK(len != NULL); + _ARGCHK(key != NULL); + + /* check that wprng/hash are not invalid */ + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + if ((err = hash_is_valid(hash)) != CRYPT_OK) { + return err; + } + + if (keylen > hash_descriptor[hash].hashsize) { + return CRYPT_INVALID_HASH; + } + + /* make a random key and export the public copy */ + if ((err = dh_make_key(prng, wprng, dh_get_size(key), &pubkey)) != CRYPT_OK) { + return err; + } + + pubkeysize = sizeof(pub_expt); + if ((err = dh_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { + dh_free(&pubkey); + return err; + } + + /* now check if the out buffer is big enough */ + if (*len < (1 + 4 + 4 + PACKET_SIZE + pubkeysize + keylen)) { + dh_free(&pubkey); + return CRYPT_BUFFER_OVERFLOW; + } + + /* make random key */ + hashsize = hash_descriptor[hash].hashsize; + + x = (unsigned long)sizeof(dh_shared); + if ((err = dh_shared_secret(&pubkey, key, dh_shared, &x)) != CRYPT_OK) { + dh_free(&pubkey); + return err; + } + dh_free(&pubkey); + + z = sizeof(skey); + if ((err = hash_memory(hash, dh_shared, x, skey, &z)) != CRYPT_OK) { + return err; + } + + /* store header */ + packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_ENC_KEY); + + /* 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]; + } + *len = y; + +#ifdef CLEAN_STACK + /* clean up */ + zeromem(pub_expt, sizeof(pub_expt)); + zeromem(dh_shared, sizeof(dh_shared)); + zeromem(skey, sizeof(skey)); +#endif + + return CRYPT_OK; +} + +int dh_decrypt_key(const unsigned char *in, unsigned long inlen, + unsigned char *outkey, unsigned long *keylen, + dh_key *key) +{ + unsigned char shared_secret[768], skey[MAXBLOCKSIZE]; + unsigned long x, y, z,hashsize, keysize; + int hash, err; + 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; + } + + /* check if initial header should fit */ + if (inlen < PACKET_SIZE+1+4+4) { + return CRYPT_INVALID_PACKET; + } else { + inlen -= PACKET_SIZE+1+4+4; + } + + /* is header correct? */ + if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_ENC_KEY)) != CRYPT_OK) { + return err; + } + + /* 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); + + /* now check if the imported key will fit */ + if (inlen < x) { + return CRYPT_INVALID_PACKET; + } else { + inlen -= x; + } + + y += 4; + if ((err = dh_import(in+y, x, &pubkey)) != CRYPT_OK) { + return err; + } + y += x; + + /* make shared key */ + x = (unsigned long)sizeof(shared_secret); + if ((err = dh_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) { + dh_free(&pubkey); + return err; + } + dh_free(&pubkey); + + z = sizeof(skey); + if ((err = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) { + return err; + } + + /* load in the encrypted key */ + LOAD32L(keysize, in+y); + + /* will the outkey fit as part of the input */ + if (inlen < keysize) { + return CRYPT_INVALID_PACKET; + } else { + inlen -= keysize; + } + + if (keysize > *keylen) { + err = CRYPT_BUFFER_OVERFLOW; + goto done; + } + y += 4; + + *keylen = keysize; + + for (x = 0; x < keysize; x++, y++) { + outkey[x] = skey[x] ^ in[y]; + } + + err = CRYPT_OK; +done: +#ifdef CLEAN_STACK + zeromem(shared_secret, sizeof(shared_secret)); + zeromem(skey, sizeof(skey)); +#endif + return err; +} + +/* perform an ElGamal Signature of a hash + * + * The math works as follows. x is the private key, M is the message to sign + + 1. pick a random k + 2. compute a = g^k mod p + 3. compute b = (M - xa)/k mod p + 4. Send (a,b) + + Now to verify with y=g^x mod p, a and b + + 1. compute y^a * a^b = g^(xa) * g^(k*(M-xa)/k) + = g^(xa + (M - xa)) + = g^M [all mod p] + + 2. Compare against g^M mod p [based on input hash]. + 3. If result of #2 == result of #1 then signature valid +*/ +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[520]; + unsigned long x, y; + int err; + + _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 ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + /* is the IDX valid ? */ + if (is_valid_idx(key->idx) != 1) { + return CRYPT_PK_INVALID_TYPE; + } + + /* make up a random value k, + * since the order of the group is prime + * we need not check if gcd(k, r) is 1 + */ + if (prng_descriptor[wprng].read(buf, sets[key->idx].size, prng) != + (unsigned long)(sets[key->idx].size)) { + return CRYPT_ERROR_READPRNG; + } + + /* init bignums */ + if ((err = mp_init_multi(&a, &b, &k, &m, &p, &g, &p1, &tmp, NULL)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + + /* load k and m */ + if ((err = mp_read_unsigned_bin(&m, (unsigned char *)in, inlen)) != MP_OKAY) { goto error; } +#ifdef FAST_PK + if ((err = mp_read_unsigned_bin(&k, buf, MIN(32,sets[key->idx].size))) != MP_OKAY) { goto error; } +#else + if ((err = mp_read_unsigned_bin(&k, buf, sets[key->idx].size)) != MP_OKAY) { goto error; } +#endif + + /* load g, p and p1 */ + if ((err = mp_read_radix(&g, sets[key->idx].base, 64)) != MP_OKAY) { goto error; } + if ((err = mp_read_radix(&p, sets[key->idx].prime, 64)) != MP_OKAY) { goto error; } + if ((err = mp_sub_d(&p, 1, &p1)) != MP_OKAY) { goto error; } + if ((err = mp_div_2(&p1, &p1)) != MP_OKAY) { goto error; } /* p1 = (p-1)/2 */ + + /* now get a = g^k mod p */ + if ((err = 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 ((err = mp_invmod(&k, &p1, &k)) != MP_OKAY) { goto error; } /* k = 1/k mod p1 */ + if ((err = mp_mulmod(&a, &key->x, &p1, &tmp)) != MP_OKAY) { goto error; } /* tmp = xa */ + if ((err = mp_submod(&m, &tmp, &p1, &tmp)) != MP_OKAY) { goto error; } /* tmp = M - xa */ + if ((err = mp_mulmod(&k, &tmp, &p1, &b)) != MP_OKAY) { goto error; } /* b = (M - xa)/k */ + + /* check for overflow */ + if ((unsigned long)(PACKET_SIZE + 4 + 4 + mp_unsigned_bin_size(&a) + mp_unsigned_bin_size(&b)) > *outlen) { + err = CRYPT_BUFFER_OVERFLOW; + goto done; + } + + /* store header */ + y = PACKET_SIZE; + + /* now store them both (a,b) */ + x = (unsigned long)mp_unsigned_bin_size(&a); + STORE32L(x, out+y); y += 4; + if ((err = mp_to_unsigned_bin(&a, out+y)) != MP_OKAY) { goto error; } + y += x; + + x = (unsigned long)mp_unsigned_bin_size(&b); + STORE32L(x, out+y); y += 4; + if ((err = mp_to_unsigned_bin(&b, out+y)) != MP_OKAY) { goto error; } + y += x; + + /* check if size too big */ + if (*outlen < y) { + err = CRYPT_BUFFER_OVERFLOW; + goto done; + } + + /* store header */ + packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_SIGNED); + *outlen = y; + + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); +done: + mp_clear_multi(&tmp, &p1, &g, &p, &m, &k, &b, &a, NULL); + return err; +} + + +/* verify the signature in sig of the given hash */ +int dh_verify_hash(const unsigned char *sig, unsigned long siglen, + const unsigned char *hash, unsigned long hashlen, + int *stat, dh_key *key) +{ + mp_int a, b, p, g, m, tmp; + unsigned long x, y; + int err; + + _ARGCHK(sig != NULL); + _ARGCHK(hash != NULL); + _ARGCHK(stat != NULL); + _ARGCHK(key != NULL); + + /* default to invalid */ + *stat = 0; + + /* check initial input length */ + if (siglen < PACKET_SIZE+4+4) { + return CRYPT_INVALID_PACKET; + } + + /* header ok? */ + if ((err = packet_valid_header((unsigned char *)sig, PACKET_SECT_DH, PACKET_SUB_SIGNED)) != CRYPT_OK) { + return err; + } + + /* get hash out of packet */ + y = PACKET_SIZE; + + /* init all bignums */ + if ((err = mp_init_multi(&a, &p, &b, &g, &m, &tmp, NULL)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + + /* load a and b */ + INPUT_BIGNUM(&a, sig, x, y, siglen); + INPUT_BIGNUM(&b, sig, x, y, siglen); + + /* load p and g */ + if ((err = mp_read_radix(&p, sets[key->idx].prime, 64)) != MP_OKAY) { goto error1; } + if ((err = mp_read_radix(&g, sets[key->idx].base, 64)) != MP_OKAY) { goto error1; } + + /* load m */ + if ((err = mp_read_unsigned_bin(&m, (unsigned char *)hash, hashlen)) != MP_OKAY) { goto error1; } + + /* find g^m mod p */ + if ((err = mp_exptmod(&g, &m, &p, &m)) != MP_OKAY) { goto error1; } /* m = g^m mod p */ + + /* find y^a * a^b */ + if ((err = mp_exptmod(&key->y, &a, &p, &tmp)) != MP_OKAY) { goto error1; } /* tmp = y^a mod p */ + if ((err = mp_exptmod(&a, &b, &p, &a)) != MP_OKAY) { goto error1; } /* a = a^b mod p */ + if ((err = mp_mulmod(&a, &tmp, &p, &a)) != MP_OKAY) { goto error1; } /* a = y^a * a^b mod p */ + + /* y^a * a^b == g^m ??? */ + if (mp_cmp(&a, &m) == 0) { + *stat = 1; + } + + /* clean up */ + err = CRYPT_OK; + goto done; +error1: + err = mpi_to_ltc_error(err); +error: +done: + mp_clear_multi(&tmp, &m, &g, &p, &b, &a, NULL); + return err; +} + diff --git a/dsa_export.c b/dsa_export.c new file mode 100644 index 0000000..995b1cf --- /dev/null +++ b/dsa_export.c @@ -0,0 +1,62 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef MDSA + +int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key) +{ + unsigned long y, z; + int err; + + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* can we store the static header? */ + if (*outlen < (PACKET_SIZE + 1 + 2)) { + return CRYPT_BUFFER_OVERFLOW; + } + + if (type == PK_PRIVATE && key->type != PK_PRIVATE) { + return CRYPT_PK_TYPE_MISMATCH; + } + + if (type != PK_PUBLIC && type != PK_PRIVATE) { + return CRYPT_INVALID_ARG; + } + + /* store header */ + packet_store_header(out, PACKET_SECT_DSA, PACKET_SUB_KEY); + y = PACKET_SIZE; + + /* store g, p, q, qord */ + out[y++] = type; + out[y++] = (key->qord>>8)&255; + out[y++] = key->qord & 255; + + OUTPUT_BIGNUM(&key->g,out,y,z); + OUTPUT_BIGNUM(&key->p,out,y,z); + OUTPUT_BIGNUM(&key->q,out,y,z); + + /* public exponent */ + OUTPUT_BIGNUM(&key->y,out,y,z); + + if (type == PK_PRIVATE) { + OUTPUT_BIGNUM(&key->x,out,y,z); + } + + *outlen = y; + return CRYPT_OK; +} + +#endif + diff --git a/dsa_free.c b/dsa_free.c new file mode 100644 index 0000000..c451951 --- /dev/null +++ b/dsa_free.c @@ -0,0 +1,21 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef MDSA + +void dsa_free(dsa_key *key) +{ + _ARGCHK(key != NULL); + mp_clear_multi(&key->g, &key->q, &key->p, &key->x, &key->y, NULL); +} + +#endif diff --git a/dsa_import.c b/dsa_import.c new file mode 100644 index 0000000..429876d --- /dev/null +++ b/dsa_import.c @@ -0,0 +1,59 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef MDSA + +int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key) +{ + unsigned long x, y; + int err; + + _ARGCHK(in != NULL); + _ARGCHK(key != NULL); + + /* check length */ + if ((1+2+PACKET_SIZE) > inlen) { + return CRYPT_INVALID_PACKET; + } + + /* check type */ + if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_DSA, PACKET_SUB_KEY)) != CRYPT_OK) { + return err; + } + y = PACKET_SIZE; + + /* init key */ + if (mp_init_multi(&key->p, &key->g, &key->q, &key->x, &key->y, NULL) != MP_OKAY) { + return CRYPT_MEM; + } + + /* read type/qord */ + key->type = in[y++]; + key->qord = ((unsigned)in[y]<<8)|((unsigned)in[y+1]); + y += 2; + + /* input publics */ + INPUT_BIGNUM(&key->g,in,x,y, inlen); + INPUT_BIGNUM(&key->p,in,x,y, inlen); + INPUT_BIGNUM(&key->q,in,x,y, inlen); + INPUT_BIGNUM(&key->y,in,x,y, inlen); + if (key->type == PK_PRIVATE) { + INPUT_BIGNUM(&key->x,in,x,y, inlen); + } + + return CRYPT_OK; +error: + mp_clear_multi(&key->p, &key->g, &key->q, &key->x, &key->y, NULL); + return err; +} + +#endif diff --git a/dsa_make_key.c b/dsa_make_key.c new file mode 100644 index 0000000..4d2af24 --- /dev/null +++ b/dsa_make_key.c @@ -0,0 +1,117 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef MDSA + +int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key) +{ + mp_int tmp, tmp2; + int err, res; + unsigned char buf[512]; + + _ARGCHK(key != NULL); + + /* check prng */ + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + /* check size */ + if (group_size >= 1024 || group_size <= 15 || + group_size >= modulus_size || (modulus_size - group_size) >= (int)sizeof(buf)) { + return CRYPT_INVALID_ARG; + } + + /* init mp_ints */ + if ((err = mp_init_multi(&tmp, &tmp2, &key->g, &key->q, &key->p, &key->x, &key->y, NULL)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + + /* make our prime q */ + if ((err = rand_prime(&key->q, group_size*8, prng, wprng)) != CRYPT_OK) { goto error2; } + + /* double q */ + if ((err = mp_mul_2(&key->q, &tmp)) != MP_OKAY) { goto error; } + + /* now make a random string and multply it against q */ + if (prng_descriptor[wprng].read(buf+1, modulus_size - group_size, prng) != (unsigned long)(modulus_size - group_size)) { + err = CRYPT_ERROR_READPRNG; + goto error2; + } + + /* force magnitude */ + buf[0] = 1; + + /* force even */ + buf[modulus_size - group_size] &= ~1; + + if ((err = mp_read_unsigned_bin(&tmp2, buf, modulus_size - group_size+1)) != MP_OKAY) { goto error; } + if ((err = mp_mul(&key->q, &tmp2, &key->p)) != MP_OKAY) { goto error; } + if ((err = mp_add_d(&key->p, 1, &key->p)) != MP_OKAY) { goto error; } + + /* now loop until p is prime */ + for (;;) { + if ((err = is_prime(&key->p, &res)) != CRYPT_OK) { goto error2; } + if (res == MP_YES) break; + + /* add 2q to p and 2 to tmp2 */ + if ((err = mp_add(&tmp, &key->p, &key->p)) != MP_OKAY) { goto error; } + if ((err = mp_add_d(&tmp2, 2, &tmp2)) != MP_OKAY) { goto error; } + } + + /* now p = (q * tmp2) + 1 is prime, find a value g for which g^tmp2 != 1 */ + mp_set(&key->g, 1); + + do { + if ((err = mp_add_d(&key->g, 1, &key->g)) != MP_OKAY) { goto error; } + if ((err = mp_exptmod(&key->g, &tmp2, &key->p, &tmp)) != MP_OKAY) { goto error; } + } while (mp_cmp_d(&tmp, 1) == MP_EQ); + + /* at this point tmp generates a group of order q mod p */ + mp_exch(&tmp, &key->g); + + /* so now we have our DH structure, generator g, order q, modulus p + Now we need a random exponent [mod q] and it's power g^x mod p + */ + do { + if (prng_descriptor[wprng].read(buf, group_size, prng) != (unsigned long)group_size) { + err = CRYPT_ERROR_READPRNG; + goto error2; + } + if ((err = mp_read_unsigned_bin(&key->x, buf, group_size)) != MP_OKAY) { goto error; } + } while (mp_cmp_d(&key->x, 1) != MP_GT); + if ((err = mp_exptmod(&key->g, &key->x, &key->p, &key->y)) != MP_OKAY) { goto error; } + + key->type = PK_PRIVATE; + key->qord = group_size; + + /* shrink the ram required */ + if ((err = mp_shrink(&key->g)) != MP_OKAY) { goto error; } + if ((err = mp_shrink(&key->p)) != MP_OKAY) { goto error; } + if ((err = mp_shrink(&key->q)) != MP_OKAY) { goto error; } + if ((err = mp_shrink(&key->x)) != MP_OKAY) { goto error; } + if ((err = mp_shrink(&key->y)) != MP_OKAY) { goto error; } + + err = CRYPT_OK; + +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + + goto done; +error : err = mpi_to_ltc_error(err); +error2: mp_clear_multi(&key->g, &key->q, &key->p, &key->x, &key->y, NULL); +done : mp_clear_multi(&tmp, &tmp2, NULL); + return err; +} + +#endif diff --git a/dsa_sign_hash.c b/dsa_sign_hash.c new file mode 100644 index 0000000..b204371 --- /dev/null +++ b/dsa_sign_hash.c @@ -0,0 +1,125 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef MDSA + +int dsa_sign_hash(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, dsa_key *key) +{ + mp_int k, kinv, tmp, r, s; + unsigned char buf[512]; + int err, y; + unsigned long len; + + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + if (key->type != PK_PRIVATE) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* check group order size */ + if (key->qord >= (int)sizeof(buf)) { + return CRYPT_INVALID_ARG; + } + + /* Init our temps */ + if ((err = mp_init_multi(&k, &kinv, &r, &s, &tmp, NULL)) != MP_OKAY) { goto error; } + +retry: + + do { + /* gen random k */ + if (prng_descriptor[wprng].read(buf, key->qord, prng) != (unsigned long)key->qord) { + err = CRYPT_ERROR_READPRNG; + goto done; + } + + /* read k */ + if ((err = mp_read_unsigned_bin(&k, buf, key->qord)) != MP_OKAY) { goto error; } + + /* k > 1 ? */ + if (mp_cmp_d(&k, 1) != MP_GT) { goto retry; } + + /* test gcd */ + if ((err = mp_gcd(&k, &key->q, &tmp)) != MP_OKAY) { goto error; } + } while (mp_cmp_d(&tmp, 1) != MP_EQ); + + /* now find 1/k mod q */ + if ((err = mp_invmod(&k, &key->q, &kinv)) != MP_OKAY) { goto error; } + + /* now find r = g^k mod p mod q */ + if ((err = mp_exptmod(&key->g, &k, &key->p, &r)) != MP_OKAY) { goto error; } + if ((err = mp_mod(&r, &key->q, &r)) != MP_OKAY) { goto error; } + + if (mp_iszero(&r) == MP_YES) { goto retry; } + + /* now find s = (in + xr)/k mod q */ + if ((err = mp_read_unsigned_bin(&tmp, (unsigned char *)in, inlen)) != MP_OKAY) { goto error; } + if ((err = mp_mul(&key->x, &r, &s)) != MP_OKAY) { goto error; } + if ((err = mp_add(&s, &tmp, &s)) != MP_OKAY) { goto error; } + if ((err = mp_mulmod(&s, &kinv, &key->q, &s)) != MP_OKAY) { goto error; } + + if (mp_iszero(&s) == MP_YES) { goto retry; } + + /* now store em both */ + + /* first check that we have enough room */ + if (*outlen < (unsigned long)(PACKET_SIZE + 4 + mp_unsigned_bin_size(&s) + mp_unsigned_bin_size(&r))) { + err = CRYPT_BUFFER_OVERFLOW; + goto done; + } + + /* packet header */ + packet_store_header(out, PACKET_SECT_DSA, PACKET_SUB_SIGNED); + y = PACKET_SIZE; + + /* store length of r */ + len = mp_unsigned_bin_size(&r); + out[y++] = (len>>8)&255; + out[y++] = len&255; + + /* store r */ + if ((err = mp_to_unsigned_bin(&r, out+y)) != MP_OKAY) { goto error; } + y += len; + + /* store length of s */ + len = mp_unsigned_bin_size(&s); + out[y++] = (len>>8)&255; + out[y++] = len&255; + + /* store s */ + if ((err = mp_to_unsigned_bin(&s, out+y)) != MP_OKAY) { goto error; } + y += len; + + /* reset size */ + *outlen = y; + + err = CRYPT_OK; + goto done; + +error : err = mpi_to_ltc_error(err); +done : mp_clear_multi(&k, &kinv, &r, &s, &tmp, NULL); +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + return err; +} + +#endif diff --git a/dsa_verify_hash.c b/dsa_verify_hash.c new file mode 100644 index 0000000..745cd7c --- /dev/null +++ b/dsa_verify_hash.c @@ -0,0 +1,97 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef MDSA + +int dsa_verify_hash(const unsigned char *sig, unsigned long siglen, + const unsigned char *hash, unsigned long inlen, + int *stat, dsa_key *key) +{ + mp_int r, s, w, v, u1, u2; + unsigned long x, y; + int err; + + _ARGCHK(sig != NULL); + _ARGCHK(hash != NULL); + _ARGCHK(stat != NULL); + _ARGCHK(key != NULL); + + /* default to invalid signature */ + *stat = 0; + + if (siglen < PACKET_SIZE+2+2) { + return CRYPT_INVALID_PACKET; + } + + /* is the message format correct? */ + if ((err = packet_valid_header((unsigned char *)sig, PACKET_SECT_DSA, PACKET_SUB_SIGNED)) != CRYPT_OK) { + return err; + } + + /* skip over header */ + y = PACKET_SIZE; + + /* init our variables */ + if ((err = mp_init_multi(&r, &s, &w, &v, &u1, &u2, NULL)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + + /* read in r followed by s */ + x = ((unsigned)sig[y]<<8)|((unsigned)sig[y+1]); + y += 2; + if (y + x > siglen) { + err = CRYPT_INVALID_PACKET; + goto done; + } + if ((err = mp_read_unsigned_bin(&r, (unsigned char *)sig+y, x)) != MP_OKAY) { goto error; } + y += x; + + /* load s */ + x = ((unsigned)sig[y]<<8)|((unsigned)sig[y+1]); + y += 2; + if (y + x > siglen) { + err = CRYPT_INVALID_PACKET; + goto done; + } + if ((err = mp_read_unsigned_bin(&s, (unsigned char *)sig+y, x)) != MP_OKAY) { goto error; } + + /* w = 1/s mod q */ + if ((err = mp_invmod(&s, &key->q, &w)) != MP_OKAY) { goto error; } + + /* u1 = m * w mod q */ + if ((err = mp_read_unsigned_bin(&u1, (unsigned char *)hash, inlen)) != MP_OKAY) { goto error; } + if ((err = mp_mulmod(&u1, &w, &key->q, &u1)) != MP_OKAY) { goto error; } + + /* u2 = r*w mod q */ + if ((err = mp_mulmod(&r, &w, &key->q, &u2)) != MP_OKAY) { goto error; } + + /* v = g^u1 * y^u2 mod p mod q */ + if ((err = mp_exptmod(&key->g, &u1, &key->p, &u1)) != MP_OKAY) { goto error; } + if ((err = mp_exptmod(&key->y, &u2, &key->p, &u2)) != MP_OKAY) { goto error; } + if ((err = mp_mulmod(&u1, &u2, &key->p, &v)) != MP_OKAY) { goto error; } + if ((err = mp_mod(&v, &key->q, &v)) != MP_OKAY) { goto error; } + + /* if r = v then we're set */ + if (mp_cmp(&r, &v) == MP_EQ) { + *stat = 1; + } + + err = CRYPT_OK; + goto done; + +error : err = mpi_to_ltc_error(err); +done : mp_clear_multi(&r, &s, &w, &v, &u1, &u2, NULL); + return err; +} + +#endif + diff --git a/dsa_verify_key.c b/dsa_verify_key.c new file mode 100644 index 0000000..c17bab8 --- /dev/null +++ b/dsa_verify_key.c @@ -0,0 +1,86 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef MDSA + +int dsa_verify_key(dsa_key *key, int *stat) +{ + mp_int tmp, tmp2; + int res, err; + + _ARGCHK(key != NULL); + _ARGCHK(stat != NULL); + + *stat = 0; + + /* first make sure key->q and key->p are prime */ + if ((err = is_prime(&key->q, &res)) != CRYPT_OK) { + return err; + } + if (res == 0) { + return CRYPT_OK; + } + + + if ((err = is_prime(&key->p, &res)) != CRYPT_OK) { + return err; + } + if (res == 0) { + return CRYPT_OK; + } + + /* now make sure that g is not -1, 0 or 1 and

g, 0) == MP_EQ || mp_cmp_d(&key->g, 1) == MP_EQ) { + return CRYPT_OK; + } + if ((err = mp_init_multi(&tmp, &tmp2, NULL)) != MP_OKAY) { goto error; } + if ((err = mp_sub_d(&key->p, 1, &tmp)) != MP_OKAY) { goto error; } + if (mp_cmp(&tmp, &key->g) == MP_EQ || mp_cmp(&key->g, &key->p) != MP_LT) { + err = CRYPT_OK; + goto done; + } + + /* 1 < y < p-1 */ + if (!(mp_cmp_d(&key->y, 1) == MP_GT && mp_cmp(&key->y, &tmp) == MP_LT)) { + err = CRYPT_OK; + goto done; + } + + /* now we have to make sure that g^q = 1, and that p-1/q gives 0 remainder */ + if ((err = mp_div(&tmp, &key->q, &tmp, &tmp2)) != MP_OKAY) { goto error; } + if (mp_iszero(&tmp2) != MP_YES) { + err = CRYPT_OK; + goto done; + } + + if ((err = mp_exptmod(&key->g, &key->q, &key->p, &tmp)) != MP_OKAY) { goto error; } + if (mp_cmp_d(&tmp, 1) != MP_EQ) { + err = CRYPT_OK; + goto done; + } + + /* now we have to make sure that y^q = 1, this makes sure y \in g^x mod p */ + if ((err = mp_exptmod(&key->y, &key->q, &key->p, &tmp)) != MP_OKAY) { goto error; } + if (mp_cmp_d(&tmp, 1) != MP_EQ) { + err = CRYPT_OK; + goto done; + } + + /* at this point we are out of tests ;-( */ + err = CRYPT_OK; + *stat = 1; + goto done; +error: err = mpi_to_ltc_error(err); +done : mp_clear_multi(&tmp, &tmp2, NULL); + return err; +} +#endif diff --git a/eax_addheader.c b/eax_addheader.c new file mode 100644 index 0000000..c7dfdd0 --- /dev/null +++ b/eax_addheader.c @@ -0,0 +1,25 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* EAX Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef EAX_MODE + +/* add header (metadata) to the stream */ +int eax_addheader(eax_state *eax, const unsigned char *header, unsigned long length) +{ + _ARGCHK(eax != NULL); + _ARGCHK(header != NULL); + return omac_process(&eax->headeromac, header, length); +} + +#endif diff --git a/eax_decrypt.c b/eax_decrypt.c new file mode 100644 index 0000000..de7c290 --- /dev/null +++ b/eax_decrypt.c @@ -0,0 +1,34 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* EAX Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef EAX_MODE + +int eax_decrypt(eax_state *eax, const unsigned char *ct, unsigned char *pt, unsigned long length) +{ + int err; + + _ARGCHK(eax != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + + /* omac ciphertext */ + if ((err = omac_process(&eax->ctomac, ct, length)) != CRYPT_OK) { + return err; + } + + /* decrypt */ + return ctr_decrypt(ct, pt, length, &eax->ctr); +} + +#endif diff --git a/eax_decrypt_verify_memory.c b/eax_decrypt_verify_memory.c new file mode 100644 index 0000000..3e68efe --- /dev/null +++ b/eax_decrypt_verify_memory.c @@ -0,0 +1,60 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* EAX Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef EAX_MODE + +int eax_decrypt_verify_memory(int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, unsigned long noncelen, + const unsigned char *header, unsigned long headerlen, + const unsigned char *ct, unsigned long ctlen, + unsigned char *pt, + unsigned char *tag, unsigned long taglen, + int *res) +{ + int err; + eax_state eax; + unsigned char buf[MAXBLOCKSIZE]; + unsigned long buflen; + + _ARGCHK(res != NULL); + + /* default to zero */ + *res = 0; + + if ((err = eax_init(&eax, cipher, key, keylen, nonce, noncelen, header, headerlen)) != CRYPT_OK) { + return err; + } + + if ((err = eax_decrypt(&eax, ct, pt, ctlen)) != CRYPT_OK) { + return err; + } + + buflen = MIN(sizeof(buf), taglen); + if ((err = eax_done(&eax, buf, &buflen)) != CRYPT_OK) { + return err; + } + + /* compare tags */ + if (buflen >= taglen && memcmp(buf, tag, taglen) == 0) { + *res = 1; + } + +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + return CRYPT_OK; +} + +#endif diff --git a/eax_done.c b/eax_done.c new file mode 100644 index 0000000..8bc3706 --- /dev/null +++ b/eax_done.c @@ -0,0 +1,56 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* EAX Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef EAX_MODE + +int eax_done(eax_state *eax, unsigned char *tag, unsigned long *taglen) +{ + int err; + unsigned char headermac[MAXBLOCKSIZE], ctmac[MAXBLOCKSIZE]; + unsigned long x, len; + + _ARGCHK(eax != NULL); + _ARGCHK(tag != NULL); + _ARGCHK(taglen != NULL); + + /* finish ctomac */ + len = sizeof(ctmac); + if ((err = omac_done(&eax->ctomac, ctmac, &len)) != CRYPT_OK) { + return err; + } + + /* finish headeromac */ + + /* note we specifically don't reset len so the two lens are minimal */ + + if ((err = omac_done(&eax->headeromac, headermac, &len)) != CRYPT_OK) { + return err; + } + + /* compute N xor H xor C */ + for (x = 0; x < len && x < *taglen; x++) { + tag[x] = eax->N[x] ^ headermac[x] ^ ctmac[x]; + } + *taglen = x; + +#ifdef CLEAN_STACK + zeromem(ctmac, sizeof(ctmac)); + zeromem(headermac, sizeof(headermac)); + zeromem(eax, sizeof(*eax)); +#endif + + return CRYPT_OK; +} + +#endif diff --git a/eax_encrypt.c b/eax_encrypt.c new file mode 100644 index 0000000..1b4930e --- /dev/null +++ b/eax_encrypt.c @@ -0,0 +1,35 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* EAX Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef EAX_MODE + +int eax_encrypt(eax_state *eax, const unsigned char *pt, unsigned char *ct, unsigned long length) +{ + int err; + + _ARGCHK(eax != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + + /* encrypt */ + if ((err = ctr_encrypt(pt, ct, length, &eax->ctr)) != CRYPT_OK) { + return err; + } + + /* omac ciphertext */ + return omac_process(&eax->ctomac, ct, length); +} + +#endif + diff --git a/eax_encrypt_authenticate_memory.c b/eax_encrypt_authenticate_memory.c new file mode 100644 index 0000000..60e9fa7 --- /dev/null +++ b/eax_encrypt_authenticate_memory.c @@ -0,0 +1,43 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* EAX Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef EAX_MODE + +int eax_encrypt_authenticate_memory(int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, unsigned long noncelen, + const unsigned char *header, unsigned long headerlen, + const unsigned char *pt, unsigned long ptlen, + unsigned char *ct, + unsigned char *tag, unsigned long *taglen) +{ + int err; + eax_state eax; + + if ((err = eax_init(&eax, cipher, key, keylen, nonce, noncelen, header, headerlen)) != CRYPT_OK) { + return err; + } + + if ((err = eax_encrypt(&eax, pt, ct, ptlen)) != CRYPT_OK) { + return err; + } + + if ((err = eax_done(&eax, tag, taglen)) != CRYPT_OK) { + return err; + } + + return CRYPT_OK; +} + +#endif diff --git a/eax_init.c b/eax_init.c new file mode 100644 index 0000000..1b1bbba --- /dev/null +++ b/eax_init.c @@ -0,0 +1,106 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* EAX Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef EAX_MODE + +int eax_init(eax_state *eax, int cipher, const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, unsigned long noncelen, + const unsigned char *header, unsigned long headerlen) +{ + unsigned char buf[MAXBLOCKSIZE]; + int err, blklen; + omac_state omac; + unsigned long len; + + + _ARGCHK(eax != NULL); + _ARGCHK(key != NULL); + _ARGCHK(nonce != NULL); + if (headerlen > 0) { + _ARGCHK(header != NULL); + } + + if ((err = cipher_is_valid(cipher)) != CRYPT_OK) { + return err; + } + blklen = cipher_descriptor[cipher].block_length; + + /* N = OMAC_0K(nonce) */ + zeromem(buf, sizeof(buf)); + if ((err = omac_init(&omac, cipher, key, keylen)) != CRYPT_OK) { + return err; + } + + /* omac the [0]_n */ + if ((err = omac_process(&omac, buf, blklen)) != CRYPT_OK) { + return err; + } + /* omac the nonce */ + if ((err = omac_process(&omac, nonce, noncelen)) != CRYPT_OK) { + return err; + } + /* store result */ + len = sizeof(eax->N); + if ((err = omac_done(&omac, eax->N, &len)) != CRYPT_OK) { + return err; + } + + /* H = OMAC_1K(header) */ + zeromem(buf, sizeof(buf)); + buf[blklen - 1] = 1; + + if ((err = omac_init(&eax->headeromac, cipher, key, keylen)) != CRYPT_OK) { + return err; + } + + /* omac the [1]_n */ + if ((err = omac_process(&eax->headeromac, buf, blklen)) != CRYPT_OK) { + return err; + } + /* omac the header */ + if (headerlen != 0) { + if ((err = omac_process(&eax->headeromac, header, headerlen)) != CRYPT_OK) { + return err; + } + } + + /* note we don't finish the headeromac, this allows us to add more header later */ + + /* setup the CTR mode */ + if ((err = ctr_start(cipher, eax->N, key, keylen, 0, &eax->ctr)) != CRYPT_OK) { + return err; + } + /* use big-endian counter */ + eax->ctr.mode = 1; + + /* setup the OMAC for the ciphertext */ + if ((err = omac_init(&eax->ctomac, cipher, key, keylen)) != CRYPT_OK) { + return err; + } + + /* omac [2]_n */ + zeromem(buf, sizeof(buf)); + buf[blklen-1] = 2; + if ((err = omac_process(&eax->ctomac, buf, blklen)) != CRYPT_OK) { + return err; + } + +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); + zeromem(&omac, sizeof(omac)); +#endif + return CRYPT_OK; +} + +#endif diff --git a/eax_test.c b/eax_test.c new file mode 100644 index 0000000..93774b0 --- /dev/null +++ b/eax_test.c @@ -0,0 +1,271 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* EAX Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef EAX_MODE + +int eax_test(void) +{ +#ifndef LTC_TEST + return CRYPT_NOP; +#else + static const struct { + int keylen, + noncelen, + headerlen, + msglen; + + unsigned char key[MAXBLOCKSIZE], + nonce[MAXBLOCKSIZE], + header[MAXBLOCKSIZE], + plaintext[MAXBLOCKSIZE], + ciphertext[MAXBLOCKSIZE], + tag[MAXBLOCKSIZE]; + } tests[] = { + +/* NULL message */ +{ + 16, 0, 0, 0, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* nonce */ + { 0 }, + /* header */ + { 0 }, + /* plaintext */ + { 0 }, + /* ciphertext */ + { 0 }, + /* tag */ + { 0x9a, 0xd0, 0x7e, 0x7d, 0xbf, 0xf3, 0x01, 0xf5, + 0x05, 0xde, 0x59, 0x6b, 0x96, 0x15, 0xdf, 0xff } +}, + +/* test with nonce */ +{ + 16, 16, 0, 0, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* nonce */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* header */ + { 0 }, + /* plaintext */ + { 0 }, + /* ciphertext */ + { 0 }, + /* tag */ + { 0x1c, 0xe1, 0x0d, 0x3e, 0xff, 0xd4, 0xca, 0xdb, + 0xe2, 0xe4, 0x4b, 0x58, 0xd6, 0x0a, 0xb9, 0xec } +}, + +/* test with header [no nonce] */ +{ + 16, 0, 16, 0, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* nonce */ + { 0 }, + /* header */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* plaintext */ + { 0 }, + /* ciphertext */ + { 0 }, + /* tag */ + { 0x3a, 0x69, 0x8f, 0x7a, 0x27, 0x0e, 0x51, 0xb0, + 0xf6, 0x5b, 0x3d, 0x3e, 0x47, 0x19, 0x3c, 0xff } +}, + +/* test with header + nonce + plaintext */ +{ + 16, 16, 16, 32, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* nonce */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* header */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* plaintext */ + { 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 }, + /* ciphertext */ + { 0x29, 0xd8, 0x78, 0xd1, 0xa3, 0xbe, 0x85, 0x7b, + 0x6f, 0xb8, 0xc8, 0xea, 0x59, 0x50, 0xa7, 0x78, + 0x33, 0x1f, 0xbf, 0x2c, 0xcf, 0x33, 0x98, 0x6f, + 0x35, 0xe8, 0xcf, 0x12, 0x1d, 0xcb, 0x30, 0xbc }, + /* tag */ + { 0x4f, 0xbe, 0x03, 0x38, 0xbe, 0x1c, 0x8c, 0x7e, + 0x1d, 0x7a, 0xe7, 0xe4, 0x5b, 0x92, 0xc5, 0x87 } +}, + +/* test with header + nonce + plaintext [not even sizes!] */ +{ + 16, 15, 14, 29, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* nonce */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e }, + /* header */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d }, + /* plaintext */ + { 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 }, + /* ciphertext */ + { 0xdd, 0x25, 0xc7, 0x54, 0xc5, 0xb1, 0x7c, 0x59, + 0x28, 0xb6, 0x9b, 0x73, 0x15, 0x5f, 0x7b, 0xb8, + 0x88, 0x8f, 0xaf, 0x37, 0x09, 0x1a, 0xd9, 0x2c, + 0x8a, 0x24, 0xdb, 0x86, 0x8b }, + /* tag */ + { 0x0d, 0x1a, 0x14, 0xe5, 0x22, 0x24, 0xff, 0xd2, + 0x3a, 0x05, 0xfa, 0x02, 0xcd, 0xef, 0x52, 0xda } +}, + +/* Vectors from Brian Gladman */ + +{ + 16, 16, 8, 0, + /* key */ + { 0x23, 0x39, 0x52, 0xde, 0xe4, 0xd5, 0xed, 0x5f, + 0x9b, 0x9c, 0x6d, 0x6f, 0xf8, 0x0f, 0xf4, 0x78 }, + /* nonce */ + { 0x62, 0xec, 0x67, 0xf9, 0xc3, 0xa4, 0xa4, 0x07, + 0xfc, 0xb2, 0xa8, 0xc4, 0x90, 0x31, 0xa8, 0xb3 }, + /* header */ + { 0x6b, 0xfb, 0x91, 0x4f, 0xd0, 0x7e, 0xae, 0x6b }, + /* PT */ + { 0x00 }, + /* CT */ + { 0x00 }, + /* tag */ + { 0xe0, 0x37, 0x83, 0x0e, 0x83, 0x89, 0xf2, 0x7b, + 0x02, 0x5a, 0x2d, 0x65, 0x27, 0xe7, 0x9d, 0x01 } +}, + +{ + 16, 16, 8, 2, + /* key */ + { 0x91, 0x94, 0x5d, 0x3f, 0x4d, 0xcb, 0xee, 0x0b, + 0xf4, 0x5e, 0xf5, 0x22, 0x55, 0xf0, 0x95, 0xa4 }, + /* nonce */ + { 0xbe, 0xca, 0xf0, 0x43, 0xb0, 0xa2, 0x3d, 0x84, + 0x31, 0x94, 0xba, 0x97, 0x2c, 0x66, 0xde, 0xbd }, + /* header */ + { 0xfa, 0x3b, 0xfd, 0x48, 0x06, 0xeb, 0x53, 0xfa }, + /* PT */ + { 0xf7, 0xfb }, + /* CT */ + { 0x19, 0xdd }, + /* tag */ + { 0x5c, 0x4c, 0x93, 0x31, 0x04, 0x9d, 0x0b, 0xda, + 0xb0, 0x27, 0x74, 0x08, 0xf6, 0x79, 0x67, 0xe5 } +}, + +{ + 16, 16, 8, 5, + /* key */ + { 0x01, 0xf7, 0x4a, 0xd6, 0x40, 0x77, 0xf2, 0xe7, + 0x04, 0xc0, 0xf6, 0x0a, 0xda, 0x3d, 0xd5, 0x23 }, + /* nonce */ + { 0x70, 0xc3, 0xdb, 0x4f, 0x0d, 0x26, 0x36, 0x84, + 0x00, 0xa1, 0x0e, 0xd0, 0x5d, 0x2b, 0xff, 0x5e }, + /* header */ + { 0x23, 0x4a, 0x34, 0x63, 0xc1, 0x26, 0x4a, 0xc6 }, + /* PT */ + { 0x1a, 0x47, 0xcb, 0x49, 0x33 }, + /* CT */ + { 0xd8, 0x51, 0xd5, 0xba, 0xe0 }, + /* Tag */ + { 0x3a, 0x59, 0xf2, 0x38, 0xa2, 0x3e, 0x39, 0x19, + 0x9d, 0xc9, 0x26, 0x66, 0x26, 0xc4, 0x0f, 0x80 } +} + +}; + int err, x, idx, res; + unsigned long len; + unsigned char outct[MAXBLOCKSIZE], outtag[MAXBLOCKSIZE]; + + /* AES can be under rijndael or aes... try to find it */ + if ((idx = find_cipher("aes")) == -1) { + if ((idx = find_cipher("rijndael")) == -1) { + return CRYPT_NOP; + } + } + + for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { + len = sizeof(outtag); + if ((err = eax_encrypt_authenticate_memory(idx, tests[x].key, tests[x].keylen, + tests[x].nonce, tests[x].noncelen, tests[x].header, tests[x].headerlen, + tests[x].plaintext, tests[x].msglen, outct, outtag, &len)) != CRYPT_OK) { + return err; + } + if (memcmp(outct, tests[x].ciphertext, tests[x].msglen) || memcmp(outtag, tests[x].tag, len)) { +#if 0 + unsigned long y; + printf("\n\nFailure: \nCT:\n"); + for (y = 0; y < (unsigned long)tests[x].msglen; ) { + printf("0x%02x", outct[y]); + if (y < (unsigned long)(tests[x].msglen-1)) printf(", "); + if (!(++y % 8)) printf("\n"); + } + printf("\nTAG:\n"); + for (y = 0; y < len; ) { + printf("0x%02x", outtag[y]); + if (y < len-1) printf(", "); + if (!(++y % 8)) printf("\n"); + } +#endif + return CRYPT_FAIL_TESTVECTOR; + } + + /* test decrypt */ + if ((err = eax_decrypt_verify_memory(idx, tests[x].key, tests[x].keylen, + tests[x].nonce, tests[x].noncelen, tests[x].header, tests[x].headerlen, + outct, tests[x].msglen, outct, outtag, len, &res)) != CRYPT_OK) { + return err; + } + if ((res != 1) || memcmp(outct, tests[x].plaintext, tests[x].msglen)) { +#if 0 + unsigned long y; + printf("\n\nFailure (res == %d): \nPT:\n", res); + for (y = 0; y < (unsigned long)tests[x].msglen; ) { + printf("0x%02x", outct[y]); + if (y < (unsigned long)(tests[x].msglen-1)) printf(", "); + if (!(++y % 8)) printf("\n"); + } + printf("\n\n"); +#endif + return CRYPT_FAIL_TESTVECTOR; + } + + } + return CRYPT_OK; +#endif /* LTC_TEST */ +} + +#endif /* EAX_MODE */ diff --git a/ecb_decrypt.c b/ecb_decrypt.c new file mode 100644 index 0000000..c25644f --- /dev/null +++ b/ecb_decrypt.c @@ -0,0 +1,31 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef ECB + +int ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_ECB *ecb) +{ + int err; + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(ecb != NULL); + + if ((err = cipher_is_valid(ecb->cipher)) != CRYPT_OK) { + return err; + } + cipher_descriptor[ecb->cipher].ecb_decrypt(ct, pt, &ecb->key); + return CRYPT_OK; +} + +#endif + + diff --git a/ecb_encrypt.c b/ecb_encrypt.c new file mode 100644 index 0000000..51b7646 --- /dev/null +++ b/ecb_encrypt.c @@ -0,0 +1,29 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef ECB + +int ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_ECB *ecb) +{ + int err; + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(ecb != NULL); + + if ((err = cipher_is_valid(ecb->cipher)) != CRYPT_OK) { + return err; + } + cipher_descriptor[ecb->cipher].ecb_encrypt(pt, ct, &ecb->key); + return CRYPT_OK; +} + +#endif diff --git a/ecb_start.c b/ecb_start.c new file mode 100644 index 0000000..073bbe9 --- /dev/null +++ b/ecb_start.c @@ -0,0 +1,29 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef ECB + +int ecb_start(int cipher, const unsigned char *key, int keylen, int num_rounds, symmetric_ECB *ecb) +{ + int err; + _ARGCHK(key != NULL); + _ARGCHK(ecb != NULL); + + if ((err = cipher_is_valid(cipher)) != CRYPT_OK) { + return err; + } + ecb->cipher = cipher; + ecb->blocklen = cipher_descriptor[cipher].block_length; + return cipher_descriptor[cipher].setup(key, keylen, num_rounds, &ecb->key); +} + +#endif diff --git a/ecc.c b/ecc.c new file mode 100644 index 0000000..ee19681 --- /dev/null +++ b/ecc.c @@ -0,0 +1,937 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* 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 + +/* This holds the key settings. ***MUST*** be organized by size from smallest to largest. */ +static const struct { + int size; + char *name, *prime, *B, *order, *Gx, *Gy; +} sets[] = { +#ifdef ECC160 +{ + 20, + "ECC-160", + /* prime */ + "G00000000000000000000000007", + /* B */ + "1oUV2vOaSlWbxr6", + /* order */ + "G0000000000004sCQUtDxaqDUN5", + /* Gx */ + "jpqOf1BHus6Yd/pyhyVpP", + /* Gy */ + "D/wykuuIFfr+vPyx7kQEPu8MixO", +}, +#endif +#ifdef ECC192 +{ + 24, + "ECC-192", + /* prime */ + "/////////////////////l//////////", + + /* B */ + "P2456UMSWESFf+chSYGmIVwutkp1Hhcn", + + /* order */ + "////////////////cTxuDXHhoR6qqYWn", + + /* Gx */ + "68se3h0maFPylo3hGw680FJ/2ls2/n0I", + + /* Gy */ + "1nahbV/8sdXZ417jQoJDrNFvTw4UUKWH" +}, +#endif +#ifdef ECC224 +{ + 28, + "ECC-224", + + /* prime */ + "400000000000000000000000000000000000BV", + + /* B */ + "21HkWGL2CxJIp", + + /* order */ + "4000000000000000000Kxnixk9t8MLzMiV264/", + + /* Gx */ + "jpqOf1BHus6Yd/pyhyVpP", + + /* Gy */ + "3FCtyo2yHA5SFjkCGbYxbOvNeChwS+j6wSIwck", +}, +#endif +#ifdef ECC256 +{ + 32, + "ECC-256", + /* Prime */ + "F////y000010000000000000000////////////////", + + /* B */ + "5h6DTYgEfFdi+kzLNQOXhnb7GQmp5EmzZlEF3udqc1B", + + /* Order */ + "F////y00000//////////+yvlgjfnUUXFEvoiByOoLH", + + /* Gx */ + "6iNqVBXB497+BpcvMEaGF9t0ts1BUipeFIXEKNOcCAM", + + /* Gy */ + "4/ZGkB+6d+RZkVhIdmFdXOhpZDNQp5UpiksG6Wtlr7r" +}, +#endif +#ifdef ECC384 +{ + 48, + "ECC-384", + /* prime */ + "//////////////////////////////////////////x/////00000000003/" + "////", + + /* B */ + "ip4lf+8+v+IOZWLhu/Wj6HWTd6x+WK4I0nG8Zr0JXrh6LZcDYYxHdIg5oEtJ" + "x2hl", + + /* Order */ + "////////////////////////////////nsDDWVGtBTzO6WsoIB2dUkpi6MhC" + "nIbp", + + /* Gx and Gy */ + "geVA8hwB1JUEiSSUyo2jT6uTEsABfvkOMVT1u89KAZXL0l9TlrKfR3fKNZXo" + "TWgt", + + "DXVUIfOcB6zTdfY/afBSAVZq7RqecXHywTen4xNmkC0AOB7E7Nw1dNf37NoG" + "wWvV" +}, +#endif +#ifdef ECC521 +{ + 65, + "ECC-521", + /* prime */ + "V///////////////////////////////////////////////////////////" + "///////////////////////////", + + /* B */ + "56LFhbXZXoQ7vAQ8Q2sXK3kejfoMvcp5VEuj8cHZl49uLOPEL7iVfDx5bB0l" + "JknlmSrSz+8FImqyUz57zHhK3y0", + + /* Order */ + "V//////////////////////////////////////////+b66XuE/BvPhVym1I" + "FS9fT0xjScuYPn7hhjljnwHE6G9", + + /* Gx and Gy */ + "CQ5ZWQt10JfpPu+osOZbRH2d6I1EGK/jI7uAAzWQqqzkg5BNdVlvrae/Xt19" + "wB/gDupIBF1XMf2c/b+VZ72vRrc", + + "HWvAMfucZl015oANxGiVHlPcFL4ILURH6WNhxqN9pvcB9VkSfbUz2P0nL2v0" + "J+j1s4rF726edB2G8Y+b7QVqMPG", +}, +#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 != 0; 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) +{ + /* prevents free'ing null arguments */ + if (p != NULL) { + 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 *mu) +{ + mp_int s, tmp, tmpx; + int err; + + if ((err = mp_init_multi(&s, &tmp, &tmpx, NULL)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + + /* s = (3Xp^2 + a) / (2Yp) */ + if ((err = mp_mul_2(&P->y, &tmp)) != MP_OKAY) { goto error; } /* tmp = 2*y */ + if ((err = mp_invmod(&tmp, modulus, &tmp)) != MP_OKAY) { goto error; } /* tmp = 1/tmp mod modulus */ + if ((err = mp_sqr(&P->x, &s)) != MP_OKAY) { goto error; } /* s = x^2 */ + if ((err = mp_reduce(&s, modulus, mu)) != MP_OKAY) { goto error; } + if ((err = mp_mul_d(&s,(mp_digit)3, &s)) != MP_OKAY) { goto error; } /* s = 3*(x^2) */ + if ((err = mp_sub_d(&s,(mp_digit)3, &s)) != MP_OKAY) { goto error; } /* s = 3*(x^2) - 3 */ + if (mp_cmp_d(&s, 0) == MP_LT) { /* if s < 0 add modulus */ + if ((err = mp_add(&s, modulus, &s)) != MP_OKAY) { goto error; } + } + if ((err = mp_mul(&s, &tmp, &s)) != MP_OKAY) { goto error; } /* s = tmp * s mod modulus */ + if ((err = mp_reduce(&s, modulus, mu)) != MP_OKAY) { goto error; } + + /* Xr = s^2 - 2Xp */ + if ((err = mp_sqr(&s, &tmpx)) != MP_OKAY) { goto error; } /* tmpx = s^2 */ + if ((err = mp_reduce(&tmpx, modulus, mu)) != MP_OKAY) { goto error; } /* tmpx = tmpx mod modulus */ + if ((err = mp_sub(&tmpx, &P->x, &tmpx)) != MP_OKAY) { goto error; } /* tmpx = tmpx - x */ + if ((err = mp_submod(&tmpx, &P->x, modulus, &tmpx)) != MP_OKAY) { goto error; } /* tmpx = tmpx - x mod modulus */ + + /* Yr = -Yp + s(Xp - Xr) */ + if ((err = mp_sub(&P->x, &tmpx, &tmp)) != MP_OKAY) { goto error; } /* tmp = x - tmpx */ + if ((err = mp_mul(&tmp, &s, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp * s */ + if ((err = mp_submod(&tmp, &P->y, modulus, &R->y)) != MP_OKAY) { goto error; } /* y = tmp - y mod modulus */ + if ((err = mp_copy(&tmpx, &R->x)) != MP_OKAY) { goto error; } /* x = tmpx */ + + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); +done: + mp_clear_multi(&tmpx, &tmp, &s, NULL); + return err; +} + +/* 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 *mu) +{ + mp_int s, tmp, tmpx; + int err; + + if ((err = mp_init(&tmp)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + + /* is P==Q or P==-Q? */ + if (((err = mp_neg(&Q->y, &tmp)) != MP_OKAY) || ((err = mp_mod(&tmp, modulus, &tmp)) != MP_OKAY)) { + mp_clear(&tmp); + return mpi_to_ltc_error(err); + } + + if (mp_cmp(&P->x, &Q->x) == MP_EQ) + if (mp_cmp(&P->y, &Q->y) == MP_EQ || mp_cmp(&P->y, &tmp) == MP_EQ) { + mp_clear(&tmp); + return dbl_point(P, R, modulus, mu); + } + + if ((err = mp_init_multi(&tmpx, &s, NULL)) != MP_OKAY) { + mp_clear(&tmp); + return mpi_to_ltc_error(err); + } + + /* get s = (Yp - Yq)/(Xp-Xq) mod p */ + if ((err = mp_sub(&P->x, &Q->x, &tmp)) != MP_OKAY) { goto error; } /* tmp = Px - Qx mod modulus */ + if (mp_cmp_d(&tmp, 0) == MP_LT) { /* if tmp<0 add modulus */ + if ((err = mp_add(&tmp, modulus, &tmp)) != MP_OKAY) { goto error; } + } + if ((err = mp_invmod(&tmp, modulus, &tmp)) != MP_OKAY) { goto error; } /* tmp = 1/tmp mod modulus */ + if ((err = mp_sub(&P->y, &Q->y, &s)) != MP_OKAY) { goto error; } /* s = Py - Qy mod modulus */ + if (mp_cmp_d(&s, 0) == MP_LT) { /* if s<0 add modulus */ + if ((err = mp_add(&s, modulus, &s)) != MP_OKAY) { goto error; } + } + if ((err = mp_mul(&s, &tmp, &s)) != MP_OKAY) { goto error; } /* s = s * tmp mod modulus */ + if ((err = mp_reduce(&s, modulus, mu)) != MP_OKAY) { goto error; } + + /* Xr = s^2 - Xp - Xq */ + if ((err = mp_sqr(&s, &tmp)) != MP_OKAY) { goto error; } /* tmp = s^2 mod modulus */ + if ((err = mp_reduce(&tmp, modulus, mu)) != MP_OKAY) { goto error; } + if ((err = mp_sub(&tmp, &P->x, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp - Px */ + if ((err = mp_sub(&tmp, &Q->x, &tmpx)) != MP_OKAY) { goto error; } /* tmpx = tmp - Qx */ + + /* Yr = -Yp + s(Xp - Xr) */ + if ((err = mp_sub(&P->x, &tmpx, &tmp)) != MP_OKAY) { goto error; } /* tmp = Px - tmpx */ + if ((err = mp_mul(&tmp, &s, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp * s */ + if ((err = mp_submod(&tmp, &P->y, modulus, &R->y)) != MP_OKAY) { goto error; } /* Ry = tmp - Py mod modulus */ + if ((err = mp_mod(&tmpx, modulus, &R->x)) != MP_OKAY) { goto error; } /* Rx = tmpx mod modulus */ + + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); +done: + mp_clear_multi(&s, &tmpx, &tmp, NULL); + return err; +} + +/* size of sliding window, don't change this! */ +#define WINSIZE 4 + +/* 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) +{ + ecc_point *tG, *M[8]; + int i, j, err; + mp_int mu; + mp_digit buf; + int first, bitbuf, bitcpy, bitcnt, mode, digidx; + + /* init barrett reduction */ + if ((err = mp_init(&mu)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + if ((err = mp_reduce_setup(&mu, modulus)) != MP_OKAY) { + mp_clear(&mu); + return mpi_to_ltc_error(err); + } + + /* alloc ram for window temps */ + for (i = 0; i < 8; i++) { + M[i] = new_point(); + if (M[i] == NULL) { + for (j = 0; j < i; j++) { + del_point(M[j]); + } + mp_clear(&mu); + return CRYPT_MEM; + } + } + + /* make a copy of G incase R==G */ + tG = new_point(); + if (tG == NULL) { err = CRYPT_MEM; goto done; } + + /* tG = G */ + if ((err = mp_copy(&G->x, &tG->x)) != MP_OKAY) { goto error; } + if ((err = mp_copy(&G->y, &tG->y)) != MP_OKAY) { goto error; } + + /* calc the M tab, which holds kG for k==8..15 */ + /* M[0] == 8G */ + if ((err = dbl_point(G, M[0], modulus, &mu)) != CRYPT_OK) { goto done; } + if ((err = dbl_point(M[0], M[0], modulus, &mu)) != CRYPT_OK) { goto done; } + if ((err = dbl_point(M[0], M[0], modulus, &mu)) != CRYPT_OK) { goto done; } + + /* now find (8+k)G for k=1..7 */ + for (j = 9; j < 16; j++) { + if ((err = add_point(M[j-9], G, M[j-8], modulus, &mu)) != CRYPT_OK) { goto done; } + } + + /* setup sliding window */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = k->used - 1; + bitcpy = bitbuf = 0; + first = 1; + + /* perform ops */ + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + if (digidx == -1) { + break; + } + buf = k->dp[digidx--]; + bitcnt = (int) DIGIT_BIT; + } + + /* grab the next msb from the multiplicand */ + i = (buf >> (DIGIT_BIT - 1)) & 1; + buf <<= 1; + + /* skip leading zero bits */ + if (mode == 0 && i == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we double */ + if (mode == 1 && i == 0) { + if ((err = dbl_point(R, R, modulus, &mu)) != CRYPT_OK) { goto done; } + continue; + } + + /* else we add it to the window */ + bitbuf |= (i << (WINSIZE - ++bitcpy)); + mode = 2; + + if (bitcpy == WINSIZE) { + /* if this is the first window we do a simple copy */ + if (first == 1) { + /* R = kG [k = first window] */ + if ((err = mp_copy(&M[bitbuf-8]->x, &R->x)) != MP_OKAY) { goto error; } + if ((err = mp_copy(&M[bitbuf-8]->y, &R->y)) != MP_OKAY) { goto error; } + first = 0; + } else { + /* normal window */ + /* ok window is filled so double as required and add */ + /* double first */ + for (j = 0; j < WINSIZE; j++) { + if ((err = dbl_point(R, R, modulus, &mu)) != CRYPT_OK) { goto done; } + } + + /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranteed */ + if ((err = add_point(R, M[bitbuf-8], R, modulus, &mu)) != CRYPT_OK) { goto done; } + } + /* empty window and reset */ + bitcpy = bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then double/add */ + if (mode == 2 && bitcpy > 0) { + /* double then add */ + for (j = 0; j < bitcpy; j++) { + /* only double if we have had at least one add first */ + if (first == 0) { + if ((err = dbl_point(R, R, modulus, &mu)) != CRYPT_OK) { goto done; } + } + + bitbuf <<= 1; + if ((bitbuf & (1 << WINSIZE)) != 0) { + if (first == 1){ + /* first add, so copy */ + if ((err = mp_copy(&tG->x, &R->x)) != MP_OKAY) { goto error; } + if ((err = mp_copy(&tG->y, &R->y)) != MP_OKAY) { goto error; } + first = 0; + } else { + /* then add */ + if ((err = add_point(R, tG, R, modulus, &mu)) != CRYPT_OK) { goto done; } + } + } + } + } + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); +done: + del_point(tG); + for (i = 0; i < 8; i++) { + del_point(M[i]); + } + mp_clear(&mu); + return err; +} + +#undef WINSIZE + +int ecc_test(void) +{ + mp_int modulus, order; + ecc_point *G, *GG; + int i, err, primality; + + if ((err = mp_init_multi(&modulus, &order, NULL)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + + G = new_point(); + GG = new_point(); + if (G == NULL || GG == NULL) { + mp_clear_multi(&modulus, &order, NULL); + del_point(G); + del_point(GG); + return CRYPT_MEM; + } + + for (i = 0; sets[i].size; i++) { + #if 0 + printf("Testing %d\n", sets[i].size); + #endif + if ((err = mp_read_radix(&modulus, (char *)sets[i].prime, 64)) != MP_OKAY) { goto error; } + if ((err = mp_read_radix(&order, (char *)sets[i].order, 64)) != MP_OKAY) { goto error; } + + /* is prime actually prime? */ + if ((err = is_prime(&modulus, &primality)) != CRYPT_OK) { goto done; } + if (primality == 0) { + err = CRYPT_FAIL_TESTVECTOR; + goto done; + } + + /* is order prime ? */ + if ((err = is_prime(&order, &primality)) != CRYPT_OK) { goto done; } + if (primality == 0) { + err = CRYPT_FAIL_TESTVECTOR; + goto done; + } + + if ((err = mp_read_radix(&G->x, (char *)sets[i].Gx, 64)) != MP_OKAY) { goto error; } + if ((err = mp_read_radix(&G->y, (char *)sets[i].Gy, 64)) != MP_OKAY) { goto error; } + + /* then we should have G == (order + 1)G */ + if ((err = mp_add_d(&order, 1, &order)) != MP_OKAY) { goto error; } + if ((err = ecc_mulmod(&order, G, GG, &modulus)) != CRYPT_OK) { goto done; } + if (mp_cmp(&G->x, &GG->x) != 0 || mp_cmp(&G->y, &GG->y) != 0) { + err = CRYPT_FAIL_TESTVECTOR; + goto done; + } + } + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); +done: + del_point(GG); + del_point(G); + mp_clear_multi(&order, &modulus, NULL); + return err; +} + +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 != 0; 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, err; + ecc_point *base; + mp_int prime; + unsigned char buf[128]; + + _ARGCHK(key != NULL); + + /* good prng? */ + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + /* find key size */ + for (x = 0; (keysize > sets[x].size) && (sets[x].size != 0); x++); + keysize = sets[x].size; + + if (sets[x].size == 0) { + return CRYPT_INVALID_KEYSIZE; + } + key->idx = x; + + /* make up random string */ + if (prng_descriptor[wprng].read(buf, (unsigned long)keysize, prng) != (unsigned long)keysize) { + return CRYPT_ERROR_READPRNG; + } + + /* setup the key variables */ + if ((err = mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->k, &prime, NULL)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + 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 ((err = mp_read_radix(&prime, (char *)sets[key->idx].prime, 64)) != MP_OKAY) { goto error; } + if ((err = mp_read_radix(&base->x, (char *)sets[key->idx].Gx, 64)) != MP_OKAY) { goto error; } + if ((err = mp_read_radix(&base->y, (char *)sets[key->idx].Gy, 64)) != MP_OKAY) { goto error; } + if ((err = mp_read_unsigned_bin(&key->k, (unsigned char *)buf, keysize)) != MP_OKAY) { goto error; } + + /* make the public key */ + if ((err = ecc_mulmod(&key->k, base, &key->pubkey, &prime)) != CRYPT_OK) { goto done; } + key->type = PK_PRIVATE; + + /* shrink key */ + if ((err = mp_shrink(&key->k)) != MP_OKAY) { goto error; } + if ((err = mp_shrink(&key->pubkey.x)) != MP_OKAY) { goto error; } + if ((err = mp_shrink(&key->pubkey.y)) != MP_OKAY) { goto error; } + + /* free up ram */ + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); +done: + del_point(base); + mp_clear(&prime); +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + return err; +} + +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 err; + + _ARGCHK(pt != NULL); + _ARGCHK(result != NULL); + + if ((err = mp_init_multi(&tmp, &tmp2, &p, NULL)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + + /* get x^3 - 3x + b */ + if ((err = mp_read_radix(&p, (char *)sets[idx].B, 64)) != MP_OKAY) { goto error; } /* p = B */ + if ((err = mp_expt_d(&pt->x, 3, &tmp)) != MP_OKAY) { goto error; } /* tmp = pX^3 */ + if ((err = mp_mul_d(&pt->x, 3, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = 3*pX^3 */ + if ((err = mp_sub(&tmp, &tmp2, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp - tmp2 */ + if ((err = mp_add(&tmp, &p, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp + p */ + if ((err = mp_read_radix(&p, (char *)sets[idx].prime, 64)) != MP_OKAY) { goto error; } /* p = prime */ + if ((err = mp_mod(&tmp, &p, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp mod p */ + + /* now find square root */ + if ((err = mp_add_d(&p, 1, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = p + 1 */ + if ((err = mp_div_2d(&tmp2, 2, &tmp2, NULL)) != MP_OKAY) { goto error; } /* tmp2 = (p+1)/4 */ + if ((err = 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; + } + + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); +done: + mp_clear_multi(&p, &tmp, &tmp2, NULL); + return err; +} + +static int expand_y_point(ecc_point *pt, int idx, int result) +{ + mp_int tmp, tmp2, p; + int err; + + _ARGCHK(pt != NULL); + + if ((err = mp_init_multi(&tmp, &tmp2, &p, NULL)) != MP_OKAY) { + return CRYPT_MEM; + } + + /* get x^3 - 3x + b */ + if ((err = mp_read_radix(&p, (char *)sets[idx].B, 64)) != MP_OKAY) { goto error; } /* p = B */ + if ((err = mp_expt_d(&pt->x, 3, &tmp)) != MP_OKAY) { goto error; } /* tmp = pX^3 */ + if ((err = mp_mul_d(&pt->x, 3, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = 3*pX^3 */ + if ((err = mp_sub(&tmp, &tmp2, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp - tmp2 */ + if ((err = mp_add(&tmp, &p, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp + p */ + if ((err = mp_read_radix(&p, (char *)sets[idx].prime, 64)) != MP_OKAY) { goto error; } /* p = prime */ + if ((err = mp_mod(&tmp, &p, &tmp)) != MP_OKAY) { goto error; } /* tmp = tmp mod p */ + + /* now find square root */ + if ((err = mp_add_d(&p, 1, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = p + 1 */ + if ((err = mp_div_2d(&tmp2, 2, &tmp2, NULL)) != MP_OKAY) { goto error; } /* tmp2 = (p+1)/4 */ + if ((err = 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 ((err = mp_copy(&tmp, &pt->y) != MP_OKAY)) { goto error; } + } else { + if ((err = mp_sub(&p, &tmp, &pt->y) != MP_OKAY)) { goto error; } + } + + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); +done: + mp_clear_multi(&p, &tmp, &tmp2, NULL); + return err; +} + +int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key) +{ + unsigned long y, z; + int cp, err; + + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* can we store the static header? */ + if (*outlen < (PACKET_SIZE + 3)) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* type valid? */ + if (key->type != PK_PRIVATE && type == PK_PRIVATE) { + return CRYPT_PK_TYPE_MISMATCH; + } + + /* output type and magic byte */ + y = PACKET_SIZE; + out[y++] = (unsigned char)type; + out[y++] = (unsigned char)sets[key->idx].size; + + /* output x coordinate */ + OUTPUT_BIGNUM(&(key->pubkey.x), out, y, z); + + /* compress y and output it */ + if ((err = compress_y_point(&key->pubkey, key->idx, &cp)) != CRYPT_OK) { + return err; + } + out[y++] = (unsigned char)cp; + + if (type == PK_PRIVATE) { + OUTPUT_BIGNUM(&key->k, out, y, z); + } + + /* store header */ + packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_KEY); + *outlen = y; + + return CRYPT_OK; +} + +int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key) +{ + unsigned long x, y, s; + int err; + + _ARGCHK(in != NULL); + _ARGCHK(key != NULL); + + /* check length */ + if ((3+PACKET_SIZE) > inlen) { + return CRYPT_INVALID_PACKET; + } + + /* check type */ + if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_ECC, PACKET_SUB_KEY)) != CRYPT_OK) { + return err; + } + + /* 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 = (int)in[y++]; + s = (unsigned long)in[y++]; + + for (x = 0; (s > (unsigned long)sets[x].size) && (sets[x].size != 0); x++); + if (sets[x].size == 0) { + err = CRYPT_INVALID_KEYSIZE; + goto error; + } + key->idx = (int)x; + + /* type check both values */ + if ((key->type != PK_PUBLIC) && (key->type != PK_PRIVATE)) { + err = CRYPT_INVALID_PACKET; + goto error; + } + + /* is the key idx valid? */ + if (is_valid_idx(key->idx) != 1) { + err = CRYPT_INVALID_PACKET; + goto error; + } + + /* load x coordinate */ + INPUT_BIGNUM(&key->pubkey.x, in, x, y, inlen); + + /* load y */ + x = (unsigned long)in[y++]; + if ((err = expand_y_point(&key->pubkey, key->idx, (int)x)) != CRYPT_OK) { + goto error; + } + + if (key->type == PK_PRIVATE) { + /* load private key */ + INPUT_BIGNUM(&key->k, in, x, y, inlen); + } + + /* eliminate private key if public */ + if (key->type == PK_PUBLIC) { + mp_clear(&key->k); + } + + return CRYPT_OK; +error: + mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->k, NULL); + return err; +} + +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 err; + + _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 ((err = mp_init(&prime)) != MP_OKAY) { + del_point(result); + return mpi_to_ltc_error(err); + } + + if ((err = mp_read_radix(&prime, (char *)sets[private_key->idx].prime, 64)) != MP_OKAY) { goto error; } + if ((err = ecc_mulmod(&private_key->k, &public_key->pubkey, result, &prime)) != CRYPT_OK) { goto done1; } + + x = (unsigned long)mp_unsigned_bin_size(&result->x); + y = (unsigned long)mp_unsigned_bin_size(&result->y); + + if (*outlen < (x+y)) { + err = CRYPT_BUFFER_OVERFLOW; + goto done1; + } + *outlen = x+y; + if ((err = mp_to_unsigned_bin(&result->x, out)) != MP_OKAY) { goto error; } + if ((err = mp_to_unsigned_bin(&result->y, out+x)) != MP_OKAY) { goto error; } + + err = CRYPT_OK; + goto done1; +error: + err = mpi_to_ltc_error(err); +done1: + mp_clear(&prime); + del_point(result); + return err; +} + +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..33e1311 --- /dev/null +++ b/ecc_sys.c @@ -0,0 +1,432 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +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 err; + + _ARGCHK(inkey != NULL); + _ARGCHK(out != NULL); + _ARGCHK(len != NULL); + _ARGCHK(key != NULL); + + /* check that wprng/cipher/hash are not invalid */ + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + if ((err = hash_is_valid(hash)) != CRYPT_OK) { + return err; + } + + if (keylen > hash_descriptor[hash].hashsize) { + return CRYPT_INVALID_HASH; + } + + /* make a random key and export the public copy */ + if ((err = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { + return err; + } + + pubkeysize = (unsigned long)sizeof(pub_expt); + if ((err = ecc_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { + ecc_free(&pubkey); + return err; + } + + /* 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 = (unsigned long)sizeof(ecc_shared); + if ((err = ecc_shared_secret(&pubkey, key, ecc_shared, &x)) != CRYPT_OK) { + ecc_free(&pubkey); + return err; + } + ecc_free(&pubkey); + z = (unsigned long)sizeof(skey); + if ((err = hash_memory(hash, ecc_shared, x, skey, &z)) != CRYPT_OK) { + return err; + } + + /* store header */ + packet_store_header(out, PACKET_SECT_ECC, PACKET_SUB_ENC_KEY); + + /* 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; + + /* Encrypt/Store the encrypted key */ + for (x = 0; x < keylen; x++, y++) { + out[y] = skey[x] ^ inkey[x]; + } + *len = y; + +#ifdef CLEAN_STACK + /* clean up */ + zeromem(pub_expt, sizeof(pub_expt)); + zeromem(ecc_shared, sizeof(ecc_shared)); + zeromem(skey, sizeof(skey)); +#endif + return CRYPT_OK; +} + +int ecc_decrypt_key(const unsigned char *in, unsigned long inlen, + unsigned char *outkey, unsigned long *keylen, + ecc_key *key) +{ + unsigned char shared_secret[256], skey[MAXBLOCKSIZE]; + unsigned long x, y, z, hashsize, keysize; + int hash, err; + 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; + } + + /* correct length ? */ + if (inlen < PACKET_SIZE+1+4+4) { + return CRYPT_INVALID_PACKET; + } else { + inlen -= PACKET_SIZE+1+4+4; + } + + /* is header correct? */ + if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_ECC, PACKET_SUB_ENC_KEY)) != CRYPT_OK) { + return err; + } + + /* 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); + if (inlen < x) { + return CRYPT_INVALID_PACKET; + } else { + inlen -= x; + } + y += 4; + if ((err = ecc_import(in+y, x, &pubkey)) != CRYPT_OK) { + return err; + } + y += x; + + /* make shared key */ + x = (unsigned long)sizeof(shared_secret); + if ((err = ecc_shared_secret(key, &pubkey, shared_secret, &x)) != CRYPT_OK) { + ecc_free(&pubkey); + return err; + } + ecc_free(&pubkey); + + z = (unsigned long)sizeof(skey); + if ((err = hash_memory(hash, shared_secret, x, skey, &z)) != CRYPT_OK) { + return err; + } + + LOAD32L(keysize, in+y); + if (inlen < keysize) { + return CRYPT_INVALID_PACKET; + } else { + inlen -= keysize; + } + y += 4; + + if (*keylen < keysize) { + err = CRYPT_BUFFER_OVERFLOW; + goto done; + } + + /* Decrypt the key */ + for (x = 0; x < keysize; x++, y++) { + outkey[x] = skey[x] ^ in[y]; + } + + *keylen = keysize; + + err = CRYPT_OK; +done: +#ifdef CLEAN_STACK + zeromem(shared_secret, sizeof(shared_secret)); + zeromem(skey, sizeof(skey)); +#endif + return err; +} + +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]; + unsigned long x, y, pubkeysize, rsize; + int err; + + _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; + } + + /* is the IDX valid ? */ + if (is_valid_idx(key->idx) != 1) { + return CRYPT_PK_INVALID_TYPE; + } + + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + /* make up a key and export the public copy */ + if ((err = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { + return err; + } + + pubkeysize = (unsigned long)sizeof(epubkey); + if ((err = ecc_export(epubkey, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) { + ecc_free(&pubkey); + return err; + } + + /* get the hash and load it as a bignum into 'b' */ + /* init the bignums */ + if ((err = mp_init_multi(&b, &p, NULL)) != MP_OKAY) { + ecc_free(&pubkey); + return mpi_to_ltc_error(err); + } + if ((err = mp_read_radix(&p, (char *)sets[key->idx].order, 64)) != MP_OKAY) { goto error; } + if ((err = mp_read_unsigned_bin(&b, (unsigned char *)in, (int)inlen)) != MP_OKAY) { goto error; } + + /* find b = (m - x)/k */ + if ((err = mp_invmod(&pubkey.k, &p, &pubkey.k)) != MP_OKAY) { goto error; } /* k = 1/k */ + if ((err = mp_submod(&b, &key->k, &p, &b)) != MP_OKAY) { goto error; } /* b = m - x */ + if ((err = mp_mulmod(&b, &pubkey.k, &p, &b)) != MP_OKAY) { goto error; } /* b = (m - x)/k */ + + /* export it */ + rsize = (unsigned long)mp_unsigned_bin_size(&b); + if (rsize > (unsigned long)sizeof(er)) { + err = CRYPT_BUFFER_OVERFLOW; + goto error; + } + if ((err = mp_to_unsigned_bin(&b, er)) != MP_OKAY) { goto error; } + + /* now lets check the outlen before we write */ + if (*outlen < (12 + rsize + pubkeysize)) { + err = CRYPT_BUFFER_OVERFLOW; + goto done; + } + + /* 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); + + /* clear memory */ + *outlen = y; + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); +done: + mp_clear_multi(&b, &p, NULL); + ecc_free(&pubkey); +#ifdef CLEAN_STACK + zeromem(er, sizeof(er)); + zeromem(epubkey, sizeof(epubkey)); +#endif + return err; +} + +/* verify that mG = (bA + Y) + * + * The signatures work by making up a fresh key "a" with a public key "A". Now we want to sign so the + * public key Y = xG can verify it. + * + * b = (m - x)/k, A is the public key embedded and Y is the users public key [who signed it] + * A = kG therefore bA == ((m-x)/k)kG == (m-x)G + * + * Adding Y = xG to the bA gives us (m-x)G + xG == mG + * + * The user given only xG, kG and b cannot determine k or x which means they can't find the private key. + * + */ +int ecc_verify_hash(const unsigned char *sig, unsigned long siglen, + const unsigned char *hash, unsigned long inlen, + int *stat, ecc_key *key) +{ + ecc_point *mG; + ecc_key pubkey; + mp_int b, p, m, mu; + unsigned long x, y; + int err; + + _ARGCHK(sig != NULL); + _ARGCHK(hash != NULL); + _ARGCHK(stat != NULL); + _ARGCHK(key != NULL); + + /* default to invalid signature */ + *stat = 0; + + if (siglen < PACKET_SIZE+4+4) { + return CRYPT_INVALID_PACKET; + } else { + siglen -= PACKET_SIZE+4+4; + } + + /* is the message format correct? */ + if ((err = packet_valid_header((unsigned char *)sig, PACKET_SECT_ECC, PACKET_SUB_SIGNED)) != CRYPT_OK) { + return err; + } + + /* get hash name */ + y = PACKET_SIZE; + + /* get size of public key */ + LOAD32L(x, sig+y); + if (siglen < x) { + return CRYPT_INVALID_PACKET; + } else { + siglen -= x; + } + y += 4; + + /* load the public key */ + if ((err = ecc_import((unsigned char*)sig+y, x, &pubkey)) != CRYPT_OK) { + return err; + } + y += x; + + /* load size of 'b' */ + LOAD32L(x, sig+y); + if (siglen < x) { + return CRYPT_INVALID_PACKET; + } else { + siglen -= x; + } + y += 4; + + /* init values */ + if ((err = mp_init_multi(&b, &m, &p, &mu, NULL)) != MP_OKAY) { + ecc_free(&pubkey); + return mpi_to_ltc_error(err); + } + + mG = new_point(); + if (mG == NULL) { + mp_clear_multi(&b, &m, &p, &mu, NULL); + ecc_free(&pubkey); + return CRYPT_MEM; + } + + /* load b */ + if ((err = mp_read_unsigned_bin(&b, (unsigned char *)sig+y, (int)x)) != MP_OKAY) { goto error; } + y += x; + + /* get m in binary a bignum */ + if ((err = mp_read_unsigned_bin(&m, (unsigned char *)hash, (int)inlen)) != MP_OKAY) { goto error; } + + /* load prime */ + if ((err = mp_read_radix(&p, (char *)sets[key->idx].prime, 64)) != MP_OKAY) { goto error; } + + /* calculate barrett stuff */ + mp_set(&mu, 1); + mp_lshd(&mu, 2 * USED(&p)); + if ((err = mp_div(&mu, &p, &mu, NULL)) != MP_OKAY) { goto error; } + + /* get bA */ + if ((err = ecc_mulmod(&b, &pubkey.pubkey, &pubkey.pubkey, &p)) != CRYPT_OK) { goto done; } + + /* get bA + Y */ + if ((err = add_point(&pubkey.pubkey, &key->pubkey, &pubkey.pubkey, &p, &mu)) != CRYPT_OK) { goto done; } + + /* get mG */ + if ((err = mp_read_radix(&mG->x, (char *)sets[key->idx].Gx, 64)) != MP_OKAY) { goto error; } + if ((err = mp_read_radix(&mG->y, (char *)sets[key->idx].Gy, 64)) != MP_OKAY) { goto error; } + if ((err = ecc_mulmod(&m, mG, mG, &p)) != CRYPT_OK) { goto done; } + + /* compare mG to bA + Y */ + if (mp_cmp(&mG->x, &pubkey.pubkey.x) == MP_EQ && mp_cmp(&mG->y, &pubkey.pubkey.y) == MP_EQ) { + *stat = 1; + } + + /* clear up and return */ + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); +done: + del_point(mG); + ecc_free(&pubkey); + mp_clear_multi(&p, &m, &b, &mu, NULL); + return err; +} + diff --git a/examples/ch1-01.c b/examples/ch1-01.c new file mode 100644 index 0000000..010ccd7 --- /dev/null +++ b/examples/ch1-01.c @@ -0,0 +1,18 @@ +/* + * Name : ch1-01.c + * Purpose : Demonstration of a basic libtomcrypt program + * Author : Tom St Denis + * + * History : v0.79 Initial release + */ + +/* ch1-01-1 */ +/* Include the default headers and libtomcrypt headers */ +#include + +int main(void) +{ + return 0; +} +/* ch1-01-1 */ + diff --git a/examples/ch1-02.c b/examples/ch1-02.c new file mode 100644 index 0000000..9d41f21 --- /dev/null +++ b/examples/ch1-02.c @@ -0,0 +1,25 @@ +/* + * Name : ch1-02.c + * Purpose : Demonstration of error handling + * Author : Tom St Denis + * + * History : v0.79 Initial release + */ + +/* ch1-01-1 */ +#include + +int main(void) +{ + int errno; + + if ((errno = some_func(...)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return EXIT_FAILURE; + } + + return 0; +} +/*ch1-01-1 */ + + diff --git a/examples/ch1-03.c b/examples/ch1-03.c new file mode 100644 index 0000000..c749aa1 --- /dev/null +++ b/examples/ch1-03.c @@ -0,0 +1,29 @@ +/* + * Name : ch1-03.c + * Purpose : Demonstration of variable length outputs + * Author : Tom St Denis + * + * History : v0.79 Initial release + */ + + /* ch1-01-1 */ + #include + + int main(void) + { + unsigned long length; + unsigned char buffer[512]; + int errno; + + length = sizeof(buffer); + if ((errno = some_func(..., buffer, &length)) != CRYPT_OK) { + printf("Error: %s\n", error_to_string(errno)); + return EXIT_FAILURE; + } + printf("Size of output is %lu bytes\n", length); + return 0; +} +/* ch1-01-1 */ + + + \ No newline at end of file diff --git a/examples/ch2-01.c b/examples/ch2-01.c new file mode 100644 index 0000000..b565479 --- /dev/null +++ b/examples/ch2-01.c @@ -0,0 +1,35 @@ +/* + * Name : ch2-01.c + * Purpose : Demonstration of reading the RNG + * Author : Tom St Denis + * + * History : v0.81 Initial release + */ + + /* ch2-02-2 */ + #include + + int main(void) + { + unsigned char buf[16]; + unsigned long len; + int ix; + + /* read the RNG */ + len = rng_get_bytes(buf, sizeof(buf), NULL); + + /* verify return */ + if (len != sizeof(buf)) { + printf("Error: Only read %lu bytes.\n", len); + } else { + printf("Read %lu bytes\n", len); + for (ix = 0; ix < sizeof(buf); ix++) { + printf("%02x ", buf[ix]); + } + printf("\n"); + } + + return EXIT_SUCCESS; +} +/* ch2-02-2 */ + diff --git a/gf.c b/gf.c new file mode 100644 index 0000000..34abb15 --- /dev/null +++ b/gf.c @@ -0,0 +1,305 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* 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_file.c b/hash_file.c new file mode 100644 index 0000000..0511f2c --- /dev/null +++ b/hash_file.c @@ -0,0 +1,41 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int hash_file(int hash, const char *fname, unsigned char *dst, unsigned long *outlen) +{ +#ifdef NO_FILE + return CRYPT_NOP; +#else + FILE *in; + int err; + _ARGCHK(fname != NULL); + _ARGCHK(dst != NULL); + _ARGCHK(outlen != NULL); + + if ((err = hash_is_valid(hash)) != CRYPT_OK) { + return err; + } + + in = fopen(fname, "rb"); + if (in == NULL) { + return CRYPT_FILE_NOTFOUND; + } + + err = hash_filehandle(hash, in, dst, outlen); + if (fclose(in) != 0) { + return CRYPT_ERROR; + } + + return err; +#endif +} + diff --git a/hash_filehandle.c b/hash_filehandle.c new file mode 100644 index 0000000..ca6be90 --- /dev/null +++ b/hash_filehandle.c @@ -0,0 +1,49 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +int hash_filehandle(int hash, FILE *in, unsigned char *dst, unsigned long *outlen) +{ +#ifdef NO_FILE + return CRYPT_NOP; +#else + hash_state md; + unsigned char buf[512]; + size_t x; + int err; + + _ARGCHK(dst != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(in != NULL); + + if ((err = hash_is_valid(hash)) != CRYPT_OK) { + return err; + } + + 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 +} + diff --git a/hash_memory.c b/hash_memory.c new file mode 100644 index 0000000..976a145 --- /dev/null +++ b/hash_memory.c @@ -0,0 +1,35 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#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 err; + + _ARGCHK(data != NULL); + _ARGCHK(dst != NULL); + _ARGCHK(outlen != NULL); + + if ((err = hash_is_valid(hash)) != CRYPT_OK) { + return err; + } + + 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; +} diff --git a/hmac_done.c b/hmac_done.c new file mode 100644 index 0000000..57ebbcd --- /dev/null +++ b/hmac_done.c @@ -0,0 +1,84 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* 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_done(hmac_state *hmac, unsigned char *hashOut, unsigned long *outlen) +{ + unsigned char buf[MAXBLOCKSIZE]; + unsigned char isha[MAXBLOCKSIZE]; + unsigned long hashsize, i; + int hash, err; + + _ARGCHK(hmac != NULL); + _ARGCHK(hashOut != NULL); + + hash = hmac->hash; + if((err = hash_is_valid(hash)) != CRYPT_OK) { + return err; + } + + /* get the hash message digest size */ + hashsize = hash_descriptor[hash].hashsize; + + // Get the hash of the first HMAC vector plus the data + if ((err = hash_descriptor[hash].done(&hmac->md, isha)) != CRYPT_OK) { + return err; + } + + // Create the second HMAC vector vector for step (3) + 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, buf); + + // copy to output + for (i = 0; i < hashsize && i < *outlen; i++) { + hashOut[i] = buf[i]; + } + *outlen = i; + +#ifdef CLEAN_STACK + zeromem(isha, sizeof(buf)); + zeromem(buf, sizeof(isha)); + zeromem(hmac, sizeof(*hmac)); +#endif + return CRYPT_OK; +} + +#endif diff --git a/hmac_file.c b/hmac_file.c new file mode 100644 index 0000000..23194bd --- /dev/null +++ b/hmac_file.c @@ -0,0 +1,96 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* 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 + +/* 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, unsigned long *dstlen) +{ +#ifdef NO_FILE + return CRYPT_NOP; +#else + hmac_state hmac; + FILE *in; + unsigned char buf[512]; + size_t x; + int err; + + _ARGCHK(fname != NULL); + _ARGCHK(key != NULL); + _ARGCHK(dst != NULL); + _ARGCHK(dstlen != NULL); + + if((err = hash_is_valid(hash)) != CRYPT_OK) { + return err; + } + + if ((err = hmac_init(&hmac, hash, key, keylen)) != CRYPT_OK) { + return err; + } + + in = fopen(fname, "rb"); + if (in == NULL) { + return CRYPT_FILE_NOTFOUND; + } + + /* process the file contents */ + do { + x = fread(buf, 1, sizeof(buf), in); + if ((err = hmac_process(&hmac, buf, (unsigned long)x)) != CRYPT_OK) { + /* we don't trap this error since we're already returning an error! */ + fclose(in); + return err; + } + } while (x == sizeof(buf)); + + if (fclose(in) != 0) { + return CRYPT_ERROR; + } + + /* get final hmac */ + if ((err = hmac_done(&hmac, dst, dstlen)) != CRYPT_OK) { + return err; + } + +#ifdef CLEAN_STACK + /* clear memory */ + zeromem(buf, sizeof(buf)); +#endif + return CRYPT_OK; +#endif +} + +#endif + diff --git a/hmac_init.c b/hmac_init.c new file mode 100644 index 0000000..7a9b801 --- /dev/null +++ b/hmac_init.c @@ -0,0 +1,87 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* 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 err; + + _ARGCHK(hmac != NULL); + _ARGCHK(key != NULL); + + if ((err = hash_is_valid(hash)) != CRYPT_OK) { + return err; + } + + /* valid key length? */ + if (keylen == 0) { + return CRYPT_INVALID_KEYSIZE; + } + + hmac->hash = hash; + + // (1) make sure we have a large enough key + hashsize = hash_descriptor[hash].hashsize; + if(keylen > HMAC_BLOCKSIZE) { + z = (unsigned long)sizeof(hmac->key); + if ((err = hash_memory(hash, key, keylen, hmac->key, &z)) != CRYPT_OK) { + return err; + } + if(hashsize < HMAC_BLOCKSIZE) { + zeromem((hmac->key) + hashsize, (size_t)(HMAC_BLOCKSIZE - hashsize)); + } + keylen = hashsize; + } else { + memcpy(hmac->key, key, (size_t)keylen); + if(keylen < HMAC_BLOCKSIZE) { + zeromem((hmac->key) + keylen, (size_t)(HMAC_BLOCKSIZE - keylen)); + } + } + + // Create the initial vector for step (3) + for(i=0; i < HMAC_BLOCKSIZE; i++) { + buf[i] = hmac->key[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; +} + +#endif diff --git a/hmac_memory.c b/hmac_memory.c new file mode 100644 index 0000000..e438a30 --- /dev/null +++ b/hmac_memory.c @@ -0,0 +1,67 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* 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_memory(int hash, const unsigned char *key, unsigned long keylen, + const unsigned char *data, unsigned long len, + unsigned char *dst, unsigned long *dstlen) +{ + hmac_state hmac; + int err; + + _ARGCHK(key != NULL); + _ARGCHK(data != NULL); + _ARGCHK(dst != NULL); + _ARGCHK(dstlen != NULL); + + if((err = hash_is_valid(hash)) != CRYPT_OK) { + return err; + } + + if ((err = hmac_init(&hmac, hash, key, keylen)) != CRYPT_OK) { + return err; + } + + if ((err = hmac_process(&hmac, data, len)) != CRYPT_OK) { + return err; + } + + if ((err = hmac_done(&hmac, dst, dstlen)) != CRYPT_OK) { + return err; + } + return CRYPT_OK; +} + +#endif + diff --git a/hmac_process.c b/hmac_process.c new file mode 100644 index 0000000..fa4c1e6 --- /dev/null +++ b/hmac_process.c @@ -0,0 +1,48 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* 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_process(hmac_state *hmac, const unsigned char *buf, unsigned long len) +{ + int err; + _ARGCHK(hmac != NULL); + _ARGCHK(buf != NULL); + if ((err = hash_is_valid(hmac->hash)) != CRYPT_OK) { + return err; + } + return hash_descriptor[hmac->hash].process(&hmac->md, buf, len); +} + +#endif + diff --git a/hmac_test.c b/hmac_test.c new file mode 100644 index 0000000..4ec7d94 --- /dev/null +++ b/hmac_test.c @@ -0,0 +1,325 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* 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 + +/* + + 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) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + unsigned char digest[MAXBLOCKSIZE]; + int i; + + static const struct hmac_test_case { + int num; + char *algo; + unsigned char key[128]; + unsigned long keylen; + unsigned char data[128]; + unsigned long 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} } + }; + + unsigned long outlen; + int err; + int tested=0,failed=0; + for(i=0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) { + int hash = find_hash(cases[i].algo); + if (hash == -1) continue; + ++tested; + outlen = sizeof(digest); + if((err = hmac_memory(hash, cases[i].key, cases[i].keylen, cases[i].data, cases[i].datalen, digest, &outlen)) != CRYPT_OK) { +#if 0 + printf("HMAC-%s test #%d\n", cases[i].algo, cases[i].num); +#endif + return err; + } + + if(memcmp(digest, cases[i].digest, (size_t)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 != 0) { + return CRYPT_FAIL_TESTVECTOR; + } else if (tested == 0) { + return CRYPT_NOP; + } else { + return CRYPT_OK; + } + #endif +} + +#endif + diff --git a/is_prime.c b/is_prime.c new file mode 100644 index 0000000..d6fc84e --- /dev/null +++ b/is_prime.c @@ -0,0 +1,27 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef MPI + +/* figures out if a number is prime (MR test) */ +int is_prime(mp_int *N, int *result) +{ + int err; + _ARGCHK(N != NULL); + _ARGCHK(result != NULL); + if ((err = mp_prime_is_prime(N, mp_prime_rabin_miller_trials(mp_count_bits(N)), result)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + return CRYPT_OK; +} + +#endif diff --git a/keyring.c b/keyring.c new file mode 100644 index 0000000..56f128d --- /dev/null +++ b/keyring.c @@ -0,0 +1,862 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* 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] = { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +}; + +#define DO1(buf) crc = crc_table[(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) +{ + //_ARGCHK(buf != NULL && len == 0); + crc = crc ^ 0xffffffffL; + while (len >= 8) { + DO8 (buf); + len -= 8; + } + + if (len > 0) { + do { + DO1 (buf); + } while (--len > 0); + } + 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(0UL, NULL, 0UL); + crc = crc32(crc, name, (unsigned long)MIN(MAXLEN, strlen((char *)name))); + crc = crc32(crc, email, (unsigned long)MIN(MAXLEN, strlen((char *)email))); + return crc32(crc, description, (unsigned long)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) == 0) { + return pk; + } + pk = pk->next; + } + return NULL; +} + + +int kr_add(pk_key *pk, int key_type, int sys, 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 (sys != RSA_KEY && sys != DH_KEY && sys != 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 = sys; + 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 (sys) { + 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 err; + _ARGCHK(pk != NULL); + + while ((*pk)->system != NON_KEY) { + if ((err = kr_del(pk, (*pk)->ID)) != CRYPT_OK) { + return err; + } + } + 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 (unsigned long)fwrite(buf, 1, (size_t)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 = (unsigned long)fread(buf, 1, (size_t)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 err; + + _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 ((err = rsa_export(obuf, &len, key_type, &(ppk->key.rsa))) != CRYPT_OK) { + return err; + } + break; + case DH_KEY: + if ((err = dh_export(obuf, &len, key_type, &(ppk->key.dh))) != CRYPT_OK) { + return err; + } + break; + case ECC_KEY: + if ((err = ecc_export(obuf, &len, key_type, &(ppk->key.ecc))) != CRYPT_OK) { + return err; + } + 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, unsigned long inlen) +{ + _pk_key key; + int sys, key_type, err; + unsigned long ID; + + _ARGCHK(pk != NULL); + _ARGCHK(in != NULL); + + if (inlen < 10) { + return CRYPT_INVALID_PACKET; + } + + if (memcmp(in, key_magic, 4) != 0) { + return CRYPT_INVALID_PACKET; + } + key_type = in[4]; /* get type */ + sys = 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)); + + /* size of remaining packet */ + inlen -= 10 + 3*MAXLEN; + + switch (sys) { + case RSA_KEY: + if ((err = rsa_import(in+10+3*MAXLEN, inlen, &(key.rsa))) != CRYPT_OK) { + return err; + } + break; + case DH_KEY: + if ((err = dh_import(in+10+3*MAXLEN, inlen, &(key.dh))) != CRYPT_OK) { + return err; + } + break; + case ECC_KEY: + if ((err = ecc_import(in+10+3*MAXLEN, inlen, &(key.ecc))) != CRYPT_OK) { + return err; + } + break; + } + return kr_add(pk, key_type, sys, + 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, err; + + _ARGCHK(pk != NULL); + _ARGCHK(in != NULL); + + /* init keyring */ + if ((err = kr_init(pk)) != CRYPT_OK) { + return err; + } + + /* read in magic bytes */ + if (_read(buf, 6, in, ctr) != 6) { goto done2; } + + if (memcmp(buf, file_magic, 4) != 0) { + 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 > (unsigned long)sizeof(buf)) { + return CRYPT_INVALID_PACKET; + } + + if (_read(buf, len, in, ctr) != len) { goto done2; } + if ((err = kr_import(*pk, buf, len)) != CRYPT_OK) { + return err; + } + } + + 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, err; + + _ARGCHK(pk != NULL); + _ARGCHK(out != NULL); + + /* write out magic bytes */ + memcpy(buf, file_magic, 4); + buf[4] = (unsigned char)(CRYPT&255); + buf[5] = (unsigned char)((CRYPT>>8)&255); + if (_write(buf, 6, out, ctr) != 6) { goto done2; } + + while (pk->system != NON_KEY) { + len = sizeof(buf); + if ((err = kr_export(pk, pk->ID, pk->key_type, buf, &len)) != CRYPT_OK) { + return err; + } + + 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 sys, int keysize, const unsigned char *name, + const unsigned char *email, const unsigned char *description) +{ + _pk_key key; + int key_type, err; + + _ARGCHK(pk != NULL); + _ARGCHK(name != NULL); + _ARGCHK(email != NULL); + _ARGCHK(description != NULL); + + /* valid PRNG? */ + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + /* make the key first */ + zeromem(&key, sizeof(key)); + switch (sys) { + case RSA_KEY: + if ((err = rsa_make_key(prng, wprng, keysize, 65537, &(key.rsa))) != CRYPT_OK) { + return err; + } + key_type = key.rsa.type; + break; + case DH_KEY: + if ((err = dh_make_key(prng, wprng, keysize, &(key.dh))) != CRYPT_OK) { + return err; + } + key_type = key.dh.type; + break; + case ECC_KEY: + if ((err = ecc_make_key(prng, wprng, keysize, &(key.ecc))) != CRYPT_OK) { + return err; + } + key_type = key.ecc.type; + break; + default: + return CRYPT_PK_INVALID_SYSTEM; + } + + /* now add the key */ + if ((err = kr_add(pk, key_type, sys, name, email, description, &key)) != CRYPT_OK) { + return err; + } + +#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 err; + + _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)-12; + switch (kr->system) { + case RSA_KEY: + if ((err = rsa_encrypt_key(in, inlen, buf+12, &len, prng, wprng, &(kr->key.rsa))) != CRYPT_OK) { + return err; + } + break; + case DH_KEY: + if ((err = dh_encrypt_key(in, inlen, buf+12, &len, prng, wprng, hash, &(kr->key.dh))) != CRYPT_OK) { + return err; + } + break; + case ECC_KEY: + if ((err = ecc_encrypt_key(in, inlen, buf+12, &len, prng, wprng, hash, &(kr->key.ecc))) != CRYPT_OK) { + return err; + } + break; + } + STORE32L(len,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_decrypt_key(pk_key *pk, const unsigned char *in, + unsigned char *out, unsigned long *outlen) +{ + unsigned char buf[8192]; + unsigned long pklen, len, ID; + pk_key *kr; + int err; + + _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 */ + LOAD32L(pklen,in+8); + len = sizeof(buf); + switch (kr->system) { + case RSA_KEY: + if ((err = rsa_decrypt_key(in+12, pklen, buf, &len, &(kr->key.rsa))) != CRYPT_OK) { + return err; + } + break; + case DH_KEY: + if ((err = dh_decrypt_key(in+12, pklen, buf, &len, &(kr->key.dh))) != CRYPT_OK) { + return err; + } + break; + case ECC_KEY: + if ((err = ecc_decrypt_key(in+12, pklen, buf, &len, &(kr->key.ecc))) != CRYPT_OK) { + return err; + } + 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 err; + + _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)-16; + switch (kr->system) { + case RSA_KEY: + if ((err = rsa_sign_hash(in, inlen, buf+16, &len, &(kr->key.rsa))) != CRYPT_OK) { + return err; + } + break; + case DH_KEY: + if ((err = dh_sign_hash(in, inlen, buf+16, &len, prng, wprng, &(kr->key.dh))) != CRYPT_OK) { + return err; + } + break; + case ECC_KEY: + if ((err = ecc_sign_hash(in, inlen, buf+16, &len, prng, wprng, &(kr->key.ecc))) != CRYPT_OK) { + return err; + } + break; + } + STORE32L(inlen,buf+8); + STORE32L(len,buf+12); + len += 16; + + 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, pklen, ID; + pk_key *kr; + int err; + + _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 */ + LOAD32L(pklen,in+12); /* size of the PK packet */ + if (inlen != hashlen) { /* size doesn't match means the signature is invalid */ + return CRYPT_OK; + } + + switch (kr->system) { + case RSA_KEY: + if ((err = rsa_verify_hash(in+16, pklen, hash, stat, &(kr->key.rsa))) != CRYPT_OK) { + return err; + } + break; + case DH_KEY: + if ((err = dh_verify_hash(in+16, pklen, hash, inlen, stat, &(kr->key.dh))) != CRYPT_OK) { + return err; + } + break; + case ECC_KEY: + if ((err = ecc_verify_hash(in+16, pklen, hash, inlen, stat, &(kr->key.ecc))) != CRYPT_OK) { + return err; + } + 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 err; + + _ARGCHK(pk != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* valid hash? */ + if ((err = hash_is_valid(hash)) != CRYPT_OK) { + return err; + } + + len = (unsigned long)sizeof(buf); + if ((err = kr_export(pk, ID, PK_PUBLIC, buf, &len)) != CRYPT_OK) { + return err; + } + + /* now hash it */ + if ((err = hash_memory(hash, buf, len, out, outlen)) != CRYPT_OK) { + return err; + } + +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + return CRYPT_OK; +} + +#endif + + diff --git a/makefile b/makefile new file mode 100644 index 0000000..25e4324 --- /dev/null +++ b/makefile @@ -0,0 +1,254 @@ +# 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.95 + +#ch1-01-1 +# Compiler and Linker Names +#CC=gcc +#LD=ld + +# Archiver [makes .a files] +#AR=ar +#ARFLAGS=r +#ch1-01-1 + +#ch1-01-3 +# Compilation flags. Note the += does not write over the user's CFLAGS! +# The rest of the flags come from the parent Dropbear makefile +CFLAGS += -c -I./ +# -Werror + +# optimize for SPEED +#CFLAGS += -O3 -funroll-loops + +#add -fomit-frame-pointer. v3.2 is buggy for certain platforms! +#CFLAGS += -fomit-frame-pointer + +# optimize for SIZE +#CFLAGS += -Os + +# compile for DEBUGING +#CFLAGS += -g3 +#ch1-01-3 + +#These flags control how the library gets built. + +#Output filenames for various targets. +LIBNAME=libtomcrypt.a +TEST=test +HASH=hashsum +CRYPT=encrypt +SMALL=small +PROF=x86_prof +TV=tv_gen + +#LIBPATH-The directory for libtomcrypt to be installed to. +#INCPATH-The directory to install the header files for libtomcrypt. +#DATAPATH-The directory to install the pdf docs. +DESTDIR= +LIBPATH=/usr/lib +INCPATH=/usr/include +DATAPATH=/usr/share/doc/libtomcrypt/pdf + +#List of objects to compile. + +#Leave MPI built-in or force developer to link against libtommath? +MPIOBJECT=mpi.o + +OBJECTS=keyring.o gf.o base64.o \ +\ +crypt.o crypt_find_cipher.o crypt_find_hash_any.o \ +crypt_hash_is_valid.o crypt_register_hash.o crypt_unregister_prng.o \ +crypt_argchk.o crypt_find_cipher_any.o crypt_find_hash_id.o \ +crypt_prng_descriptor.o crypt_register_prng.o crypt_cipher_descriptor.o \ +crypt_find_cipher_id.o crypt_find_prng.o crypt_prng_is_valid.o \ +crypt_unregister_cipher.o crypt_cipher_is_valid.o crypt_find_hash.o \ +crypt_hash_descriptor.o crypt_register_cipher.o crypt_unregister_hash.o \ +\ +sprng.o yarrow.o rc4.o rng_get_bytes.o rng_make_prng.o \ +\ +rand_prime.o is_prime.o \ +\ +ecc.o dh.o \ +\ +rsa.o rsa_exptmod.o rsa_free.o rsa_make_key.o \ +\ +dsa_export.o dsa_free.o dsa_import.o dsa_make_key.o dsa_sign_hash.o dsa_verify_hash.o dsa_verify_key.o \ +\ +xtea.o aes.o des.o safer_tab.o safer.o saferp.o rc2.o \ +rc6.o rc5.o cast5.o noekeon.o blowfish.o twofish.o skipjack.o \ +\ +md2.o md4.o md5.o sha1.o sha256.o sha512.o tiger.o whirl.o \ +rmd128.o rmd160.o \ +\ +packet_store_header.o packet_valid_header.o \ +\ +eax_addheader.o eax_decrypt.o eax_decrypt_verify_memory.o eax_done.o eax_encrypt.o \ +eax_encrypt_authenticate_memory.o eax_init.o eax_test.o \ +\ +ocb_decrypt.o ocb_decrypt_verify_memory.o ocb_done_decrypt.o ocb_done_encrypt.o \ +ocb_encrypt.o ocb_encrypt_authenticate_memory.o ocb_init.o ocb_ntz.o \ +ocb_shift_xor.o ocb_test.o s_ocb_done.o \ +\ +omac_done.o omac_file.o omac_init.o omac_memory.o omac_process.o omac_test.o \ +\ +pmac_done.o pmac_file.o pmac_init.o pmac_memory.o pmac_ntz.o pmac_process.o \ +pmac_shift_xor.o pmac_test.o \ +\ +cbc_start.o cbc_encrypt.o cbc_decrypt.o \ +cfb_start.o cfb_encrypt.o cfb_decrypt.o \ +ofb_start.o ofb_encrypt.o ofb_decrypt.o \ +ctr_start.o ctr_encrypt.o ctr_decrypt.o \ +ecb_start.o ecb_encrypt.o ecb_decrypt.o \ +\ +hash_file.o hash_filehandle.o hash_memory.o \ +\ +hmac_done.o hmac_file.o hmac_init.o hmac_memory.o hmac_process.o hmac_test.o \ +\ +pkcs_1_mgf1.o pkcs_1_oaep_encode.o pkcs_1_oaep_decode.o \ +pkcs_1_pss_encode.o pkcs_1_pss_decode.o pkcs_1_i2osp.o pkcs_1_os2ip.o \ +\ +pkcs_5_1.o pkcs_5_2.o \ +\ +burn_stack.o zeromem.o \ +$(MPIOBJECT) + +TESTOBJECTS=demos/test.o +HASHOBJECTS=demos/hashsum.o +CRYPTOBJECTS=demos/encrypt.o +SMALLOBJECTS=demos/small.o +PROFS=demos/x86_prof.o +TVS=demos/tv_gen.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=tommath.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 \ +mycrypt_custom.h mycrypt_pkcs.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 +twofish.o: twofish.c twofish_tab.c +sha512.o: sha512.c sha384.c +sha256.o: sha256.c sha224.c + +#This rule makes the libtomcrypt library. +library: $(LIBNAME) + +$(LIBNAME): $(OBJECTS) + $(AR) $(ARFLAGS) $@ $(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) + +x86_prof: library $(PROFS) + $(CC) $(PROFS) $(LIBNAME) -o $(PROF) + +tv_gen: library $(TVS) + $(CC) $(TVS) $(LIBNAME) -o $(TV) + + +#make a profiled library (takes a while!!!) +# +# This will build the library with profile generation +# then run the test demo and rebuild the library. +# +# So far I've seen improvements in the MP math +# +# This works with GCC v3.3.x [tested with 3.3.3] +profiled: $(TESTOBJECTS) + make CFLAGS="$(CFLAGS) -fprofile-arcs" + $(CC) $(TESTOBJECTS) $(LIBNAME) -o $(TEST) + ./test + rm -f *.a *.o test demos/test.o + make CFLAGS="$(CFLAGS) -fbranch-probabilities" + + +#Profiling in GCC 3.4.x is a little diff. +# +#Tested with GCC v3.4.0 +profiled34: $(TESTOBJECTS) + make CFLAGS="$(CFLAGS) -fprofile-generate" + $(CC) $(TESTOBJECTS) $(LIBNAME) -lgcov -o $(TEST) + ./test + rm -f *.a *.o test demos/test.o + make CFLAGS="$(CFLAGS) -fprofile-use" + + +#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 docs + install -d -g root -o root $(DESTDIR)$(LIBPATH) + install -d -g root -o root $(DESTDIR)$(INCPATH) + install -d -g root -o root $(DESTDIR)$(DATAPATH) + install -g root -o root $(LIBNAME) $(DESTDIR)$(LIBPATH) + install -g root -o root $(HEADERS) $(DESTDIR)$(INCPATH) + install -g root -o root crypt.pdf $(DESTDIR)$(DATAPATH) + +#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) $(PROFS) $(PROF) $(TVS) $(TV) + rm -f *.a *.dll *stackdump *.lib *.exe *.obj demos/*.obj demos/*.o *.bat *.txt *.il *.da demos/*.il demos/*.da *.dyn *.dpi \ + *.gcda *.gcno demos/*.gcno demos/*.gcda *~ + +#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 $(LEFTOVERS) + latex crypt > /dev/null + makeindex crypt > /dev/null + latex crypt > /dev/null + latex crypt > /dev/null + dvipdf crypt + rm -f $(LEFTOVERS) + +#beta +beta: clean + cd .. ; rm -rf crypt* libtomcrypt-$(VERSION)-beta ; mkdir libtomcrypt-$(VERSION)-beta ; \ + cp -R ./libtomcrypt/* ./libtomcrypt-$(VERSION)-beta/ ; tar -c libtomcrypt-$(VERSION)-beta/* > crypt-$(VERSION)-beta.tar ; \ + bzip2 -9vv crypt-$(VERSION)-beta.tar ; zip -9 -r crypt-$(VERSION)-beta.zip libtomcrypt-$(VERSION)-beta/* + +#zipup the project (take that!) +zipup: clean docs + cd .. ; 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)/* diff --git a/makefile.cygwin_dll b/makefile.cygwin_dll new file mode 100644 index 0000000..abec0a5 --- /dev/null +++ b/makefile.cygwin_dll @@ -0,0 +1,84 @@ + + +default: ltc_dll + + +# Compilation flags. Note the += does not write over the user's CFLAGS! +CFLAGS += -I./ -Wall -Wsign-compare -W -Wno-unused -Wshadow -mno-cygwin -DWIN32 + +# optimize for SPEED +#CFLAGS += -O3 -funroll-loops + +#add -fomit-frame-pointer. v3.2 is buggy for certain platforms! +#CFLAGS += -fomit-frame-pointer + +# optimize for SIZE +CFLAGS += -Os + +#Leave MPI built-in or force developer to link against libtommath? +MPIOBJECT=mpi.o + +OBJECTS=keyring.o gf.o strings.o base64.o \ +\ +crypt.o crypt_find_cipher.o crypt_find_hash_any.o \ +crypt_hash_is_valid.o crypt_register_hash.o crypt_unregister_prng.o \ +crypt_argchk.o crypt_find_cipher_any.o crypt_find_hash_id.o \ +crypt_prng_descriptor.o crypt_register_prng.o crypt_cipher_descriptor.o \ +crypt_find_cipher_id.o crypt_find_prng.o crypt_prng_is_valid.o \ +crypt_unregister_cipher.o crypt_cipher_is_valid.o crypt_find_hash.o \ +crypt_hash_descriptor.o crypt_register_cipher.o crypt_unregister_hash.o \ +\ +sprng.o yarrow.o rc4.o rng_get_bytes.o rng_make_prng.o \ +\ +rand_prime.o is_prime.o \ +\ +ecc.o dh.o \ +\ +rsa.o rsa_exptmod.o rsa_free.o rsa_make_key.o \ +\ +dsa_export.o dsa_free.o dsa_import.o dsa_make_key.o dsa_sign_hash.o dsa_verify_hash.o dsa_verify_key.o \ +\ +xtea.o aes.o des.o safer_tab.o safer.o saferp.o rc2.o \ +rc6.o rc5.o cast5.o noekeon.o blowfish.o twofish.o skipjack.o \ +\ +md2.o md4.o md5.o sha1.o sha256.o sha512.o tiger.o whirl.o \ +rmd128.o rmd160.o \ +\ +packet_store_header.o packet_valid_header.o \ +\ +eax_addheader.o eax_decrypt.o eax_decrypt_verify_memory.o eax_done.o eax_encrypt.o \ +eax_encrypt_authenticate_memory.o eax_init.o eax_test.o \ +\ +ocb_decrypt.o ocb_decrypt_verify_memory.o ocb_done_decrypt.o ocb_done_encrypt.o \ +ocb_encrypt.o ocb_encrypt_authenticate_memory.o ocb_init.o ocb_ntz.o \ +ocb_shift_xor.o ocb_test.o s_ocb_done.o \ +\ +omac_done.o omac_file.o omac_init.o omac_memory.o omac_process.o omac_test.o \ +\ +pmac_done.o pmac_file.o pmac_init.o pmac_memory.o pmac_ntz.o pmac_process.o \ +pmac_shift_xor.o pmac_test.o \ +\ +cbc_start.o cbc_encrypt.o cbc_decrypt.o \ +cfb_start.o cfb_encrypt.o cfb_decrypt.o \ +ofb_start.o ofb_encrypt.o ofb_decrypt.o \ +ctr_start.o ctr_encrypt.o ctr_decrypt.o \ +ecb_start.o ecb_encrypt.o ecb_decrypt.o \ +\ +hash_file.o hash_filehandle.o hash_memory.o \ +\ +hmac_done.o hmac_file.o hmac_init.o hmac_memory.o hmac_process.o hmac_test.o \ +\ +pkcs_1_mgf1.o pkcs_1_oaep_encode.o pkcs_1_oaep_decode.o \ +pkcs_1_pss_encode.o pkcs_1_pss_decode.o pkcs_1_i2osp.o pkcs_1_os2ip.o \ +\ +pkcs_5_1.o pkcs_5_2.o \ +\ +burn_stack.o zeromem.o \ +$(MPIOBJECT) + +ltc_dll: $(OBJECTS) $(MPIOBJECT) + gcc -mno-cygwin -mdll -o libtomcrypt.dll -Wl,--out-implib=libtomcrypt.dll.a -Wl,--export-all-symbols *.o -ladvapi32 + ranlib libtomcrypt.dll.a + +test: ltc_dll + gcc $(CFLAGS) demos/test.c libtomcrypt.dll.a -Wl,--enable-auto-import -o test -s diff --git a/makefile.icc b/makefile.icc new file mode 100644 index 0000000..de547a0 --- /dev/null +++ b/makefile.icc @@ -0,0 +1,213 @@ +# MAKEFILE for linux ICC (Intel C compiler) +# +# Tested with ICC v8.... +# +# Be aware that ICC isn't quite as stable as GCC and several optimization switches +# seem to break the code (that GCC and MSVC compile just fine). In particular +# "-ip" and "-x*" seem to break the code (ROL/ROR macro problems). As the makefile +# is shipped the code will build and execute properly. +# +# Also note that ICC often makes code that is slower than GCC. This is probably due to +# a mix of not being able to use "-ip" and just having fewer optimization algos than GCC. +# +# Tom St Denis + +#ch1-01-1 +# Compiler and Linker Names +CC=icc +#LD=ld + +# Archiver [makes .a files] +#AR=ar +#ARFLAGS=r + +# Compilation flags. Note the += does not write over the user's CFLAGS! +CFLAGS += -c -I./ -DINTEL_CC + +# optimize for SPEED +# +# -mcpu= can be pentium, pentiumpro (covers PII through PIII) or pentium4 +# -ax? specifies make code specifically for ? but compatible with IA-32 +# -x? specifies compile solely for ? [not specifically IA-32 compatible] +# +# where ? is +# K - PIII +# W - first P4 [Williamette] +# N - P4 Northwood +# P - P4 Prescott +# B - Blend of P4 and PM [mobile] +# +# Default to just generic max opts +CFLAGS += -O3 -xN -ip + +# want to see stuff? +#CFLAGS += -opt_report + +#These flags control how the library gets built. + +#Output filenames for various targets. +LIBNAME=libtomcrypt.a +TEST=test +HASH=hashsum +CRYPT=encrypt +SMALL=small +PROF=x86_prof +TV=tv_gen + +#LIBPATH-The directory for libtomcrypt to be installed to. +#INCPATH-The directory to install the header files for libtomcrypt. +#DATAPATH-The directory to install the pdf docs. +DESTDIR= +LIBPATH=/usr/lib +INCPATH=/usr/include +DATAPATH=/usr/share/doc/libtomcrypt/pdf + +#List of objects to compile. + +#Leave MPI built-in or force developer to link against libtommath? +MPIOBJECT=mpi.o + +OBJECTS=keyring.o gf.o strings.o base64.o \ +\ +crypt.o crypt_find_cipher.o crypt_find_hash_any.o \ +crypt_hash_is_valid.o crypt_register_hash.o crypt_unregister_prng.o \ +crypt_argchk.o crypt_find_cipher_any.o crypt_find_hash_id.o \ +crypt_prng_descriptor.o crypt_register_prng.o crypt_cipher_descriptor.o \ +crypt_find_cipher_id.o crypt_find_prng.o crypt_prng_is_valid.o \ +crypt_unregister_cipher.o crypt_cipher_is_valid.o crypt_find_hash.o \ +crypt_hash_descriptor.o crypt_register_cipher.o crypt_unregister_hash.o \ +\ +sprng.o yarrow.o rc4.o rng_get_bytes.o rng_make_prng.o \ +\ +rand_prime.o is_prime.o \ +\ +ecc.o dh.o \ +\ +rsa.o rsa_exptmod.o rsa_free.o rsa_make_key.o \ +\ +dsa_export.o dsa_free.o dsa_import.o dsa_make_key.o dsa_sign_hash.o dsa_verify_hash.o dsa_verify_key.o \ +\ +xtea.o aes.o des.o safer_tab.o safer.o saferp.o rc2.o \ +rc6.o rc5.o cast5.o noekeon.o blowfish.o twofish.o skipjack.o \ +\ +md2.o md4.o md5.o sha1.o sha256.o sha512.o tiger.o whirl.o \ +rmd128.o rmd160.o \ +\ +packet_store_header.o packet_valid_header.o \ +\ +eax_addheader.o eax_decrypt.o eax_decrypt_verify_memory.o eax_done.o eax_encrypt.o \ +eax_encrypt_authenticate_memory.o eax_init.o eax_test.o \ +\ +ocb_decrypt.o ocb_decrypt_verify_memory.o ocb_done_decrypt.o ocb_done_encrypt.o \ +ocb_encrypt.o ocb_encrypt_authenticate_memory.o ocb_init.o ocb_ntz.o \ +ocb_shift_xor.o ocb_test.o s_ocb_done.o \ +\ +omac_done.o omac_file.o omac_init.o omac_memory.o omac_process.o omac_test.o \ +\ +pmac_done.o pmac_file.o pmac_init.o pmac_memory.o pmac_ntz.o pmac_process.o \ +pmac_shift_xor.o pmac_test.o \ +\ +cbc_start.o cbc_encrypt.o cbc_decrypt.o \ +cfb_start.o cfb_encrypt.o cfb_decrypt.o \ +ofb_start.o ofb_encrypt.o ofb_decrypt.o \ +ctr_start.o ctr_encrypt.o ctr_decrypt.o \ +ecb_start.o ecb_encrypt.o ecb_decrypt.o \ +\ +hash_file.o hash_filehandle.o hash_memory.o \ +\ +hmac_done.o hmac_file.o hmac_init.o hmac_memory.o hmac_process.o hmac_test.o \ +\ +pkcs_1_mgf1.o pkcs_1_oaep_encode.o pkcs_1_oaep_decode.o \ +pkcs_1_pss_encode.o pkcs_1_pss_decode.o pkcs_1_i2osp.o pkcs_1_os2ip.o \ +\ +pkcs_5_1.o pkcs_5_2.o \ +\ +burn_stack.o zeromem.o \ +$(MPIOBJECT) + +TESTOBJECTS=demos/test.o +HASHOBJECTS=demos/hashsum.o +CRYPTOBJECTS=demos/encrypt.o +SMALLOBJECTS=demos/small.o +PROFS=demos/x86_prof.o +TVS=demos/tv_gen.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=tommath.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 mycrypt_custom.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 +twofish.o: twofish.c twofish_tab.c +sha512.o: sha512.c sha384.c +sha256.o: sha256.c sha224.c + +#This rule makes the libtomcrypt library. +library: $(LIBNAME) + +$(LIBNAME): $(OBJECTS) + $(AR) $(ARFLAGS) $@ $(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) + +x86_prof: library $(PROFS) + $(CC) $(PROFS) $(LIBNAME) -o $(PROF) + +tv_gen: library $(TVS) + $(CC) $(TVS) $(LIBNAME) -o $(TV) + + +#make a profiled library (takes a while!!!) +# +# This will build the library with profile generation +# then run the test demo and rebuild the library. +# +# So far I've seen improvements in the MP math +profiled: + make -f makefile.icc CFLAGS="$(CFLAGS) -prof_gen" test + ./test + rm -f *.a *.o test demos/test.o + make -f makefile.icc CFLAGS="$(CFLAGS) -prof_use" + +#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 -d -g root -o root $(DESTDIR)$(LIBPATH) + install -d -g root -o root $(DESTDIR)$(INCPATH) + install -g root -o root $(LIBNAME) $(DESTDIR)$(LIBPATH) + install -g root -o root $(HEADERS) $(DESTDIR)$(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) $(PROFS) $(PROF) $(TVS) $(TV) + rm -f *.a *.dll *stackdump *.lib *.exe *.obj demos/*.obj demos/*.o *.bat *.txt *.il *.da demos/*.il demos/*.da *.dyn diff --git a/makefile.msvc b/makefile.msvc new file mode 100644 index 0000000..5c3c410 --- /dev/null +++ b/makefile.msvc @@ -0,0 +1,86 @@ +#MSVC Makefile [tested with MSVC 6.00 with SP5] +# +#Tom St Denis +CFLAGS = /I. /Ox /DWIN32 /W3 + +default: library + +# leave this blank and link against libtommath if you want better link resolution +MPIOBJECT=mpi.obj + +#List of objects to compile. +OBJECTS=keyring.obj gf.obj strings.obj base64.obj \ +\ +crypt.obj crypt_find_cipher.obj crypt_find_hash_any.obj \ +crypt_hash_is_valid.obj crypt_register_hash.obj crypt_unregister_prng.obj \ +crypt_argchk.obj crypt_find_cipher_any.obj crypt_find_hash_id.obj \ +crypt_prng_descriptor.obj crypt_register_prng.obj crypt_cipher_descriptor.obj \ +crypt_find_cipher_id.obj crypt_find_prng.obj crypt_prng_is_valid.obj \ +crypt_unregister_cipher.obj crypt_cipher_is_valid.obj crypt_find_hash.obj \ +crypt_hash_descriptor.obj crypt_register_cipher.obj crypt_unregister_hash.obj \ +\ +sprng.obj yarrow.obj rc4.obj rng_get_bytes.obj rng_make_prng.obj \ +\ +rand_prime.obj is_prime.obj \ +\ +ecc.obj dh.obj \ +\ +rsa.obj rsa_exptmod.obj rsa_free.obj rsa_make_key.obj \ +\ +dsa_export.obj dsa_free.obj dsa_import.obj dsa_make_key.obj dsa_sign_hash.obj dsa_verify_hash.obj dsa_verify_key.obj \ +\ +xtea.obj aes.obj des.obj safer_tab.obj safer.obj saferp.obj rc2.obj \ +rc6.obj rc5.obj cast5.obj noekeon.obj blowfish.obj twofish.obj skipjack.obj \ +\ +md2.obj md4.obj md5.obj sha1.obj sha256.obj sha512.obj tiger.obj whirl.obj \ +rmd128.obj rmd160.obj \ +\ +packet_store_header.obj packet_valid_header.obj \ +\ +eax_addheader.obj eax_decrypt.obj eax_decrypt_verify_memory.obj eax_done.obj eax_encrypt.obj \ +eax_encrypt_authenticate_memory.obj eax_init.obj eax_test.obj \ +\ +ocb_decrypt.obj ocb_decrypt_verify_memory.obj ocb_done_decrypt.obj ocb_done_encrypt.obj \ +ocb_encrypt.obj ocb_encrypt_authenticate_memory.obj ocb_init.obj ocb_ntz.obj \ +ocb_shift_xor.obj ocb_test.obj s_ocb_done.obj \ +\ +omac_done.obj omac_file.obj omac_init.obj omac_memory.obj omac_process.obj omac_test.obj \ +\ +pmac_done.obj pmac_file.obj pmac_init.obj pmac_memory.obj pmac_ntz.obj pmac_process.obj \ +pmac_shift_xor.obj pmac_test.obj \ +\ +cbc_start.obj cbc_encrypt.obj cbc_decrypt.obj \ +cfb_start.obj cfb_encrypt.obj cfb_decrypt.obj \ +ofb_start.obj ofb_encrypt.obj ofb_decrypt.obj \ +ctr_start.obj ctr_encrypt.obj ctr_decrypt.obj \ +ecb_start.obj ecb_encrypt.obj ecb_decrypt.obj \ +\ +hash_file.obj hash_filehandle.obj hash_memory.obj \ +\ +hmac_done.obj hmac_file.obj hmac_init.obj hmac_memory.obj hmac_process.obj hmac_test.obj \ +\ +pkcs_1_mgf1.obj pkcs_1_oaep_encode.obj pkcs_1_oaep_decode.obj \ +pkcs_1_pss_encode.obj pkcs_1_pss_decode.obj pkcs_1_i2osp.obj pkcs_1_os2ip.obj \ +\ +pkcs_5_1.obj pkcs_5_2.obj \ +\ +burn_stack.obj zeromem.obj \ +$(MPIOBJECT) + +library: $(OBJECTS) + lib /out:tomcrypt.lib $(OBJECTS) + +test.obj: demos/test.c + cl $(CFLAGS) /c demos/test.c + +test: library test.obj + cl test.obj tomcrypt.lib advapi32.lib + +x86_prof: demos/x86_prof.c library + cl $(CFLAGS) demos/x86_prof.c tomcrypt.lib advapi32.lib + +tv_gen: demos/tv_gen.c library + cl $(CFLAGS) demos/tv_gen.c tomcrypt.lib advapi32.lib + +hashsum: demos/hashsum.c library + cl $(CFLAGS) demos/hashsum.c tomcrypt.lib advapi32.lib diff --git a/md2.c b/md2.c new file mode 100644 index 0000000..73b0092 --- /dev/null +++ b/md2.c @@ -0,0 +1,214 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* 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[(int)(md->md2.buf[j] ^ L)] & 255); + } +} + +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 = (unsigned char)0; + + /* do 18 rounds */ + for (j = 0; j < 18; j++) { + for (k = 0; k < 48; k++) { + t = (md->md2.X[k] ^= PI_SUBST[(int)(t & 255)]); + } + t = (t + (unsigned char)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; +} + +int md2_process(hash_state *md, const unsigned char *buf, unsigned long len) +{ + unsigned long n; + _ARGCHK(md != NULL); + _ARGCHK(buf != NULL); + if (md-> md2 .curlen > sizeof(md-> md2 .buf)) { + return CRYPT_INVALID_ARG; + } + while (len > 0) { + n = MIN(len, (16 - md->md2.curlen)); + memcpy(md->md2.buf + md->md2.curlen, buf, (size_t)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; + } + } + return CRYPT_OK; +} + +int md2_done(hash_state * md, unsigned char *hash) +{ + unsigned long i, k; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->md2.curlen >= sizeof(md->md2.buf)) { + return CRYPT_INVALID_ARG; + } + + + /* pad the message */ + k = 16 - md->md2.curlen; + for (i = md->md2.curlen; i < 16; i++) { + md->md2.buf[i] = (unsigned char)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 + return CRYPT_OK; +} + +int md2_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + 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, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg)); + md2_done(&md, buf); + if (memcmp(buf, tests[i].md, 16) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + +#endif + diff --git a/md4.c b/md4.c new file mode 100644 index 0000000..1017b03 --- /dev/null +++ b/md4.c @@ -0,0 +1,266 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* 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) (z ^ (x & (y ^ z))) +#define G(x, y, z) ((x & y) | (z & (x | y))) +#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, unsigned char *buf) +#else +static void md4_compress(hash_state *md, unsigned char *buf) +#endif +{ + ulong32 x[16], a, b, c, d; + int i; + + /* 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], 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, unsigned char *buf) +{ + _md4_compress(md, buf); + burn_stack(sizeof(ulong32) * 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; +} + +HASH_PROCESS(md4_process, md4_compress, md4, 64) + +int md4_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->md4.curlen >= sizeof(md->md4.buf)) { + return CRYPT_INVALID_ARG; + } + + /* increase the length of the message */ + md->md4.length += md->md4.curlen * 8; + + /* append the '1' bit */ + md->md4.buf[md->md4.curlen++] = (unsigned char)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++] = (unsigned char)0; + } + md4_compress(md, md->md4.buf); + md->md4.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->md4.curlen < 56) { + md->md4.buf[md->md4.curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64L(md->md4.length, md->md4.buf+56); + md4_compress(md, md->md4.buf); + + /* 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 + return CRYPT_OK; +} + +int md4_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct md4_test_case { + char *input; + unsigned char digest[16]; + } cases[] = { + { "", + {0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31, + 0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0} }, + { "a", + {0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46, + 0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24} }, + { "abc", + {0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52, + 0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d} }, + { "message digest", + {0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8, + 0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b} }, + { "abcdefghijklmnopqrstuvwxyz", + {0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd, + 0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9} }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + {0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35, + 0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4} }, + { "12345678901234567890123456789012345678901234567890123456789012345678901234567890", + {0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19, + 0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36} }, + }; + int i; + hash_state md; + unsigned char digest[16]; + + for(i = 0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) { + md4_init(&md); + md4_process(&md, (unsigned char *)cases[i].input, (unsigned long)strlen(cases[i].input)); + md4_done(&md, digest); + if (memcmp(digest, cases[i].digest, 16) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + + } + return CRYPT_OK; + #endif +} + +#endif + + diff --git a/md5.c b/md5.c new file mode 100644 index 0000000..768c711 --- /dev/null +++ b/md5.c @@ -0,0 +1,258 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* MD5 hash function by Tom St Denis */ + +#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) (z ^ (x & (y ^ z))) +#define G(x,y,z) (y ^ (z & (y ^ x))) +#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) + b; + +#define GG(a,b,c,d,M,s,t) \ + a = (a + G(b,c,d) + M + t); a = ROL(a, s) + b; + +#define HH(a,b,c,d,M,s,t) \ + a = (a + H(b,c,d) + M + t); a = ROL(a, s) + b; + +#define II(a,b,c,d,M,s,t) \ + a = (a + I(b,c,d) + M + t); a = ROL(a, s) + b; + +#ifdef CLEAN_STACK +static void _md5_compress(hash_state *md, unsigned char *buf) +#else +static void md5_compress(hash_state *md, unsigned char *buf) +#endif +{ + ulong32 i, W[16], a, b, c, d; + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD32L(W[i], 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, unsigned char *buf) +{ + _md5_compress(md, buf); + burn_stack(sizeof(ulong32) * 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; +} + +HASH_PROCESS(md5_process, md5_compress, md5, 64) + +int md5_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->md5.curlen >= sizeof(md->md5.buf)) { + return CRYPT_INVALID_ARG; + } + + + /* increase the length of the message */ + md->md5.length += md->md5.curlen * 8; + + /* append the '1' bit */ + md->md5.buf[md->md5.curlen++] = (unsigned char)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++] = (unsigned char)0; + } + md5_compress(md, md->md5.buf); + md->md5.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->md5.curlen < 56) { + md->md5.buf[md->md5.curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64L(md->md5.length, md->md5.buf+56); + md5_compress(md, md->md5.buf); + + /* 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 + return CRYPT_OK; +} + +int md5_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + 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 i; + unsigned char tmp[16]; + hash_state md; + + for (i = 0; tests[i].msg != NULL; i++) { + md5_init(&md); + md5_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg)); + md5_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 16) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + +#endif + + diff --git a/mpi.c b/mpi.c new file mode 100644 index 0000000..584bb00 --- /dev/null +++ b/mpi.c @@ -0,0 +1,8414 @@ +/* Start: bn_error.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +static const struct { + int code; + char *msg; +} msgs[] = { + { MP_OKAY, "Successful" }, + { MP_MEM, "Out of heap" }, + { MP_VAL, "Value out of range" } +}; + +/* return a char * string for a given code */ +char *mp_error_to_string(int code) +{ + int x; + + /* scan the lookup table for the given message */ + for (x = 0; x < (int)(sizeof(msgs) / sizeof(msgs[0])); x++) { + if (msgs[x].code == code) { + return msgs[x].msg; + } + } + + /* generic reply for invalid code */ + return "Invalid error code"; +} + + +/* End: bn_error.c */ + +/* Start: bn_fast_mp_invmod.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes the modular inverse via binary extended euclidean algorithm, + * that is c = 1/a mod b + * + * Based on mp_invmod except this is optimized for the case where b is + * odd as per HAC Note 14.64 on pp. 610 + */ +int +fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, B, D; + int res, neg; + + /* 2. [modified] b must be odd */ + if (mp_iseven (b) == 1) { + return MP_VAL; + } + + /* init all our temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x == modulus, y == value to invert */ + if ((res = mp_copy (b, &x)) != MP_OKAY) { + goto __ERR; + } + + /* we need y = |a| */ + if ((res = mp_abs (a, &y)) != MP_OKAY) { + goto __ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto __ERR; + } + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto __ERR; + } + /* 4.2 if B is odd then */ + if (mp_isodd (&B) == 1) { + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto __ERR; + } + } + /* B = B/2 */ + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto __ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto __ERR; + } + /* 5.2 if D is odd then */ + if (mp_isodd (&D) == 1) { + /* D = (D-x)/2 */ + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto __ERR; + } + } + /* D = D/2 */ + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto __ERR; + } + } else { + /* v - v - u, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) { + goto top; + } + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto __ERR; + } + + /* b is now the inverse */ + neg = a->sign; + while (D.sign == MP_NEG) { + if ((res = mp_add (&D, b, &D)) != MP_OKAY) { + goto __ERR; + } + } + mp_exch (&D, c); + c->sign = neg; + res = MP_OKAY; + +__ERR:mp_clear_multi (&x, &y, &u, &v, &B, &D, NULL); + return res; +} + +/* End: bn_fast_mp_invmod.c */ + +/* Start: bn_fast_mp_montgomery_reduce.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes xR**-1 == x (mod N) via Montgomery Reduction + * + * This is an optimized implementation of mp_montgomery_reduce + * which uses the comba method to quickly calculate the columns of the + * reduction. + * + * Based on Algorithm 14.32 on pp.601 of HAC. +*/ +int +fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, olduse; + mp_word W[MP_WARRAY]; + + /* get old used count */ + olduse = x->used; + + /* grow a as required */ + if (x->alloc < n->used + 1) { + if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) { + return res; + } + } + + /* first we have to get the digits of the input into + * an array of double precision words W[...] + */ + { + register mp_word *_W; + register mp_digit *tmpx; + + /* alias for the W[] array */ + _W = W; + + /* alias for the digits of x*/ + tmpx = x->dp; + + /* copy the digits of a into W[0..a->used-1] */ + for (ix = 0; ix < x->used; ix++) { + *_W++ = *tmpx++; + } + + /* zero the high words of W[a->used..m->used*2] */ + for (; ix < n->used * 2 + 1; ix++) { + *_W++ = 0; + } + } + + /* now we proceed to zero successive digits + * from the least significant upwards + */ + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * m' mod b + * + * We avoid a double precision multiplication (which isn't required) + * by casting the value down to a mp_digit. Note this requires + * that W[ix-1] have the carry cleared (see after the inner loop) + */ + register mp_digit mu; + mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK); + + /* a = a + mu * m * b**i + * + * This is computed in place and on the fly. The multiplication + * by b**i is handled by offseting which columns the results + * are added to. + * + * Note the comba method normally doesn't handle carries in the + * inner loop In this case we fix the carry from the previous + * column since the Montgomery reduction requires digits of the + * result (so far) [see above] to work. This is + * handled by fixing up one carry after the inner loop. The + * carry fixups are done in order so after these loops the + * first m->used words of W[] have the carries fixed + */ + { + register int iy; + register mp_digit *tmpn; + register mp_word *_W; + + /* alias for the digits of the modulus */ + tmpn = n->dp; + + /* Alias for the columns set by an offset of ix */ + _W = W + ix; + + /* inner loop */ + for (iy = 0; iy < n->used; iy++) { + *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++); + } + } + + /* now fix carry for next digit, W[ix+1] */ + W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); + } + + /* now we have to propagate the carries and + * shift the words downward [all those least + * significant digits we zeroed]. + */ + { + register mp_digit *tmpx; + register mp_word *_W, *_W1; + + /* nox fix rest of carries */ + + /* alias for current word */ + _W1 = W + ix; + + /* alias for next word, where the carry goes */ + _W = W + ++ix; + + for (; ix <= n->used * 2 + 1; ix++) { + *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); + } + + /* copy out, A = A/b**n + * + * The result is A/b**n but instead of converting from an + * array of mp_word to mp_digit than calling mp_rshd + * we just copy them in the right order + */ + + /* alias for destination word */ + tmpx = x->dp; + + /* alias for shifted double precision result */ + _W = W + n->used; + + for (ix = 0; ix < n->used + 1; ix++) { + *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK)); + } + + /* zero oldused digits, if the input a was larger than + * m->used+1 we'll have to clear the digits + */ + for (; ix < olduse; ix++) { + *tmpx++ = 0; + } + } + + /* set the max used and clamp */ + x->used = n->used + 1; + mp_clamp (x); + + /* if A >= m then A = A - m */ + if (mp_cmp_mag (x, n) != MP_LT) { + return s_mp_sub (x, n, x); + } + return MP_OKAY; +} + +/* End: bn_fast_mp_montgomery_reduce.c */ + +/* Start: bn_fast_s_mp_mul_digs.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* Fast (comba) multiplier + * + * This is the fast column-array [comba] multiplier. It is + * designed to compute the columns of the product first + * then handle the carries afterwards. This has the effect + * of making the nested loops that compute the columns very + * simple and schedulable on super-scalar processors. + * + * This has been modified to produce a variable number of + * digits of output so if say only a half-product is required + * you don't have to compute the upper half (a feature + * required for fast Barrett reduction). + * + * Based on Algorithm 14.12 on pp.595 of HAC. + * + */ +int +fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix; + mp_word W[MP_WARRAY]; + + /* grow the destination as required */ + if (c->alloc < digs) { + if ((res = mp_grow (c, digs)) != MP_OKAY) { + return res; + } + } + + /* clear temp buf (the columns) */ + memset (W, 0, sizeof (mp_word) * digs); + + /* calculate the columns */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* this multiplier has been modified to allow you to + * control how many digits of output are produced. + * So at most we want to make upto "digs" digits of output. + * + * this adds products to distinct columns (at ix+iy) of W + * note that each step through the loop is not dependent on + * the previous which means the compiler can easily unroll + * the loop without scheduling problems + */ + { + register mp_digit tmpx, *tmpy; + register mp_word *_W; + register int iy, pb; + + /* alias for the the word on the left e.g. A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for the right side */ + tmpy = b->dp; + + /* alias for the columns, each step through the loop adds a new + term to each column + */ + _W = W + ix; + + /* the number of digits is limited by their placement. E.g. + we avoid multiplying digits that will end up above the # of + digits of precision requested + */ + pb = MIN (b->used, digs - ix); + + for (iy = 0; iy < pb; iy++) { + *_W++ += ((mp_word)tmpx) * ((mp_word)*tmpy++); + } + } + + } + + /* setup dest */ + olduse = c->used; + c->used = digs; + + { + register mp_digit *tmpc; + + /* At this point W[] contains the sums of each column. To get the + * correct result we must take the extra bits from each column and + * carry them down + * + * Note that while this adds extra code to the multiplier it + * saves time since the carry propagation is removed from the + * above nested loop.This has the effect of reducing the work + * from N*(N+N*c)==N**2 + c*N**2 to N**2 + N*c where c is the + * cost of the shifting. On very small numbers this is slower + * but on most cryptographic size numbers it is faster. + * + * In this particular implementation we feed the carries from + * behind which means when the loop terminates we still have one + * last digit to copy + */ + tmpc = c->dp; + for (ix = 1; ix < digs; ix++) { + /* forward the carry from the previous temp */ + W[ix] += (W[ix - 1] >> ((mp_word) DIGIT_BIT)); + + /* now extract the previous digit [below the carry] */ + *tmpc++ = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); + } + /* fetch the last digit */ + *tmpc++ = (mp_digit) (W[digs - 1] & ((mp_word) MP_MASK)); + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_fast_s_mp_mul_digs.c */ + +/* Start: bn_fast_s_mp_mul_high_digs.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ + #include + +/* this is a modified version of fast_s_mp_mul_digs that only produces + * output digits *above* digs. See the comments for fast_s_mp_mul_digs + * to see how it works. + * + * This is used in the Barrett reduction since for one of the multiplications + * only the higher digits were needed. This essentially halves the work. + * + * Based on Algorithm 14.12 on pp.595 of HAC. + */ +int +fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int oldused, newused, res, pa, pb, ix; + mp_word W[MP_WARRAY]; + + /* calculate size of product and allocate more space if required */ + newused = a->used + b->used + 1; + if (c->alloc < newused) { + if ((res = mp_grow (c, newused)) != MP_OKAY) { + return res; + } + } + + /* like the other comba method we compute the columns first */ + pa = a->used; + pb = b->used; + memset (W + digs, 0, (pa + pb + 1 - digs) * sizeof (mp_word)); + for (ix = 0; ix < pa; ix++) { + { + register mp_digit tmpx, *tmpy; + register int iy; + register mp_word *_W; + + /* work todo, that is we only calculate digits that are at "digs" or above */ + iy = digs - ix; + + /* copy of word on the left of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias for right side */ + tmpy = b->dp + iy; + + /* alias for the columns of output. Offset to be equal to or above the + * smallest digit place requested + */ + _W = W + digs; + + /* skip cases below zero where ix > digs */ + if (iy < 0) { + iy = abs(iy); + tmpy += iy; + _W += iy; + iy = 0; + } + + /* compute column products for digits above the minimum */ + for (; iy < pb; iy++) { + *_W++ += ((mp_word) tmpx) * ((mp_word)*tmpy++); + } + } + } + + /* setup dest */ + oldused = c->used; + c->used = newused; + + /* now convert the array W downto what we need + * + * See comments in bn_fast_s_mp_mul_digs.c + */ + for (ix = digs + 1; ix < newused; ix++) { + W[ix] += (W[ix - 1] >> ((mp_word) DIGIT_BIT)); + c->dp[ix - 1] = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); + } + c->dp[newused - 1] = (mp_digit) (W[newused - 1] & ((mp_word) MP_MASK)); + + for (; ix < oldused; ix++) { + c->dp[ix] = 0; + } + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_fast_s_mp_mul_high_digs.c */ + +/* Start: bn_fast_s_mp_sqr.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* fast squaring + * + * This is the comba method where the columns of the product + * are computed first then the carries are computed. This + * has the effect of making a very simple inner loop that + * is executed the most + * + * W2 represents the outer products and W the inner. + * + * A further optimizations is made because the inner + * products are of the form "A * B * 2". The *2 part does + * not need to be computed until the end which is good + * because 64-bit shifts are slow! + * + * Based on Algorithm 14.16 on pp.597 of HAC. + * + */ +int fast_s_mp_sqr (mp_int * a, mp_int * b) +{ + int olduse, newused, res, ix, pa; + mp_word W2[MP_WARRAY], W[MP_WARRAY]; + + /* calculate size of product and allocate as required */ + pa = a->used; + newused = pa + pa + 1; + if (b->alloc < newused) { + if ((res = mp_grow (b, newused)) != MP_OKAY) { + return res; + } + } + + /* zero temp buffer (columns) + * Note that there are two buffers. Since squaring requires + * a outer and inner product and the inner product requires + * computing a product and doubling it (a relatively expensive + * op to perform n**2 times if you don't have to) the inner and + * outer products are computed in different buffers. This way + * the inner product can be doubled using n doublings instead of + * n**2 + */ + memset (W, 0, newused * sizeof (mp_word)); + memset (W2, 0, newused * sizeof (mp_word)); + + /* This computes the inner product. To simplify the inner N**2 loop + * the multiplication by two is done afterwards in the N loop. + */ + for (ix = 0; ix < pa; ix++) { + /* compute the outer product + * + * Note that every outer product is computed + * for a particular column only once which means that + * there is no need todo a double precision addition + * into the W2[] array. + */ + W2[ix + ix] = ((mp_word)a->dp[ix]) * ((mp_word)a->dp[ix]); + + { + register mp_digit tmpx, *tmpy; + register mp_word *_W; + register int iy; + + /* copy of left side */ + tmpx = a->dp[ix]; + + /* alias for right side */ + tmpy = a->dp + (ix + 1); + + /* the column to store the result in */ + _W = W + (ix + ix + 1); + + /* inner products */ + for (iy = ix + 1; iy < pa; iy++) { + *_W++ += ((mp_word)tmpx) * ((mp_word)*tmpy++); + } + } + } + + /* setup dest */ + olduse = b->used; + b->used = newused; + + /* now compute digits + * + * We have to double the inner product sums, add in the + * outer product sums, propagate carries and convert + * to single precision. + */ + { + register mp_digit *tmpb; + + /* double first value, since the inner products are + * half of what they should be + */ + W[0] += W[0] + W2[0]; + + tmpb = b->dp; + for (ix = 1; ix < newused; ix++) { + /* double/add next digit */ + W[ix] += W[ix] + W2[ix]; + + /* propagate carry forwards [from the previous digit] */ + W[ix] = W[ix] + (W[ix - 1] >> ((mp_word) DIGIT_BIT)); + + /* store the current digit now that the carry isn't + * needed + */ + *tmpb++ = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); + } + /* set the last value. Note even if the carry is zero + * this is required since the next step will not zero + * it if b originally had a value at b->dp[2*a.used] + */ + *tmpb++ = (mp_digit) (W[(newused) - 1] & ((mp_word) MP_MASK)); + + /* clear high digits of b if there were any originally */ + for (; ix < olduse; ix++) { + *tmpb++ = 0; + } + } + + mp_clamp (b); + return MP_OKAY; +} + +/* End: bn_fast_s_mp_sqr.c */ + +/* Start: bn_mp_2expt.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes a = 2**b + * + * Simple algorithm which zeroes the int, grows it then just sets one bit + * as required. + */ +int +mp_2expt (mp_int * a, int b) +{ + int res; + + /* zero a as per default */ + mp_zero (a); + + /* grow a to accomodate the single bit */ + if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + + /* set the used count of where the bit will go */ + a->used = b / DIGIT_BIT + 1; + + /* put the single bit in its place */ + a->dp[b / DIGIT_BIT] = 1 << (b % DIGIT_BIT); + + return MP_OKAY; +} + +/* End: bn_mp_2expt.c */ + +/* Start: bn_mp_abs.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* b = |a| + * + * Simple function copies the input and fixes the sign to positive + */ +int +mp_abs (mp_int * a, mp_int * b) +{ + int res; + + /* copy a to b */ + if (a != b) { + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + } + + /* force the sign of b to positive */ + b->sign = MP_ZPOS; + + return MP_OKAY; +} + +/* End: bn_mp_abs.c */ + +/* Start: bn_mp_add.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* high level addition (handles signs) */ +int mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + /* get sign of both inputs */ + sa = a->sign; + sb = b->sign; + + /* handle two cases, not four */ + if (sa == sb) { + /* both positive or both negative */ + /* add their magnitudes, copy the sign */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* one positive, the other negative */ + /* subtract the one with the greater magnitude from */ + /* the one of the lesser magnitude. The result gets */ + /* the sign of the one with the greater magnitude. */ + if (mp_cmp_mag (a, b) == MP_LT) { + c->sign = sb; + res = s_mp_sub (b, a, c); + } else { + c->sign = sa; + res = s_mp_sub (a, b, c); + } + } + return res; +} + + +/* End: bn_mp_add.c */ + +/* Start: bn_mp_add_d.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* single digit addition */ +int +mp_add_d (mp_int * a, mp_digit b, mp_int * c) +{ + int res, ix, oldused; + mp_digit *tmpa, *tmpc, mu; + + /* grow c as required */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* if a is negative and |a| >= b, call c = |a| - b */ + if (a->sign == MP_NEG && (a->used > 1 || a->dp[0] >= b)) { + /* temporarily fix sign of a */ + a->sign = MP_ZPOS; + + /* c = |a| - b */ + res = mp_sub_d(a, b, c); + + /* fix sign */ + a->sign = c->sign = MP_NEG; + + return res; + } + + /* old number of used digits in c */ + oldused = c->used; + + /* sign always positive */ + c->sign = MP_ZPOS; + + /* source alias */ + tmpa = a->dp; + + /* destination alias */ + tmpc = c->dp; + + /* if a is positive */ + if (a->sign == MP_ZPOS) { + /* add digit, after this we're propagating + * the carry. + */ + *tmpc = *tmpa++ + b; + mu = *tmpc >> DIGIT_BIT; + *tmpc++ &= MP_MASK; + + /* now handle rest of the digits */ + for (ix = 1; ix < a->used; ix++) { + *tmpc = *tmpa++ + mu; + mu = *tmpc >> DIGIT_BIT; + *tmpc++ &= MP_MASK; + } + /* set final carry */ + ix++; + *tmpc++ = mu; + + /* setup size */ + c->used = a->used + 1; + } else { + /* a was negative and |a| < b */ + c->used = 1; + + /* the result is a single digit */ + if (a->used == 1) { + *tmpc++ = b - a->dp[0]; + } else { + *tmpc++ = b; + } + + /* setup count so the clearing of oldused + * can fall through correctly + */ + ix = 1; + } + + /* now zero to oldused */ + while (ix++ < oldused) { + *tmpc++ = 0; + } + mp_clamp(c); + + return MP_OKAY; +} + + +/* End: bn_mp_add_d.c */ + +/* Start: bn_mp_addmod.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* d = a + b (mod c) */ +int +mp_addmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_add (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + +/* End: bn_mp_addmod.c */ + +/* Start: bn_mp_and.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* AND two ints together */ +int +mp_and (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] &= x->dp[ix]; + } + + /* zero digits above the last from the smallest mp_int */ + for (; ix < t.used; ix++) { + t.dp[ix] = 0; + } + + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_and.c */ + +/* Start: bn_mp_clamp.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* trim unused digits + * + * This is used to ensure that leading zero digits are + * trimed and the leading "used" digit will be non-zero + * Typically very fast. Also fixes the sign if there + * are no more leading digits + */ +void +mp_clamp (mp_int * a) +{ + /* decrease used while the most significant digit is + * zero. + */ + while (a->used > 0 && a->dp[a->used - 1] == 0) { + --(a->used); + } + + /* reset the sign flag if used == 0 */ + if (a->used == 0) { + a->sign = MP_ZPOS; + } +} + +/* End: bn_mp_clamp.c */ + +/* Start: bn_mp_clear.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* clear one (frees) */ +void +mp_clear (mp_int * a) +{ + /* only do anything if a hasn't been freed previously */ + if (a->dp != NULL) { + /* first zero the digits */ + memset (a->dp, 0, sizeof (mp_digit) * a->used); + + /* free ram */ + XFREE(a->dp); + + /* reset members to make debugging easier */ + a->dp = NULL; + a->alloc = a->used = 0; + a->sign = MP_ZPOS; + } +} + +/* End: bn_mp_clear.c */ + +/* Start: bn_mp_clear_multi.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include +#include + +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); +} + +/* End: bn_mp_clear_multi.c */ + +/* Start: bn_mp_cmp.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* compare two ints (signed)*/ +int +mp_cmp (mp_int * a, mp_int * b) +{ + /* compare based on sign */ + if (a->sign != b->sign) { + if (a->sign == MP_NEG) { + return MP_LT; + } else { + return MP_GT; + } + } + + /* compare digits */ + if (a->sign == MP_NEG) { + /* if negative compare opposite direction */ + return mp_cmp_mag(b, a); + } else { + return mp_cmp_mag(a, b); + } +} + +/* End: bn_mp_cmp.c */ + +/* Start: bn_mp_cmp_d.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* compare a digit */ +int mp_cmp_d(mp_int * a, mp_digit b) +{ + /* compare based on sign */ + if (a->sign == MP_NEG) { + return MP_LT; + } + + /* compare based on magnitude */ + if (a->used > 1) { + return MP_GT; + } + + /* compare the only digit of a to b */ + if (a->dp[0] > b) { + return MP_GT; + } else if (a->dp[0] < b) { + return MP_LT; + } else { + return MP_EQ; + } +} + +/* End: bn_mp_cmp_d.c */ + +/* Start: bn_mp_cmp_mag.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* compare maginitude of two ints (unsigned) */ +int mp_cmp_mag (mp_int * a, mp_int * b) +{ + int n; + mp_digit *tmpa, *tmpb; + + /* compare based on # of non-zero digits */ + if (a->used > b->used) { + return MP_GT; + } + + if (a->used < b->used) { + return MP_LT; + } + + /* alias for a */ + tmpa = a->dp + (a->used - 1); + + /* alias for b */ + tmpb = b->dp + (a->used - 1); + + /* compare based on digits */ + for (n = 0; n < a->used; ++n, --tmpa, --tmpb) { + if (*tmpa > *tmpb) { + return MP_GT; + } + + if (*tmpa < *tmpb) { + return MP_LT; + } + } + return MP_EQ; +} + +/* End: bn_mp_cmp_mag.c */ + +/* Start: bn_mp_cnt_lsb.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +static const int lnz[16] = { + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +}; + +/* Counts the number of lsbs which are zero before the first zero bit */ +int mp_cnt_lsb(mp_int *a) +{ + int x; + mp_digit q, qq; + + /* easy out */ + if (mp_iszero(a) == 1) { + return 0; + } + + /* scan lower digits until non-zero */ + for (x = 0; x < a->used && a->dp[x] == 0; x++); + q = a->dp[x]; + x *= DIGIT_BIT; + + /* now scan this digit until a 1 is found */ + if ((q & 1) == 0) { + do { + qq = q & 15; + x += lnz[qq]; + q >>= 4; + } while (qq == 0); + } + return x; +} + + +/* End: bn_mp_cnt_lsb.c */ + +/* Start: bn_mp_copy.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* copy, b = a */ +int +mp_copy (mp_int * a, mp_int * b) +{ + int res, n; + + /* if dst == src do nothing */ + if (a == b) { + return MP_OKAY; + } + + /* grow dest */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + /* zero b and copy the parameters over */ + { + register mp_digit *tmpa, *tmpb; + + /* pointer aliases */ + + /* source */ + tmpa = a->dp; + + /* destination */ + tmpb = b->dp; + + /* copy all the digits */ + for (n = 0; n < a->used; n++) { + *tmpb++ = *tmpa++; + } + + /* clear high digits */ + for (; n < b->used; n++) { + *tmpb++ = 0; + } + } + + /* copy used count and sign */ + b->used = a->used; + b->sign = a->sign; + return MP_OKAY; +} + +/* End: bn_mp_copy.c */ + +/* Start: bn_mp_count_bits.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* returns the number of bits in an int */ +int +mp_count_bits (mp_int * a) +{ + int r; + mp_digit q; + + /* shortcut */ + if (a->used == 0) { + return 0; + } + + /* get number of digits and add that */ + r = (a->used - 1) * DIGIT_BIT; + + /* take the last digit and count the bits in it */ + q = a->dp[a->used - 1]; + while (q > ((mp_digit) 0)) { + ++r; + q >>= ((mp_digit) 1); + } + return r; +} + +/* End: bn_mp_count_bits.c */ + +/* Start: bn_mp_div.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* integer signed division. + * c*b + d == a [e.g. a/b, c=quotient, d=remainder] + * HAC pp.598 Algorithm 14.20 + * + * Note that the description in HAC is horribly + * incomplete. For example, it doesn't consider + * the case where digits are removed from 'x' in + * the inner loop. It also doesn't consider the + * case that y has fewer than three digits, etc.. + * + * The overall algorithm is as described as + * 14.20 from HAC but fixed to treat these cases. +*/ +int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int q, x, y, t1, t2; + int res, n, t, i, norm, neg; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { + return res; + } + q.used = a->used + 2; + + if ((res = mp_init (&t1)) != MP_OKAY) { + goto __Q; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto __T1; + } + + if ((res = mp_init_copy (&x, a)) != MP_OKAY) { + goto __T2; + } + + if ((res = mp_init_copy (&y, b)) != MP_OKAY) { + goto __X; + } + + /* fix the sign */ + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + x.sign = y.sign = MP_ZPOS; + + /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ + norm = mp_count_bits(&y) % DIGIT_BIT; + if (norm < (int)(DIGIT_BIT-1)) { + norm = (DIGIT_BIT-1) - norm; + if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { + goto __Y; + } + if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { + goto __Y; + } + } else { + norm = 0; + } + + /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ + n = x.used - 1; + t = y.used - 1; + + /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ + if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ + goto __Y; + } + + while (mp_cmp (&x, &y) != MP_LT) { + ++(q.dp[n - t]); + if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { + goto __Y; + } + } + + /* reset y by shifting it back down */ + mp_rshd (&y, n - t); + + /* step 3. for i from n down to (t + 1) */ + for (i = n; i >= (t + 1); i--) { + if (i > x.used) { + continue; + } + + /* step 3.1 if xi == yt then set q{i-t-1} to b-1, + * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ + if (x.dp[i] == y.dp[t]) { + q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); + } else { + mp_word tmp; + tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); + tmp |= ((mp_word) x.dp[i - 1]); + tmp /= ((mp_word) y.dp[t]); + if (tmp > (mp_word) MP_MASK) + tmp = MP_MASK; + q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); + } + + /* while (q{i-t-1} * (yt * b + y{t-1})) > + xi * b**2 + xi-1 * b + xi-2 + + do q{i-t-1} -= 1; + */ + q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; + do { + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; + + /* find left hand */ + mp_zero (&t1); + t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; + t1.dp[1] = y.dp[t]; + t1.used = 2; + if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto __Y; + } + + /* find right hand */ + t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; + t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; + t2.dp[2] = x.dp[i]; + t2.used = 3; + } while (mp_cmp_mag(&t1, &t2) == MP_GT); + + /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ + if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto __Y; + } + + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto __Y; + } + + if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { + goto __Y; + } + + /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ + if (x.sign == MP_NEG) { + if ((res = mp_copy (&y, &t1)) != MP_OKAY) { + goto __Y; + } + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto __Y; + } + if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { + goto __Y; + } + + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; + } + } + + /* now q is the quotient and x is the remainder + * [which we have to normalize] + */ + + /* get sign before writing to c */ + x.sign = a->sign; + + if (c != NULL) { + mp_clamp (&q); + mp_exch (&q, c); + c->sign = neg; + } + + if (d != NULL) { + mp_div_2d (&x, norm, &x, NULL); + mp_exch (&x, d); + } + + res = MP_OKAY; + +__Y:mp_clear (&y); +__X:mp_clear (&x); +__T2:mp_clear (&t2); +__T1:mp_clear (&t1); +__Q:mp_clear (&q); + return res; +} + +/* End: bn_mp_div.c */ + +/* Start: bn_mp_div_2.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* b = a/2 */ +int mp_div_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* copy */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* source alias */ + tmpa = a->dp + b->used - 1; + + /* dest alias */ + tmpb = b->dp + b->used - 1; + + /* carry */ + r = 0; + for (x = b->used - 1; x >= 0; x--) { + /* get the carry for the next iteration */ + rr = *tmpa & 1; + + /* shift the current digit, add in carry and store */ + *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); + + /* forward carry to next iteration */ + r = rr; + } + + /* zero excess digits */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + mp_clamp (b); + return MP_OKAY; +} + +/* End: bn_mp_div_2.c */ + +/* Start: bn_mp_div_2d.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* shift right by a certain bit count (store quotient in c, optional remainder in d) */ +int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) +{ + mp_digit D, r, rr; + int x, res; + mp_int t; + + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + res = mp_copy (a, c); + if (d != NULL) { + mp_zero (d); + } + return res; + } + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + /* get the remainder */ + if (d != NULL) { + if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + mp_rshd (c, b / DIGIT_BIT); + } + + /* shift any bit count < DIGIT_BIT */ + D = (mp_digit) (b % DIGIT_BIT); + if (D != 0) { + register mp_digit *tmpc, mask, shift; + + /* mask */ + mask = (((mp_digit)1) << D) - 1; + + /* shift for lsb */ + shift = DIGIT_BIT - D; + + /* alias */ + tmpc = c->dp + (c->used - 1); + + /* carry */ + r = 0; + for (x = c->used - 1; x >= 0; x--) { + /* get the lower bits of this word in a temp */ + rr = *tmpc & mask; + + /* shift the current word and mix in the carry bits from the previous word */ + *tmpc = (*tmpc >> D) | (r << shift); + --tmpc; + + /* set the carry to the carry bits of the current word found above */ + r = rr; + } + } + mp_clamp (c); + if (d != NULL) { + mp_exch (&t, d); + } + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_div_2d.c */ + +/* Start: bn_mp_div_3.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* divide by three (based on routine from MPI and the GMP manual) */ +int +mp_div_3 (mp_int * a, mp_int *c, mp_digit * d) +{ + mp_int q; + mp_word w, t; + mp_digit b; + int res, ix; + + /* b = 2**DIGIT_BIT / 3 */ + b = (((mp_word)1) << ((mp_word)DIGIT_BIT)) / ((mp_word)3); + + if ((res = mp_init_size(&q, a->used)) != MP_OKAY) { + return res; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]); + + if (w >= 3) { + /* multiply w by [1/3] */ + t = (w * ((mp_word)b)) >> ((mp_word)DIGIT_BIT); + + /* now subtract 3 * [w/3] from w, to get the remainder */ + w -= t+t+t; + + /* fixup the remainder as required since + * the optimization is not exact. + */ + while (w >= 3) { + t += 1; + w -= 3; + } + } else { + t = 0; + } + q.dp[ix] = (mp_digit)t; + } + + /* [optional] store the remainder */ + if (d != NULL) { + *d = (mp_digit)w; + } + + /* [optional] store the quotient */ + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return res; +} + + +/* End: bn_mp_div_3.c */ + +/* Start: bn_mp_div_d.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +static int s_is_power_of_two(mp_digit b, int *p) +{ + int x; + + for (x = 1; x < DIGIT_BIT; x++) { + if (b == (((mp_digit)1)<dp[0] & ((1<used)) != MP_OKAY) { + return res; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]); + + if (w >= b) { + t = (mp_digit)(w / b); + w -= ((mp_word)t) * ((mp_word)b); + } else { + t = 0; + } + q.dp[ix] = (mp_digit)t; + } + + if (d != NULL) { + *d = (mp_digit)w; + } + + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return res; +} + + +/* End: bn_mp_div_d.c */ + +/* Start: bn_mp_dr_is_modulus.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines if a number is a valid DR modulus */ +int mp_dr_is_modulus(mp_int *a) +{ + int ix; + + /* must be at least two digits */ + if (a->used < 2) { + return 0; + } + + /* must be of the form b**k - a [a <= b] so all + * but the first digit must be equal to -1 (mod b). + */ + for (ix = 1; ix < a->used; ix++) { + if (a->dp[ix] != MP_MASK) { + return 0; + } + } + return 1; +} + + +/* End: bn_mp_dr_is_modulus.c */ + +/* Start: bn_mp_dr_reduce.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* reduce "x" in place modulo "n" using the Diminished Radix algorithm. + * + * Based on algorithm from the paper + * + * "Generating Efficient Primes for Discrete Log Cryptosystems" + * Chae Hoon Lim, Pil Loong Lee, + * POSTECH Information Research Laboratories + * + * The modulus must be of a special format [see manual] + * + * Has been modified to use algorithm 7.10 from the LTM book instead + * + * Input x must be in the range 0 <= x <= (n-1)**2 + */ +int +mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k) +{ + int err, i, m; + mp_word r; + mp_digit mu, *tmpx1, *tmpx2; + + /* m = digits in modulus */ + m = n->used; + + /* ensure that "x" has at least 2m digits */ + if (x->alloc < m + m) { + if ((err = mp_grow (x, m + m)) != MP_OKAY) { + return err; + } + } + +/* top of loop, this is where the code resumes if + * another reduction pass is required. + */ +top: + /* aliases for digits */ + /* alias for lower half of x */ + tmpx1 = x->dp; + + /* alias for upper half of x, or x/B**m */ + tmpx2 = x->dp + m; + + /* set carry to zero */ + mu = 0; + + /* compute (x mod B**m) + k * [x/B**m] inline and inplace */ + for (i = 0; i < m; i++) { + r = ((mp_word)*tmpx2++) * ((mp_word)k) + *tmpx1 + mu; + *tmpx1++ = (mp_digit)(r & MP_MASK); + mu = (mp_digit)(r >> ((mp_word)DIGIT_BIT)); + } + + /* set final carry */ + *tmpx1++ = mu; + + /* zero words above m */ + for (i = m + 1; i < x->used; i++) { + *tmpx1++ = 0; + } + + /* clamp, sub and return */ + mp_clamp (x); + + /* if x >= n then subtract and reduce again + * Each successive "recursion" makes the input smaller and smaller. + */ + if (mp_cmp_mag (x, n) != MP_LT) { + s_mp_sub(x, n, x); + goto top; + } + return MP_OKAY; +} + +/* End: bn_mp_dr_reduce.c */ + +/* Start: bn_mp_dr_setup.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines the setup value */ +void mp_dr_setup(mp_int *a, mp_digit *d) +{ + /* the casts are required if DIGIT_BIT is one less than + * the number of bits in a mp_digit [e.g. DIGIT_BIT==31] + */ + *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) - + ((mp_word)a->dp[0])); +} + + +/* End: bn_mp_dr_setup.c */ + +/* Start: bn_mp_exch.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* swap the elements of two integers, for cases where you can't simply swap the + * mp_int pointers around + */ +void +mp_exch (mp_int * a, mp_int * b) +{ + mp_int t; + + t = *a; + *a = *b; + *b = t; +} + +/* End: bn_mp_exch.c */ + +/* Start: bn_mp_expt_d.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* calculate c = a**b using a square-multiply algorithm */ +int mp_expt_d (mp_int * a, mp_digit b, mp_int * c) +{ + int res, x; + mp_int g; + + if ((res = mp_init_copy (&g, a)) != MP_OKAY) { + return res; + } + + /* set initial result */ + mp_set (c, 1); + + for (x = 0; x < (int) DIGIT_BIT; x++) { + /* square */ + if ((res = mp_sqr (c, c)) != MP_OKAY) { + mp_clear (&g); + return res; + } + + /* if the bit is set multiply */ + if ((b & (mp_digit) (((mp_digit)1) << (DIGIT_BIT - 1))) != 0) { + if ((res = mp_mul (c, &g, c)) != MP_OKAY) { + mp_clear (&g); + return res; + } + } + + /* shift to next bit */ + b <<= 1; + } + + mp_clear (&g); + return MP_OKAY; +} + +/* End: bn_mp_expt_d.c */ + +/* Start: bn_mp_exptmod.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + + +/* this is a shell function that calls either the normal or Montgomery + * exptmod functions. Originally the call to the montgomery code was + * embedded in the normal function but that wasted alot of stack space + * for nothing (since 99% of the time the Montgomery code would be called) + */ +int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + int dr; + + /* modulus P must be positive */ + if (P->sign == MP_NEG) { + return MP_VAL; + } + + /* if exponent X is negative we have to recurse */ + if (X->sign == MP_NEG) { + mp_int tmpG, tmpX; + int err; + + /* first compute 1/G mod P */ + if ((err = mp_init(&tmpG)) != MP_OKAY) { + return err; + } + if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + + /* now get |X| */ + if ((err = mp_init(&tmpX)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* and now compute (1/G)**|X| instead of G**X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* is it a DR modulus? */ + dr = mp_dr_is_modulus(P); + + /* if not, is it a uDR modulus? */ + if (dr == 0) { + dr = mp_reduce_is_2k(P) << 1; + } + + /* if the modulus is odd or dr != 0 use the fast method */ + if (mp_isodd (P) == 1 || dr != 0) { + return mp_exptmod_fast (G, X, P, Y, dr); + } else { + /* otherwise use the generic Barrett reduction technique */ + return s_mp_exptmod (G, X, P, Y); + } +} + + +/* End: bn_mp_exptmod.c */ + +/* Start: bn_mp_exptmod_fast.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85 + * + * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. + * The value of k changes based on the size of the exponent. + * + * Uses Montgomery or Diminished Radix reduction [whichever appropriate] + */ + +#ifdef MP_LOW_MEM + #define TAB_SIZE 32 +#else + #define TAB_SIZE 256 +#endif + +int +mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res; + mp_digit buf, mp; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* use a pointer to the reduction algorithm. This allows us to use + * one of many reduction algorithms without modding the guts of + * the code with if statements everywhere. + */ + int (*redux)(mp_int*,mp_int*,mp_digit); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* determine and setup reduction code */ + if (redmode == 0) { + /* now setup montgomery */ + if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { + goto __M; + } + + /* automatically pick the comba one if available (saves quite a few calls/ifs) */ + if (((P->used * 2 + 1) < MP_WARRAY) && + P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + redux = fast_mp_montgomery_reduce; + } else { + /* use slower baseline Montgomery method */ + redux = mp_montgomery_reduce; + } + } else if (redmode == 1) { + /* setup DR reduction for moduli of the form B**k - b */ + mp_dr_setup(P, &mp); + redux = mp_dr_reduce; + } else { + /* setup DR reduction for moduli of the form 2**k - b */ + if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { + goto __M; + } + redux = mp_reduce_2k; + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto __M; + } + + /* create M table + * + * The M table contains powers of the input base, e.g. M[x] = G^x mod P + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + + if (redmode == 0) { + /* now we need R mod m */ + if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { + goto __RES; + } + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { + goto __RES; + } + } else { + mp_set(&res, 1); + if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { + goto __RES; + } + } + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __RES; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&M[x], P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits so break */ + if (digidx == -1) { + break; + } + /* read next digit and reset bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int)DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + + /* get next bit of the window */ + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + } + } + } + + if (redmode == 0) { + /* fixup result if Montgomery reduction is used + * recall that any value in a Montgomery system is + * actually multiplied by R mod n. So we have + * to reduce one more time to cancel out the factor + * of R. + */ + if ((err = mp_montgomery_reduce (&res, P, mp)) != MP_OKAY) { + goto __RES; + } + } + + /* swap res with Y */ + mp_exch (&res, Y); + err = MP_OKAY; +__RES:mp_clear (&res); +__M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + +/* End: bn_mp_exptmod_fast.c */ + +/* Start: bn_mp_exteuclid.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* Extended euclidean algorithm of (a, b) produces + a*u1 + b*u2 = u3 + */ +int mp_exteuclid(mp_int *a, mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3) +{ + mp_int u1,u2,u3,v1,v2,v3,t1,t2,t3,q,tmp; + int err; + + if ((err = mp_init_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL)) != MP_OKAY) { + return err; + } + + /* initialize, (u1,u2,u3) = (1,0,a) */ + mp_set(&u1, 1); + if ((err = mp_copy(a, &u3)) != MP_OKAY) { goto _ERR; } + + /* initialize, (v1,v2,v3) = (0,1,b) */ + mp_set(&v2, 1); + if ((err = mp_copy(b, &v3)) != MP_OKAY) { goto _ERR; } + + /* loop while v3 != 0 */ + while (mp_iszero(&v3) == MP_NO) { + /* q = u3/v3 */ + if ((err = mp_div(&u3, &v3, &q, NULL)) != MP_OKAY) { goto _ERR; } + + /* (t1,t2,t3) = (u1,u2,u3) - (v1,v2,v3)q */ + if ((err = mp_mul(&v1, &q, &tmp)) != MP_OKAY) { goto _ERR; } + if ((err = mp_sub(&u1, &tmp, &t1)) != MP_OKAY) { goto _ERR; } + if ((err = mp_mul(&v2, &q, &tmp)) != MP_OKAY) { goto _ERR; } + if ((err = mp_sub(&u2, &tmp, &t2)) != MP_OKAY) { goto _ERR; } + if ((err = mp_mul(&v3, &q, &tmp)) != MP_OKAY) { goto _ERR; } + if ((err = mp_sub(&u3, &tmp, &t3)) != MP_OKAY) { goto _ERR; } + + /* (u1,u2,u3) = (v1,v2,v3) */ + if ((err = mp_copy(&v1, &u1)) != MP_OKAY) { goto _ERR; } + if ((err = mp_copy(&v2, &u2)) != MP_OKAY) { goto _ERR; } + if ((err = mp_copy(&v3, &u3)) != MP_OKAY) { goto _ERR; } + + /* (v1,v2,v3) = (t1,t2,t3) */ + if ((err = mp_copy(&t1, &v1)) != MP_OKAY) { goto _ERR; } + if ((err = mp_copy(&t2, &v2)) != MP_OKAY) { goto _ERR; } + if ((err = mp_copy(&t3, &v3)) != MP_OKAY) { goto _ERR; } + } + + /* copy result out */ + if (U1 != NULL) { mp_exch(U1, &u1); } + if (U2 != NULL) { mp_exch(U2, &u2); } + if (U3 != NULL) { mp_exch(U3, &u3); } + + err = MP_OKAY; +_ERR: mp_clear_multi(&u1, &u2, &u3, &v1, &v2, &v3, &t1, &t2, &t3, &q, &tmp, NULL); + return err; +} + +/* End: bn_mp_exteuclid.c */ + +/* Start: bn_mp_fread.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* read a bigint from a file stream in ASCII */ +int mp_fread(mp_int *a, int radix, FILE *stream) +{ + int err, ch, neg, y; + + /* clear a */ + mp_zero(a); + + /* if first digit is - then set negative */ + ch = fgetc(stream); + if (ch == '-') { + neg = MP_NEG; + ch = fgetc(stream); + } else { + neg = MP_ZPOS; + } + + for (;;) { + /* find y in the radix map */ + for (y = 0; y < radix; y++) { + if (mp_s_rmap[y] == ch) { + break; + } + } + if (y == radix) { + break; + } + + /* shift up and add */ + if ((err = mp_mul_d(a, radix, a)) != MP_OKAY) { + return err; + } + if ((err = mp_add_d(a, y, a)) != MP_OKAY) { + return err; + } + + ch = fgetc(stream); + } + if (mp_cmp_d(a, 0) != MP_EQ) { + a->sign = neg; + } + + return MP_OKAY; +} + + +/* End: bn_mp_fread.c */ + +/* Start: bn_mp_fwrite.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +int mp_fwrite(mp_int *a, int radix, FILE *stream) +{ + char *buf; + int err, len, x; + + if ((err = mp_radix_size(a, radix, &len)) != MP_OKAY) { + return err; + } + + buf = OPT_CAST(char) XMALLOC (len); + if (buf == NULL) { + return MP_MEM; + } + + if ((err = mp_toradix(a, buf, radix)) != MP_OKAY) { + XFREE (buf); + return err; + } + + for (x = 0; x < len; x++) { + if (fputc(buf[x], stream) == EOF) { + XFREE (buf); + return MP_VAL; + } + } + + XFREE (buf); + return MP_OKAY; +} + + +/* End: bn_mp_fwrite.c */ + +/* Start: bn_mp_gcd.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* Greatest Common Divisor using the binary method */ +int mp_gcd (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int u, v; + int k, u_lsb, v_lsb, res; + + /* either zero than gcd is the largest */ + if (mp_iszero (a) == 1 && mp_iszero (b) == 0) { + return mp_abs (b, c); + } + if (mp_iszero (a) == 0 && mp_iszero (b) == 1) { + return mp_abs (a, c); + } + + /* optimized. At this point if a == 0 then + * b must equal zero too + */ + if (mp_iszero (a) == 1) { + mp_zero(c); + return MP_OKAY; + } + + /* get copies of a and b we can modify */ + if ((res = mp_init_copy (&u, a)) != MP_OKAY) { + return res; + } + + if ((res = mp_init_copy (&v, b)) != MP_OKAY) { + goto __U; + } + + /* must be positive for the remainder of the algorithm */ + u.sign = v.sign = MP_ZPOS; + + /* B1. Find the common power of two for u and v */ + u_lsb = mp_cnt_lsb(&u); + v_lsb = mp_cnt_lsb(&v); + k = MIN(u_lsb, v_lsb); + + if (k > 0) { + /* divide the power of two out */ + if ((res = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) { + goto __V; + } + + if ((res = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) { + goto __V; + } + } + + /* divide any remaining factors of two out */ + if (u_lsb != k) { + if ((res = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) { + goto __V; + } + } + + if (v_lsb != k) { + if ((res = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) { + goto __V; + } + } + + while (mp_iszero(&v) == 0) { + /* make sure v is the largest */ + if (mp_cmp_mag(&u, &v) == MP_GT) { + /* swap u and v to make sure v is >= u */ + mp_exch(&u, &v); + } + + /* subtract smallest from largest */ + if ((res = s_mp_sub(&v, &u, &v)) != MP_OKAY) { + goto __V; + } + + /* Divide out all factors of two */ + if ((res = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) { + goto __V; + } + } + + /* multiply by 2**k which we divided out at the beginning */ + if ((res = mp_mul_2d (&u, k, c)) != MP_OKAY) { + goto __V; + } + c->sign = MP_ZPOS; + res = MP_OKAY; +__V:mp_clear (&u); +__U:mp_clear (&v); + return res; +} + +/* End: bn_mp_gcd.c */ + +/* Start: bn_mp_get_int.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* get the lower 32-bits of an mp_int */ +unsigned long mp_get_int(mp_int * a) +{ + int i; + unsigned long res; + + if (a->used == 0) { + return 0; + } + + /* get number of digits of the lsb we have to read */ + i = MIN(a->used,(int)((sizeof(unsigned long)*CHAR_BIT+DIGIT_BIT-1)/DIGIT_BIT))-1; + + /* get most significant digit of result */ + res = DIGIT(a,i); + + while (--i >= 0) { + res = (res << DIGIT_BIT) | DIGIT(a,i); + } + + /* force result to 32-bits always so it is consistent on non 32-bit platforms */ + return res & 0xFFFFFFFFUL; +} + +/* End: bn_mp_get_int.c */ + +/* Start: bn_mp_grow.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* grow as required */ +int mp_grow (mp_int * a, int size) +{ + int i; + mp_digit *tmp; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* ensure there are always at least MP_PREC digits extra on top */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* reallocate the array a->dp + * + * We store the return in a temporary variable + * in case the operation failed we don't want + * to overwrite the dp member of a. + */ + tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size); + if (tmp == NULL) { + /* reallocation failed but "a" is still valid [can be freed] */ + return MP_MEM; + } + + /* reallocation succeeded so set a->dp */ + a->dp = tmp; + + /* zero excess digits */ + i = a->alloc; + a->alloc = size; + for (; i < a->alloc; i++) { + a->dp[i] = 0; + } + } + return MP_OKAY; +} + +/* End: bn_mp_grow.c */ + +/* Start: bn_mp_init.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* init a new bigint */ +int mp_init (mp_int * a) +{ + /* allocate memory required and clear it */ + a->dp = OPT_CAST(mp_digit) XCALLOC (sizeof (mp_digit), MP_PREC); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the used to zero, allocated digits to the default precision + * and sign to positive */ + a->used = 0; + a->alloc = MP_PREC; + a->sign = MP_ZPOS; + + return MP_OKAY; +} + +/* End: bn_mp_init.c */ + +/* Start: bn_mp_init_copy.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* creates "a" then copies b into it */ +int mp_init_copy (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_init (a)) != MP_OKAY) { + return res; + } + return mp_copy (b, a); +} + +/* End: bn_mp_init_copy.c */ + +/* Start: bn_mp_init_multi.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include +#include + +int 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; + + /* end the current list */ + va_end(args); + + /* now start cleaning up */ + 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. */ +} + + +/* End: bn_mp_init_multi.c */ + +/* Start: bn_mp_init_set.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* initialize and set a digit */ +int mp_init_set (mp_int * a, mp_digit b) +{ + int err; + if ((err = mp_init(a)) != MP_OKAY) { + return err; + } + mp_set(a, b); + return err; +} + +/* End: bn_mp_init_set.c */ + +/* Start: bn_mp_init_set_int.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* initialize and set a digit */ +int mp_init_set_int (mp_int * a, unsigned long b) +{ + int err; + if ((err = mp_init(a)) != MP_OKAY) { + return err; + } + return mp_set_int(a, b); +} + +/* End: bn_mp_init_set_int.c */ + +/* Start: bn_mp_init_size.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* init an mp_init for a given size */ +int mp_init_size (mp_int * a, int size) +{ + /* pad size so there are always extra digits */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* alloc mem */ + a->dp = OPT_CAST(mp_digit) XCALLOC (sizeof (mp_digit), size); + if (a->dp == NULL) { + return MP_MEM; + } + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + + return MP_OKAY; +} + +/* End: bn_mp_init_size.c */ + +/* Start: bn_mp_invmod.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* hac 14.61, pp608 */ +int mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, A, B, C, D; + int res; + + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + + /* if the modulus is odd we can use a faster routine instead */ + if (mp_isodd (b) == 1) { + return fast_mp_invmod (a, b, c); + } + + /* init temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, + &A, &B, &C, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x = a, y = b */ + if ((res = mp_copy (a, &x)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_copy (b, &y)) != MP_OKAY) { + goto __ERR; + } + + /* 2. [modified] if x,y are both even then return an error! */ + if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { + res = MP_VAL; + goto __ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto __ERR; + } + mp_set (&A, 1); + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto __ERR; + } + /* 4.2 if A or B is odd then */ + if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) { + /* A = (A+y)/2, B = (B-x)/2 */ + if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto __ERR; + } + } + /* A = A/2, B = B/2 */ + if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto __ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto __ERR; + } + /* 5.2 if C or D is odd then */ + if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto __ERR; + } + } + /* C = C/2, D = D/2 */ + if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { + goto __ERR; + } + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, A = A - C, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto __ERR; + } + } else { + /* v - v - u, C = C - A, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { + goto __ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto __ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) + goto top; + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto __ERR; + } + + /* if its too low */ + while (mp_cmp_d(&C, 0) == MP_LT) { + if ((res = mp_add(&C, b, &C)) != MP_OKAY) { + goto __ERR; + } + } + + /* too big */ + while (mp_cmp_mag(&C, b) != MP_LT) { + if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { + goto __ERR; + } + } + + /* C is now the inverse */ + mp_exch (&C, c); + res = MP_OKAY; +__ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); + return res; +} + +/* End: bn_mp_invmod.c */ + +/* Start: bn_mp_is_square.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* Check if remainders are possible squares - fast exclude non-squares */ +static const char rem_128[128] = { + 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 +}; + +static const char rem_105[105] = { + 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1 +}; + +/* Store non-zero to ret if arg is square, and zero if not */ +int mp_is_square(mp_int *arg,int *ret) +{ + int res; + mp_digit c; + mp_int t; + unsigned long r; + + /* Default to Non-square :) */ + *ret = MP_NO; + + if (arg->sign == MP_NEG) { + return MP_VAL; + } + + /* digits used? (TSD) */ + if (arg->used == 0) { + return MP_OKAY; + } + + /* First check mod 128 (suppose that DIGIT_BIT is at least 7) */ + if (rem_128[127 & DIGIT(arg,0)] == 1) { + return MP_OKAY; + } + + /* Next check mod 105 (3*5*7) */ + if ((res = mp_mod_d(arg,105,&c)) != MP_OKAY) { + return res; + } + if (rem_105[c] == 1) { + return MP_OKAY; + } + + /* product of primes less than 2^31 */ + if ((res = mp_init_set_int(&t,11L*13L*17L*19L*23L*29L*31L)) != MP_OKAY) { + return res; + } + if ((res = mp_mod(arg,&t,&t)) != MP_OKAY) { + goto ERR; + } + r = mp_get_int(&t); + /* Check for other prime modules, note it's not an ERROR but we must + * free "t" so the easiest way is to goto ERR. We know that res + * is already equal to MP_OKAY from the mp_mod call + */ + if ( (1L<<(r%11)) & 0x5C4L ) goto ERR; + if ( (1L<<(r%13)) & 0x9E4L ) goto ERR; + if ( (1L<<(r%17)) & 0x5CE8L ) goto ERR; + if ( (1L<<(r%19)) & 0x4F50CL ) goto ERR; + if ( (1L<<(r%23)) & 0x7ACCA0L ) goto ERR; + if ( (1L<<(r%29)) & 0xC2EDD0CL ) goto ERR; + if ( (1L<<(r%31)) & 0x6DE2B848L ) goto ERR; + + /* Final check - is sqr(sqrt(arg)) == arg ? */ + if ((res = mp_sqrt(arg,&t)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sqr(&t,&t)) != MP_OKAY) { + goto ERR; + } + + *ret = (mp_cmp_mag(&t,arg) == MP_EQ) ? MP_YES : MP_NO; +ERR:mp_clear(&t); + return res; +} + +/* End: bn_mp_is_square.c */ + +/* Start: bn_mp_jacobi.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes the jacobi c = (a | n) (or Legendre if n is prime) + * HAC pp. 73 Algorithm 2.149 + */ +int mp_jacobi (mp_int * a, mp_int * p, int *c) +{ + mp_int a1, p1; + int k, s, r, res; + mp_digit residue; + + /* if p <= 0 return MP_VAL */ + if (mp_cmp_d(p, 0) != MP_GT) { + return MP_VAL; + } + + /* step 1. if a == 0, return 0 */ + if (mp_iszero (a) == 1) { + *c = 0; + return MP_OKAY; + } + + /* step 2. if a == 1, return 1 */ + if (mp_cmp_d (a, 1) == MP_EQ) { + *c = 1; + return MP_OKAY; + } + + /* default */ + s = 0; + + /* step 3. write a = a1 * 2**k */ + if ((res = mp_init_copy (&a1, a)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&p1)) != MP_OKAY) { + goto __A1; + } + + /* divide out larger power of two */ + k = mp_cnt_lsb(&a1); + if ((res = mp_div_2d(&a1, k, &a1, NULL)) != MP_OKAY) { + goto __P1; + } + + /* step 4. if e is even set s=1 */ + if ((k & 1) == 0) { + s = 1; + } else { + /* else set s=1 if p = 1/7 (mod 8) or s=-1 if p = 3/5 (mod 8) */ + residue = p->dp[0] & 7; + + if (residue == 1 || residue == 7) { + s = 1; + } else if (residue == 3 || residue == 5) { + s = -1; + } + } + + /* step 5. if p == 3 (mod 4) *and* a1 == 3 (mod 4) then s = -s */ + if ( ((p->dp[0] & 3) == 3) && ((a1.dp[0] & 3) == 3)) { + s = -s; + } + + /* if a1 == 1 we're done */ + if (mp_cmp_d (&a1, 1) == MP_EQ) { + *c = s; + } else { + /* n1 = n mod a1 */ + if ((res = mp_mod (p, &a1, &p1)) != MP_OKAY) { + goto __P1; + } + if ((res = mp_jacobi (&p1, &a1, &r)) != MP_OKAY) { + goto __P1; + } + *c = s * r; + } + + /* done */ + res = MP_OKAY; +__P1:mp_clear (&p1); +__A1:mp_clear (&a1); + return res; +} + +/* End: bn_mp_jacobi.c */ + +/* Start: bn_mp_karatsuba_mul.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* c = |a| * |b| using Karatsuba Multiplication using + * three half size multiplications + * + * Let B represent the radix [e.g. 2**DIGIT_BIT] and + * let n represent half of the number of digits in + * the min(a,b) + * + * a = a1 * B**n + a0 + * b = b1 * B**n + b0 + * + * Then, a * b => + a1b1 * B**2n + ((a1 - a0)(b1 - b0) + a0b0 + a1b1) * B + a0b0 + * + * Note that a1b1 and a0b0 are used twice and only need to be + * computed once. So in total three half size (half # of + * digit) multiplications are performed, a0b0, a1b1 and + * (a1-b1)(a0-b0) + * + * Note that a multiplication of half the digits requires + * 1/4th the number of single precision multiplications so in + * total after one call 25% of the single precision multiplications + * are saved. Note also that the call to mp_mul can end up back + * in this function if the a0, a1, b0, or b1 are above the threshold. + * This is known as divide-and-conquer and leads to the famous + * O(N**lg(3)) or O(N**1.584) work which is asymptopically lower than + * the standard O(N**2) that the baseline/comba methods use. + * Generally though the overhead of this method doesn't pay off + * until a certain size (N ~ 80) is reached. + */ +int mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x0, x1, y0, y1, t1, x0y0, x1y1; + int B, err; + + /* default the return code to an error */ + err = MP_MEM; + + /* min # of digits */ + B = MIN (a->used, b->used); + + /* now divide in two */ + B = B >> 1; + + /* init copy all the temps */ + if (mp_init_size (&x0, B) != MP_OKAY) + goto ERR; + if (mp_init_size (&x1, a->used - B) != MP_OKAY) + goto X0; + if (mp_init_size (&y0, B) != MP_OKAY) + goto X1; + if (mp_init_size (&y1, b->used - B) != MP_OKAY) + goto Y0; + + /* init temps */ + if (mp_init_size (&t1, B * 2) != MP_OKAY) + goto Y1; + if (mp_init_size (&x0y0, B * 2) != MP_OKAY) + goto T1; + if (mp_init_size (&x1y1, B * 2) != MP_OKAY) + goto X0Y0; + + /* now shift the digits */ + x0.sign = x1.sign = a->sign; + y0.sign = y1.sign = b->sign; + + x0.used = y0.used = B; + x1.used = a->used - B; + y1.used = b->used - B; + + { + register int x; + register mp_digit *tmpa, *tmpb, *tmpx, *tmpy; + + /* we copy the digits directly instead of using higher level functions + * since we also need to shift the digits + */ + tmpa = a->dp; + tmpb = b->dp; + + tmpx = x0.dp; + tmpy = y0.dp; + for (x = 0; x < B; x++) { + *tmpx++ = *tmpa++; + *tmpy++ = *tmpb++; + } + + tmpx = x1.dp; + for (x = B; x < a->used; x++) { + *tmpx++ = *tmpa++; + } + + tmpy = y1.dp; + for (x = B; x < b->used; x++) { + *tmpy++ = *tmpb++; + } + } + + /* only need to clamp the lower words since by definition the + * upper words x1/y1 must have a known number of digits + */ + mp_clamp (&x0); + mp_clamp (&y0); + + /* now calc the products x0y0 and x1y1 */ + /* after this x0 is no longer required, free temp [x0==t2]! */ + if (mp_mul (&x0, &y0, &x0y0) != MP_OKAY) + goto X1Y1; /* x0y0 = x0*y0 */ + if (mp_mul (&x1, &y1, &x1y1) != MP_OKAY) + goto X1Y1; /* x1y1 = x1*y1 */ + + /* now calc x1-x0 and y1-y0 */ + if (mp_sub (&x1, &x0, &t1) != MP_OKAY) + goto X1Y1; /* t1 = x1 - x0 */ + if (mp_sub (&y1, &y0, &x0) != MP_OKAY) + goto X1Y1; /* t2 = y1 - y0 */ + if (mp_mul (&t1, &x0, &t1) != MP_OKAY) + goto X1Y1; /* t1 = (x1 - x0) * (y1 - y0) */ + + /* add x0y0 */ + if (mp_add (&x0y0, &x1y1, &x0) != MP_OKAY) + goto X1Y1; /* t2 = x0y0 + x1y1 */ + if (mp_sub (&x0, &t1, &t1) != MP_OKAY) + goto X1Y1; /* t1 = x0y0 + x1y1 - (x1-x0)*(y1-y0) */ + + /* shift by B */ + if (mp_lshd (&t1, B) != MP_OKAY) + goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))< + +/* Karatsuba squaring, computes b = a*a using three + * half size squarings + * + * See comments of mp_karatsuba_mul for details. It + * is essentially the same algorithm but merely + * tuned to perform recursive squarings. + */ +int mp_karatsuba_sqr (mp_int * a, mp_int * b) +{ + mp_int x0, x1, t1, t2, x0x0, x1x1; + int B, err; + + err = MP_MEM; + + /* min # of digits */ + B = a->used; + + /* now divide in two */ + B = B >> 1; + + /* init copy all the temps */ + if (mp_init_size (&x0, B) != MP_OKAY) + goto ERR; + if (mp_init_size (&x1, a->used - B) != MP_OKAY) + goto X0; + + /* init temps */ + if (mp_init_size (&t1, a->used * 2) != MP_OKAY) + goto X1; + if (mp_init_size (&t2, a->used * 2) != MP_OKAY) + goto T1; + if (mp_init_size (&x0x0, B * 2) != MP_OKAY) + goto T2; + if (mp_init_size (&x1x1, (a->used - B) * 2) != MP_OKAY) + goto X0X0; + + { + register int x; + register mp_digit *dst, *src; + + src = a->dp; + + /* now shift the digits */ + dst = x0.dp; + for (x = 0; x < B; x++) { + *dst++ = *src++; + } + + dst = x1.dp; + for (x = B; x < a->used; x++) { + *dst++ = *src++; + } + } + + x0.used = B; + x1.used = a->used - B; + + mp_clamp (&x0); + + /* now calc the products x0*x0 and x1*x1 */ + if (mp_sqr (&x0, &x0x0) != MP_OKAY) + goto X1X1; /* x0x0 = x0*x0 */ + if (mp_sqr (&x1, &x1x1) != MP_OKAY) + goto X1X1; /* x1x1 = x1*x1 */ + + /* now calc (x1-x0)**2 */ + if (mp_sub (&x1, &x0, &t1) != MP_OKAY) + goto X1X1; /* t1 = x1 - x0 */ + if (mp_sqr (&t1, &t1) != MP_OKAY) + goto X1X1; /* t1 = (x1 - x0) * (x1 - x0) */ + + /* add x0y0 */ + if (s_mp_add (&x0x0, &x1x1, &t2) != MP_OKAY) + goto X1X1; /* t2 = x0x0 + x1x1 */ + if (mp_sub (&t2, &t1, &t1) != MP_OKAY) + goto X1X1; /* t1 = x0x0 + x1x1 - (x1-x0)*(x1-x0) */ + + /* shift by B */ + if (mp_lshd (&t1, B) != MP_OKAY) + goto X1X1; /* t1 = (x0x0 + x1x1 - (x1-x0)*(x1-x0))< + +/* computes least common multiple as |a*b|/(a, b) */ +int mp_lcm (mp_int * a, mp_int * b, mp_int * c) +{ + int res; + mp_int t1, t2; + + + if ((res = mp_init_multi (&t1, &t2, NULL)) != MP_OKAY) { + return res; + } + + /* t1 = get the GCD of the two inputs */ + if ((res = mp_gcd (a, b, &t1)) != MP_OKAY) { + goto __T; + } + + /* divide the smallest by the GCD */ + if (mp_cmp_mag(a, b) == MP_LT) { + /* store quotient in t2 such that t2 * b is the LCM */ + if ((res = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) { + goto __T; + } + res = mp_mul(b, &t2, c); + } else { + /* store quotient in t2 such that t2 * a is the LCM */ + if ((res = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) { + goto __T; + } + res = mp_mul(a, &t2, c); + } + + /* fix the sign to positive */ + c->sign = MP_ZPOS; + +__T: + mp_clear_multi (&t1, &t2, NULL); + return res; +} + +/* End: bn_mp_lcm.c */ + +/* Start: bn_mp_lshd.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* shift left a certain amount of digits */ +int mp_lshd (mp_int * a, int b) +{ + int x, res; + + /* if its less than zero return */ + if (b <= 0) { + return MP_OKAY; + } + + /* grow to fit the new digits */ + if (a->alloc < a->used + b) { + if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { + return res; + } + } + + { + register mp_digit *top, *bottom; + + /* increment the used by the shift amount then copy upwards */ + a->used += b; + + /* top */ + top = a->dp + a->used - 1; + + /* base */ + bottom = a->dp + a->used - 1 - b; + + /* much like mp_rshd this is implemented using a sliding window + * except the window goes the otherway around. Copying from + * the bottom to the top. see bn_mp_rshd.c for more info. + */ + for (x = a->used - 1; x >= b; x--) { + *top-- = *bottom--; + } + + /* zero the lower digits */ + top = a->dp; + for (x = 0; x < b; x++) { + *top++ = 0; + } + } + return MP_OKAY; +} + +/* End: bn_mp_lshd.c */ + +/* Start: bn_mp_mod.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* c = a mod b, 0 <= c < b */ +int +mp_mod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int t; + int res; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + if (t.sign != b->sign) { + res = mp_add (b, &t, c); + } else { + res = MP_OKAY; + mp_exch (&t, c); + } + + mp_clear (&t); + return res; +} + +/* End: bn_mp_mod.c */ + +/* Start: bn_mp_mod_2d.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* calc a value mod 2**b */ +int +mp_mod_2d (mp_int * a, int b, mp_int * c) +{ + int x, res; + + /* if b is <= 0 then zero the int */ + if (b <= 0) { + mp_zero (c); + return MP_OKAY; + } + + /* if the modulus is larger than the value than return */ + if (b > (int) (a->used * DIGIT_BIT)) { + res = mp_copy (a, c); + return res; + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + + /* zero digits above the last digit of the modulus */ + for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { + c->dp[x] = 0; + } + /* clear the digit that is not completely outside/inside the modulus */ + c->dp[b / DIGIT_BIT] &= + (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_mp_mod_2d.c */ + +/* Start: bn_mp_mod_d.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +int +mp_mod_d (mp_int * a, mp_digit b, mp_digit * c) +{ + return mp_div_d(a, b, NULL, c); +} + +/* End: bn_mp_mod_d.c */ + +/* Start: bn_mp_montgomery_calc_normalization.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* calculates a = B^n mod b for Montgomery reduction + * Where B is the base [e.g. 2^DIGIT_BIT]. + * B^n mod b is computed by first computing + * A = B^(n-1) which doesn't require a reduction but a simple OR. + * then C = A * B = B^n is computed by performing upto DIGIT_BIT + * shifts with subtractions when the result is greater than b. + * + * The method is slightly modified to shift B unconditionally upto just under + * the leading bit of b. This saves alot of multiple precision shifting. + */ +int +mp_montgomery_calc_normalization (mp_int * a, mp_int * b) +{ + int x, bits, res; + + /* how many bits of last digit does b use */ + bits = mp_count_bits (b) % DIGIT_BIT; + + /* compute A = B^(n-1) * 2^(bits-1) */ + if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { + return res; + } + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)DIGIT_BIT; x++) { + if ((res = mp_mul_2 (a, a)) != MP_OKAY) { + return res; + } + if (mp_cmp_mag (a, b) != MP_LT) { + if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { + return res; + } + } + } + + return MP_OKAY; +} + +/* End: bn_mp_montgomery_calc_normalization.c */ + +/* Start: bn_mp_montgomery_reduce.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes xR**-1 == x (mod N) via Montgomery Reduction */ +int +mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, digs; + mp_digit mu; + + /* can the fast reduction [comba] method be used? + * + * Note that unlike in mp_mul you're safely allowed *less* + * than the available columns [255 per default] since carries + * are fixed up in the inner loop. + */ + digs = n->used * 2 + 1; + if ((digs < MP_WARRAY) && + n->used < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_mp_montgomery_reduce (x, n, rho); + } + + /* grow the input as required */ + if (x->alloc < digs) { + if ((res = mp_grow (x, digs)) != MP_OKAY) { + return res; + } + } + x->used = digs; + + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * rho mod b + * + * The value of rho must be precalculated via + * bn_mp_montgomery_setup() such that + * it equals -1/n0 mod b this allows the + * following inner loop to reduce the + * input one digit at a time + */ + mu = (mp_digit) (((mp_word)x->dp[ix]) * ((mp_word)rho) & MP_MASK); + + /* a = a + mu * m * b**i */ + { + register int iy; + register mp_digit *tmpn, *tmpx, u; + register mp_word r; + + /* alias for digits of the modulus */ + tmpn = n->dp; + + /* alias for the digits of x [the input] */ + tmpx = x->dp + ix; + + /* set the carry to zero */ + u = 0; + + /* Multiply and add in place */ + for (iy = 0; iy < n->used; iy++) { + /* compute product and sum */ + r = ((mp_word)mu) * ((mp_word)*tmpn++) + + ((mp_word) u) + ((mp_word) * tmpx); + + /* get carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + + /* fix digit */ + *tmpx++ = (mp_digit)(r & ((mp_word) MP_MASK)); + } + /* At this point the ix'th digit of x should be zero */ + + + /* propagate carries upwards as required*/ + while (u) { + *tmpx += u; + u = *tmpx >> DIGIT_BIT; + *tmpx++ &= MP_MASK; + } + } + } + + /* at this point the n.used'th least + * significant digits of x are all zero + * which means we can shift x to the + * right by n.used digits and the + * residue is unchanged. + */ + + /* x = x/b**n.used */ + mp_clamp(x); + mp_rshd (x, n->used); + + /* if x >= n then x = x - n */ + if (mp_cmp_mag (x, n) != MP_LT) { + return s_mp_sub (x, n, x); + } + + return MP_OKAY; +} + +/* End: bn_mp_montgomery_reduce.c */ + +/* Start: bn_mp_montgomery_setup.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* setups the montgomery reduction stuff */ +int +mp_montgomery_setup (mp_int * n, mp_digit * rho) +{ + mp_digit x, b; + +/* fast inversion mod 2**k + * + * Based on the fact that + * + * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) + * => 2*X*A - X*X*A*A = 1 + * => 2*(1) - (1) = 1 + */ + b = n->dp[0]; + + if ((b & 1) == 0) { + return MP_VAL; + } + + x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ + x *= 2 - b * x; /* here x*a==1 mod 2**8 */ +#if !defined(MP_8BIT) + x *= 2 - b * x; /* here x*a==1 mod 2**16 */ +#endif +#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) + x *= 2 - b * x; /* here x*a==1 mod 2**32 */ +#endif +#ifdef MP_64BIT + x *= 2 - b * x; /* here x*a==1 mod 2**64 */ +#endif + + /* rho = -1/m mod b */ + *rho = (((mp_digit) 1 << ((mp_digit) DIGIT_BIT)) - x) & MP_MASK; + + return MP_OKAY; +} + +/* End: bn_mp_montgomery_setup.c */ + +/* Start: bn_mp_mul.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* high level multiplication (handles sign) */ +int mp_mul (mp_int * a, mp_int * b, mp_int * c) +{ + int res, neg; + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + + /* use Toom-Cook? */ + if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) { + res = mp_toom_mul(a, b, c); + /* use Karatsuba? */ + } else if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) { + res = mp_karatsuba_mul (a, b, c); + } else { + /* can we use the fast multiplier? + * + * The fast multiplier can be used if the output will + * have less than MP_WARRAY digits and the number of + * digits won't affect carry propagation + */ + int digs = a->used + b->used + 1; + + if ((digs < MP_WARRAY) && + MIN(a->used, b->used) <= + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + res = fast_s_mp_mul_digs (a, b, c, digs); + } else { + res = s_mp_mul (a, b, c); + } + } + c->sign = neg; + return res; +} + +/* End: bn_mp_mul.c */ + +/* Start: bn_mp_mul_2.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* b = a*2 */ +int mp_mul_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* grow to accomodate result */ + if (b->alloc < a->used + 1) { + if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* alias for source */ + tmpa = a->dp; + + /* alias for dest */ + tmpb = b->dp; + + /* carry */ + r = 0; + for (x = 0; x < a->used; x++) { + + /* get what will be the *next* carry bit from the + * MSB of the current digit + */ + rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0) { + /* add a MSB which is always 1 at this point */ + *tmpb = 1; + ++(b->used); + } + + /* now zero any excess digits on the destination + * that we didn't write to + */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + return MP_OKAY; +} + +/* End: bn_mp_mul_2.c */ + +/* Start: bn_mp_mul_2d.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* shift left by a certain bit count */ +int mp_mul_2d (mp_int * a, int b, mp_int * c) +{ + mp_digit d; + int res; + + /* copy */ + if (a != c) { + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + } + + if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) { + if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { + return res; + } + } + + /* shift any bit count < DIGIT_BIT */ + d = (mp_digit) (b % DIGIT_BIT); + if (d != 0) { + register mp_digit *tmpc, shift, mask, r, rr; + register int x; + + /* bitmask for carries */ + mask = (((mp_digit)1) << d) - 1; + + /* shift for msbs */ + shift = DIGIT_BIT - d; + + /* alias */ + tmpc = c->dp; + + /* carry */ + r = 0; + for (x = 0; x < c->used; x++) { + /* get the higher bits of the current word */ + rr = (*tmpc >> shift) & mask; + + /* shift the current word and OR in the carry */ + *tmpc = ((*tmpc << d) | r) & MP_MASK; + ++tmpc; + + /* set the carry to the carry bits of the current word */ + r = rr; + } + + /* set final carry */ + if (r != 0) { + c->dp[(c->used)++] = r; + } + } + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_mp_mul_2d.c */ + +/* Start: bn_mp_mul_d.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* multiply by a digit */ +int +mp_mul_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit u, *tmpa, *tmpc; + mp_word r; + int ix, res, olduse; + + /* make sure c is big enough to hold a*b */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* get the original destinations used count */ + olduse = c->used; + + /* set the sign */ + c->sign = a->sign; + + /* alias for a->dp [source] */ + tmpa = a->dp; + + /* alias for c->dp [dest] */ + tmpc = c->dp; + + /* zero carry */ + u = 0; + + /* compute columns */ + for (ix = 0; ix < a->used; ix++) { + /* compute product and carry sum for this term */ + r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b); + + /* mask off higher bits to get a single digit */ + *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* send carry into next iteration */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + + /* store final carry [if any] */ + *tmpc++ = u; + + /* now zero digits above the top */ + while (ix++ < olduse) { + *tmpc++ = 0; + } + + /* set used count */ + c->used = a->used + 1; + mp_clamp(c); + + return MP_OKAY; +} + +/* End: bn_mp_mul_d.c */ + +/* Start: bn_mp_mulmod.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* d = a * b (mod c) */ +int +mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_mul (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + +/* End: bn_mp_mulmod.c */ + +/* Start: bn_mp_n_root.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* find the n'th root of an integer + * + * Result found such that (c)**b <= a and (c+1)**b > a + * + * This algorithm uses Newton's approximation + * x[i+1] = x[i] - f(x[i])/f'(x[i]) + * which will find the root in log(N) time where + * each step involves a fair bit. This is not meant to + * find huge roots [square and cube, etc]. + */ +int mp_n_root (mp_int * a, mp_digit b, mp_int * c) +{ + mp_int t1, t2, t3; + int res, neg; + + /* input must be positive if b is even */ + if ((b & 1) == 0 && a->sign == MP_NEG) { + return MP_VAL; + } + + if ((res = mp_init (&t1)) != MP_OKAY) { + return res; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto __T1; + } + + if ((res = mp_init (&t3)) != MP_OKAY) { + goto __T2; + } + + /* if a is negative fudge the sign but keep track */ + neg = a->sign; + a->sign = MP_ZPOS; + + /* t2 = 2 */ + mp_set (&t2, 2); + + do { + /* t1 = t2 */ + if ((res = mp_copy (&t2, &t1)) != MP_OKAY) { + goto __T3; + } + + /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */ + + /* t3 = t1**(b-1) */ + if ((res = mp_expt_d (&t1, b - 1, &t3)) != MP_OKAY) { + goto __T3; + } + + /* numerator */ + /* t2 = t1**b */ + if ((res = mp_mul (&t3, &t1, &t2)) != MP_OKAY) { + goto __T3; + } + + /* t2 = t1**b - a */ + if ((res = mp_sub (&t2, a, &t2)) != MP_OKAY) { + goto __T3; + } + + /* denominator */ + /* t3 = t1**(b-1) * b */ + if ((res = mp_mul_d (&t3, b, &t3)) != MP_OKAY) { + goto __T3; + } + + /* t3 = (t1**b - a)/(b * t1**(b-1)) */ + if ((res = mp_div (&t2, &t3, &t3, NULL)) != MP_OKAY) { + goto __T3; + } + + if ((res = mp_sub (&t1, &t3, &t2)) != MP_OKAY) { + goto __T3; + } + } while (mp_cmp (&t1, &t2) != MP_EQ); + + /* result can be off by a few so check */ + for (;;) { + if ((res = mp_expt_d (&t1, b, &t2)) != MP_OKAY) { + goto __T3; + } + + if (mp_cmp (&t2, a) == MP_GT) { + if ((res = mp_sub_d (&t1, 1, &t1)) != MP_OKAY) { + goto __T3; + } + } else { + break; + } + } + + /* reset the sign of a first */ + a->sign = neg; + + /* set the result */ + mp_exch (&t1, c); + + /* set the sign of the result */ + c->sign = neg; + + res = MP_OKAY; + +__T3:mp_clear (&t3); +__T2:mp_clear (&t2); +__T1:mp_clear (&t1); + return res; +} + +/* End: bn_mp_n_root.c */ + +/* Start: bn_mp_neg.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* b = -a */ +int mp_neg (mp_int * a, mp_int * b) +{ + int res; + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + if (mp_iszero(b) != MP_YES) { + b->sign = (a->sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; + } + return MP_OKAY; +} + +/* End: bn_mp_neg.c */ + +/* Start: bn_mp_or.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* OR two ints together */ +int mp_or (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] |= x->dp[ix]; + } + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_or.c */ + +/* Start: bn_mp_prime_fermat.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* performs one Fermat test. + * + * If "a" were prime then b**a == b (mod a) since the order of + * the multiplicative sub-group would be phi(a) = a-1. That means + * it would be the same as b**(a mod (a-1)) == b**1 == b (mod a). + * + * Sets result to 1 if the congruence holds, or zero otherwise. + */ +int mp_prime_fermat (mp_int * a, mp_int * b, int *result) +{ + mp_int t; + int err; + + /* default to composite */ + *result = MP_NO; + + /* ensure b > 1 */ + if (mp_cmp_d(b, 1) != MP_GT) { + return MP_VAL; + } + + /* init t */ + if ((err = mp_init (&t)) != MP_OKAY) { + return err; + } + + /* compute t = b**a mod a */ + if ((err = mp_exptmod (b, a, a, &t)) != MP_OKAY) { + goto __T; + } + + /* is it equal to b? */ + if (mp_cmp (&t, b) == MP_EQ) { + *result = MP_YES; + } + + err = MP_OKAY; +__T:mp_clear (&t); + return err; +} + +/* End: bn_mp_prime_fermat.c */ + +/* Start: bn_mp_prime_is_divisible.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines if an integers is divisible by one + * of the first PRIME_SIZE primes or not + * + * sets result to 0 if not, 1 if yes + */ +int mp_prime_is_divisible (mp_int * a, int *result) +{ + int err, ix; + mp_digit res; + + /* default to not */ + *result = MP_NO; + + for (ix = 0; ix < PRIME_SIZE; ix++) { + /* what is a mod __prime_tab[ix] */ + if ((err = mp_mod_d (a, __prime_tab[ix], &res)) != MP_OKAY) { + return err; + } + + /* is the residue zero? */ + if (res == 0) { + *result = MP_YES; + return MP_OKAY; + } + } + + return MP_OKAY; +} + +/* End: bn_mp_prime_is_divisible.c */ + +/* Start: bn_mp_prime_is_prime.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* performs a variable number of rounds of Miller-Rabin + * + * Probability of error after t rounds is no more than + * (1/4)^t when 1 <= t <= PRIME_SIZE + * + * Sets result to 1 if probably prime, 0 otherwise + */ +int mp_prime_is_prime (mp_int * a, int t, int *result) +{ + mp_int b; + int ix, err, res; + + /* default to no */ + *result = MP_NO; + + /* valid value of t? */ + if (t <= 0 || t > PRIME_SIZE) { + return MP_VAL; + } + + /* is the input equal to one of the primes in the table? */ + for (ix = 0; ix < PRIME_SIZE; ix++) { + if (mp_cmp_d(a, __prime_tab[ix]) == MP_EQ) { + *result = 1; + return MP_OKAY; + } + } + + /* first perform trial division */ + if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) { + return err; + } + + /* return if it was trivially divisible */ + if (res == MP_YES) { + return MP_OKAY; + } + + /* now perform the miller-rabin rounds */ + if ((err = mp_init (&b)) != MP_OKAY) { + return err; + } + + for (ix = 0; ix < t; ix++) { + /* set the prime */ + mp_set (&b, __prime_tab[ix]); + + if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) { + goto __B; + } + + if (res == MP_NO) { + goto __B; + } + } + + /* passed the test */ + *result = MP_YES; +__B:mp_clear (&b); + return err; +} + +/* End: bn_mp_prime_is_prime.c */ + +/* Start: bn_mp_prime_miller_rabin.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* Miller-Rabin test of "a" to the base of "b" as described in + * HAC pp. 139 Algorithm 4.24 + * + * Sets result to 0 if definitely composite or 1 if probably prime. + * Randomly the chance of error is no more than 1/4 and often + * very much lower. + */ +int mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result) +{ + mp_int n1, y, r; + int s, j, err; + + /* default */ + *result = MP_NO; + + /* ensure b > 1 */ + if (mp_cmp_d(b, 1) != MP_GT) { + return MP_VAL; + } + + /* get n1 = a - 1 */ + if ((err = mp_init_copy (&n1, a)) != MP_OKAY) { + return err; + } + if ((err = mp_sub_d (&n1, 1, &n1)) != MP_OKAY) { + goto __N1; + } + + /* set 2**s * r = n1 */ + if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) { + goto __N1; + } + + /* count the number of least significant bits + * which are zero + */ + s = mp_cnt_lsb(&r); + + /* now divide n - 1 by 2**s */ + if ((err = mp_div_2d (&r, s, &r, NULL)) != MP_OKAY) { + goto __R; + } + + /* compute y = b**r mod a */ + if ((err = mp_init (&y)) != MP_OKAY) { + goto __R; + } + if ((err = mp_exptmod (b, &r, a, &y)) != MP_OKAY) { + goto __Y; + } + + /* if y != 1 and y != n1 do */ + if (mp_cmp_d (&y, 1) != MP_EQ && mp_cmp (&y, &n1) != MP_EQ) { + j = 1; + /* while j <= s-1 and y != n1 */ + while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) { + if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) { + goto __Y; + } + + /* if y == 1 then composite */ + if (mp_cmp_d (&y, 1) == MP_EQ) { + goto __Y; + } + + ++j; + } + + /* if y != n1 then composite */ + if (mp_cmp (&y, &n1) != MP_EQ) { + goto __Y; + } + } + + /* probably prime now */ + *result = MP_YES; +__Y:mp_clear (&y); +__R:mp_clear (&r); +__N1:mp_clear (&n1); + return err; +} + +/* End: bn_mp_prime_miller_rabin.c */ + +/* Start: bn_mp_prime_next_prime.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* finds the next prime after the number "a" using "t" trials + * of Miller-Rabin. + * + * bbs_style = 1 means the prime must be congruent to 3 mod 4 + */ +int mp_prime_next_prime(mp_int *a, int t, int bbs_style) +{ + int err, res, x, y; + mp_digit res_tab[PRIME_SIZE], step, kstep; + mp_int b; + + /* ensure t is valid */ + if (t <= 0 || t > PRIME_SIZE) { + return MP_VAL; + } + + /* force positive */ + a->sign = MP_ZPOS; + + /* simple algo if a is less than the largest prime in the table */ + if (mp_cmp_d(a, __prime_tab[PRIME_SIZE-1]) == MP_LT) { + /* find which prime it is bigger than */ + for (x = PRIME_SIZE - 2; x >= 0; x--) { + if (mp_cmp_d(a, __prime_tab[x]) != MP_LT) { + if (bbs_style == 1) { + /* ok we found a prime smaller or + * equal [so the next is larger] + * + * however, the prime must be + * congruent to 3 mod 4 + */ + if ((__prime_tab[x + 1] & 3) != 3) { + /* scan upwards for a prime congruent to 3 mod 4 */ + for (y = x + 1; y < PRIME_SIZE; y++) { + if ((__prime_tab[y] & 3) == 3) { + mp_set(a, __prime_tab[y]); + return MP_OKAY; + } + } + } + } else { + mp_set(a, __prime_tab[x + 1]); + return MP_OKAY; + } + } + } + /* at this point a maybe 1 */ + if (mp_cmp_d(a, 1) == MP_EQ) { + mp_set(a, 2); + return MP_OKAY; + } + /* fall through to the sieve */ + } + + /* generate a prime congruent to 3 mod 4 or 1/3 mod 4? */ + if (bbs_style == 1) { + kstep = 4; + } else { + kstep = 2; + } + + /* at this point we will use a combination of a sieve and Miller-Rabin */ + + if (bbs_style == 1) { + /* if a mod 4 != 3 subtract the correct value to make it so */ + if ((a->dp[0] & 3) != 3) { + if ((err = mp_sub_d(a, (a->dp[0] & 3) + 1, a)) != MP_OKAY) { return err; }; + } + } else { + if (mp_iseven(a) == 1) { + /* force odd */ + if ((err = mp_sub_d(a, 1, a)) != MP_OKAY) { + return err; + } + } + } + + /* generate the restable */ + for (x = 1; x < PRIME_SIZE; x++) { + if ((err = mp_mod_d(a, __prime_tab[x], res_tab + x)) != MP_OKAY) { + return err; + } + } + + /* init temp used for Miller-Rabin Testing */ + if ((err = mp_init(&b)) != MP_OKAY) { + return err; + } + + for (;;) { + /* skip to the next non-trivially divisible candidate */ + step = 0; + do { + /* y == 1 if any residue was zero [e.g. cannot be prime] */ + y = 0; + + /* increase step to next candidate */ + step += kstep; + + /* compute the new residue without using division */ + for (x = 1; x < PRIME_SIZE; x++) { + /* add the step to each residue */ + res_tab[x] += kstep; + + /* subtract the modulus [instead of using division] */ + if (res_tab[x] >= __prime_tab[x]) { + res_tab[x] -= __prime_tab[x]; + } + + /* set flag if zero */ + if (res_tab[x] == 0) { + y = 1; + } + } + } while (y == 1 && step < ((((mp_digit)1)<= ((((mp_digit)1)< + +/* makes a truly random prime of a given size (bits), + * + * Flags are as follows: + * + * LTM_PRIME_BBS - make prime congruent to 3 mod 4 + * LTM_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies LTM_PRIME_BBS) + * LTM_PRIME_2MSB_OFF - make the 2nd highest bit zero + * LTM_PRIME_2MSB_ON - make the 2nd highest bit one + * + * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can + * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself + * so it can be NULL + * + */ + +/* This is possibly the mother of all prime generation functions, muahahahahaha! */ +int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat) +{ + unsigned char *tmp, maskAND, maskOR_msb, maskOR_lsb; + int res, err, bsize, maskOR_msb_offset; + + /* sanity check the input */ + if (size <= 1 || t <= 0) { + return MP_VAL; + } + + /* LTM_PRIME_SAFE implies LTM_PRIME_BBS */ + if (flags & LTM_PRIME_SAFE) { + flags |= LTM_PRIME_BBS; + } + + /* calc the byte size */ + bsize = (size>>3)+(size&7?1:0); + + /* we need a buffer of bsize bytes */ + tmp = OPT_CAST(unsigned char) XMALLOC(bsize); + if (tmp == NULL) { + return MP_MEM; + } + + /* calc the maskAND value for the MSbyte*/ + maskAND = 0xFF >> (8 - (size & 7)); + + /* calc the maskOR_msb */ + maskOR_msb = 0; + maskOR_msb_offset = (size - 2) >> 3; + if (flags & LTM_PRIME_2MSB_ON) { + maskOR_msb |= 1 << ((size - 2) & 7); + } else if (flags & LTM_PRIME_2MSB_OFF) { + maskAND &= ~(1 << ((size - 2) & 7)); + } + + /* get the maskOR_lsb */ + maskOR_lsb = 0; + if (flags & LTM_PRIME_BBS) { + maskOR_lsb |= 3; + } + + do { + /* read the bytes */ + if (cb(tmp, bsize, dat) != bsize) { + err = MP_VAL; + goto error; + } + + /* work over the MSbyte */ + tmp[0] &= maskAND; + tmp[0] |= 1 << ((size - 1) & 7); + + /* mix in the maskORs */ + tmp[maskOR_msb_offset] |= maskOR_msb; + tmp[bsize-1] |= maskOR_lsb; + + /* read it in */ + if ((err = mp_read_unsigned_bin(a, tmp, bsize)) != MP_OKAY) { goto error; } + + /* is it prime? */ + if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { goto error; } + + if (flags & LTM_PRIME_SAFE) { + /* see if (a-1)/2 is prime */ + if ((err = mp_sub_d(a, 1, a)) != MP_OKAY) { goto error; } + if ((err = mp_div_2(a, a)) != MP_OKAY) { goto error; } + + /* is it prime? */ + if ((err = mp_prime_is_prime(a, t, &res)) != MP_OKAY) { goto error; } + } + } while (res == MP_NO); + + if (flags & LTM_PRIME_SAFE) { + /* restore a to the original value */ + if ((err = mp_mul_2(a, a)) != MP_OKAY) { goto error; } + if ((err = mp_add_d(a, 1, a)) != MP_OKAY) { goto error; } + } + + err = MP_OKAY; +error: + XFREE(tmp); + return err; +} + + + +/* End: bn_mp_prime_random_ex.c */ + +/* Start: bn_mp_radix_size.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* returns size of ASCII reprensentation */ +int mp_radix_size (mp_int * a, int radix, int *size) +{ + int res, digs; + mp_int t; + mp_digit d; + + *size = 0; + + /* special case for binary */ + if (radix == 2) { + *size = mp_count_bits (a) + (a->sign == MP_NEG ? 1 : 0) + 1; + return MP_OKAY; + } + + /* make sure the radix is in range */ + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + /* init a copy of the input */ + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + /* digs is the digit count */ + digs = 0; + + /* if it's negative add one for the sign */ + if (t.sign == MP_NEG) { + ++digs; + t.sign = MP_ZPOS; + } + + /* fetch out all of the digits */ + while (mp_iszero (&t) == 0) { + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return res; + } + ++digs; + } + mp_clear (&t); + + /* return digs + 1, the 1 is for the NULL byte that would be required. */ + *size = digs + 1; + return MP_OKAY; +} + + +/* End: bn_mp_radix_size.c */ + +/* Start: bn_mp_radix_smap.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* chars used in radix conversions */ +const char *mp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; + +/* End: bn_mp_radix_smap.c */ + +/* Start: bn_mp_rand.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* makes a pseudo-random int of a given size */ +int +mp_rand (mp_int * a, int digits) +{ + int res; + mp_digit d; + + mp_zero (a); + if (digits <= 0) { + return MP_OKAY; + } + + /* first place a random non-zero digit */ + do { + d = ((mp_digit) abs (rand ())); + } while (d == 0); + + if ((res = mp_add_d (a, d, a)) != MP_OKAY) { + return res; + } + + while (digits-- > 0) { + if ((res = mp_lshd (a, 1)) != MP_OKAY) { + return res; + } + + if ((res = mp_add_d (a, ((mp_digit) abs (rand ())), a)) != MP_OKAY) { + return res; + } + } + + return MP_OKAY; +} + +/* End: bn_mp_rand.c */ + +/* Start: bn_mp_read_radix.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* read a string [ASCII] in a given radix */ +int mp_read_radix (mp_int * a, char *str, int radix) +{ + int y, res, neg; + char ch; + + /* make sure the radix is ok */ + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + /* if the leading digit is a + * minus set the sign to negative. + */ + if (*str == '-') { + ++str; + neg = MP_NEG; + } else { + neg = MP_ZPOS; + } + + /* set the integer to the default of zero */ + mp_zero (a); + + /* process each digit of the string */ + while (*str) { + /* if the radix < 36 the conversion is case insensitive + * this allows numbers like 1AB and 1ab to represent the same value + * [e.g. in hex] + */ + ch = (char) ((radix < 36) ? toupper (*str) : *str); + for (y = 0; y < 64; y++) { + if (ch == mp_s_rmap[y]) { + break; + } + } + + /* if the char was found in the map + * and is less than the given radix add it + * to the number, otherwise exit the loop. + */ + if (y < radix) { + if ((res = mp_mul_d (a, (mp_digit) radix, a)) != MP_OKAY) { + return res; + } + if ((res = mp_add_d (a, (mp_digit) y, a)) != MP_OKAY) { + return res; + } + } else { + break; + } + ++str; + } + + /* set the sign only if a != 0 */ + if (mp_iszero(a) != 1) { + a->sign = neg; + } + return MP_OKAY; +} + +/* End: bn_mp_read_radix.c */ + +/* Start: bn_mp_read_signed_bin.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* read signed bin, big endian, first byte is 0==positive or 1==negative */ +int +mp_read_signed_bin (mp_int * a, unsigned char *b, int c) +{ + int res; + + /* read magnitude */ + if ((res = mp_read_unsigned_bin (a, b + 1, c - 1)) != MP_OKAY) { + return res; + } + + /* first byte is 0 for positive, non-zero for negative */ + if (b[0] == 0) { + a->sign = MP_ZPOS; + } else { + a->sign = MP_NEG; + } + + return MP_OKAY; +} + +/* End: bn_mp_read_signed_bin.c */ + +/* Start: bn_mp_read_unsigned_bin.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +int +mp_read_unsigned_bin (mp_int * a, unsigned char *b, int c) +{ + int res; + + /* make sure there are at least two digits */ + if (a->alloc < 2) { + if ((res = mp_grow(a, 2)) != MP_OKAY) { + return res; + } + } + + /* zero the int */ + mp_zero (a); + + /* read the bytes in */ + while (c-- > 0) { + if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { + return res; + } + +#ifndef MP_8BIT + a->dp[0] |= *b++; + a->used += 1; +#else + a->dp[0] = (*b & MP_MASK); + a->dp[1] |= ((*b++ >> 7U) & 1); + a->used += 2; +#endif + } + mp_clamp (a); + return MP_OKAY; +} + +/* End: bn_mp_read_unsigned_bin.c */ + +/* Start: bn_mp_reduce.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* reduces x mod m, assumes 0 < x < m**2, mu is + * precomputed via mp_reduce_setup. + * From HAC pp.604 Algorithm 14.42 + */ +int +mp_reduce (mp_int * x, mp_int * m, mp_int * mu) +{ + mp_int q; + int res, um = m->used; + + /* q = x */ + if ((res = mp_init_copy (&q, x)) != MP_OKAY) { + return res; + } + + /* q1 = x / b**(k-1) */ + mp_rshd (&q, um - 1); + + /* according to HAC this optimization is ok */ + if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) { + if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { + goto CLEANUP; + } + } else { + if ((res = s_mp_mul_high_digs (&q, mu, &q, um - 1)) != MP_OKAY) { + goto CLEANUP; + } + } + + /* q3 = q2 / b**(k+1) */ + mp_rshd (&q, um + 1); + + /* x = x mod b**(k+1), quick (no division) */ + if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { + goto CLEANUP; + } + + /* q = q * m mod b**(k+1), quick (no division) */ + if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + + /* 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_d (x, 0) == MP_LT) { + mp_set (&q, 1); + if ((res = 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) != MP_LT) { + if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { + goto CLEANUP; + } + } + +CLEANUP: + mp_clear (&q); + + return res; +} + +/* End: bn_mp_reduce.c */ + +/* Start: bn_mp_reduce_2k.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* reduces a modulo n where n is of the form 2**p - d */ +int +mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (d != 1) { + /* q = q * d */ + if ((res = mp_mul_d(&q, d, &q)) != MP_OKAY) { + goto ERR; + } + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + + +/* End: bn_mp_reduce_2k.c */ + +/* Start: bn_mp_reduce_2k_setup.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines the setup value */ +int +mp_reduce_2k_setup(mp_int *a, mp_digit *d) +{ + int res, p; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(a); + if ((res = mp_2expt(&tmp, p)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + *d = tmp.dp[0]; + mp_clear(&tmp); + return MP_OKAY; +} + +/* End: bn_mp_reduce_2k_setup.c */ + +/* Start: bn_mp_reduce_is_2k.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* determines if mp_reduce_2k can be used */ +int mp_reduce_is_2k(mp_int *a) +{ + int ix, iy, iz, iw; + + if (a->used == 0) { + return 0; + } else if (a->used == 1) { + return 1; + } else if (a->used > 1) { + iy = mp_count_bits(a); + iz = 1; + iw = 1; + + /* Test every bit from the second digit up, must be 1 */ + for (ix = DIGIT_BIT; ix < iy; ix++) { + if ((a->dp[iw] & iz) == 0) { + return 0; + } + iz <<= 1; + if (iz > (int)MP_MASK) { + ++iw; + iz = 1; + } + } + } + return 1; +} + + +/* End: bn_mp_reduce_is_2k.c */ + +/* Start: bn_mp_reduce_setup.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +int +mp_reduce_setup (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { + return res; + } + return mp_div (a, b, a, NULL); +} + +/* End: bn_mp_reduce_setup.c */ + +/* Start: bn_mp_rshd.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* shift right a certain amount of digits */ +void mp_rshd (mp_int * a, int b) +{ + int x; + + /* if b <= 0 then ignore it */ + if (b <= 0) { + return; + } + + /* if b > used then simply zero it and return */ + if (a->used <= b) { + mp_zero (a); + return; + } + + { + register mp_digit *bottom, *top; + + /* shift the digits down */ + + /* bottom */ + bottom = a->dp; + + /* top [offset into digits] */ + top = a->dp + b; + + /* this is implemented as a sliding window where + * the window is b-digits long and digits from + * the top of the window are copied to the bottom + * + * e.g. + + b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> + /\ | ----> + \-------------------/ ----> + */ + for (x = 0; x < (a->used - b); x++) { + *bottom++ = *top++; + } + + /* zero the top digits */ + for (; x < a->used; x++) { + *bottom++ = 0; + } + } + + /* remove excess digits */ + a->used -= b; +} + +/* End: bn_mp_rshd.c */ + +/* Start: bn_mp_set.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* set to a digit */ +void mp_set (mp_int * a, mp_digit b) +{ + mp_zero (a); + a->dp[0] = b & MP_MASK; + a->used = (a->dp[0] != 0) ? 1 : 0; +} + +/* End: bn_mp_set.c */ + +/* Start: bn_mp_set_int.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* set a 32-bit const */ +int mp_set_int (mp_int * a, unsigned long b) +{ + int x, res; + + mp_zero (a); + + /* set four bits at a time */ + for (x = 0; x < 8; x++) { + /* shift the number up four bits */ + if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) { + return res; + } + + /* OR in the top four bits of the source */ + a->dp[0] |= (b >> 28) & 15; + + /* shift the source up to the next four bits */ + b <<= 4; + + /* ensure that digits are not clamped off */ + a->used += 1; + } + mp_clamp (a); + return MP_OKAY; +} + +/* End: bn_mp_set_int.c */ + +/* Start: bn_mp_shrink.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* shrink a bignum */ +int mp_shrink (mp_int * a) +{ + mp_digit *tmp; + if (a->alloc != a->used && a->used > 0) { + if ((tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * a->used)) == NULL) { + return MP_MEM; + } + a->dp = tmp; + a->alloc = a->used; + } + return MP_OKAY; +} + +/* End: bn_mp_shrink.c */ + +/* Start: bn_mp_signed_bin_size.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* get the size for an signed equivalent */ +int mp_signed_bin_size (mp_int * a) +{ + return 1 + mp_unsigned_bin_size (a); +} + +/* End: bn_mp_signed_bin_size.c */ + +/* Start: bn_mp_sqr.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* computes b = a*a */ +int +mp_sqr (mp_int * a, mp_int * b) +{ + int res; + + /* use Toom-Cook? */ + if (a->used >= TOOM_SQR_CUTOFF) { + res = mp_toom_sqr(a, b); + /* Karatsuba? */ + } else if (a->used >= KARATSUBA_SQR_CUTOFF) { + res = mp_karatsuba_sqr (a, b); + } else { + /* can we use the fast comba multiplier? */ + if ((a->used * 2 + 1) < MP_WARRAY && + a->used < + (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { + res = fast_s_mp_sqr (a, b); + } else { + res = s_mp_sqr (a, b); + } + } + b->sign = MP_ZPOS; + return res; +} + +/* End: bn_mp_sqr.c */ + +/* Start: bn_mp_sqrmod.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* c = a * a (mod b) */ +int +mp_sqrmod (mp_int * a, mp_int * b, mp_int * c) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sqr (a, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, b, c); + mp_clear (&t); + return res; +} + +/* End: bn_mp_sqrmod.c */ + +/* Start: bn_mp_sqrt.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* this function is less generic than mp_n_root, simpler and faster */ +int mp_sqrt(mp_int *arg, mp_int *ret) +{ + int res; + mp_int t1,t2; + + /* must be positive */ + if (arg->sign == MP_NEG) { + return MP_VAL; + } + + /* easy out */ + if (mp_iszero(arg) == MP_YES) { + mp_zero(ret); + return MP_OKAY; + } + + if ((res = mp_init_copy(&t1, arg)) != MP_OKAY) { + return res; + } + + if ((res = mp_init(&t2)) != MP_OKAY) { + goto E2; + } + + /* First approx. (not very bad for large arg) */ + mp_rshd (&t1,t1.used/2); + + /* t1 > 0 */ + if ((res = mp_div(arg,&t1,&t2,NULL)) != MP_OKAY) { + goto E1; + } + if ((res = mp_add(&t1,&t2,&t1)) != MP_OKAY) { + goto E1; + } + if ((res = mp_div_2(&t1,&t1)) != MP_OKAY) { + goto E1; + } + /* And now t1 > sqrt(arg) */ + do { + if ((res = mp_div(arg,&t1,&t2,NULL)) != MP_OKAY) { + goto E1; + } + if ((res = mp_add(&t1,&t2,&t1)) != MP_OKAY) { + goto E1; + } + if ((res = mp_div_2(&t1,&t1)) != MP_OKAY) { + goto E1; + } + /* t1 >= sqrt(arg) >= t2 at this point */ + } while (mp_cmp_mag(&t1,&t2) == MP_GT); + + mp_exch(&t1,ret); + +E1: mp_clear(&t2); +E2: mp_clear(&t1); + return res; +} + + +/* End: bn_mp_sqrt.c */ + +/* Start: bn_mp_sub.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* high level subtraction (handles signs) */ +int +mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + sa = a->sign; + sb = b->sign; + + if (sa != sb) { + /* subtract a negative from a positive, OR */ + /* subtract a positive from a negative. */ + /* In either case, ADD their magnitudes, */ + /* and use the sign of the first number. */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* subtract a positive from a positive, OR */ + /* subtract a negative from a negative. */ + /* First, take the difference between their */ + /* magnitudes, then... */ + if (mp_cmp_mag (a, b) != MP_LT) { + /* Copy the sign from the first */ + c->sign = sa; + /* The first has a larger or equal magnitude */ + res = s_mp_sub (a, b, c); + } else { + /* The result has the *opposite* sign from */ + /* the first number. */ + c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; + /* The second has a larger magnitude */ + res = s_mp_sub (b, a, c); + } + } + return res; +} + + +/* End: bn_mp_sub.c */ + +/* Start: bn_mp_sub_d.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* single digit subtraction */ +int +mp_sub_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit *tmpa, *tmpc, mu; + int res, ix, oldused; + + /* grow c as required */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* if a is negative just do an unsigned + * addition [with fudged signs] + */ + if (a->sign == MP_NEG) { + a->sign = MP_ZPOS; + res = mp_add_d(a, b, c); + a->sign = c->sign = MP_NEG; + return res; + } + + /* setup regs */ + oldused = c->used; + tmpa = a->dp; + tmpc = c->dp; + + /* if a <= b simply fix the single digit */ + if ((a->used == 1 && a->dp[0] <= b) || a->used == 0) { + if (a->used == 1) { + *tmpc++ = b - *tmpa; + } else { + *tmpc++ = b; + } + ix = 1; + + /* negative/1digit */ + c->sign = MP_NEG; + c->used = 1; + } else { + /* positive/size */ + c->sign = MP_ZPOS; + c->used = a->used; + + /* subtract first digit */ + *tmpc = *tmpa++ - b; + mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1); + *tmpc++ &= MP_MASK; + + /* handle rest of the digits */ + for (ix = 1; ix < a->used; ix++) { + *tmpc = *tmpa++ - mu; + mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1); + *tmpc++ &= MP_MASK; + } + } + + /* zero excess digits */ + while (ix++ < oldused) { + *tmpc++ = 0; + } + mp_clamp(c); + return MP_OKAY; +} + + +/* End: bn_mp_sub_d.c */ + +/* Start: bn_mp_submod.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* d = a - b (mod c) */ +int +mp_submod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sub (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + +/* End: bn_mp_submod.c */ + +/* Start: bn_mp_to_signed_bin.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* store in signed [big endian] format */ +int +mp_to_signed_bin (mp_int * a, unsigned char *b) +{ + int res; + + if ((res = mp_to_unsigned_bin (a, b + 1)) != MP_OKAY) { + return res; + } + b[0] = (unsigned char) ((a->sign == MP_ZPOS) ? 0 : 1); + return MP_OKAY; +} + +/* End: bn_mp_to_signed_bin.c */ + +/* Start: bn_mp_to_unsigned_bin.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* store in unsigned [big endian] format */ +int +mp_to_unsigned_bin (mp_int * a, unsigned char *b) +{ + int x, res; + mp_int t; + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + x = 0; + while (mp_iszero (&t) == 0) { +#ifndef MP_8BIT + b[x++] = (unsigned char) (t.dp[0] & 255); +#else + b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); +#endif + if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + bn_reverse (b, x); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_to_unsigned_bin.c */ + +/* Start: bn_mp_toom_mul.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* multiplication using the Toom-Cook 3-way algorithm */ +int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c) +{ + mp_int w0, w1, w2, w3, w4, tmp1, tmp2, a0, a1, a2, b0, b1, b2; + int res, B; + + /* init temps */ + if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, + &a0, &a1, &a2, &b0, &b1, + &b2, &tmp1, &tmp2, NULL)) != MP_OKAY) { + return res; + } + + /* B */ + B = MIN(a->used, b->used) / 3; + + /* a = a2 * B**2 + a1 * B + a0 */ + if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(a, &a1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a1, B); + mp_mod_2d(&a1, DIGIT_BIT * B, &a1); + + if ((res = mp_copy(a, &a2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a2, B*2); + + /* b = b2 * B**2 + b1 * B + b0 */ + if ((res = mp_mod_2d(b, DIGIT_BIT * B, &b0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(b, &b1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&b1, B); + mp_mod_2d(&b1, DIGIT_BIT * B, &b1); + + if ((res = mp_copy(b, &b2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&b2, B*2); + + /* w0 = a0*b0 */ + if ((res = mp_mul(&a0, &b0, &w0)) != MP_OKAY) { + goto ERR; + } + + /* w4 = a2 * b2 */ + if ((res = mp_mul(&a2, &b2, &w4)) != MP_OKAY) { + goto ERR; + } + + /* w1 = (a2 + 2(a1 + 2a0))(b2 + 2(b1 + 2b0)) */ + if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul_2(&b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b2, &tmp2)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul(&tmp1, &tmp2, &w1)) != MP_OKAY) { + goto ERR; + } + + /* w3 = (a0 + 2(a1 + 2a2))(b0 + 2(b1 + 2b2)) */ + if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul_2(&b2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul(&tmp1, &tmp2, &w3)) != MP_OKAY) { + goto ERR; + } + + + /* w2 = (a2 + a1 + a0)(b2 + b1 + b0) */ + if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&b2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul(&tmp1, &tmp2, &w2)) != MP_OKAY) { + goto ERR; + } + + /* now solve the matrix + + 0 0 0 0 1 + 1 2 4 8 16 + 1 1 1 1 1 + 16 8 4 2 1 + 1 0 0 0 0 + + using 12 subtractions, 4 shifts, + 2 small divisions and 1 small multiplication + */ + + /* r1 - r4 */ + if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r0 */ + if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/2 */ + if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3/2 */ + if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { + goto ERR; + } + /* r2 - r0 - r4 */ + if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1 - 8r0 */ + if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - 8r4 */ + if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + /* 3r2 - r1 - r3 */ + if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/3 */ + if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { + goto ERR; + } + /* r3/3 */ + if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { + goto ERR; + } + + /* at this point shift W[n] by B*n */ + if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_add(&w0, &w1, c)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, c, c)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear_multi(&w0, &w1, &w2, &w3, &w4, + &a0, &a1, &a2, &b0, &b1, + &b2, &tmp1, &tmp2, NULL); + return res; +} + + +/* End: bn_mp_toom_mul.c */ + +/* Start: bn_mp_toom_sqr.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* squaring using Toom-Cook 3-way algorithm */ +int +mp_toom_sqr(mp_int *a, mp_int *b) +{ + mp_int w0, w1, w2, w3, w4, tmp1, a0, a1, a2; + int res, B; + + /* init temps */ + if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL)) != MP_OKAY) { + return res; + } + + /* B */ + B = a->used / 3; + + /* a = a2 * B**2 + a1 * B + a0 */ + if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(a, &a1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a1, B); + mp_mod_2d(&a1, DIGIT_BIT * B, &a1); + + if ((res = mp_copy(a, &a2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a2, B*2); + + /* w0 = a0*a0 */ + if ((res = mp_sqr(&a0, &w0)) != MP_OKAY) { + goto ERR; + } + + /* w4 = a2 * a2 */ + if ((res = mp_sqr(&a2, &w4)) != MP_OKAY) { + goto ERR; + } + + /* w1 = (a2 + 2(a1 + 2a0))**2 */ + if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_sqr(&tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + + /* w3 = (a0 + 2(a1 + 2a2))**2 */ + if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_sqr(&tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + + + /* w2 = (a2 + a1 + a0)**2 */ + if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sqr(&tmp1, &w2)) != MP_OKAY) { + goto ERR; + } + + /* now solve the matrix + + 0 0 0 0 1 + 1 2 4 8 16 + 1 1 1 1 1 + 16 8 4 2 1 + 1 0 0 0 0 + + using 12 subtractions, 4 shifts, 2 small divisions and 1 small multiplication. + */ + + /* r1 - r4 */ + if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r0 */ + if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/2 */ + if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3/2 */ + if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { + goto ERR; + } + /* r2 - r0 - r4 */ + if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1 - 8r0 */ + if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - 8r4 */ + if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + /* 3r2 - r1 - r3 */ + if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/3 */ + if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { + goto ERR; + } + /* r3/3 */ + if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { + goto ERR; + } + + /* at this point shift W[n] by B*n */ + if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_add(&w0, &w1, b)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, b, b)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL); + return res; +} + + +/* End: bn_mp_toom_sqr.c */ + +/* Start: bn_mp_toradix.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* stores a bignum as a ASCII string in a given radix (2..64) */ +int mp_toradix (mp_int * a, char *str, int radix) +{ + int res, digs; + mp_int t; + mp_digit d; + char *_s = str; + + /* check range of the radix */ + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + /* quick out if its zero */ + if (mp_iszero(a) == 1) { + *str++ = '0'; + *str = '\0'; + return MP_OKAY; + } + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + /* if it is negative output a - */ + if (t.sign == MP_NEG) { + ++_s; + *str++ = '-'; + t.sign = MP_ZPOS; + } + + digs = 0; + while (mp_iszero (&t) == 0) { + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return res; + } + *str++ = mp_s_rmap[d]; + ++digs; + } + + /* reverse the digits of the string. In this case _s points + * to the first digit [exluding the sign] of the number] + */ + bn_reverse ((unsigned char *)_s, digs); + + /* append a NULL so the string is properly terminated */ + *str = '\0'; + + mp_clear (&t); + return MP_OKAY; +} + + +/* End: bn_mp_toradix.c */ + +/* Start: bn_mp_toradix_n.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* stores a bignum as a ASCII string in a given radix (2..64) + * + * Stores upto maxlen-1 chars and always a NULL byte + */ +int mp_toradix_n(mp_int * a, char *str, int radix, int maxlen) +{ + int res, digs; + mp_int t; + mp_digit d; + char *_s = str; + + /* check range of the maxlen, radix */ + if (maxlen < 3 || radix < 2 || radix > 64) { + return MP_VAL; + } + + /* quick out if its zero */ + if (mp_iszero(a) == 1) { + *str++ = '0'; + *str = '\0'; + return MP_OKAY; + } + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + /* if it is negative output a - */ + if (t.sign == MP_NEG) { + /* we have to reverse our digits later... but not the - sign!! */ + ++_s; + + /* store the flag and mark the number as positive */ + *str++ = '-'; + t.sign = MP_ZPOS; + + /* subtract a char */ + --maxlen; + } + + digs = 0; + while (mp_iszero (&t) == 0) { + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return res; + } + *str++ = mp_s_rmap[d]; + ++digs; + + if (--maxlen == 1) { + /* no more room */ + break; + } + } + + /* reverse the digits of the string. In this case _s points + * to the first digit [exluding the sign] of the number] + */ + bn_reverse ((unsigned char *)_s, digs); + + /* append a NULL so the string is properly terminated */ + *str = '\0'; + + mp_clear (&t); + return MP_OKAY; +} + + +/* End: bn_mp_toradix_n.c */ + +/* Start: bn_mp_unsigned_bin_size.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* get the size for an unsigned equivalent */ +int +mp_unsigned_bin_size (mp_int * a) +{ + int size = mp_count_bits (a); + return (size / 8 + ((size & 7) != 0 ? 1 : 0)); +} + +/* End: bn_mp_unsigned_bin_size.c */ + +/* Start: bn_mp_xor.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* XOR two ints together */ +int +mp_xor (mp_int * a, mp_int * b, mp_int * c) +{ + int res, ix, px; + mp_int t, *x; + + if (a->used > b->used) { + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + px = b->used; + x = b; + } else { + if ((res = mp_init_copy (&t, b)) != MP_OKAY) { + return res; + } + px = a->used; + x = a; + } + + for (ix = 0; ix < px; ix++) { + t.dp[ix] ^= x->dp[ix]; + } + mp_clamp (&t); + mp_exch (c, &t); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_mp_xor.c */ + +/* Start: bn_mp_zero.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* set to zero */ +void +mp_zero (mp_int * a) +{ + a->sign = MP_ZPOS; + a->used = 0; + memset (a->dp, 0, sizeof (mp_digit) * a->alloc); +} + +/* End: bn_mp_zero.c */ + +/* Start: bn_prime_sizes_tab.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* this table gives the # of rabin miller trials for a prob of failure lower than 2^-96 */ +static const struct { + int k, t; +} sizes[] = { +{ 128, 28 }, +{ 256, 16 }, +{ 384, 10 }, +{ 512, 7 }, +{ 640, 6 }, +{ 768, 5 }, +{ 896, 4 }, +{ 1024, 4 }, +{ 1152, 3 }, +{ 1280, 3 }, +{ 1408, 3 }, +{ 1536, 3 }, +{ 1664, 3 }, +{ 1792, 2 } }; + +/* returns # of RM trials required for a given bit size */ +int mp_prime_rabin_miller_trials(int size) +{ + int x; + + for (x = 0; x < (int)(sizeof(sizes)/(sizeof(sizes[0]))); x++) { + if (sizes[x].k == size) { + return sizes[x].t; + } else if (sizes[x].k > size) { + return (x == 0) ? sizes[0].t : sizes[x - 1].t; + } + } + return 1; +} + + + +/* End: bn_prime_sizes_tab.c */ + +/* Start: bn_prime_tab.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include +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, +#ifndef MP_8BIT + 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 +#endif +}; + +/* End: bn_prime_tab.c */ + +/* Start: bn_reverse.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* reverse an array, used for radix code */ +void +bn_reverse (unsigned char *s, int len) +{ + int ix, iy; + unsigned char t; + + ix = 0; + iy = len - 1; + while (ix < iy) { + t = s[ix]; + s[ix] = s[iy]; + s[iy] = t; + ++ix; + --iy; + } +} + +/* End: bn_reverse.c */ + +/* Start: bn_s_mp_add.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* low level addition, based on HAC pp.594, Algorithm 14.7 */ +int +s_mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int *x; + int olduse, res, min, max; + + /* find sizes, we let |a| <= |b| which means we have to sort + * them. "x" will point to the input with the most digits + */ + if (a->used > b->used) { + min = b->used; + max = a->used; + x = a; + } else { + min = a->used; + max = b->used; + x = b; + } + + /* init result */ + if (c->alloc < max + 1) { + if ((res = mp_grow (c, max + 1)) != MP_OKAY) { + return res; + } + } + + /* get old used digit count and set new one */ + olduse = c->used; + c->used = max + 1; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + + /* first input */ + tmpa = a->dp; + + /* second input */ + tmpb = b->dp; + + /* destination */ + tmpc = c->dp; + + /* zero the carry */ + u = 0; + for (i = 0; i < min; i++) { + /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ + *tmpc = *tmpa++ + *tmpb++ + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, that is in A+B + * if A or B has more digits add those in + */ + if (min != max) { + for (; i < max; i++) { + /* T[i] = X[i] + U */ + *tmpc = x->dp[i] + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + } + + /* add carry */ + *tmpc++ = u; + + /* clear digits above oldused */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + +/* End: bn_s_mp_add.c */ + +/* Start: bn_s_mp_exptmod.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +#ifdef MP_LOW_MEM + #define TAB_SIZE 32 +#else + #define TAB_SIZE 256 +#endif + +int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + mp_int M[TAB_SIZE], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* create mu, used for Barrett reduction */ + if ((err = mp_init (&mu)) != MP_OKAY) { + goto __M; + } + if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { + goto __MU; + } + + /* create M table + * + * The M table contains powers of the base, + * e.g. M[x] = G**x mod P + * + * The first half of the table is not + * computed though accept for M[0] and M[1] + */ + if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { + goto __MU; + } + + /* compute the value at M[1<<(winsize-1)] by squaring + * M[1] (winsize-1) times + */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __MU; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], + &M[1 << (winsize - 1)])) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { + goto __MU; + } + } + + /* create upper table, that is M[x] = M[x-1] * M[1] (mod P) + * for x = (2**(winsize - 1) + 1) to (2**winsize - 1) + */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce (&M[x], P, &mu)) != MP_OKAY) { + goto __MU; + } + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto __MU; + } + mp_set (&res, 1); + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits */ + if (digidx == -1) { + break; + } + /* read next digit and reset the bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto __RES; + } + if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) { + goto __RES; + } + } + } + } + + mp_exch (&res, Y); + err = MP_OKAY; +__RES:mp_clear (&res); +__MU:mp_clear (&mu); +__M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + +/* End: bn_s_mp_exptmod.c */ + +/* Start: bn_s_mp_mul_digs.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* multiplies |a| * |b| and only computes upto digs digits of result + * HAC pp. 595, Algorithm 14.12 Modified so you can control how + * many digits of output are created. + */ +int +s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((digs) < MP_WARRAY) && + MIN (a->used, b->used) < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, digs)) != MP_OKAY) { + return res; + } + t.used = digs; + + /* compute the digits of the product directly */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* set the carry to zero */ + u = 0; + + /* limit ourselves to making digs digits of output */ + pb = MIN (b->used, digs - ix); + + /* setup some aliases */ + /* copy of the digit from a used within the nested loop */ + tmpx = a->dp[ix]; + + /* an alias for the destination shifted ix places */ + tmpt = t.dp + ix; + + /* an alias for the digits of b */ + tmpy = b->dp; + + /* compute the columns of the output and propagate the carry */ + for (iy = 0; iy < pb; iy++) { + /* compute the column as a mp_word */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* the new column is the lower part of the result */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry word from the result */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + /* set carry if it is placed below digs */ + if (ix + iy < digs) { + *tmpt = u; + } + } + + mp_clamp (&t); + mp_exch (&t, c); + + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_s_mp_mul_digs.c */ + +/* Start: bn_s_mp_mul_high_digs.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +int +s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((a->used + b->used + 1) < MP_WARRAY) + && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_high_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { + return res; + } + t.used = a->used + b->used + 1; + + pa = a->used; + pb = b->used; + for (ix = 0; ix < pa; ix++) { + /* clear the carry */ + u = 0; + + /* left hand side of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias to the address of where the digits will be stored */ + tmpt = &(t.dp[digs]); + + /* alias for where to read the right hand side from */ + tmpy = b->dp + (digs - ix); + + for (iy = digs - ix; iy < pb; iy++) { + /* calculate the double precision result */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* get the lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* carry the carry */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + *tmpt = u; + } + mp_clamp (&t); + mp_exch (&t, c); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_s_mp_mul_high_digs.c */ + +/* Start: bn_s_mp_sqr.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ +int +s_mp_sqr (mp_int * a, mp_int * b) +{ + mp_int t; + int res, ix, iy, pa; + mp_word r; + mp_digit u, tmpx, *tmpt; + + pa = a->used; + if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) { + return res; + } + + /* default used is maximum possible size */ + t.used = 2*pa + 1; + + for (ix = 0; ix < pa; ix++) { + /* first calculate the digit at 2*ix */ + /* calculate double precision result */ + r = ((mp_word) t.dp[2*ix]) + + ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]); + + /* store lower part in result */ + t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + + /* left hand side of A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for where to store the results */ + tmpt = t.dp + (2*ix + 1); + + for (iy = ix + 1; iy < pa; iy++) { + /* first calculate the product */ + r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]); + + /* now calculate the double precision result, note we use + * addition instead of *2 since it's easier to optimize + */ + r = ((mp_word) *tmpt) + r + r + ((mp_word) u); + + /* store lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + /* propagate upwards */ + while (u != ((mp_digit) 0)) { + r = ((mp_word) *tmpt) + ((mp_word) u); + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + } + + mp_clamp (&t); + mp_exch (&t, b); + mp_clear (&t); + return MP_OKAY; +} + +/* End: bn_s_mp_sqr.c */ + +/* Start: bn_s_mp_sub.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +int +s_mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int olduse, res, min, max; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if (c->alloc < max) { + if ((res = mp_grow (c, max)) != MP_OKAY) { + return res; + } + } + olduse = c->used; + c->used = max; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + tmpa = a->dp; + tmpb = b->dp; + tmpc = c->dp; + + /* set carry to zero */ + u = 0; + for (i = 0; i < min; i++) { + /* T[i] = A[i] - B[i] - U */ + *tmpc = *tmpa++ - *tmpb++ - u; + + /* U = carry bit of T[i] + * Note this saves performing an AND operation since + * if a carry does occur it will propagate all the way to the + * MSB. As a result a single shift is enough to get the carry + */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, e.g. if A has more digits than B */ + for (; i < max; i++) { + /* T[i] = A[i] - U */ + *tmpc = *tmpa++ - u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* clear digits above used (since we may not have grown result above) */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + + +/* End: bn_s_mp_sub.c */ + +/* Start: bncore.c */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#include + +/* Known optimal configurations + + CPU /Compiler /MUL CUTOFF/SQR CUTOFF +------------------------------------------------------------- + Intel P4 /GCC v3.2 / 70/ 108 + AMD Athlon XP /GCC v3.2 / 109/ 127 + +*/ + +/* configured for a AMD XP Thoroughbred core with etc/tune.c */ +int KARATSUBA_MUL_CUTOFF = 70, /* Min. number of digits before Karatsuba multiplication is used. */ + KARATSUBA_SQR_CUTOFF = 108, /* Min. number of digits before Karatsuba squaring is used. */ + + TOOM_MUL_CUTOFF = 350, /* no optimal values of these are known yet so set em high */ + TOOM_SQR_CUTOFF = 400; + +/* End: bncore.c */ + + +/* EOF */ diff --git a/mycrypt.h b/mycrypt.h new file mode 100644 index 0000000..0160d64 --- /dev/null +++ b/mycrypt.h @@ -0,0 +1,83 @@ +#ifndef CRYPT_H_ +#define CRYPT_H_ +#include +#include +#include +#include +#include +#include +#include + +/* if there is a custom definition header file use it */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* version */ +#define CRYPT 0x0095 +#define SCRYPT "0.95" + +/* max size of either a cipher/hash block or symmetric key [largest of the two] */ +#define MAXBLOCKSIZE 128 + +/* descriptor table size */ +/* Dropbear change - this should be smaller, saves some size */ +#define TAB_SIZE 4 + +/* error codes [will be expanded in future releases] */ +enum { + CRYPT_OK=0, /* Result OK */ + CRYPT_ERROR, /* Generic Error */ + CRYPT_NOP, /* Not a failure but no operation was performed */ + + CRYPT_INVALID_KEYSIZE, /* Invalid key size given */ + CRYPT_INVALID_ROUNDS, /* Invalid number of rounds */ + CRYPT_FAIL_TESTVECTOR, /* Algorithm failed test vectors */ + + CRYPT_BUFFER_OVERFLOW, /* Not enough space for output */ + CRYPT_INVALID_PACKET, /* Invalid input packet given */ + + CRYPT_INVALID_PRNGSIZE, /* Invalid number of bits for a PRNG */ + CRYPT_ERROR_READPRNG, /* Could not read enough from PRNG */ + + CRYPT_INVALID_CIPHER, /* Invalid cipher specified */ + CRYPT_INVALID_HASH, /* Invalid hash specified */ + CRYPT_INVALID_PRNG, /* Invalid PRNG specified */ + + CRYPT_MEM, /* Out of memory */ + + CRYPT_PK_TYPE_MISMATCH, /* Not equivalent types of PK keys */ + CRYPT_PK_NOT_PRIVATE, /* Requires a private PK key */ + + CRYPT_INVALID_ARG, /* Generic invalid argument */ + CRYPT_FILE_NOTFOUND, /* File Not Found */ + + CRYPT_PK_INVALID_TYPE, /* Invalid type of PK key */ + CRYPT_PK_INVALID_SYSTEM,/* Invalid PK system specified */ + CRYPT_PK_DUP, /* Duplicate key already in key ring */ + CRYPT_PK_NOT_FOUND, /* Key not found in keyring */ + CRYPT_PK_INVALID_SIZE, /* Invalid size input for PK parameters */ + + CRYPT_INVALID_PRIME_SIZE/* Invalid size of prime requested */ +}; + +#include +#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..6af99e4 --- /dev/null +++ b/mycrypt_argchk.h @@ -0,0 +1,24 @@ +/* Defines the _ARGCHK macro used within the library */ + +/* ch1-01-1 */ +/* ARGTYPE is defined in mycrypt_cfg.h */ +#if ARGTYPE == 2 || defined(NDEBUG) + +#define _ARGCHK(x) + +#elif ARGTYPE == 0 + +#include + +/* this is the default LibTomCrypt macro */ +extern void crypt_argchk(char *v, char *s, int d); +#define _ARGCHK(x) if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); } + +#elif ARGTYPE == 1 + +/* fatal type of error */ +#define _ARGCHK(x) assert((x)) + +#endif +/* ch1-01-1 */ + diff --git a/mycrypt_cfg.h b/mycrypt_cfg.h new file mode 100644 index 0000000..4d6c5db --- /dev/null +++ b/mycrypt_cfg.h @@ -0,0 +1,78 @@ +/* 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 *REALLOC(void *p, 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); + +/* ch1-01-1 */ +/* type of argument checking, 0=default, 1=fatal and 2=none */ +#define ARGTYPE 0 +/* ch1-01-1 */ + +/* Controls endianess and size of registers. Leave uncommented to get platform neutral [slower] code */ +/* detect x86-32 machines somewhat */ +#if defined(INTEL_CC) || (defined(_MSC_VER) && defined(WIN32)) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__))) + #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 YARROW + #ifndef CTR + #error YARROW requires CTR chaining mode to be defined! + #endif +#endif + +/* packet code */ +#if defined(MRSA) || defined(MDH) || defined(MECC) + #define PACKET + + /* size of a packet header in bytes */ + #define PACKET_SIZE 4 + + /* Section tags */ + #define PACKET_SECT_RSA 0 + #define PACKET_SECT_DH 1 + #define PACKET_SECT_ECC 2 + #define PACKET_SECT_DSA 3 + + /* 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 + +#endif /* MYCRYPT_CFG_H */ + diff --git a/mycrypt_cipher.h b/mycrypt_cipher.h new file mode 100644 index 0000000..a694044 --- /dev/null +++ b/mycrypt_cipher.h @@ -0,0 +1,378 @@ +/* ---- 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 { + ulong32 S[4][256]; + ulong32 K[18]; +}; +#endif + +#ifdef RC5 +struct rc5_key { + int rounds; + ulong32 K[50]; +}; +#endif + +#ifdef RC6 +struct rc6_key { + ulong32 K[44]; +}; +#endif + +#ifdef SAFERP +struct saferp_key { + unsigned char K[33][16]; + long rounds; +}; +#endif + +#ifdef RIJNDAEL +struct rijndael_key { + ulong32 eK[64], dK[64]; + int Nr; +}; +#endif + +#ifdef XTEA +struct xtea_key { + unsigned long A[32], B[32]; +}; +#endif + +#ifdef TWOFISH +#ifndef TWOFISH_SMALL + struct twofish_key { + ulong32 S[4][256], K[40]; + }; +#else + struct twofish_key { + ulong32 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 { + ulong32 ek[32], dk[32]; +}; + +struct des3_key { + ulong32 ek[3][32], dk[3][32]; +}; +#endif + +#ifdef CAST5 +struct cast5_key { + ulong32 K[32], keylen; +}; +#endif + +#ifdef NOEKEON +struct noekeon_key { + ulong32 K[4], dK[4]; +}; +#endif + +#ifdef SKIPJACK +struct skipjack_key { + unsigned char key[10]; +}; +#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 RIJNDAEL + struct rijndael_key rijndael; +#endif +#ifdef XTEA + struct xtea_key xtea; +#endif +#ifdef CAST5 + struct cast5_key cast5; +#endif +#ifdef NOEKEON + struct noekeon_key noekeon; +#endif +#ifdef SKIPJACK + struct skipjack_key skipjack; +#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, mode; + 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; + int 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 RIJNDAEL + +/* make aes an alias */ +#define aes_setup rijndael_setup +#define aes_ecb_encrypt rijndael_ecb_encrypt +#define aes_ecb_decrypt rijndael_ecb_decrypt +#define aes_test rijndael_test +#define aes_keysize rijndael_keysize + +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, aes_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 NOEKEON +extern int noekeon_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int noekeon_test(void); +extern int noekeon_keysize(int *desired_keysize); +extern const struct _cipher_descriptor noekeon_desc; +#endif + +#ifdef SKIPJACK +extern int skipjack_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); +extern void skipjack_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); +extern void skipjack_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); +extern int skipjack_test(void); +extern int skipjack_keysize(int *desired_keysize); +extern const struct _cipher_descriptor skipjack_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_custom.h b/mycrypt_custom.h new file mode 100644 index 0000000..492adf2 --- /dev/null +++ b/mycrypt_custom.h @@ -0,0 +1,68 @@ +/* This header is meant to be included before mycrypt.h in projects where + * you don't want to throw all the defines in a makefile. + */ + +#ifndef MYCRYPT_CUSTOM_H_ +#define MYCRYPT_CUSTOM_H_ + +/* this will sort out which stuff based on the user-config in options.h */ +#include "../options.h" + +#ifdef CRYPT + #error mycrypt_custom.h should be included before mycrypt.h +#endif + +#define XMALLOC malloc +#define XREALLOC realloc +#define XCALLOC calloc +#define XFREE free +#define XCLOCK clock +#define XCLOCKS_PER_SEC CLOCKS_PER_SEC + +#ifdef DROPBEAR_SMALL_CODE +#define SMALL_CODE +#endif + +/* #define LTC_TEST */ + +#ifdef DROPBEAR_BLOWFISH_CBC +#define BLOWFISH +#endif + +#ifdef DROPBEAR_AES128_CBC +#define RIJNDAEL +#endif + +#ifdef DROPBEAR_TWOFISH128_CBC +#define TWOFISH + +/* enabling just TWOFISH_SMALL will make the binary ~1kB smaller, turning on + * TWOFISH_TABLES will make it a few kB bigger, but perhaps reduces runtime + * memory usage? */ +#define TWOFISH_SMALL +/*#define TWOFISH_TABLES*/ +#endif + +#ifdef DROPBEAR_3DES_CBC +#define DES +#endif + +#define CBC + +#if defined(DROPBEAR_DSS) && defined(DSS_PROTOK) +#define SHA512 +#endif + +#define SHA1 + +#ifdef DROPBEAR_MD5_HMAC +#define MD5 +#endif + +#define HMAC +#define BASE64 + +#include + +#endif + 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..e59b5d6 --- /dev/null +++ b/mycrypt_hash.h @@ -0,0 +1,447 @@ +/* ---- 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; + ulong32 state[8], curlen; + unsigned char buf[64]; +}; +#endif + +#ifdef SHA1 +struct sha1_state { + ulong64 length; + ulong32 state[5], curlen; + unsigned char buf[64]; +}; +#endif + +#ifdef MD5 +struct md5_state { + ulong64 length; + ulong32 state[4], curlen; + unsigned char buf[64]; +}; +#endif + +#ifdef MD4 +struct md4_state { + ulong64 length; + ulong32 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 + +#ifdef RIPEMD128 +struct rmd128_state { + ulong64 length; + unsigned char buf[64]; + ulong32 curlen, state[4]; +}; +#endif + +#ifdef RIPEMD160 +struct rmd160_state { + ulong64 length; + unsigned char buf[64]; + ulong32 curlen, state[5]; +}; +#endif + +#ifdef WHIRLPOOL +struct whirlpool_state { + ulong64 length, state[8]; + unsigned char buf[64]; + ulong32 curlen; +}; +#endif + +typedef union Hash_state { +#ifdef WHIRLPOOL + struct whirlpool_state whirlpool; +#endif +#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 +#ifdef RIPEMD128 + struct rmd128_state rmd128; +#endif +#ifdef RIPEMD160 + struct rmd160_state rmd160; +#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 *); + int (*process)(hash_state *, const unsigned char *, unsigned long); + int (*done)(hash_state *, unsigned char *); + int (*test)(void); +} hash_descriptor[]; + + +#ifdef WHIRLPOOL +extern void whirlpool_init(hash_state * md); +extern int whirlpool_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern int whirlpool_done(hash_state * md, unsigned char *hash); +extern int whirlpool_test(void); +extern const struct _hash_descriptor whirlpool_desc; +#endif + +#ifdef SHA512 +extern void sha512_init(hash_state * md); +extern int sha512_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern int sha512_done(hash_state * md, unsigned char *hash); +extern int sha512_test(void); +extern const struct _hash_descriptor sha512_desc; +#endif + +#ifdef SHA384 +#ifndef SHA512 + #error SHA512 is required for SHA384 +#endif +extern void sha384_init(hash_state * md); +#define sha384_process sha512_process +extern int 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 int sha256_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern int sha256_done(hash_state * md, unsigned char *hash); +extern int sha256_test(void); +extern const struct _hash_descriptor sha256_desc; + +#ifdef SHA224 +#ifndef SHA256 + #error SHA256 is required for SHA224 +#endif +extern void sha224_init(hash_state * md); +#define sha224_process sha256_process +extern int sha224_done(hash_state * md, unsigned char *hash); +extern int sha224_test(void); +extern const struct _hash_descriptor sha224_desc; +#endif +#endif + +#ifdef SHA1 +extern void sha1_init(hash_state * md); +extern int sha1_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern int 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 int md5_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern int 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 int md4_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern int 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 int md2_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern int 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 int tiger_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern int tiger_done(hash_state * md, unsigned char *hash); +extern int tiger_test(void); +extern const struct _hash_descriptor tiger_desc; +#endif + +#ifdef RIPEMD128 +extern void rmd128_init(hash_state * md); +extern int rmd128_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern int rmd128_done(hash_state * md, unsigned char *hash); +extern int rmd128_test(void); +extern const struct _hash_descriptor rmd128_desc; +#endif + +#ifdef RIPEMD160 +extern void rmd160_init(hash_state * md); +extern int rmd160_process(hash_state * md, const unsigned char *buf, unsigned long len); +extern int rmd160_done(hash_state * md, unsigned char *hash); +extern int rmd160_test(void); +extern const struct _hash_descriptor rmd160_desc; +#endif + + +extern int find_hash(const char *name); +extern int find_hash_id(unsigned char ID); +extern int find_hash_any(const char *name, int digestlen); +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); + +/* a simple macro for making hash "process" functions */ +#define HASH_PROCESS(func_name, compress_name, state_var, block_size) \ +int func_name (hash_state * md, const unsigned char *buf, unsigned long len) \ +{ \ + unsigned long n; \ + _ARGCHK(md != NULL); \ + _ARGCHK(buf != NULL); \ + if (md-> state_var .curlen > sizeof(md-> state_var .buf)) { \ + return CRYPT_INVALID_ARG; \ + } \ + while (len > 0) { \ + if (md-> state_var .curlen == 0 && len >= block_size) { \ + compress_name (md, (unsigned char *)buf); \ + md-> state_var .length += block_size * 8; \ + buf += block_size; \ + len -= block_size; \ + } else { \ + n = MIN(len, (block_size - md-> state_var .curlen)); \ + memcpy(md-> state_var .buf + md-> state_var.curlen, buf, (size_t)n); \ + md-> state_var .curlen += n; \ + buf += n; \ + len -= n; \ + if (md-> state_var .curlen == block_size) { \ + compress_name (md, md-> state_var .buf); \ + md-> state_var .length += 8*block_size; \ + md-> state_var .curlen = 0; \ + } \ + } \ + } \ + return CRYPT_OK; \ +} + +#ifdef HMAC +typedef struct Hmac_state { + hash_state md; + int hash; + 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 *hashOut, unsigned long *outlen); +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, unsigned long *dstlen); +extern int hmac_file(int hash, const char *fname, const unsigned char *key, + unsigned long keylen, + unsigned char *dst, unsigned long *dstlen); +#endif + +#ifdef OMAC + +typedef struct { + int cipher_idx, + buflen, + blklen; + unsigned char block[MAXBLOCKSIZE], + prev[MAXBLOCKSIZE], + Lu[2][MAXBLOCKSIZE]; + symmetric_key key; +} omac_state; + +extern int omac_init(omac_state *omac, int cipher, const unsigned char *key, unsigned long keylen); +extern int omac_process(omac_state *state, const unsigned char *buf, unsigned long len); +extern int omac_done(omac_state *state, unsigned char *out, unsigned long *outlen); +extern int omac_memory(int cipher, const unsigned char *key, unsigned long keylen, + const unsigned char *msg, unsigned long msglen, + unsigned char *out, unsigned long *outlen); +extern int omac_file(int cipher, const unsigned char *key, unsigned long keylen, + const char *filename, unsigned char *out, unsigned long *outlen); +extern int omac_test(void); +#endif /* OMAC */ + +#ifdef PMAC + +typedef struct { + unsigned char Ls[32][MAXBLOCKSIZE], /* L shifted by i bits to the left */ + Li[MAXBLOCKSIZE], /* value of Li [current value, we calc from previous recall] */ + Lr[MAXBLOCKSIZE], /* L * x^-1 */ + block[MAXBLOCKSIZE], /* currently accumulated block */ + checksum[MAXBLOCKSIZE]; /* current checksum */ + + symmetric_key key; /* scheduled key for cipher */ + unsigned long block_index; /* index # for current block */ + int cipher_idx, /* cipher idx */ + block_len, /* length of block */ + buflen; /* number of bytes in the buffer */ +} pmac_state; + +extern int pmac_init(pmac_state *pmac, int cipher, const unsigned char *key, unsigned long keylen); +extern int pmac_process(pmac_state *state, const unsigned char *buf, unsigned long len); +extern int pmac_done(pmac_state *state, unsigned char *out, unsigned long *outlen); + +extern int pmac_memory(int cipher, const unsigned char *key, unsigned long keylen, + const unsigned char *msg, unsigned long msglen, + unsigned char *out, unsigned long *outlen); + +extern int pmac_file(int cipher, const unsigned char *key, unsigned long keylen, + const char *filename, unsigned char *out, unsigned long *outlen); + +extern int pmac_test(void); + +/* internal functions */ +extern int pmac_ntz(unsigned long x); +extern void pmac_shift_xor(pmac_state *pmac); + +#endif /* PMAC */ + +#ifdef EAX_MODE + +#if !(defined(OMAC) && defined(CTR)) + #error EAX_MODE requires OMAC and CTR +#endif + +typedef struct { + unsigned char N[MAXBLOCKSIZE]; + symmetric_CTR ctr; + omac_state headeromac, ctomac; +} eax_state; + +extern int eax_init(eax_state *eax, int cipher, const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, unsigned long noncelen, + const unsigned char *header, unsigned long headerlen); + +extern int eax_encrypt(eax_state *eax, const unsigned char *pt, unsigned char *ct, unsigned long length); +extern int eax_decrypt(eax_state *eax, const unsigned char *ct, unsigned char *pt, unsigned long length); +extern int eax_addheader(eax_state *eax, const unsigned char *header, unsigned long length); +extern int eax_done(eax_state *eax, unsigned char *tag, unsigned long *taglen); + +extern int eax_encrypt_authenticate_memory(int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, unsigned long noncelen, + const unsigned char *header, unsigned long headerlen, + const unsigned char *pt, unsigned long ptlen, + unsigned char *ct, + unsigned char *tag, unsigned long *taglen); + +extern int eax_decrypt_verify_memory(int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, unsigned long noncelen, + const unsigned char *header, unsigned long headerlen, + const unsigned char *ct, unsigned long ctlen, + unsigned char *pt, + unsigned char *tag, unsigned long taglen, + int *res); + +extern int eax_test(void); +#endif /* EAX MODE */ + +#ifdef OCB_MODE +typedef struct { + unsigned char L[MAXBLOCKSIZE], /* L value */ + Ls[32][MAXBLOCKSIZE], /* L shifted by i bits to the left */ + Li[MAXBLOCKSIZE], /* value of Li [current value, we calc from previous recall] */ + Lr[MAXBLOCKSIZE], /* L * x^-1 */ + R[MAXBLOCKSIZE], /* R value */ + checksum[MAXBLOCKSIZE]; /* current checksum */ + + symmetric_key key; /* scheduled key for cipher */ + unsigned long block_index; /* index # for current block */ + int cipher, /* cipher idx */ + block_len; /* length of block */ +} ocb_state; + +extern int ocb_init(ocb_state *ocb, int cipher, + const unsigned char *key, unsigned long keylen, const unsigned char *nonce); + +extern int ocb_encrypt(ocb_state *ocb, const unsigned char *pt, unsigned char *ct); +extern int ocb_decrypt(ocb_state *ocb, const unsigned char *ct, unsigned char *pt); + +extern int ocb_done_encrypt(ocb_state *ocb, + const unsigned char *pt, unsigned long ptlen, + unsigned char *ct, + unsigned char *tag, unsigned long *taglen); + +extern int ocb_done_decrypt(ocb_state *ocb, + const unsigned char *ct, unsigned long ctlen, + unsigned char *pt, + const unsigned char *tag, unsigned long taglen, int *res); + +extern int ocb_encrypt_authenticate_memory(int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, + const unsigned char *pt, unsigned long ptlen, + unsigned char *ct, + unsigned char *tag, unsigned long *taglen); + +extern int ocb_decrypt_verify_memory(int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, + const unsigned char *ct, unsigned long ctlen, + unsigned char *pt, + const unsigned char *tag, unsigned long taglen, + int *res); + +extern int ocb_test(void); + +/* internal functions */ +extern void ocb_shift_xor(ocb_state *ocb, unsigned char *Z); +extern int ocb_ntz(unsigned long x); +extern int __ocb_done(ocb_state *ocb, const unsigned char *pt, unsigned long ptlen, + unsigned char *ct, unsigned char *tag, unsigned long *taglen, int mode); + +#endif /* OCB_MODE */ + + diff --git a/mycrypt_kr.h b/mycrypt_kr.h new file mode 100644 index 0000000..6dc16cd --- /dev/null +++ b/mycrypt_kr.h @@ -0,0 +1,81 @@ +#ifdef KR + +#if !defined(MRSA) || !defined(MDH) || !defined(MECC) + #error "Keyring code requires all three public key algorithms." +#endif + +#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 sys, 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 sys, 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, unsigned long inlen); + +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..9fa6899 --- /dev/null +++ b/mycrypt_macros.h @@ -0,0 +1,241 @@ +/* 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 + +/* this is the "32-bit at least" data type + * Re-define it to suit your platform but it must be at least 32-bits + */ +typedef unsigned long ulong32; + +/* ---- 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)[z0] = (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) ) + +#ifdef _MSC_VER + +/* instrinsic rotate */ +#include +#pragma intrinsic(_lrotr,_lrotl) +#define ROR(x,n) _lrotr(x,n) +#define ROL(x,n) _lrotl(x,n) + +#elif defined(__GNUC__) && defined(__i386__) && !defined(INTEL_CC) + +static inline unsigned long ROL(unsigned long word, int i) +{ + __asm__("roll %%cl,%0" + :"=r" (word) + :"0" (word),"c" (i)); + return word; +} + +static inline unsigned long ROR(unsigned long word, int i) +{ + __asm__("rorl %%cl,%0" + :"=r" (word) + :"0" (word),"c" (i)); + return word; +} + +#else + +/* rotates the hard way */ +#define ROL(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) +#define ROR(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) + +#endif + +#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) ) + +/* extract a byte portably */ +#ifdef _MSC_VER + #define byte(x, n) ((unsigned char)((x) >> (8 * (n)))) +#else + #define byte(x, n) (((x) >> (8 * (n))) & 255) +#endif diff --git a/mycrypt_misc.h b/mycrypt_misc.h new file mode 100644 index 0000000..7524c9d --- /dev/null +++ b/mycrypt_misc.h @@ -0,0 +1,20 @@ +/* ---- 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, size_t len); +extern void burn_stack(unsigned long len); + +extern const char *error_to_string(int err); +extern int mpi_to_ltc_error(int err); + +#if 0 +/* Takes up space we don\'t need for Dropbear */ +extern const char *crypt_build_settings; +#endif diff --git a/mycrypt_pk.h b/mycrypt_pk.h new file mode 100644 index 0000000..47e1c02 --- /dev/null +++ b/mycrypt_pk.h @@ -0,0 +1,245 @@ +/* ---- NUMBER THEORY ---- */ +#ifdef MPI + +#include "tommath.h" + +/* in/out macros */ +#define OUTPUT_BIGNUM(num, out, y, z) \ +{ \ + if ((y + 4) > *outlen) { return CRYPT_BUFFER_OVERFLOW; } \ + z = (unsigned long)mp_unsigned_bin_size(num); \ + STORE32L(z, out+y); \ + y += 4; \ + if ((y + z) > *outlen) { return CRYPT_BUFFER_OVERFLOW; } \ + if ((err = mp_to_unsigned_bin(num, out+y)) != MP_OKAY) { return mpi_to_ltc_error(err); } \ + y += z; \ +} + + +#define INPUT_BIGNUM(num, in, x, y, inlen) \ +{ \ + /* load value */ \ + if ((y + 4) > inlen) { \ + err = CRYPT_INVALID_PACKET; \ + goto error; \ + } \ + LOAD32L(x, in+y); \ + y += 4; \ + \ + /* sanity check... */ \ + if ((x+y) > inlen) { \ + err = CRYPT_INVALID_PACKET; \ + goto error; \ + } \ + \ + /* load it */ \ + if ((err = mp_read_unsigned_bin(num, (unsigned char *)in+y, (int)x)) != MP_OKAY) {\ + err = mpi_to_ltc_error(err); \ + goto error; \ + } \ + y += x; \ + if ((err = mp_shrink(num)) != MP_OKAY) { \ + err = mpi_to_ltc_error(err); \ + goto error; \ + } \ +} + +extern int is_prime(mp_int *, int *); +extern int rand_prime(mp_int *N, long len, prng_state *prng, int wprng); + +#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 + #ifdef MDSA + #error DSA requires the big int library + #endif +#endif /* MPI */ + + +/* ---- 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); +extern int packet_valid_header(unsigned char *src, int section, int subsection); + +#endif + + +/* ---- RSA ---- */ +#ifdef MRSA + +/* Min and Max RSA key sizes (in bits) */ +#define MIN_RSA_SIZE 1024 +#define MAX_RSA_SIZE 4096 + +/* Stack required for temps (plus padding) */ +#define RSA_STACK (8 + (MAX_RSA_SIZE/8)) + +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); + +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 long inlen, + 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, unsigned long siglen, + 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, unsigned long inlen, 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, unsigned long inlen, dh_key *key); + +extern int dh_shared_secret(dh_key *private_key, dh_key *public_key, + unsigned char *out, unsigned long *outlen); + +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 long inlen, + 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, unsigned long siglen, + const unsigned char *hash, unsigned long hashlen, + 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, unsigned long inlen, ecc_key *key); + +extern int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, + unsigned char *out, unsigned long *outlen); + +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 long inlen, + 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, unsigned long siglen, + const unsigned char *hash, unsigned long hashlen, + int *stat, ecc_key *key); +#endif + +#ifdef MDSA + +typedef struct { + int type, qord; + mp_int g, q, p, x, y; +} dsa_key; + +extern int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key); +extern void dsa_free(dsa_key *key); + +extern int dsa_sign_hash(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + prng_state *prng, int wprng, dsa_key *key); + +extern int dsa_verify_hash(const unsigned char *sig, unsigned long siglen, + const unsigned char *hash, unsigned long inlen, + int *stat, dsa_key *key); + +extern int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key); + +extern int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key); + +extern int dsa_verify_key(dsa_key *key, int *stat); + +#endif diff --git a/mycrypt_pkcs.h b/mycrypt_pkcs.h new file mode 100644 index 0000000..72d8d67 --- /dev/null +++ b/mycrypt_pkcs.h @@ -0,0 +1,53 @@ +/* PKCS Header Info */ + +/* ===> PKCS #1 -- RSA Cryptography <=== */ +#ifdef PKCS_1 + +int pkcs_1_mgf1(const unsigned char *seed, unsigned long seedlen, + int hash_idx, + unsigned char *mask, unsigned long masklen); + +int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, + const unsigned char *lparam, unsigned long lparamlen, + unsigned long modulus_bitlen, int hash_idx, + int prng_idx, prng_state *prng, + unsigned char *out, unsigned long *outlen); + +int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, + const unsigned char *lparam, unsigned long lparamlen, + unsigned long modulus_bitlen, int hash_idx, + unsigned char *out, unsigned long *outlen); + +int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, + unsigned long saltlen, int hash_idx, + int prng_idx, prng_state *prng, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen); + +int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, + const unsigned char *sig, unsigned long siglen, + unsigned long saltlen, int hash_idx, + unsigned long modulus_bitlen, int *res); + +int pkcs_1_i2osp(mp_int *n, unsigned long modulus_len, unsigned char *out); +int pkcs_1_os2ip(mp_int *n, unsigned char *in, unsigned long inlen); + + +#endif /* PKCS_1 */ + +/* ===> PKCS #5 -- Password Based Cryptography <=== */ +#ifdef PKCS_5 + +/* Algorithm #1 (old) */ +int pkcs_5_alg1(const unsigned char *password, unsigned long password_len, + const unsigned char *salt, + int iteration_count, int hash_idx, + unsigned char *out, unsigned long *outlen); + +/* Algorithm #2 (new) */ +int pkcs_5_alg2(const unsigned char *password, unsigned long password_len, + const unsigned char *salt, unsigned long salt_len, + int iteration_count, int hash_idx, + unsigned char *out, unsigned long *outlen); + +#endif /* PKCS_5 */ diff --git a/mycrypt_prng.h b/mycrypt_prng.h new file mode 100644 index 0000000..b96fa43 --- /dev/null +++ b/mycrypt_prng.h @@ -0,0 +1,66 @@ +/* ---- 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 + */ +/* ch2-02-1 */ +extern unsigned long rng_get_bytes(unsigned char *buf, + unsigned long len, + void (*callback)(void)); +/* ch2-02-1 */ + +extern int rng_make_prng(int bits, int wprng, prng_state *prng, void (*callback)(void)); + diff --git a/noekeon.c b/noekeon.c new file mode 100644 index 0000000..7c6e87f --- /dev/null +++ b/noekeon.c @@ -0,0 +1,270 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* Implementation of the Noekeon block cipher by Tom St Denis */ +#include "mycrypt.h" + +#ifdef NOEKEON + +const struct _cipher_descriptor noekeon_desc = +{ + "noekeon", + 16, + 16, 16, 16, 16, + &noekeon_setup, + &noekeon_ecb_encrypt, + &noekeon_ecb_decrypt, + &noekeon_test, + &noekeon_keysize +}; + +static const ulong32 RC[] = { + 0x00000080UL, 0x0000001bUL, 0x00000036UL, 0x0000006cUL, + 0x000000d8UL, 0x000000abUL, 0x0000004dUL, 0x0000009aUL, + 0x0000002fUL, 0x0000005eUL, 0x000000bcUL, 0x00000063UL, + 0x000000c6UL, 0x00000097UL, 0x00000035UL, 0x0000006aUL, + 0x000000d4UL +}; + + +#define kTHETA(a, b, c, d) \ + temp = a^c; temp = temp ^ ROL(temp, 8) ^ ROR(temp, 8); \ + b ^= temp; d ^= temp; \ + temp = b^d; temp = temp ^ ROL(temp, 8) ^ ROR(temp, 8); \ + a ^= temp; c ^= temp; + +#define THETA(k, a, b, c, d) \ + temp = a^c; temp = temp ^ ROL(temp, 8) ^ ROR(temp, 8); \ + b ^= temp ^ k[1]; d ^= temp ^ k[3]; \ + temp = b^d; temp = temp ^ ROL(temp, 8) ^ ROR(temp, 8); \ + a ^= temp ^ k[0]; c ^= temp ^ k[2]; + +#define GAMMA(a, b, c, d) \ + b ^= ~(d|c); \ + a ^= c&b; \ + temp = d; d = a; a = temp;\ + c ^= a ^ b ^ d; \ + b ^= ~(d|c); \ + a ^= c&b; + +#define PI1(a, b, c, d) \ + a = ROL(a, 1); c = ROL(c, 5); d = ROL(d, 2); + +#define PI2(a, b, c, d) \ + a = ROR(a, 1); c = ROR(c, 5); d = ROR(d, 2); + +int noekeon_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + ulong32 temp; + + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + if (keylen != 16) { + return CRYPT_INVALID_KEYSIZE; + } + + if (num_rounds != 16 && num_rounds != 0) { + return CRYPT_INVALID_ROUNDS; + } + + LOAD32H(skey->noekeon.K[0],&key[0]); + LOAD32H(skey->noekeon.K[1],&key[4]); + LOAD32H(skey->noekeon.K[2],&key[8]); + LOAD32H(skey->noekeon.K[3],&key[12]); + + LOAD32H(skey->noekeon.dK[0],&key[0]); + LOAD32H(skey->noekeon.dK[1],&key[4]); + LOAD32H(skey->noekeon.dK[2],&key[8]); + LOAD32H(skey->noekeon.dK[3],&key[12]); + + kTHETA(skey->noekeon.dK[0], skey->noekeon.dK[1], skey->noekeon.dK[2], skey->noekeon.dK[3]); + + return CRYPT_OK; +} + +#ifdef CLEAN_STACK +static void _noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#else +void noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#endif +{ + ulong32 a,b,c,d,temp; +#ifdef SMALL_CODE + int r; +#endif + + _ARGCHK(key != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + + LOAD32H(a,&pt[0]); LOAD32H(b,&pt[4]); + LOAD32H(c,&pt[8]); LOAD32H(d,&pt[12]); + +#define ROUND(i) \ + a ^= RC[i]; \ + THETA(key->noekeon.K, a,b,c,d); \ + PI1(a,b,c,d); \ + GAMMA(a,b,c,d); \ + PI2(a,b,c,d); + +#ifdef SMALL_CODE + for (r = 0; r < 16; ++r) { + ROUND(r); + } +#else + ROUND( 0); ROUND( 1); ROUND( 2); ROUND( 3); + ROUND( 4); ROUND( 5); ROUND( 6); ROUND( 7); + ROUND( 8); ROUND( 9); ROUND(10); ROUND(11); + ROUND(12); ROUND(13); ROUND(14); ROUND(15); +#endif + +#undef ROUND + + a ^= RC[16]; + THETA(key->noekeon.K, a, b, c, d); + + STORE32H(a,&ct[0]); STORE32H(b,&ct[4]); + STORE32H(c,&ct[8]); STORE32H(d,&ct[12]); +} + +#ifdef CLEAN_STACK +void noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + _noekeon_ecb_encrypt(pt, ct, key); + burn_stack(sizeof(ulong32) * 5 + sizeof(int)); +} +#endif + +#ifdef CLEAN_STACK +static void _noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#else +void noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#endif +{ + ulong32 a,b,c,d, temp; +#ifdef SMALL_CODE + int r; +#endif + + _ARGCHK(key != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + + LOAD32H(a,&ct[0]); LOAD32H(b,&ct[4]); + LOAD32H(c,&ct[8]); LOAD32H(d,&ct[12]); + + +#define ROUND(i) \ + THETA(key->noekeon.dK, a,b,c,d); \ + a ^= RC[i]; \ + PI1(a,b,c,d); \ + GAMMA(a,b,c,d); \ + PI2(a,b,c,d); + +#ifdef SMALL_CODE + for (r = 16; r > 0; --r) { + ROUND(r); + } +#else + ROUND(16); ROUND(15); ROUND(14); ROUND(13); + ROUND(12); ROUND(11); ROUND(10); ROUND( 9); + ROUND( 8); ROUND( 7); ROUND( 6); ROUND( 5); + ROUND( 4); ROUND( 3); ROUND( 2); ROUND( 1); +#endif + +#undef ROUND + + THETA(key->noekeon.dK, a,b,c,d); + a ^= RC[0]; + STORE32H(a,&pt[0]); STORE32H(b, &pt[4]); + STORE32H(c,&pt[8]); STORE32H(d, &pt[12]); +} + +#ifdef CLEAN_STACK +void noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +{ + _noekeon_ecb_decrypt(ct, pt, key); + burn_stack(sizeof(ulong32) * 5 + sizeof(int)); +} +#endif + +int noekeon_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + int keylen; + unsigned char key[16], pt[16], ct[16]; + } tests[] = { + { + 16, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 0x18, 0xa6, 0xec, 0xe5, 0x28, 0xaa, 0x79, 0x73, + 0x28, 0xb2, 0xc0, 0x91, 0xa0, 0x2f, 0x54, 0xc5} + } + }; + symmetric_key key; + unsigned char tmp[2][16]; + int err, i, y; + + for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) { + zeromem(&key, sizeof(key)); + if ((err = noekeon_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) { + return err; + } + + noekeon_ecb_encrypt(tests[i].pt, tmp[0], &key); + noekeon_ecb_decrypt(tmp[0], tmp[1], &key); + if (memcmp(tmp[0], tests[i].ct, 16) || memcmp(tmp[1], tests[i].pt, 16)) { +#if 0 + printf("\n\nTest %d failed\n", i); + if (memcmp(tmp[0], tests[i].ct, 16)) { + printf("CT: "); + for (i = 0; i < 16; i++) { + printf("%02x ", tmp[0][i]); + } + printf("\n"); + } else { + printf("PT: "); + for (i = 0; i < 16; i++) { + printf("%02x ", tmp[1][i]); + } + printf("\n"); + } +#endif + return CRYPT_FAIL_TESTVECTOR; + } + + /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ + for (y = 0; y < 16; y++) tmp[0][y] = 0; + for (y = 0; y < 1000; y++) noekeon_ecb_encrypt(tmp[0], tmp[0], &key); + for (y = 0; y < 1000; y++) noekeon_ecb_decrypt(tmp[0], tmp[0], &key); + for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; + } + return CRYPT_OK; + #endif +} + +int noekeon_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize != NULL); + if (*desired_keysize < 16) { + return CRYPT_INVALID_KEYSIZE; + } else { + *desired_keysize = 16; + return CRYPT_OK; + } +} + +#endif + diff --git a/notes/base64_tv.txt b/notes/base64_tv.txt new file mode 100644 index 0000000..01c8a4e --- /dev/null +++ b/notes/base64_tv.txt @@ -0,0 +1,35 @@ +Base64 vectors. These are the base64 encodings of the strings 00,01,02...NN-1 + + 0: + 1: AA== + 2: AAE= + 3: AAEC + 4: AAECAw== + 5: AAECAwQ= + 6: AAECAwQF + 7: AAECAwQFBg== + 8: AAECAwQFBgc= + 9: AAECAwQFBgcI +10: AAECAwQFBgcICQ== +11: AAECAwQFBgcICQo= +12: AAECAwQFBgcICQoL +13: AAECAwQFBgcICQoLDA== +14: AAECAwQFBgcICQoLDA0= +15: AAECAwQFBgcICQoLDA0O +16: AAECAwQFBgcICQoLDA0ODw== +17: AAECAwQFBgcICQoLDA0ODxA= +18: AAECAwQFBgcICQoLDA0ODxAR +19: AAECAwQFBgcICQoLDA0ODxAREg== +20: AAECAwQFBgcICQoLDA0ODxAREhM= +21: AAECAwQFBgcICQoLDA0ODxAREhMU +22: AAECAwQFBgcICQoLDA0ODxAREhMUFQ== +23: AAECAwQFBgcICQoLDA0ODxAREhMUFRY= +24: AAECAwQFBgcICQoLDA0ODxAREhMUFRYX +25: AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGA== +26: AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBk= +27: AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBka +28: AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGw== +29: AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxw= +30: AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwd +31: AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHg== +32: AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8= diff --git a/notes/cipher_tv.txt b/notes/cipher_tv.txt new file mode 100644 index 0000000..f144fae --- /dev/null +++ b/notes/cipher_tv.txt @@ -0,0 +1,1539 @@ +Cipher Test Vectors + +These are test encryptions with key of nn bytes '00 01 02 03 .. (nn-1)' and original PT of the same style. +The output of step N is used as the key and plaintext for step N+1 (key bytes repeated as required to fill the key) + +Cipher: aes +Key Size: 16 bytes + 0: 0A940BB5416EF045F1C39458C653EA5A + 1: 2B20AF92A928562CF645B1B824F2E6D9 + 2: FC29C3356937ECC3159D8D6EF5E883A1 + 3: 4C07B5A2EF31A3229C87AB2E4DE88602 + 4: 93AFA1147E793FFCC3D852695A62D008 + 5: D4BCC317DC9AFE0E6C7AD1E76F79DBE9 + 6: FEDB3371F3C65162AFCCDC6D18C79A65 + 7: 4AF2A76F93F07C14161C16B5C176E439 + 8: 00A1A596AF7CF44FD12981FA12CB1515 + 9: 8013D7006AB38AEBD40D0DC10328751C +10: 81A077F3A262FA4D00D98EE4D1BEC390 +11: 0CCBC99A3135F26D2BE824D633C0366F +12: CDBB5568610AD428706408B64DB66E50 +13: CE94461EB0D57C8DB6AEB2BC8E8CE1D2 +14: 06F14868F4298979462595C0FBF33F5A +15: FE22A7097513246074B7C8DFD57D32B2 +16: 0F2D936610F6D9E32C0E624568BB8E6F +17: F32BCD92B563D475E98322E5850AC277 +18: 6E6FCB72930D81469F9E05B20FD406C0 +19: 42FF674CBA6C19C4AD84D42816173099 +20: 41C12474A49B6B2B5E7D38E03A4DD4E0 +21: F9E234E3CE3FCED184C775B6140AD733 +22: 7EB5CC6B183D8B3EB4FBA4717CD8838A +23: CB6C5D78F9721E5BF8E980F0EDCAD4AF +24: B3F20EF6C26FD9301576D82DA6D50809 +25: F9375037377D86599FB4F241166C43E9 +26: 98BAF9AB7402479C2DA356F5DAE35D5F +27: 58D1A8E0DC3BC53FD995BB0F60F25FE7 +28: 0A75C0D22D2627C97BA2A7344B9B8C74 +29: 88C299B2F8C9EDAF86A301BBF534BDA7 +30: 755E3A17420281F2C619588A6B521FF9 +31: 0E540DD25C0C147461146E11F832A63D +32: DC5B58691C6BA5B243036A41301BD7D1 +33: E9299A7336C2D8A51D6C7E2BD1B8F054 +34: 78CA6F682FC649DB289DD62D28D3A22D +35: 98D96EDA081DE416083650B22BD3869D +36: E747DE96D122CE1EF6F89BDE0FAE75FF +37: E48DDF2EDDEB54C861A1E42F5B649EEE +38: C650C2CF1E903B7F9C8536A2446CA762 +39: CF0BCDCE0F1FE7EB40016C1231FB2962 +40: 37B1C8BE3812147E0D5D115A797663EF +41: 45DD8184581049C4B28FBC0809690C5D +42: 11B0D889F96E677EEC2E934E9F7F5398 +43: CEC30BC1128A96CD506E406B5ADFAE19 +44: DE67D5439BF83D5338D53F362FCF79B6 +45: 724FBB2D95CBEABC568AA44941D9B6E5 +46: C63F480DA3C73B2A661F1FBC3E4D1F89 +47: 225CD18789D18FF09C982EF38AEF0AAF +48: B493DEC7E3D11911DEF8788102453670 +49: 23E0B12A67DF025CB77CBDF9E295FCAF + +Key Size: 24 bytes + 0: 0060BFFE46834BB8DA5CF9A61FF220AE + 1: 597FA00D03EDDC81C2575B4DD6B6AEFD + 2: 4881E4EF69005DCB9110BA327CAC8460 + 3: FC4A968AF65FCFF45E4698455918673D + 4: 3079D7B27A3DA5C0805A61CC37109EE0 + 5: 9B3F2C7C35806276E2C53826EC1B3C84 + 6: FCDFCB1FD9FCF1B63E1AB6737FC154E8 + 7: 4A8012AFD410D29CE2CEE0FD195EF9DA + 8: 9F4201C4174C71A3AEF8FD6822197D67 + 9: DE3E5E98DA60E895389A1C17E3D50DA1 +10: 20C9064A076C01D1BC121A5A2A1F913C +11: BA41A36CD24B515545B8B464B244E5BE +12: 2CC1DE9DBCAC45269C6DBBC9203095F4 +13: 2ED2499CFEB30203E6305B3E1C329C4D +14: FD709FC0AB48B204C95B74AD189C8832 +15: 7ED298B472C53A4CB7A3BAE588805E86 +16: CB0C6FE2BA76901F9EDE752634DCC31D +17: 6C5CA6EFCF7101881507AB8770ACF1DE +18: DEC3C5209E98BBFAA469C5FE6C02A674 +19: CFAC040C1198C8264679CACEAA7E9DE7 +20: EF990992EBA8ECA7E5F95E3B9D69D3A4 +21: 8FC1B640EB55A96D08D83D1184B77769 +22: E1F3DFB9D055BCB2D6CED6DCB8361BFB +23: 6621F47057706F2A079819DBC0197B9C +24: 882611AC68778CBD6A46FB5DD4611A37 +25: F35E1367A283CC641FBCE26512A8F2F1 +26: 5A4A71F69056CFBAB67DDA777F5CD945 +27: C446F2BFAD060A9E9E17F71B05ADABD0 +28: 1F0E50F71A67FAA7D169A7A1017FFD65 +29: A6A38588848915509451A2354D2AAC8E +30: 4C887574F2C5DB00ED4FBAF814A70302 +31: 1B642944162A049CCA9FD0284D7AB4C3 +32: 431BD9293C5BFD12F948C255C838880B +33: 32CD23A30039AE2FB80B804B905362B1 +34: EBB30E07E7517580A645CD1B5F664182 +35: 292F2BB28BB172620B05C7621BA347D6 +36: 46C06E1223F392D57B98EFCF4C832C18 +37: 451DFBAD2AA92080204F85432236A42C +38: 768D6206D2B3DD1B9C26FAA5977A6477 +39: 3705F9CEBFE8F91ECE07F84578C05494 +40: 085EB0DCF360F5403FF1E7402A0F7A03 +41: 2A0D56F2E7C7FCE3095F511BDE4AD9A2 +42: A8AB2F3643A61AF164F99FEFAE2CE1B4 +43: E73FD4B1FAE0E5E6A6A31CCC2AF96386 +44: 578E84FD1AA16FF350374E4FD5FDD529 +45: EEAE301DD57084801DB01F8B9C4036CE +46: 1C44A93B404298327857F71962E0604C +47: B5F64CD5835C85A68DC23E26D4B8FF80 +48: 6C6F97850A87088AF195D0500B3F5D78 +49: 0BAB3A60A25CD1A750C2C443AA01C57A + +Key Size: 32 bytes + 0: 5A6E045708FB7196F02E553D02C3A692 + 1: 5F7229D6AACF0DAFE3B518C0D4ADBAB4 + 2: 96477F47C0A6F482AC4036D2C60FAAD8 + 3: 7F791D54914F12E9F0D92F4416EFBEC0 + 4: 87DDB19415BEDC42BD361FE380553C5A + 5: 8EDB2A09DC8731DB76D9F67A03AC4D9E + 6: 269A7C08C28D5E4D9355DDBA161F862E + 7: 042A3397BA5029C443DD76755008DB2A + 8: 469C82A94BC5F7B2DF57F0CE1716EE74 + 9: 5A84A93077FA19146078310035F4B7E4 +10: 28CAF1C0D811F86CFD3C5EFC30DF79F9 +11: 05B575D06C2D593B708F7C695CE97571 +12: B7E8CACF0A0BD7F2F5DA0B09CC8B8AEC +13: 0ADDE90F66F1BCF38CEC63EFBF9DBD46 +14: 9BF99E7F5B8F176DD686AF017D5196E2 +15: ABC189EE80D4A4588B3D54DDACCD9778 +16: A57405378580B1E8A8D877791300374C +17: D1EF03F72FAB3DB68022FC60A2CEC13D +18: 3D2406231BA17FF7CC973C5E203872DF +19: C3E07233BD101502953D6186001838E4 +20: DC281C0CE02A83098C80D6C9463F3449 +21: A923023D2390B2230FCE9217776AAAFC +22: 92E28E69009959FB84046C5ED1B64D1A +23: CEF8F684EC64A31C651280CDC942DFC2 +24: 5A954684B22691F9CFC60442A654EF61 +25: 56A38A0D93188BAA50DFAF2CB799A76C +26: 54503340C5DE26679AA5F35215DE85EA +27: E74BFAF64946DFD699583FF9C47A1EAF +28: 01F234F9868B085E9B1A2EC84738E2DB +29: BBCA3DAEAB24EF25BC7B623F4D9FD680 +30: 3956C880F7F7D94ABC259D3D86157F27 +31: 4672C2149054C839C537BDA1F5BBF8F4 +32: CF1E9ACBEB391062593BD88C7948F64D +33: CA5B4E867AE9D8BA2D4416C908EB99F1 +34: 36666180C768636CF1708CC5C85A6875 +35: 53E396D2755218675494C7AA515A2310 +36: C2B7D31A59A602A65E155F80353DB83D +37: 0EBCE19FF6FC03E327A2602F858D835E +38: E47CC2A5E6C7FEF185806E2CFB304D91 +39: D61F15FF75E0F523FA3872132A09AF42 +40: DCC25495052980986AE30756BA0417DA +41: 451BF5B7C1F1AED9F3D5E18A391EA4DA +42: 1B6B105C580083D23F3A8EACE41B7984 +43: 8C2F86CD6C86B67C9EBDCAFC5720E4F8 +44: 41360BDB3E4C6836BE0D15B659CEC5AA +45: F972104AD851BAE0AD963817A3F03F58 +46: 396095F7C102B5A238110DD3D6D4ADFF +47: F58391AEB9A5D8BB32A3055B37556E81 +48: A23789B146CE89C876F3C331901261D8 +49: 2684AF345C4B13FA154E93A3E2CD2A90 + + +Cipher: blowfish +Key Size: 8 bytes + 0: 84BF44A1442B8217 + 1: 3981205BDD22C01E + 2: 0ACC5CCBA118CD07 + 3: DF76980D5E089145 + 4: A8503E8D849C599D + 5: 5E56574687038F5F + 6: D63296B036996F50 + 7: FD2FD7A0669A9E7A + 8: BC6583720A962585 + 9: 4B38C2856256103E +10: 48A4FA354DB3A8A6 +11: EF97C32734BE2A10 +12: A7467E9C729F8123 +13: 04D2507F9C4B5854 +14: 57F76A4D406B22D1 +15: ED0A3B26D842C8F2 +16: 047CB457E9730CD1 +17: 9F13BB1A97BF5E2F +18: 628CA4F77161C95A +19: 37C7D8EF718DFD50 +20: 2C9A9C655B839B1E +21: AB222D66579DBE0D +22: 57950CDEAD6FAE88 +23: 67AAB3669431E403 +24: 6B35C87144F6B748 +25: 94C2E8A1DBC963C2 +26: ECD68F56EED1F78E +27: 2E7BE0B866B1D3C7 +28: 6671DCDCB3D8EED4 +29: 8ACBE7A2F77FBB35 +30: 0BF0AC4EAE284F93 +31: 29928AE5DC8A57C6 +32: 84E48C27E21264DF +33: 4EF0E943E4F48ED3 +34: DA155BEFBFFD2638 +35: 611EC83E0931FFBE +36: 3BDDEC15BC543A92 +37: D7B9564BBAEE19FC +38: DE44907E9F0A1F11 +39: C8638C0594D13614 +40: 9E67F1B15418BF14 +41: EDF531A083F72852 +42: 7E5F8F9A72890BB3 +43: 2A0B060E3EDDE9C3 +44: 9B4B0F6FE6511106 +45: 328658F222C7FCE4 +46: F6F1B50B4F9F9C93 +47: A620519E69952F5E +48: 24DA24DFE96AD818 +49: 226C43435FBDA34A + +Key Size: 32 bytes + 0: 46CDCC4D4D14BA2E + 1: C079641BD6584E5A + 2: 38828DF8B4C4920C + 3: B4ABCF6B78A721F3 + 4: 8E7E2914CBBA708C + 5: C0EBE7002C888495 + 6: C60F404DE7CF9B78 + 7: B29E843E1771EF26 + 8: 983033386CA6A09B + 9: 76F1F89AFDCF7130 +10: BED4E2114F4376FA +11: 879A2B9D19AFAB87 +12: 366201BC87532AE5 +13: 6F409580FA907A64 +14: F7A202F00A38863E +15: 98B0A9C79FFC27B1 +16: 1CB68D9BBF8A1A8A +17: C21A2C54E5471D23 +18: 76A81C3DFC149934 +19: C7A0627412FC323A +20: A034684D7058E7A6 +21: AC87722F27029BC2 +22: 36A6C2AF10245E3E +23: 1F85B90D11217EBE +24: 9C2A0C383A4AB7D5 +25: 11D5C689039CA179 +26: B0B38C7077E1450B +27: C59C7DCCC3B8A1BB +28: 9BC539F29208AC24 +29: 8546F17C77C60C05 +30: B189C3E92AF53844 +31: 3C7689163B8D2776 +32: 6AFEB9A0671156A8 +33: 05514E39F2990008 +34: C941E31A2A1F42BF +35: 87C3777C74A730A0 +36: 2861667755C8B727 +37: AF75A0312433B151 +38: F76939331E9C9792 +39: 819FF8C81FC7C8DC +40: 31E7B07EB03D170D +41: 696E5EC1A741170E +42: 6C5BF0E0BA48FEC3 +43: 6D751BCCDC475797 +44: BB5A91D0CA7E60F4 +45: 7F7EC0531C88B14C +46: 9F302392529B70E8 +47: CAC9A1A88F09AC1D +48: 39D56A652E02D5B0 +49: 13641D42BC126517 + +Key Size: 56 bytes + 0: 373C66BBA50EB9CC + 1: A4E8C602AE3A2CEB + 2: A59F08BA78502F32 + 3: D0D4968015F4E4FF + 4: 0D3C2F291E6C2EE0 + 5: 3F99F5DADAD5FD2C + 6: 5BA41EC1A506396D + 7: 0BDE3B5B50591D35 + 8: 5C4A6AEFA69A115D + 9: ADABFE96D6D159E8 +10: F97F0B9C88ACD5C0 +11: 8882A163F0F02BB2 +12: F00556C9F5A56A32 +13: 257615BEC96CC228 +14: D58DAEC547DD8B89 +15: E677F4953EC44097 +16: 20156D066DC37000 +17: 6F18E01C6FDF947E +18: C8DFF24F12621237 +19: 032F91C5119AE308 +20: 394194AD8BC1E5CF +21: 6F24E937F3925581 +22: 086A4510D95759F3 +23: 073204BADF0EE942 +24: 5BC8B8E402D90F43 +25: A10B7E9D01DD3809 +26: 22C0B183AFFDA506 +27: 216306AE6DDBAF3F +28: E275E1F52430A1FD +29: C3BDB49D588D31BB +30: B860818C5923B688 +31: BE1BC7A444B0E141 +32: E4C4B67900DBC8DB +33: 36D7B7ECB6679A9C +34: C1EAD201EE34BEF7 +35: 9ABBC877CE825B14 +36: 3B211121C0C3C09A +37: BE3B34FF2E83F5A7 +38: 46C2B3E628A53EAD +39: B7E7DDE16C7DFF62 +40: 3C9A14C4226EBCC5 +41: C5FD46242DB29704 +42: D45A96723FF62201 +43: BB015D10878CF70D +44: 71DB021BE398D41A +45: 06F52D237F06C260 +46: 3552F47E8CCFC73F +47: 769E33828AD5D88E +48: 659861DDF080AA67 +49: CF7A13782F317342 + + +Cipher: xtea +Key Size: 16 bytes + 0: 256004E1F55BC0C7 + 1: 2D385C151A691C42 + 2: F93BFEA758A7DDB4 + 3: 2A905D97C0CA3E48 + 4: 12C7C2787B913AE6 + 5: FB24B1F32549EF59 + 6: 2A8BFF867FB4FF73 + 7: 5692243526C6BA77 + 8: 4CD423ADFCDD1B6C + 9: 9B99AFC35EB2FED0 +10: 416B4AA4E07DA7F4 +11: 4DBC9052ABFF9510 +12: 8AF9457F8E599216 +13: BC3CA2B1C7267395 +14: E4BE31DF42282F7A +15: B344CA8AA57E9E40 +16: 57A1F94CD2F4576D +17: 96177FCD28BFF1BB +18: 78A1F63A0EBAAC33 +19: 5F3FCBCD7442B617 +20: D6F7CD5ECA688967 +21: D92EDF70CBDE703F +22: E2E2C2EE5D18E58E +23: 4BF00478CB7833C3 +24: F9936D550815FE8F +25: 19A3B07B3E47D7D8 +26: ACA441F099A7E30C +27: F70183F199988E3F +28: 0A41FC22F369310A +29: ABFAF40853A4A38C +30: 6B5D29DB1155D96B +31: 0DD0C08A27561D66 +32: 4C56E22292F17AA3 +33: 3F925ED65613DF4A +34: 521B4C97081DC901 +35: 2B1EC3E1C8CF84EC +36: 2A412556F42A48F6 +37: 0A57B8A527DFE507 +38: EB55C9C157E3C922 +39: 6E6D6E9AB925ED92 +40: A4C5C90A0D4A8F16 +41: 7F9F9F658C427D55 +42: 9A5139994FF04C3F +43: 9054771F027E29BC +44: 90543E7BAED313BD +45: 5DEC1EBE6A617D36 +46: 19AB6A708CDB9B2D +47: BABB97BB5CF9D4E4 +48: 2C2ADC05AF255861 +49: 52266710153E3F7E + + +Cipher: rc5 +Key Size: 8 bytes + 0: 04F6B9B18E6828C1 + 1: BEA50D165E50EA04 + 2: 6F3728FE19F09B03 + 3: C682C26278B372FE + 4: 78BCC81E144E1B0F + 5: B62775716366450F + 6: 5BC49690F97CBCFC + 7: 359414E9EACDE379 + 8: D3331D8ECBF684FF + 9: 13129FB10EAFC82E +10: 7F29218421CC4B5A +11: FC225A4F31A75162 +12: 29BF8BFDA8A15D37 +13: 6854AC5BD98EEE95 +14: DEF05AB6D102E992 +15: 317C3EA6F0600016 +16: D6F3658B2E80B77F +17: 7C1DF7ED6C92C23D +18: F8665145BAFE28C5 +19: 9D8059C34B79F0EF +20: DC8D1617D3EBC7DB +21: 2D8FF59FCA19BE6C +22: 5C6956743715EA13 +23: 91160BE1F4F3D4A0 +24: 1D482C2359EC93F5 +25: 9C21D1A3755A7251 +26: E48D1BB926D51E63 +27: 08A054946263F617 +28: 9C900BA37199B7C7 +29: 0C6C58743EC83082 +30: B24197EEB5603D3D +31: CF5B735F8A492E49 +32: 337C504698BBE553 +33: 3A2BCCC88BE9ED51 +34: F3E9241743203ABF +35: B67BCC625815C585 +36: F8E96E4EEBC2566C +37: E27D162006C67C8D +38: 08CE8C1A5E3C169A +39: 0CF8AD04125EFCD8 +40: 6712F9F044864FAA +41: 0FD465AFFD64085E +42: 6BA8C82B3974391F +43: A5FFF24CE9659357 +44: 0947F81E1EB4970E +45: DEA966CA50243067 +46: 1F1BE4866F48E39F +47: 03A7D7CE793F52C7 +48: A1FADE3F801B414A +49: DE7DA6D14A50E305 + +Key Size: 68 bytes + 0: C8704ABBDA9624EE + 1: C719C645E301FC16 + 2: 32D82553B0E35EF8 + 3: C63C77EE6C2A6E36 + 4: F84EDA1E77ECB5F0 + 5: 382C1E72AA1FD1BC + 6: 6B00939F535F9C83 + 7: 3CE0825AE10C2B0E + 8: 1F9E7738602BDD0A + 9: 9273E7933CED0B0A +10: 4CAB45EEA45C32DC +11: FD0208C6A89FB519 +12: 520D8E6912E9551D +13: 5B88684544868BD5 +14: 32AA2A8EE58135D4 +15: 281045702DD38766 +16: 26D68E073C996747 +17: 23DFB9E174D86192 +18: E32FD5AF5101E45C +19: 3DEFB679670A143C +20: E616394D859BFE94 +21: 217B9BE0ED47DDAD +22: 4F7901A5620EA484 +23: 6654C042783F5737 +24: 752AA74BACF9BE65 +25: 2FAEBEB8B325F89B +26: 6FEA020B058F32CB +27: 2A32682A36691665 +28: 338C8AB628A30105 +29: DFAE9DD082DFE38C +30: 51B451C29DBA19C4 +31: A2993DA9B8C1D5FD +32: 24D92FA331E2F93A +33: 821A961C0524C89D +34: A07BF305EE8964D9 +35: 981652361262C5CE +36: 3DD770C3761B695B +37: F36359AFE1C8A07C +38: BEBC629B8938F4A3 +39: 2E31DC53F77898B3 +40: 52E4104C4E8E6901 +41: 75C912DA610525EA +42: 2F280F70963F82DE +43: D7E3FCCA75AEE5DF +44: 8EBC7E825A14A2BB +45: C1138701F64187DB +46: 1294E21ED2550DFA +47: 577820D772BE2C8E +48: 48CE93C46BFD33CD +49: 3B50D264382E03BC + +Key Size: 128 bytes + 0: 236CF0A207576E8E + 1: AC12D8F1AE55F057 + 2: CEC4230F747B547A + 3: 61EA1B510D033B26 + 4: E064F51998E20804 + 5: 6247797DF02BAEF7 + 6: D25A766244063A7F + 7: 2C2B3FDDA0E07067 + 8: 04EED646C3F6FF90 + 9: 05487E7702865E4A +10: 6C0A92AC23ED07C5 +11: 6E54E768C797F797 +12: A7C53BF7B252A884 +13: 731052795E12C80B +14: 3E4DAD15A826C43D +15: 10B1191B4012C2A0 +16: ADD244B33AEAEF7E +17: F6CC7B5F0885E056 +18: E23489F3B7BE438E +19: B0C27661692FDE4C +20: E81CE014DA769F07 +21: 7A8BE0D2D52623A8 +22: 082F444E00D5E127 +23: AE42F684ADD1DAC7 +24: 9061BA686F76A450 +25: 9BEB7141B8F6F5F0 +26: 38CBA9933AEF85E7 +27: C66F4245901CB341 +28: 8659AA47E6B06BC3 +29: 357AB20DCE2DDA3E +30: 236689C2F36976D9 +31: 331EFD7D5CF7AD50 +32: C373526C2D44DB80 +33: 79F7ACBA770F5C92 +34: 64325C5A67F364F6 +35: DF2F720829FF1694 +36: 9EE17F47ED487BC6 +37: C41067896AF4CFC5 +38: 5776E1E5FBE59933 +39: 07A05B1508B739E0 +40: B19EF72A65B3C035 +41: F8BF5FF4095C0173 +42: 7F1226C6CA7B4072 +43: 8A6C8F26A97DD33B +44: 62948A9A627E98AD +45: 9EC58E3F8A477D21 +46: A656F285AE0684B4 +47: 8489690681A53EE5 +48: 940915E733721837 +49: 1221956BCEE0143B + + +Cipher: rc6 +Key Size: 8 bytes + 0: 6533F7041D69B9B883A5305180A85520 + 1: 496683D6356950E8F4AF4582630BE46C + 2: CA421828FCFCEF2F042F6D81F14CBE76 + 3: 92DB67F2F057858FC806E071D239F245 + 4: 203CDFE0C36434AEDDBE2DA68ADC5EF0 + 5: 8EB23BDBD58A279C1F3BF75199FC9E34 + 6: 8FA8BB4E772E09DD1EFBE03090E77FF8 + 7: 2018803BFD91D157AE20C6E8FF1894B0 + 8: 267319634294F0684AFA7B26EB612B3C + 9: 108745E1F2E80864D9043582CD5550EE +10: E4F9EFE5A6C426BB719EA17174890D0A +11: EFFD4CAE649740B3309692AA19ACA227 +12: EB909E6D0789F649538E7EA1686FC0F9 +13: 0216851E23EDAE52D9964939DA0A7493 +14: D6A9CD3429D1679D26A9599EBDE5409A +15: 5DCDECA6E89A7F0EB40649EFDE6420AF +16: B74FD556B06C07BA8D9E517348CC66CC +17: 9A22CB5B73EF1DDE68A5AEF1B1510ECC +18: 77F78557143E08A7449A75A13098FEF8 +19: 548FE6700BD17D0AE247B07C2F1AB0E7 +20: B7DFD8CB428A36733BBE9A51CF45C072 +21: E7E8B7AA2D93E3DE99C543A473CC6760 +22: 3FA5821248B0F0AEB5CF00EEF7958F5E +23: 0A655AC6C51DB33849BCDA72DAE106F1 +24: 9EE93EAB01E1A1DC57B698C266469481 +25: A7D398720E0ABA2D0D143D8306FD5AC8 +26: 98A46C94125BD2E5600BD26EEA420F2A +27: F4789EDC3C50BC4186816F14A86403D1 +28: F8AFBA8EC652EFDC3AF5EA5CFE143E16 +29: CEEEBD4B6724A30E1859A5B4EF9B2B3D +30: 766715B4C4FA7CD4B365A2A67C79E48A +31: 92C5EB7BE61155D79DE0A6F55715DA22 +32: 42CF0C9B2BAACB085CB1603688037D0F +33: 6C4BE816F7B573CCFA8BB6E399EEB17F +34: B6D7E606CC99D267ECCFDBC006878691 +35: 2048B58B74F9A721B2E33D2EB86F5991 +36: 3E458C1015ECB08CC7B8980135E71893 +37: E4E28A032CF2F3C8262CD4BBE7A4CDF8 +38: 701EAA449AD9E5AF81DF3F436AB25620 +39: D1C3FB7C16F5249503EB389A692B112F +40: 7012790DB65526DC87F9A2BF0FBB5664 +41: B782A3104FFE65DDB340F713ACFFE25B +42: A155F033E4536FB1176EBDF9EB5FEC4C +43: 8898BCC7A008127014850D5529327352 +44: 8F4B3BE150FAA0371CDE69891E52A3C9 +45: D371C8283F68DE983C98D98A7563B934 +46: DEB679915E8F0D0B65B37918BE4596F7 +47: 84D74F7FA199304A47BB37B8AF893CF0 +48: 5367B0187496539F6DF6CCE0965B376D +49: 4B9C6011D43CF2D8FAFA2E7105D85024 + +Key Size: 68 bytes + 0: 6BBF763FF30876A4BBB68A7E7E290770 + 1: 59852279E82E98B8B680E5CEE12BB99A + 2: F96989565E5B163EA483FF74ACA22DC9 + 3: 221F7A410F5AD73C1C67DEBA99683E0A + 4: 55F058D1D9B8C372E2A28AB6E953A851 + 5: 24A8F7E07620A55D69CC3981B92E5CCE + 6: F4D9DA95BF66FE28BA3A84E77E62822D + 7: EE7EAC2BD34DDE6F83E6D4F23C0A49D3 + 8: 4218AA697FB7C5D897E66EB00A9FB489 + 9: 55A8CDF8608A3B1A6B14275E2258A096 +10: 18D50743982F5C8A5C528BDB5896CDFC +11: 391403B889F0CEE865893EBE9F1BF90A +12: F3CA9C30C163C510432D3207DB6967EA +13: B14B6574DF53257BE4508DBE78843B47 +14: F52F1E5FD6FB19C1F5466276F9C33A97 +15: 9D5AABA86E8B65E4F633B6EDE17516E8 +16: 9038CF746F722DA1A0C34461359FD378 +17: 398E317E9CC074C2293B59598F72EA64 +18: 9D75D897D487DD2B5BC534B4B223ADD1 +19: 6C6DFF734BFB9700EDD6B3CFC6E311F7 +20: E27591407CA9771F227A5B6B3A77C928 +21: 1618F15FFA8E2692A3B3EF8EB6151427 +22: FA426AC6161F31F0D63FC9DA97A6A393 +23: 1281869E9959DED2CF75F50DA7FAB66A +24: E8BF17E4B76D6DC5C1D07DC80970665A +25: 9A869B6C5EEF391C7E7C4585FFD9FF3A +26: 59564F799AFC984D39A8168D1A30C8C8 +27: 1D3927AA2E2C48E6CFEF88D04ADD30DE +28: 39BF89DE1365DF15A8ABA86856ED074B +29: 0CCC4A4DEB36A000E7EB271F5EE54543 +30: 26476623D35A514B8833D868426A2BE9 +31: C3C85993EA15AB2D056D670707851802 +32: BF5F7ED18E1320BAD536DCEDEE1A9AF7 +33: 337BDC5FF0F7AD44E6A3F5D6712BD5DF +34: 7DBA76B3D9C818D0CE1A530BC79E77D2 +35: 20DF55E617CD2598F18534DA7A22B555 +36: B0A0C1BDF9E81B4F07F47D31A9CC8408 +37: CB9586F4B27F759B9B9C6C7DB01D26A8 +38: 1E79A2894906A64098AC43799CEFED38 +39: 82FA120F237EB0B3A1F8B52379B8346F +40: 3DB9848603E3B1134585E5C9001D119B +41: A750875900E244996887EC995131D151 +42: 12133748D3745F77C161470A921F73BD +43: A265C351694574B44517FDAD8816133F +44: 5E50CC8281C2A69FD376250D99620DD3 +45: 443ABBC1AD5605A0BA05B8E6ABA5D2A1 +46: 73546A87B39C54F0639EBEC118ADA007 +47: 380244C822817453C75405B727D67C4B +48: 73F1E23DFF05EFAB5D39E503031C4165 +49: 8030071491490590A8913AE4B5D082CC + +Key Size: 128 bytes + 0: 24B06811BD97AE9512B3799E3189DCD3 + 1: 92DBA6269E880F8D8A09143D792A46DE + 2: F956F459C333DFBA4C6A309C613DD661 + 3: C31488EA551CC0FC8885F6817CA696FF + 4: F59634FE907F9DF9467BD1059F82DAAC + 5: 051AF11DD2FCF742169B58A786128CE7 + 6: 87326A3A4A98CC15B23DFBFFC5AE16D3 + 7: 58FCDE2E88A79D5682729ADB4D971142 + 8: EAA787D68EB68CA79CCC6BFAC3BE9247 + 9: 8BCF6980AEED36AF38B68A50DD454AF0 +10: 4B0E31AE48E903DFF52939800BB16DC0 +11: 19766AA929B40840715D53D9170C986F +12: F9CAEB36F03CE7B3BB363AC7EB3ACF99 +13: C8E34A6BDEDA4DB836DF3D863D02A6EB +14: 370547CEA441FDCBAFD281A8653BE2D4 +15: 77E0F33343158A8C3AC3C6D14FD69431 +16: 7A985B1368F842C644538C654D081FD3 +17: 60E0C8933F43D40003030196E8E881AC +18: 3473474B58AE6BC7582ADD7AE24711B7 +19: 75936C8D46F6D5AF5C7EE0E8DCEB5AB2 +20: 4A04F619FB0E05F7B07C43F4B9F2E134 +21: FD53A5A7F4F0B9D933E38D9F07AC88CD +22: F62EE43B20F582AC77879AD7E66FCCAC +23: 4436AD771624896683D7D29E8879F89F +24: F88F3C0EF2B9FD0CA997BEF17787DA2F +25: FF5576F42CE9A0665A1D6A2420A691D0 +26: C077D6AEBA65B61CD1A9AAE17FCFC04D +27: 84D0D7C52D6DB3979BC3F6F34456CB91 +28: F163121D9EB7569CA7DE3B7619E0BE51 +29: 727D23FB43215467B57DC67A8890CF26 +30: 60BA577F3C6627267D7B33E693FB7BCB +31: 82C66B23586CCEA2AE1480B469B3F3C3 +32: A65092726D6CF2F77CE00648E2D117B0 +33: EC30662CBA891A3380B846DA6C64024E +34: CE1B253FBCE36B217ED1EFBAAAD2E783 +35: 9D963CD5E65A9ECD2DAEE93B6C6C1178 +36: 1B8E3D07E7BD4BB4248B6A7DF8935980 +37: DBC3FD5888B80C4CEFC6C5E170E271CE +38: 307CA8CDDFE5DA152B66E10346BB2E1C +39: 8858250F933650D978B403A4504EA581 +40: F06005FA6E56E0C0D96988A3FAD359FC +41: 816CBE37FDE3719804DBFD093E3FD87D +42: 4878C07B127D696214393DDC66F5EB36 +43: EFBA6045243050C0D8D82046B17008E8 +44: 3D30C3E5892D32BA3C685DC5B186E959 +45: D4A4C41F0E6687E4021FB90D7A8A9F81 +46: FE1057B2013308C4CE839B4186F43B4C +47: D7333AC65F66ED6D4BB8D069E265020F +48: 33C262F58BF0D91DF2047E799BAA5F37 +49: B960A18764D7A6E17FA1F88487EFF192 + + +Cipher: safer+ +Key Size: 16 bytes + 0: 7D42607880B424C27E5A73A34FECE686 + 1: 1A99D469F1946EA46523083FBAA79CBB + 2: 831385E400FD681C8A30AAD9477F1ABB + 3: 5C1BB8F259CDEC2C1BE0B803C7D9447F + 4: C57C1CBB18D87FCF72A87B247392752D + 5: 1625183B0C595A33FE0E8AE0DCE40ADE + 6: 4AF3A9D6733DC4FFF3422AA5BE5ADC94 + 7: 853133894C87A23318DFAD2B247FBFF3 + 8: 8C7F68E01A8413D19B9A479246E54722 + 9: 8620898ECD3BF91A47CC54E6D9987FA7 +10: 33F12ABB7CC6A9041543A2073AEDFFA7 +11: A096E46F2834F79C096D0B655EDC9A63 +12: 3DD0D7824A87C9F5D8D25F5AF57E70B7 +13: 6B7C99E5CD29AC1C5A8D66AB460E5AD5 +14: 95A9F6009AB4DD2AC7E8E45F36D91E9C +15: 60CCEFC6630329C341782B17365995A2 +16: 0276C96A7B1191BC16C8A9C98468DB05 +17: 1F352CB77C21139C058837B8194E3E64 +18: 2DB8E340F58844705F217551782F6B4D +19: 34E99832E0722C5AE8F0CA1A50E9E7E2 +20: 7E1538DC10C1F56C3723A87BFD127743 +21: 36B9714A8ACDC8B8A17E85E2803A8C88 +22: 11848329B0DB9DC7768C07D95F0CF662 +23: 93ECEDEB4C6369AC56AF1F49345720A6 +24: A3ED7F9D17067C2650728E266B623124 +25: F33574590B435D1DDBBA925F0D0EA8AD +26: 87E542DBD40DCBD80C4AB52555C264C1 +27: 6D806991AB8E3604C8267AC1EBEC2E21 +28: 4B7333F87EBB46BB2A8ECD392C85A12B +29: 4FF49ACA62898F558AC065B66CAD0234 +30: 62DE7B2133B09544EDD0DF66DC4F5E2A +31: 82195B39FF7B8A85D7F0EE52D19E510F +32: 24FA56176A4F0B37F851CBAB176C9702 +33: 85FA9230D9B93CDCC0752FC738211703 +34: D441132032BDAC6715F4453CBC2434D8 +35: 438AB9BEA8A900368D84EF870EAF7E84 +36: 433BE5BFE1529BFA7C5688CFE3BD4DE5 +37: 2A79FB6F37AA08533445B8BEA5098EA2 +38: B9C986EE45D204B6A1CA152944912C9F +39: 8289C9F78760D02AA71873FD97E2ECB8 +40: 48B0D1244523165055BE9A5E95CF852E +41: 471E211E5E784C2AF476DB3CB555CF35 +42: F290CBEB1F1009D250F7B12E044B80C3 +43: 1B9796D80C3976FE3071B1C01154D42E +44: A80E21A1A1007B69E8BCAE728BBE6A92 +45: 652058EF0FAF8549424F998669660931 +46: 89418FB4740E9801F6DFFEDC593FA32E +47: 907561A69CFA117F167A52B88777D89C +48: EA2EB4B1EE739320F99894B476A8A51E +49: E627E64AAB6E2FF6B99643A7FBB84BFC + +Key Size: 24 bytes + 0: E8975F94A8B1392FBA78CBDDCC8E8F08 + 1: 708CEFB68A0281AEA424B3D4698D2F2B + 2: 21A0DE56545BC950FCE4DF209C96CE6F + 3: F2CA4103B703264D46CBC09E13D5B8EE + 4: 2892101077FEE427C434CCFBBAB598B5 + 5: C2F191CC5C681CBFC098B264C479B2AD + 6: 308C3B794C8A7971BBA96FE4C727F48E + 7: 8A4F9D4463B5DC4DD461ED0763CDAEA2 + 8: B7E1BBBE455AEDF18329A6EECD6E222C + 9: C80DAAE7FBDF56DE05A897FBDBB53DEC +10: 6A3D38758BF0390156F22F83C20F0262 +11: CA493DF771E37A93822D6117ED14B60C +12: 623012748826A08F3C59B71FF3D66327 +13: A283BCB126B9795D306B129035BCC2DC +14: 3790A6704BB0F119139A0264F7E8B2C8 +15: 9B369BBC095428EBD712517B2C4D06F0 +16: 0F488018162193ADB11E4C39CFDEE0DC +17: 8AFB7C6FD7D6DD64C2C77DA3A0D91EE2 +18: B8BEFA241BA339BF6F059464C533F9F0 +19: E76141C8CD54200FAB2F8C2B76AF5FEE +20: 80B4FE57851C0240D81E78DA8200F195 +21: 8BF1C690EF5FCE7ADC74E31C24F83F5E +22: D30C4F78703BDE91750E0E49FA0E8982 +23: 86C5D1E0B88EF0AF9B899850510000EB +24: FDE727442BCC0305A7B06E6EE179D836 +25: 0B4A719342F9226FA680796887A98FA5 +26: 980D4BE9AF3E3CF9D4558478D1DD03AB +27: 03ECD11992D3D5864B8D1987966BA544 +28: 8DBC2931D7D17657BF38E3931F486850 +29: 76AE069E39FA7308BBF507ABE35BC1E8 +30: 9541B59CE18EA255CDC06DFD3FFCD1C1 +31: 5A382748AE3641ABF6D9CA24A35B2002 +32: 9B7A49DCC2CFC5A6078AB41E6F62B4CD +33: 91B2EAC878E5628DBCC7C876B91B73D1 +34: 31125CFFC41A0D3528FB16BAE761C47A +35: 916D2A769DA002ADCA8C87F8241BB50D +36: 681C3F601EE5D82F9B040932F2FB4AEF +37: 6B6F32E5EAC2F424074C33F7C988D5FE +38: D15A5FDC2A4956DE61BA6E1C98867242 +39: 0747BCFE1B979E947EED5225FAFCA44F +40: 133B43C85CCBC360DF8649BBBD2EB45B +41: 052D943062A6D475D30100EA412C30EE +42: BD6401C591D585F4A82CDCF678679D5B +43: F95D1A5E338F56760C425D972D67B57B +44: 9B1569308608CA00BB1E2BC9E20289A7 +45: B6454C52C64F64D69F1D36D2D224A222 +46: 529B5B013AE3F37E38BE340D1D200A64 +47: 1B65904F177212AC8E9ED4D8DB287810 +48: CD5CAC56236E0B9A25A5D306F12D8C4B +49: 01DF7E1D0F5F7A5DAA0B379388425126 + +Key Size: 32 bytes + 0: 7FBC212996ECE9CA2C4D5BD88FA0B3D9 + 1: EA3D788C25CF3BE7F4101EDECF23455B + 2: BD0B98481366AE0869ABA11DB18D1E95 + 3: 53393E2B757C90489EB6B47F67837337 + 4: E1D350640CCA6C13648C3B57BE00B950 + 5: 951E1EF99E6DE72744A9D8D9EBFBA94E + 6: 433E4D4E64B41818097BD5E2EBA01D8E + 7: 8FCBD07E303B381B2935FB82CA0CBF13 + 8: CF46569005BD968B9310149E892B4D69 + 9: F1B672657C2657AD53BFFE2BA5DDE1D2 +10: 0035337210703240F9CF2F5A9184FDB7 +11: 773951841F77DCF8A6730109DEDF3E9A +12: E47DC0FB381DB86EBD208A0D649E7B03 +13: 0D9E34ADB257146EAB95AF14636301D2 +14: AB5D5C106E52AC7662C26F9F27F2CD55 +15: 6938F205DC23C3500B7723281E9F626F +16: 3CABD52558D7F418CAF6B41CEC334DAD +17: D2192F1E5AFC3B989C42C396B3764862 +18: 59D32E3A41141C6CAA2A8F44FD587D94 +19: 483CFECF65D71CB2994E1C12A1A7F907 +20: 8F086AD81B1FD5B13195EDB4DAB7DC73 +21: EFEB1328CE7AE6A63E7D8B3ECA9E12B9 +22: 362AAE308B3BBA588DBCFBB7197E693C +23: B817A136EB30CD127B5015A85A7B6E95 +24: 03796E7F244CC916BE02AF61E5FEC42F +25: 5854F2889CFF44B0688718C23B0A822D +26: 0F772AC6E37364AA7B844AEACB33F4A2 +27: B3E95F5195BA646DAF333AA89130451F +28: 911A32AF7CC44309B37D75E158A4AB18 +29: 232CFE228EB72A949616B307C2BEED15 +30: 7C8989F135B8DE6FD26C7792B8354F35 +31: E79231779BFB9F792BD179C0625280A8 +32: 015F6CCAE8A1275A2E836A207D8254EA +33: 4EB94709245CE1FBF7C6D9587FA92D40 +34: 63D82005320F974EFDC4C021FB73ABB5 +35: 0F15B2E8E389C2D59289D7DA41ABD07D +36: CEE7FBBF766540D4E39903D0494DB797 +37: FB564C18A15D53108C1954FCD3518FC1 +38: A67C5F4A4A95AF2BD8E4FC1182B2EEBB +39: 0D354E664C35B9364E4EE9DB8DE0CA76 +40: 3295826D52F3B980B50EFF3E9317F1CB +41: BC65592A9C0BADD84F363A175EE6BC54 +42: 58DE762ADA621FE2A7A6A83F68E93213 +43: AD774FC8402F7DDBB881B703EC836057 +44: F1C95AD5E004AF35AE315AE88A2577FA +45: 968775A2C3485875B024B008D96182EC +46: 623E736238B5800ACD9B67D76C84D236 +47: 1C5E9F65D43343D743E50C80D0E0F648 +48: A62E4A197E15CF90C2569DC38D9FC915 +49: 165B139BE483A71381B9A8E93D9473DA + + +Cipher: twofish +Key Size: 16 bytes + 0: 9FB63337151BE9C71306D159EA7AFAA4 + 1: 8CC5A931DEC29B4C7D85595D24FF8405 + 2: E867FC0E144FDEA24FEA88D22D8776EA + 3: B450A2969C67D93E1AE3A4093BA4C48F + 4: 7AEA41F9956149F336612E868E42B3C4 + 5: F201FBB730E6E58CF9E5AD1DC4844C4C + 6: 13D8869E66412C6C288B5D7F37F2D94A + 7: CD57DDDDB782C0A04C40E47D920799DC + 8: 65371C8ABC919EC09004A7D63D9302BF + 9: CC31DFD3B7DCCC86866CC79D45A89C3F +10: 541D548D311714EF8661BFA721568D16 +11: 269F3AA2D2D10DBD3DD3992BFEE23C05 +12: F86DA5D73AFBA94A9D592D02B5855D25 +13: EAD8D785B50E036437E39F3B27DB4657 +14: 2AD0A13C493B9F3EDD259E11A495B205 +15: C05F9D72AA384F05B28A3519AF218CA9 +16: D442072F588D38AC8B9D447762E9FCF3 +17: FDD3BFB91EFD127196FF9F19ADADBF28 +18: F56717661B424E41D7DE1CD13E21DF89 +19: 0F6C952D9BE6CA49B5147EFD44455A92 +20: 6C214935726364F2766BE7B4C2B64362 +21: 5D5316D7E057FF481CCC10C7452D1A17 +22: 56C78DBD802CC9B040446A3EFF3F12AC +23: A38CEADA8448DBE29C2D11DF2A487715 +24: CB2F786AB8063350F3FAE11EC8C65A5B +25: F5B7298B6F558E2C4FCC11744AD22653 +26: 01BF89C1B48C5F6918FC6BDC10B12A21 +27: A031F25AAFF294EE79220BC76E73E52E +28: 42C94B50E12499DA35F14BB6BB6E684D +29: FD68B6840DC9A271CDE2032EF0200295 +30: A9863C1B04B3FE3945D29966F67B87E2 +31: 6226D4CEEC1E8AEC1B7B3E13D80A83FF +32: 6100A71B1E3ABBBA48A9ED280DD1617E +33: 5CE93A26D4EFF0CC7DFA2DD43A511871 +34: 282D165BFBA0F7F229161BE533BFC4D9 +35: E6AC479970891392972B2845C949A068 +36: 4E4A887368F8443BE51FA7CD16CF0B87 +37: 121AFC81AA2750572B35D100BDC34DB5 +38: 7C41FA7E0A18A87E44BE488F331B35E0 +39: C8847D295E1F505C04E2F5CE2CBF5E00 +40: 4686EE8628BC1BBB92CE825F04B1D5E8 +41: 397DFACD19C283B3FC27D3FCBE952254 +42: 815B6C69608B5A379E3C9E67FB1BA15A +43: A73E72B912EB3AA4929E9EAF73A448BB +44: 5BC4E2C88512BCD55408CC5AEAD15A91 +45: EF20B2BF297456DED1F4AB7BE0747902 +46: 3D876135E19BB56B98050450C6B0FD06 +47: D68100E1BAD07B438786337C0957471D +48: CE85A91938049B5E21C983F7C45ECA3E +49: 9FACEFFB9D08BB65DDC34E3C575B8442 + +Key Size: 24 bytes + 0: 95ACCC625366547617F8BE4373D10CD7 + 1: 99AEB25CCE73B3796C351A19791ACD52 + 2: 56B9D6689830275C1A3E4266B3D56D53 + 3: 2F5F822E11F087BCB8A0F428414855A0 + 4: 65400F729990FE175AAA894BCFBB1A59 + 5: 947BA33D20194BBB0D4904023FB32FFB + 6: 116B0C6744D215AE98DEB1F9FF1D36C0 + 7: BA6964C101FA044ED06877E46D540850 + 8: A36B18526FA0004CF557C99A3AC1423A + 9: 573099674B8AFC2DD6424A2E4C581B89 +10: F46169CFE9496A2696A93EEB7EC561FB +11: 2C64BC052898F3F3A2B78F2591F2BF1E +12: E8A0D40B08585459199DD6ECC108A490 +13: 47927989BE5EB55B9A0F294C04FF035F +14: 54A3024E3AD86005A2C44E4B8BDBBEFB +15: D0AD51D1DADFAD7ED0EBCC756DBCDCC9 +16: 5DE698B7014C34AA6F0099CBB5937A20 +17: 9BA30F49470C6DB9632C5EDE34F8EE73 +18: 0BDF558A2AE9298288E60616442D3408 +19: 25F6DD23BA4E090E1CFFA6EE3487AFA7 +20: DAC5FB99E299D2672F79F0C38E177D83 +21: 58CB113430895C9890D96EA60E3DDC23 +22: 48A0771F0049B776A44AE8877B57EFFB +23: 2F12B26A4BF7065076417530CDEE14CC +24: AA6ADCB0176D5324C4C1FFD640D502EE +25: 384B52A66F4C7A70ED36091BC3FEA09C +26: 2AFE7ACF071C6B0FD69930A09D6DD5E5 +27: 9A2DB9A5E7712A5BFB095D2C09453CA3 +28: 716C0EF522A13EA05A48F16BAD3FD10A +29: 44AB46F3CCFD02BDD2C77A332293A4D9 +30: CE6AB27A0F60F410B1B3CACD9AB923A8 +31: 69EAFAFC171C55D1D90ED1C6E1F3A48F +32: 5EEEB0B7833121AD7D27BCFAF2D4F8ED +33: 47133445A4EBCC60E27B29FCC160FA75 +34: 9F1BFEB9715A20D5FA7BA3BFF1A27BBC +35: 516D4615F07756B4DBE7D37EBBF4684E +36: B88744E53073BDA0F1B115E3DB224E83 +37: 1B77C3D067BBE00420450BA5CD9A83CA +38: 94B87AC96F8CBFF36B01A68E0651E591 +39: 52ACE87A1A8E46655935536FB3701290 +40: B406BB632D5B7985400EC78D621C8801 +41: 20F9ABCBF97A9917EC6C5DE3CB2C925B +42: 539A8AF920833F9E81A20A6D10543176 +43: B79AFB8BB39B0351094F37C6EC93F8A9 +44: 5830BD21289FED3F95C3E3740AC6C5BF +45: 86C4AF5839ECB9860B175642ADA32895 +46: A6427E5E08CEA2A50B8426B063AEE189 +47: 2E872129B5BC5F535BCE2B81F013A103 +48: 2203EB9B2BF51FC2025549D0BF1924A7 +49: 6A5E383A4FC78F6E03B9B276F81195BE + +Key Size: 32 bytes + 0: 8EF0272C42DB838BCF7B07AF0EC30F38 + 1: 9F8801E94E41A7DC875665663BFA7912 + 2: EBE2CA6B45A0BEE83B54402E1A843A3B + 3: F6C5A1187AEF4B5A88E97E866CD757A1 + 4: B3E62CD473E53812EDF9ECE875F39F5B + 5: D8C38B1EC23264BB7C42B5589C1300B2 + 6: BE315EB75B944EC9E51F5EAE65F70BD2 + 7: D4275409941A44993037364886B60598 + 8: FC34F1D4E9C4A634C1349F6D4E9AB94E + 9: BE712387C59A40A8A35F854333A0302E +10: 1F1FE164834BABC71DBFDFCCA7D2B4B6 +11: BB2413CCB5347B5157651819E698D988 +12: 6EB5523A968ECE965D9AA4B975D7C2EF +13: B5DD49AB7E269F9D8516FB57EB47D57D +14: 74F5D81856F192D49A70B3743945BFC0 +15: 95437BB00D57CD88BD52DE0A66D934C6 +16: AE4804A975D67C6B6F99176F407AAA3C +17: 5E5B2FB9B2A028A5467B56F8BDBA6980 +18: 8C617FF1F9C50A36BE2EC19A629BA96B +19: E3401F7CBE177A1D224117894E7EA08A +20: F8451D9DD31A08BE828FA9AF39708921 +21: 5BE66DD577826804817B85A07BCEDE28 +22: E426227780943AA1A830B7E7D7F7CA0A +23: B39C7277C3A5CA21897563DBD8DD6D94 +24: FA9992385396F959841D1E0E68CCE00D +25: E1DE89B1DD5CC31685558A51CC731E6C +26: 64618455C46C6FF117F19FF300B3B557 +27: 882758C02B3C11D406A21012977D4BF8 +28: F948B62F8038D3A3AFB73041B2F263AE +29: AE3BF626020D2877052B90B31E70B8A4 +30: F1C6DBBC166985C9EC2E1A3A61BD8E75 +31: 82C343FA36B6D4E9E7AF6D0B7741FB09 +32: 0BFB756EC55AC63BEA71E4A8187C2B10 +33: F1941AD10BE60DAD3FBA33CB899B63A3 +34: 18236A39CD34743DE7B60B2575A9B204 +35: AA37FBC2525F74710D7561D316E8D90B +36: 413E0F72C2B349FE2691554F77162B5C +37: 5B9E6F98B2CA0F637E463BE4A6EFD39E +38: 1B4A4CA36DC60D51BA981392D6070379 +39: B1E26163A90F339E33F86D252EFBAB99 +40: BB98F9F844FA81B25ECC89A8482404BE +41: CE142F512A42A28F4788847B971AA7E9 +42: C5CE782936F3D28C69C2BD45FD7BC117 +43: 9B6E142582E0A309EDB550DED51238B0 +44: 0D9D80C01612977FF3A2C7A982D0894A +45: A7630C752B1F787B07C382693334C6AF +46: 9F24990F270D575881C746481A59C245 +47: C38B5E11479C200B5ACE1D6522FC6B1F +48: 99118D8114D24B6559CC5D9456F1BEDB +49: F8B974A4BC134F39BE9B27BD8B2F1129 + + +Cipher: rc2 +Key Size: 8 bytes + 0: 83B189DE87161805 + 1: 7DCB9C9E50D15508 + 2: C724D535853CDE79 + 3: 113AFD4BA7D3D7E3 + 4: CFA06CFB93C2280C + 5: B3F291C1AAD9CB07 + 6: 606F74D9AAD4FA71 + 7: 1CC3F7AD551C5F89 + 8: 43F8772BA6C6B60D + 9: 2F933E12F57689DD +10: 2BC1AF0D5571D17E +11: 4123AAFABDB254E5 +12: 413E0AD5C709DCE0 +13: 6B3CF01A7542BD2F +14: 1E5E2CA0CD605999 +15: D0F7C9DC472A0709 +16: 00482798857A2BB9 +17: EED583440CFA8B48 +18: DFB377FE1EE5E055 +19: 30511C4C565E8F75 +20: F74A72482B43B99E +21: 1EE4EA7849B0B070 +22: DB7A4ACF022706FD +23: 2D7EBABC8C8E4DD4 +24: 6F0369BF66A8B637 +25: 59E5D13B247EE0F6 +26: C7BAB430AA89A5FE +27: AE0F03746D38138B +28: 942DF0B523D02482 +29: 929CE0963CFA46B1 +30: F8C68A91DC53B7CC +31: 5735395C63E15094 +32: 7821605C18D83D42 +33: DEC892FD743BA6DC +34: 77AC80C1177963D3 +35: 3E223EB4EA297456 +36: AF63B231D671D9DC +37: 665CA287AF32E92C +38: E451EAB337DC1EB6 +39: 95B179EC950992CA +40: B8937115492802AE +41: 355A6E5EDF40A939 +42: 353E77D4A5A28D79 +43: C958FA5903F921B8 +44: C334E296BCB24ABE +45: 4F37F7F652FE31ED +46: 77304A655B03ED67 +47: 3548A4209ACB6EE2 +48: 696E712B1911B695 +49: E4B63641D22A3DDD + +Key Size: 68 bytes + 0: 7ED68E8B30A7D5DA + 1: 867E18AE64B783EE + 2: 032E554D6AAD7055 + 3: 26BD785D0DDAD48B + 4: FFBD4009ABF53D03 + 5: A71006E1E30C3855 + 6: 92638EE741BE65B5 + 7: FC8C5F28CB38C83D + 8: F03F145CBCC4CF80 + 9: A28A7C63F67DDE7B +10: 3089486A2247B72A +11: CDD6E6BA5ED53A8D +12: B75A2DE8CB96A267 +13: F74D72A2CD68CEF5 +14: 3865AC8D170EEDBA +15: B1B520CE5FC2BA39 +16: 658DACFDD701B4EA +17: 6B5C1DA9484FCEDF +18: E3CDFB5755BDFFC1 +19: 56DAFF7E9A908880 +20: B6F8B970F68BC2BD +21: 7A00DEE6977A91F2 +22: 6C0CE4FD2D02B36C +23: 8EDA10D868504648 +24: 76FB106689E66EA7 +25: 67F45BB28A20E110 +26: 5F3207099AF93B07 +27: F5E382F7266AB342 +28: 0E31AC2E4CEFFBDC +29: 8DBA1B2FC6980FF0 +30: 311368E62EC2A9E2 +31: 50DD1F7A319727EB +32: F0DE146C9ECF5662 +33: 81CE0842CE223F15 +34: 4C442535A8BC9AD2 +35: 06EE8869DB91EBDA +36: 4078E7CAC29DCEE7 +37: 115D619FB705F289 +38: 3D3F8A380DCB8FB1 +39: 9044E5AB8049D21A +40: 66327F00B07CFC76 +41: 811AB23A4AD3F132 +42: D4A507E96BB39BC2 +43: 51C9E4C9318F87D9 +44: D2255C13DBD09E88 +45: ECB76BCB961F812D +46: 83D7E39727BBBEC5 +47: 415540F0AE34DD65 +48: 232D20F9E188E2C7 +49: EE37261ABA270B22 + +Key Size: 128 bytes + 0: 8A8F8E5C5A04C73B + 1: B197CF922883CE71 + 2: 8AF3F896460CC597 + 3: 755F313AEB18D3B8 + 4: F1DB52688BB879A8 + 5: 29D68EA6456B1CF9 + 6: BE7C444267A7925D + 7: 46A7BF7DED575933 + 8: E2C7AD7C902E5E15 + 9: 90A38AE1DD69C2EA +10: AA95FA050CD3388C +11: 23822B6AD5B83018 +12: 8FD42F0DBFF3FEE1 +13: 645098BC94FDE21B +14: 7E43D43EAC50E992 +15: 2F540FC66A9E0F43 +16: 453E52EA7B2D1F92 +17: F6F731E8C5A32C54 +18: B1E89646504E4D7C +19: AB8168452A7984E1 +20: 044BB0758DB5435B +21: E9BAE7C99A152BFF +22: B758F70708B6597E +23: 23A1EFD0AA925D7E +24: CA60DD174CBA23DC +25: 5E916F2DF7B6B3CF +26: F2723A9BFD82BB62 +27: 2BC381F6C048687E +28: 573BFD71896A4133 +29: 03DF7250C3D69801 +30: 8639060454669BCB +31: E31945F0A87221AB +32: AA39447BBF0A77EA +33: 174F1B65BF6A34A3 +34: 2712F966022A9589 +35: B6358876D6D56D16 +36: 2A92C131E68B77BE +37: 040C6935F4CFC43B +38: F23503C74121C660 +39: EDD120883F1F813D +40: AFC6500D34BD9D33 +41: 963117444417BDD3 +42: 2FC3A58861B4A58E +43: CFDB70ED8BCD1173 +44: 91B75760CF38B8D5 +45: 93A59048B78B3415 +46: 7E60C5E75225D45F +47: D4212C6422878FFA +48: DDD1B241E0E0EF6E +49: 20337DB931078078 + + +Cipher: des +Key Size: 8 bytes + 0: E1B246E5A7C74CBC + 1: 9262AFD8AD571E2E + 2: 36D2067D960EB870 + 3: 319834DC66705192 + 4: B4508A7C5F012C93 + 5: CAD1DECDDEE81342 + 6: AE9E1CBB71C719E6 + 7: D7FBB1CDAFD5B2C1 + 8: BE1A70564E3BFB5A + 9: 96D9EC1407A1BD34 +10: 05E4B9AF3A4DABB3 +11: 0DC77419E1F12C02 +12: F73E62369190A5E3 +13: 830C1CA7820ABA2D +14: D2574B6AEED0A4F4 +15: BC08782E293546A1 +16: A35DCC9AAD1EBFB3 +17: 79B2224667B33706 +18: F9462FFD2808233A +19: D6421CD0D9697DC5 +20: 57CB2173D67E7001 +21: DBE2DB0BDC07644F +22: 014E72E7E99C969F +23: 37901B1963D0B29B +24: 8E12C23929125686 +25: 73AA9E2A60C327A1 +26: 54A19D07D941EAC2 +27: ADB8CBBAEE1848D6 +28: 3997E866119856B5 +29: 4D647526FE7E1E27 +30: D574FE7342104F93 +31: B84383E34A790E11 +32: 322214BE9B93BB6F +33: D4C8E0B7AA139D68 +34: 2B9747CD280E48C8 +35: F92EB2E3711FEE2C +36: 5CEE84E124B7882B +37: 82427488597FF618 +38: B1E8B313D2DC76CF +39: 03E237CD40D7F214 +40: 8C8DC1299293E15D +41: D6C7463FE86D4EF8 +42: CF1550CACE647779 +43: B998B3D32B69F00B +44: 1B94C342C3D91107 +45: ABD4551B27F58BE8 +46: 2B24D978D1BFB3DA +47: 85361D36950635CB +48: 448009F38F1DBB4A +49: 6B901B2B79B6950C + + +Cipher: 3des +Key Size: 24 bytes + 0: 58ED248F77F6B19E + 1: DA5C39983FD34F30 + 2: 0BD322177B935920 + 3: 9D093F3174EDBAE3 + 4: 756B1F2CDF02B791 + 5: 57C31C2A913C1126 + 6: CF936257517C53FA + 7: 5F06305849E5E158 + 8: 9A85DFD788C59D19 + 9: 6392279BBE29DC1F +10: 76B0AF835D79C4E8 +11: 7073F36DB1E31464 +12: 276258605F2CAB3B +13: 3B69E97811FDA996 +14: 3E6E491D2862A1F3 +15: F8F3F68BDB006520 +16: FD376E66D401A097 +17: CA2FE47825804996 +18: 6F5C256F84FD14AF +19: D7B07F5C40FF0CDE +20: 73F2E074F1324496 +21: 0B2A35016F24BD21 +22: B040D2E3B311C193 +23: 3938DEA347112E2E +24: 9D7C1703CEC0BFAA +25: A07949F76BDFAF68 +26: 43087EEF52564C4C +27: 11132B599734AF0E +28: 62A04C819FDD9A8C +29: B74F0E5649D33690 +30: 8E77E5009B0AA322 +31: 5174134B9A1889B9 +32: 053E33441D11AE63 +33: 01EF381013F86E4C +34: BCA358DEF35DFD60 +35: 5908A88513E2E5A0 +36: A3214C8367E04B05 +37: B2CBBE851A54BE9C +38: B271817F63B3B76A +39: 08AFBF82ABB97D8A +40: 2CE02ED014186B86 +41: 63F3011C97F6E990 +42: C392351F432738D9 +43: 0534DDA50E685725 +44: 1509456871F5CC20 +45: 2383029935901342 +46: 8714F1A53CCB213A +47: 2491B2FD3CE6A7CB +48: 4BB02399D85BB66E +49: B8AC2CDFF7AC22C1 + + +Cipher: cast5 +Key Size: 5 bytes + 0: 9B32EF7653DAB4E6 + 1: 48AEB06B1BDB2397 + 2: B530927183622D58 + 3: 0ECC8F24BA742216 + 4: F6352F9B6461D82C + 5: AF6315AE98E12A71 + 6: C364D4B506EF28B9 + 7: 817061BEDF5E0A5D + 8: C19DE7B1F2066C04 + 9: A6E1345E3AA1B79D +10: 06B036B04785428F +11: 244DAB3F7223F567 +12: B9CF3791F6C79F4A +13: 86C5A02AF0517C5E +14: A16E3198F1317E04 +15: CF72A44C01E36DDD +16: 199C72ECD5E632ED +17: 0BC66BF05EB7887A +18: AE1F696F3D6B7952 +19: 685C92084F600885 +20: DBC1353A95AD2097 +21: F481E98CB36CAB3B +22: 8F1C06A482C70BB6 +23: EA087739954A9CE5 +24: 6D0AD727D8E4EF9D +25: 61CA0F7965FEE246 +26: 0D664CA16BA785DA +27: 2359D363755605B9 +28: 6B6E3A216ABFB55A +29: 6FBCCF7B0342D3C9 +30: 3431F4572E2CBE57 +31: 36D84FCE6D5D8FE4 +32: C234F6AD41E34E76 +33: 522F12E8D0617263 +34: AD8199B6E94D4E74 +35: 56DEC7C21C83B2AD +36: 22CDBFBC5B476E69 +37: 70BAD497381F378D +38: 4584F15DBC0EB7F3 +39: DE0603CEE19BCFCD +40: EA8D582C1CE62FC9 +41: 4299C28A912CE568 +42: 7208AB000E3FA9D4 +43: 7AAE6CB398D01665 +44: 33A6AA42B6D7949C +45: 2AEC5640AD535D69 +46: 74D37D9DD7B67248 +47: A5300FFF5CF85833 +48: 834F83398D591C38 +49: 85C787A8B7E519DB + +Key Size: 10 bytes + 0: 95827CB504BD43C7 + 1: 8FBF4EBCB8413ABF + 2: 5CFF411BECED9971 + 3: CEE2AEB4415E0A5D + 4: BB3A8DF7C54FA88F + 5: D508B933EF335111 + 6: 993745722EF0D8D3 + 7: 04EFB233AA88E796 + 8: 478A7DCEAF243F90 + 9: 269CC3D138ED48E7 +10: 88EBD14D2F999C89 +11: B7441626D4487A20 +12: 46A6E2CE6C66058E +13: 60687D2D5381757F +14: 885D05ABBF187B89 +15: 5032A7ECD3D51521 +16: 50BAF36BC5C14A8B +17: 8E805499569FBB0E +18: F8359B18AF3E69C5 +19: F24E415CB4D2AA95 +20: 361805D4E45B56B4 +21: 3172336F01E3530C +22: 333A551E0A03C4A3 +23: E2B991995A2D2962 +24: 067CEEDD8F213B67 +25: FEC3F306851F8616 +26: 4B80DAE6AB11894F +27: 250C26E21A8273A2 +28: 313F2A505915C909 +29: 42E0DC3D4816B38D +30: 9FAEEF0510DEE721 +31: 3BB5F5EF74B4CD7E +32: 0FBC9007F462BEAC +33: B9D1467B0D7A1043 +34: D9B991C9348DF321 +35: 061D577806C50742 +36: 48AEA67AAAB6FA23 +37: 22F7910383BDA87C +38: 9987087EDBA56FD8 +39: 2FCC8341B69BAA14 +40: 29DEDB6C2A433F50 +41: E067D2746B99A9CB +42: A5C9CB975A856D57 +43: AAFEFD3A82D6185B +44: BBE8952CC93CCCC8 +45: FC08CE0934EF2E25 +46: E44E642DBA7CF3F0 +47: CC26F0E8E85AB372 +48: D95D63B8389082E0 +49: BCA941C921B91E16 + +Key Size: 16 bytes + 0: 20B42D77A79EBAE5 + 1: 96CF6C91E5183CA2 + 2: BD87E77A38DDB4E2 + 3: E7454CA30B69DE2D + 4: 888F278D219384EE + 5: 972CB887CDE920F8 + 6: 49BEC1E7913F3CAE + 7: 96A81B37FEF63CA5 + 8: 408DD23A6DA940FC + 9: DA86E92BB735755F +10: 2032F2D972F228BD +11: 8F9EF7DEEF74EFEA +12: 547C92025DCAF9F4 +13: 80CD440DFF2EA62A +14: 7D6141D102E1B941 +15: 307596ABF5C9A6B2 +16: 82E3F1B17EBD52FE +17: 5917DDD11EDB55A3 +18: 2909F77166F24F9F +19: 88BDE9D686328942 +20: 8F987B737F6A011A +21: A74B3D1D6433B9F4 +22: DA8F95DE949482EC +23: 953BA9B26B9AC476 +24: 76A52FE193CBFAF9 +25: 4BB7D2597A78F2D8 +26: 5C8BE951251F4B1D +27: 6E8AB32A4A279D84 +28: BB94BC9937B42848 +29: FF0EE686F97BF8DB +30: 4146656AB1477E13 +31: 1BFCA7053E6DB8AC +32: 4B9A6A349BFA926E +33: 3B5F6FDD127B0A87 +34: 53C996E956598599 +35: 62C142E63C28B5EE +36: BBB71D6548F32693 +37: 107576AA26352455 +38: DE32E31FFE02B6F9 +39: 4C5DB81D1715FF5C +40: 8E5C706206F493A6 +41: 4BBC51E184A67C92 +42: AAE216B413DE2A06 +43: 77AE26F467233B06 +44: E8680D0E71F6AAD6 +45: 7061DCED4BC94F78 +46: 06772D63818C7E86 +47: EE5B9CFC06CBD639 +48: 5784B3EFCDC28DD4 +49: 4F962107A2EF843C + + +Cipher: noekeon +Key Size: 16 bytes + 0: 18A6ECE528AA797328B2C091A02F54C5 + 1: 2A570E89CD8B7EEEE2C0249C8B68682E + 2: 828F4F6E3F3CB82EEEF26F37B26AEA78 + 3: A3CA71833499F244BF26F487620266A4 + 4: 333ACCE84B0A9DE91A22D1407F9DA83C + 5: 224285F3DB3D0D184D53F8FFDC8008D0 + 6: DE39E2973025FE9EC1ACDE8F06985F91 + 7: 2F00F45A01B1B0AA979E164DC5CCFE10 + 8: 43775F3CBEE629EF6A9BA77CA36171D9 + 9: 1E6A67ABF1B6ACF59FB484866AC15A86 +10: 70490989E2CD2145730921CCC37F0A17 +11: 67B0DD0EA903486B1CB56591FCF42678 +12: 774AAB71FF28E49A30E1E718D98114E8 +13: DF4797990E1C65C9F6735BD967164D45 +14: DE2779DF26FC1B99F576ED4CFBAE76CB +15: A13AD17440641B3460A01175E3274AB9 +16: 1166499165F2A1196CA2DB831F264E77 +17: 35D24A385416CF2A44AB97A4AEC45E14 +18: D3D0E0DC962B1AD1AED92F57129088B2 +19: 00EF3E246B32634ABAF8BEE31D5C592A +20: 79BBF3F807675B9F264BABC67DF4C2AB +21: F391F2D58F0998F24BC9E5FA75DB9E99 +22: 066EF13C2617E97E6015B86BA1E059B2 +23: 5B0E2D7AE1E2734B9D5734C87F7BE272 +24: CDF7020212B7CF21F4817829386A6F8E +25: 24873E1A0EF4908DF85114ED9BDB0168 +26: 99904360C843472F71AB86B26DC78A00 +27: BEE70B3735A67268578FF107C328940B +28: 97DBB283536BC8AE8DBF56F3474C7740 +29: 2F4C903975EF709E004D24DC132A8A51 +30: 3EF0859A281782F905198C607FBE5C43 +31: 2D9CD48BC6A99E86468CBDD2A55C7D5F +32: 5518D3ED18D5E5A62752CDF0846D0C77 +33: F751E9CAF107BAD8A1F1F9C374277A6A +34: C5BA4DE907C41221FBABC5EC43710D0C +35: 5CA48836330870365A10E7B676695C9D +36: 937A964E0EA4D246E97293375B167EFD +37: C0A876CB6957717541A90CCCB034BFB8 +38: A57C93A09F9160A28D3D4DEDC987746C +39: 1FFA1E0B5EE0F0A18425F62717254419 +40: 8411C87262AE482CFC43C3092BEAFD90 +41: 0B9BB379FB3587A9ACEEED4771D8DC20 +42: 3B32EDBF9557E1DFBCEEC269B51FA494 +43: D1104E2888679A9EF6A13AE00ED7E1FB +44: 0EC9849BAD58A279B42B5BA629B0045B +45: CF206E8D3399918E75DE4765DD743060 +46: 55CCEB28E27D4DC7CE2546454FFD2C33 +47: 6E2339281583420B76E1750D35296C12 +48: 7800EC3D8C344BE7F2D2812F5AFF3DA4 +49: B80F4B0BDAA54A04D5A26BCA185F4EA2 + + +Cipher: skipjack +Key Size: 10 bytes + 0: F62E83484FE30190 + 1: 03B4DFE5423A117B + 2: 8CE4DAA2307CF018 + 3: 77D8C958DAE4336D + 4: 00D367D5C1FC95D8 + 5: C1F1305A5B01A474 + 6: C3956225C846F695 + 7: 2A8977DC186749A3 + 8: 433AC6B56AE5C200 + 9: 10489A7E87F803CE +10: F176DF022D02D136 +11: 1395AE1C0C00AA1B +12: 0C1C3FF32E93F789 +13: 901EAAD562EE92DF +14: 59D55D9EE3EA0154 +15: D9135CE0BBF68AC7 +16: 90A8E4A8E76349A3 +17: C04ED52AA69D1ED0 +18: 19E842698B5008A4 +19: 26FCA0FA3AA7718D +20: 62635FD1A542C7C0 +21: 5A3695398C979E40 +22: 34998BB72108D89F +23: F889CF892998D689 +24: 2C6A4D61F468F19C +25: EC70D59FC906349B +26: B95F11FD098B34A6 +27: 32F86206BB4E525B +28: E6BE51063B60CB9A +29: 8964E47BAC22F995 +30: B1C297883819747B +31: F2AE1F39F55FB6C2 +32: E633EA2DE342767E +33: AF1F0ECBCA788A28 +34: 6A898F4407696B27 +35: CD9CB5374EA080BD +36: 15881B0200AE6A42 +37: 579D05E5F5DE7840 +38: 86F8C683D23EB976 +39: FDAC7DC6C8F7777D +40: 10D6F7641409F027 +41: FCDAA0872D1EC61A +42: 7A353991A81344DC +43: 43661187956D3F8D +44: 5190FDFB904A78F0 +45: EF651E67F65CCD57 +46: 5E539C61748BDE3D +47: E11E23BA8BEBA42E +48: BAEF0956173B32AD +49: 0AAB29DF65861F4C + + diff --git a/notes/eax_tv.txt b/notes/eax_tv.txt new file mode 100644 index 0000000..bf4a52a --- /dev/null +++ b/notes/eax_tv.txt @@ -0,0 +1,331 @@ +EAX Test Vectors. Uses the 00010203...NN-1 pattern for header/nonce/plaintext/key. The outputs +are of the form ciphertext,tag for a given NN. The key for step N>1 is the tag of the previous +step repeated sufficiently. + +EAX-aes (16 byte key) + 0: , 9AD07E7DBFF301F505DE596B9615DFFF + 1: 47, 57C4AC75A42D05260AFA093ACD4499ED + 2: C4E2, 26C5AB00325306772E6F6E4C8093F3D2 + 3: 16177B, 852260F91F27898D4FC176E311F6E1D1 + 4: F09F68BE, 700766CA231643B5D60C3B91B1B700C1 + 5: 8472705EDF, AC4C3359326EEA4CF71FC03E0E0292F2 + 6: 14C25EB5FD0D, 8DBD749CA79CCF11C1B370F8C975858C + 7: F6A37F60670A85, AFBD1D5921557187504ADE61014C9622 + 8: 1AACFEAE8FBAD833, 82F477325D6F76BB81940AE25F9801C2 + 9: 069414324EC293697C, B980E21C09CA129B69E9032D980A9DC5 + 10: D8174DE9A2FC92B7DA9C, 1E42CC58BA2C8BFD83806444EA29DB61 + 11: 2C087DEA30F8B7EE510990, 83DB400A080C4D43CAA6EC3F1085A923 + 12: F36B93C272A703D3422C6A11, 1370C3AF2F3392916364BBBCC2C62EC1 + 13: A0F33477BAE2E28E6747AA3193, B626DC719528CAC65DB0EF94E35422CE + 14: FCF5193506052E8BFA095C1A5205, F5BD02E0B3C91CC7D6FAAA8A9A76CE6A + 15: 3797D7F8599B8EEAB39C56241880DC, 0B70003E77146B903F06EF294FECD517 + 16: C4BAD0E0356FFD369110C048D45D81BE, DE7C2B1D83BE2CC8EA402ABE1038BB79 + 17: AF5C358BD31CDCAC2F0EA5252F1C3BE1E4, 2D700986F93B22DFE6695C2A243B4E42 + 18: 7DEF9056FBDAF491D7206B26B19DEF617AA1, E71A7D00BE972D85C77931D7591B2151 + 19: 6E9B2C0A90BF9D38A6EA3B5D2B9B2D97F938EB, 5B483D7F15C39602C2918181E57DA341 + 20: 7C5F68DEE9BBA3B04F11D5FC7C9C7FE6E8B5025C, 0AE6A12D37A9C10BB1A494E16705DC05 + 21: AF0A886BF673BC72045FC074F06A0176C96105E2E6, 06B2DC9A2868C23F86D710E01E37E07B + 22: 5F228A986DFE4301EDBAF07A02E114F1B30932995CD1, 74EBF68627C78B1FD024A59B56B2A8FA + 23: 911322F60555118CBECD8DD82F186AC19514316E8D48BA, B6A8BAF2F175CD0C71B63B1EF37E185E + 24: E7F52730CFB808EFDB376A5D5DF31A7EF8292DC5FC37E9BC, BA2AD158A2D2E5CE01296402B592E1DB + 25: B3F8D7CA47D8D86E94D670AFBAFA3B8D9E186C97DC029D4705, 709D2D2B9975D4729C19D4EAC430E65E + 26: 7178FEC027AFADDC2C03518E75CF34D207CAC2EB1537A0DBA520, A315F034CE5E66601444402520F55DE2 + 27: FC230B2B8522F53459D0B968421469BBA7E683ACB0190393B2870F, 48679A78E470E175CF3D3E9B46CEDFCE + 28: 35A641127C78C721ECDC50866C21637FDC9515E41CE60F09015EA713, 0062987222F6412B7AAF8A9ABF6FBF98 + 29: 3D42D6C113421743C08A6F682CFA0E517D5531BB66241C02EC4DCC26F7, B1AAFE11FA2D6E0C870177DDD7F98FF0 + 30: DAD065B4669B7C59C8392D8E7BD7E64BC01CEFFF27E335B25A328D356F0E, 8973B9B9ECF26DAB58CCF0787EE928E5 + 31: EBE626F9E241FD233D9781C359430C982667AA26921B62E98FAEC502C01B0B, 2AC0D7052A2CDCCE8E26FEA7595198AA + 32: 64D842B66796A797C2B4C6905742FDF2148FFC445E192F9E03B53810C082F788, 9778B345EC12D222DCC6DBABD2651750 + +EAX-blowfish (8 byte key) + 0: , D8C4C23A6AC0B7B7 + 1: 2A, 5E0E4BDDB60772FB + 2: 7695, 7581B16CCC9C45F1 + 3: EB14C8, 6223A121CFA216C7 + 4: 5A5C809C, 4A47658796337D6A + 5: 8BC2041181, E1FBA8DBA00571FC + 6: 89C666F015FA, 2B4A76A0E699FCFE + 7: 86C1FA92484AF6, 31B3B738A261D6F5 + 8: D1F401C145C9328B, 4C4A045EB489F59C + 9: 70C9C7753698324A73, AB298B5B20567EB4 + 10: A50D9D88DC101B6DC8D2, 529DFCBFD13B8E6C + 11: 7CC2885C2BE79C44F28FF2, 566255022B40C81C + 12: 6902D58347C29250EE07981C, 34619AF18E14C690 + 13: AB6C3C4AD3EC45143392B642DA, E6D2DD323DA175BB + 14: 7065B28BA8AB67B2FB7B6D5E3FAF, AEDCAA54F4B0772F + 15: CBBA14A74AD4ADC0EF036EDAE42D51, F2BFFA4D81BAC034 + 16: 60A315193F58144F5701D547C79FEEED, 912FDBDB05467DF5 + +EAX-xtea (16 byte key) + 0: , 86881D824E3BC561 + 1: EE, 4C3505F04611D9C2 + 2: 80C8, 6A3428BEEAD60738 + 3: BF88E7, 04F1E99E9F5906C2 + 4: E06574B7, 33B0153AAEF9776F + 5: 42D950AF63, 4A0F415640322FDF + 6: C30F6AD46EC9, 9646FE909D2B95CB + 7: A0049FCA856A14, A0257289C6BBF278 + 8: 2814B0C1358440E0, C4B0A2354925E887 + 9: BF4F062B52C1E489CF, B56442A3CA57A041 + 10: 63DF433956831B8780FC, ADF9ED0B46DCA19E + 11: C317FD079817F50E0E8A16, 2EA0EC993FC603AE + 12: 2BD12FDDD81EB11660346D2A, FBC6F69125BBA88D + 13: 85D356536FE2843C6BBE60EDBC, BB2FEFD04F230E79 + 14: 22493009DB01B4746F4927A8C4FB, 64CC08471D93C9AC + 15: C0F3C0DB08DC93FBA725D1E02DE084, 77B762213DDCCFFE + 16: 568B66D3112556BD98FF9339E9C002E5, C8355F508219FE0C + +EAX-rc5 (8 byte key) + 0: , 169C7954341EF44D + 1: 22, DABFDA9A0B0BA067 + 2: 2E54, 6A3D6D9AA5877C5A + 3: 2A6ECF, 2A34A3AF5DE8919E + 4: 9CC5F84F, D3F673EDAF75E3B5 + 5: FF5611756C, CC647FAAC8D49BF1 + 6: 74C939BEB31C, C335999CCFE8F5FA + 7: 7976B6F7709B5F, 2A7969C5FD063A88 + 8: 421EEC5022276174, 2C9BFB1EAC3C54A2 + 9: 6A4761CD266B1C0ECB, 3EA3CCEBC85FAC4E + 10: 7C09201098E764239A2E, 8043ABA9BF4D5AEE + 11: 8CE26277562F646DE33C88, D72AED48895E3B40 + 12: 52150F44D37D121560DA87F6, 58E865E22B485906 + 13: BA0A73B45F93ECFBFC3AB3D8D0, 683D52FA47FB1A52 + 14: 96546CBE01054AD24CC95DB54724, D80D0D530E5D1DDE + 15: 61E654BB18CD26FC36C09F874DC2C7, C65884CB9D9FEC1E + 16: 1D77B8BF02CDEAB4A707C07628826D5B, F18D1730C3D64701 + +EAX-rc6 (16 byte key) + 0: , 1DF8B0B92A3F0C951C425AF4830E63FD + 1: 1A, 8A2959EBBE90180999994DEB7036DB85 + 2: 435D, 7EF00CB57DB7B4155DB530D75CE6B025 + 3: 08A6CF, 2ED6AF0F2D5BAB05F623D389480A01F2 + 4: A86E54D3, FC69547C8BD922A5BF2F7B26C4D20F98 + 5: ED0822E439, 0007A3C6DEFC6C912C0E5B853B520368 + 6: 7BEFC7FD4054, D32C43A4D1086D57C5BCFAEE04EBC600 + 7: 5235E58E79287C, A27E9C781327C0FC7C55410EB0C828A9 + 8: CEB5EE99BE521F4D, 547F46383987F2A3582A81A3BCF9B280 + 9: 0358B063D5F99C3770, C0A73730512CDA6AD49599775D59EDA1 + 10: 434B9AEE07DFADD0A332, 499BD88881E558E09A8E822BE27D2496 + 11: D47849E650F350BB622D74, 638E37A84E7FAAF8F5D77F1B061773DC + 12: 814592F568284085E79A024B, 9EB1405E8422FE50BC0D88D837A2C650 + 13: 6F2B55EC91B591082053AF692E, C48F91EF01AA43A1EE3B36D233DDD48B + 14: 506CBDD2901838EE2F178B6953DA, 03778957F536509BFCA577B23A18F726 + 15: 446EE435D3D1848B51BB8C5F7BE4A1, 1129EAEAADE534940546D43242A4C839 + 16: FB9D2B150C42465B1685D8F069CC06DB, 41E2940F5DC63CB4E2FBEC25ED8A31E6 + 17: 9684F683260107BE8FEBBEE1D3EEDAA7BD, BAE7C116F7FF96631F4ACEE95C65CEF3 + 18: 5082B1FE48CD3AB58F63C2DCFDD4069AC736, 19AC7B8EE315CBB7131A283851B32266 + 19: 8C72AE495B6F003A3C784D144E84E88885F78E, FA4CEC023740A8D670E351FBCF62C1CB + 20: 815D6361C7AE34C9D796ADF9C71ABC46AEF88BC9, 9A1F7288C61A6623B9A82748137ED7CC + 21: 904A853E2E96BD2B85AAB3F5DFB900E9B3642EE667, 9AA90DBDD461CAD20495DCFBCB513DD2 + 22: 79D738A462F727B3D3C529ED999B6FDCCD991D1C5A4D, BF0987BEDDE650D73CAE7D380FED3431 + 23: B2DEFDB7D503A84E83155A04B8DE8C8DBB68C2FC475007, B7CE900CF43CD518024123C76F6DA328 + 24: 9E723E15439E12F6C46DF8A309AE1E97B6FD18436259CFB0, DF8B6E1E23512CC4CF5FF531A1908F69 + 25: A7F0AD03CEBCC9202718AA164886E1026975306A664C5AC7A9, 4A771BF8B9A4325705C85E5499FD98E9 + 26: A53A92AD1C6835F28E04EF591E783D36F3D76E489B31B87BEB7A, AA263B52A6E6A043DE4D7029D4DC73F5 + 27: 79BE3C38291A7F77E932C8A9DEAC08DE6442EA9B3895B101A14E7B, 33B84DE06342E675E019CD0237292ED0 + 28: FA108123C5A69571CFDFE8C3D00535121FDE3096DDC0D700F8F26A5A, 764025D7CA1A3F2C54D28956423B0C77 + 29: 36EC2D67FD977BD2B73DB6D8EB756B3EADA13690E1B6DFC12A4781B34B, 4BC6B38DE3B02283D92F4DF19A5C48C5 + 30: 96D3243C945905C9732B5927E46F00886D511463B38C86002FC26B65AB8C, 5B5511CDEC35687AB8425AB22D58B4F1 + 31: 9CF83B87BEA3374AF7722E999863E3DABB858B0383383EAC7757F5B80FD44B, 1E0CBC961940FDA93B73A92DACFD67F3 + 32: CE3BC3C9FA5EF4AFE5272B3EDD24B1B003FED2C2E501528CFF44D3FABFF52CB4, DC94FDDC78AAB2B7CAA1E1EF149AC355 + +EAX-safer+ (16 byte key) + 0: , B120C7B37450C46189712E4DFD1F0C44 + 1: CA, 82BA1869C5FF1EF2A4F6ADC1E7DC1F1D + 2: DD20, 6BD5601B16C9943A84AC1F99A176E6D1 + 3: C1C09F, 0911DC63AA414C004E2BD825BECDC93B + 4: 27E43F59, BD858F084B082F76814DC385E1FB20D1 + 5: 2A9A92F246, 5ADC4A32491934AC0BD00FCE686B26F1 + 6: 52C78C0CD6F4, F35886F46C03EDCA10B3D01CF07B1E0A + 7: 23E0D3CED3795F, FE33D96FC98B78A30C0A412C60E93992 + 8: CD3FC9961559F239, 9982364A61609FC41068260267231EE9 + 9: 6EA46CB7AD7505C1BC, BB15053EF0F78B9091B3064118F3E9BF + 10: 05D9BA230A56CCA0703A, 1338E68E3DC992B6EB2685C668E75869 + 11: 7AAD6049DFDCA6771AE42B, 35267E431051E1812495615324C4CBE6 + 12: 8695091532B83B23C296F620, 7B2EEA861E9A91E6B6A911E10FC3FDD1 + 13: D909DA4BC7372ACAEA78E6A0EE, EA6C1CD16180DF0B07F4E204A4B4FACB + 14: 7DEC8443600D0563AEFE87A2064F, DA454728069B3B409889664783588189 + 15: C042FE656742CD2FE5D9C212D18C6C, 5929E4AECC2CA047BAE948E7023FE4D0 + 16: 0B84D3CF59EEF7319633F4A397D47CF8, 31F892FFDB7535DF5D9143456E404163 + 17: 8C9E57AAFA7969B142742B63AB73286600, C418231C44F96660DDBA8C26B3BB3681 + 18: E9EED66D370A3A6A39C7E0E570D96F807EAC, A4AFE8D1D3C31B956A3BDBD043E7A665 + 19: 1A5D47992DA5597D1449B4C8DD47B7404C7657, F3ECEE5182014FC3365FDBC4C33CC06A + 20: E7C7945FD1AFD3F5DCE666D8A5A2E8A3C11A7A5F, 86D78B2FBA7597B8806BED505B52BDF6 + 21: 9E2165B47B29CBC4ACD50660E011D691F061209969, E9B1E860BD02085177E1A94E1EE6F3F0 + 22: 48EA2945C8DD3FE09407BAC8973A861DB15B788C8FFD, 502926712EDB1B3DD13806052C6C75D7 + 23: F37D46B35B60819EA52B00457D79155C04B55972D0DFA9, BB2B7D210BF0570F422640BF81F39B9E + 24: 12E85C0C78227205CC682360C79E35BF58EC6551CF8FE2D0, 042990D7A58D458C570A15DD375DB4E7 + 25: 4F6C15109DE980DD14A7F4C27F48671E4787C53A564232F427, B097A5990D8067DD89C21473150C070F + 26: AAC472E49DB101B564A8A01E2C80C0C6AE9065D332C2DE79FAB6, ACDD587A7DB86542E195DF73AF1C1CBC + 27: B9912CE18019C31692A1F7E11D9CCB20297ACCB9DC62C47C01D2C2, B0ACBF028CA5B15E0035D2EB8CA916BE + 28: B4F2B1FE14A1ECDC9C8EA1A0120395E6ED1E69D3FC85DD0F3F90F350, 9A561EBC769369B95B9CB74FC6AC27D3 + 29: 3FE397C8AD02689B7437A37861F0907AF1F6014A293B46419348771C5A, 6B7BEB9BD5018FECD71BE5081C7C2544 + 30: 5019089142199F7207E1B7731B8B247A18A685B231499DF12A73F5D67D37, 307E93446777005BA1B088F178A0DB6E + 31: EAE8F9F02F8DB3D70B78B08CFB0949D99F1A86C958A8E3823736BCEAB86BE1, 6C94F48591C18BF9C450515B73379973 + 32: B9C795F7A87305B4AD36DBA10B3B1C70B329D29E49C8C6A932D96A74334AEE4A, D18E6E233FEFD6E5C7148BDC1504299C + +EAX-twofish (16 byte key) + 0: , DB0C02CB069E3773296D3BD4A87A381B + 1: 99, 7D21D19E9C440F68E99F1F2EA2668694 + 2: 0696, EA590EC417C88E23FD23917F9ECFB0C6 + 3: B9B082, 82D4C9B68DDB02C906496413E13A2D68 + 4: D6B29D74, 5BCE5CA4F662E883BF7FCAAE5FB2CE01 + 5: A59C9CB009, CBFB04226D1029A7EC9D64A48A6729BE + 6: F4924FE3E355, 3D85B3900DECA0528C815F1447A1F209 + 7: 679C88D52FB519, 931C7A863C3701D8015FDBD8696C6C30 + 8: 26DA41C0D115375E, 7627E23E791A4DCB0FA5ED71B1ED2288 + 9: 8FEC6EB7016AD2B178, F65ED0286A724F0CB2EA317D5022B0D8 + 10: B5F22415B1334133C531, 87C4F3A8991BBB85984BC4D3305A5CF1 + 11: 23E1D0ED2E820AFE7DA2FE, 100499F1093FAB2ECF73B643594E98E3 + 12: 79519ABA91F46B8DAD6D5335, FBDCD1FCDB20AB99135F28A714C6992F + 13: 5968D0B4198A0AAD3D0395018F, 781F22E2DA98F83398FCF911B2010057 + 14: 4E55B14432B601E3EF2EF567CB15, 8BF6E53D7657E56EA3DA1BFD9C9EC06E + 15: 6ED89651CE19B3DD1EE5C8780B5015, 131CFD657D32D4E1B35140ADDCA0E13A + 16: 2295A968B4D072D12757756247554850, F35FAC95C2AA4155450EAAA6E2E789B5 + 17: F9B2AA2AA502EA79BBA0C5EAD932B8E1EE, 0ED81AA40B9BF39A9AAEDDDB7A04BEA6 + 18: 385055F1C1C26C0472A504B4CD225DCA55FE, 24831680B56368231AC54227D737F582 + 19: 771529585C741A3F8B1C973709892F255A99EE, 2A132B4BF96FD5109DB04459103F5E84 + 20: E7A2197D9FAA8AB8B303B5EC71AE34AD5EC5DD66, CCAB6518371EC8E0A9E9EE4F7CA5878B + 21: 279E54F755EAC6B57375B9EC4406E43DB3139D740C, 7B6F26F2C0ECC9F2DF4EDD7513E6E0B7 + 22: 27816AA94CBA2BF98E49E595AF5B3FAD12BF1D6F1AC6, D04876C5492D275F15C834E3CF794F0E + 23: B5658DC148855F68B282211D879F688F3C142FE555CF81, 4539CDA8A65DB9047AAD76B421B81120 + 24: 72F0BD4F939C2C9B4FA734DCB0AE4FB9BD342BC8459ED2FE, CEA8469BC0457EBF3418C1114288C904 + 25: 70568245E6E6BD5D11AD0C74030D7AE08BA05057DEA0FBF4AD, 71554FDE6B87477A51EE4499D78783D2 + 26: 8702D35BE07D7ADF70684046CC6C72FBBBF821E0BBCCBC973601, 33CC6FBFDA15E306919E0C3BB2E22BB6 + 27: 0BA23F4A6174165D4A8BA80B7C875340B0F8B2A6967D34E106BC22, 00E6679496714236EECEC84B9AF3072E + 28: B9E25ABA84C6BD95B5149E7616FE2E1D6FAACEAAD77A636C60279176, 8D8AD0B9D4C709E1DA370EE01611482A + 29: 74759711F6D542581F9F83498FB616638D092732BA07109BF4B5BE045C, 71A40DC777BD09F75362F7B20E0B7576 + 30: ADBF7E98926484BA2C7F6CD7CD9734FC19265F68AF3BFCAEB025F6296E37, 8DF15B5F69B67F7DABE44E3666B55047 + 31: 2DC26D449379997D110309B2A0DC2760FCE8CADB4B14ED580F86C70F69C9BA, EFCB60EB2B25737E256BC76700B198EF + 32: 2B1890EB9FC0B8293E45D42D2126F4072754AA54E220C853C5F20FBA86BE0795, 1A1B15BBC287372FB9AF035FB124B6A1 + +EAX-rc2 (8 byte key) + 0: , D6CC8632EEE0F46B + 1: 4C, EA19572CB8970CB4 + 2: 5537, 3EDD3253F6D0C1A8 + 3: 206FA6, 20FA88F03F240D31 + 4: 17EE8B40, 702E8194F1FCBFDE + 5: 2A89287136, 31C5534786E15FB3 + 6: 3A6AEDC7066B, 3C663A4081E1D243 + 7: 8BC5203947A644, 6AAC806C92BFBD6E + 8: 2E0274BBE14D21A3, CEB0E0CB73C3664C + 9: 9C4B292B0CF17E3A29, F23CD535559023EC + 10: 8E322734308F85662877, 46363D7EFC322821 + 11: C413C405767FF5F98E3667, E7BA35D8F3678E7E + 12: D77806B7A218098B1569EADC, BA67C306E5C0181B + 13: 4BE5EF74F9E9799A4D636FEA9F, 4C511C44ADBA4030 + 14: 7E19969170C2C8D8AEBA8C7FBC2C, 54CC6D466A2DF6DA + 15: 2EF1CEDC1DD3403CF440FC5561BE33, 61C6FB277E93701F + 16: DE052719153EBACE9D7B19F52AC4282F, 4AC2A96F2FA8634C + +EAX-des (8 byte key) + 0: , 44048B7F240B6F5F + 1: 0A, 37009B7D4E09953A + 2: 03BA, BFD2FD7758961728 + 3: 37EE10, 16A6AF96DE888A19 + 4: 07F44290, 100CA84AA0EDAA1D + 5: 389EF0023B, 9614FB800A533268 + 6: 3F4DBA8AA01C, EFA6B55B7ED5E40F + 7: 8C7B837896EAE7, C113CE8F664CE3D4 + 8: 7011D993D8EDB0C7, B4C370A919F60497 + 9: 0DEB30A31351B13D7B, 00ABC82DC5F3A1AF + 10: 8D3897B2CBE323D6EE1C, 7A2D15627CA1441B + 11: DBC002C817DEBFB419F94B, D8EB87F86D6ACDEF + 12: 17048E2976FA85AA849E9A80, 229FCD1C9D1E3B9C + 13: 30B989EF646544885A478AC198, C1B7EB4F799105C8 + 14: 5C2E12A7F118A08D6FD585F9C839, C358679FEE6FE7D7 + 15: 8D1A1E888BBB8648E638C4E74E11B8, 685E006C441448B8 + 16: 93AE906B8BE4EAC8ED6D8F48F04A7AFF, 71DD7AF752FE28FB + +EAX-3des (24 byte key) + 0: , 8914311BB990B725 + 1: D8, 2094EDC5D03E54B1 + 2: FEE5, 781CFB0EBE3895CA + 3: DECF5E, 59918E8A5C4B459B + 4: BD583AAD, 2013BEEBEEA795A1 + 5: 2BC01C6C78, 0B1134DBBEAB5D3F + 6: 4D5EAF01A895, AB4D17516ECBA50A + 7: AF229F90614480, D3113C0A9D133CD4 + 8: BCA6F375DF4568E0, 8E9EAEC8E77786BC + 9: 575F34219E6DD8DB4C, B40C75139E5D1860 + 10: A199B8AC433B615EC96F, 774AF803698ADE3D + 11: 718A2975DD9A872A68AE10, 3B9460F849CBA7FB + 12: AB38E148180F6E2FFBB96F91, E3EE3B8FC50DADBC + 13: EB10E0233507459D4A6C29EE80, 8D90B46BB1EAB27E + 14: EB48559C320DFB056C37458E19B5, 9315F0C4AF8500EB + 15: 9E8C73EADA105749B5D8D97392EDC3, 2E749EE66C1E6A16 + 16: 600FA4149AF252C87B828C780AEFF8BC, 33D7D11DCDC19936 + +EAX-cast5 (8 byte key) + 0: , 382FB8F7E9F69FDC + 1: 99, 20DA959849B3F7AB + 2: C54B, D05547C6AFA3484A + 3: 579836, AAA92B2321FC50C5 + 4: FEB7AE55, 639EDF01C4FB965D + 5: EA8A6023FA, 01274B3ED5CE102C + 6: B7C4E995121F, 712BFE27CAFF6DDE + 7: F44236660B0004, FAC51D1DF8EC7093 + 8: 01CD7E3D0BF29E8A, 049C47A45D868D0B + 9: DAB170493DFD6E0365, 6F3AEDD9A3ECF4FD + 10: 82C9EEC4803D9CD11FA8, 32683C0A9128C6EA + 11: 324AC59E87B244ECE0F32F, F6B095AAB49353CF + 12: DBDDAB11D02C9CA5843C406E, EA728FC46DDD3B04 + 13: D67376C2A4AD92E7DD80E39303, CAF72B7E7C237EB3 + 14: F2B9BBEF08036C2982C6DDD06918, 70A29D780C22752C + 15: 96E3D9141F8EBF520540C2BC9A9C23, CEFC86A1CD48203D + 16: 70CABBA983179106AE7FCD5F1F31D5C3, BF7F9168F4F82F56 + +EAX-noekeon (16 byte key) + 0: , 556805EEA595CFB9A30FAD196103D7FD + 1: F5, 0A7DAEDFB656526CEF4DDBA8087A227A + 2: 7B8C, 249895D79962D5B4D18FE07366281B72 + 3: ACFF15, DCC489D24832EB106F576AE6B6EB957A + 4: 08ADE7DB, 0D3215999E9960EDAB29B78744C7F139 + 5: 66139213F6, 505E1E7141D043E903C26EE0959EEECD + 6: 078B79F880A8, 35B7EB326A55E50332866EEDB682EC20 + 7: 2809E34D9667D4, FFDEC555F68524A09A6ABACA372077D9 + 8: 93D267DE1EC635D3, 4FF3561990A56E4B374618722EF850FF + 9: F377A4D93FF32F4A51, 91D4070423A90FC54D305169C03F49ED + 10: 6244B717E082993EB7A1, 2E3A8A354AFA9473667ED7FDD46BE9FC + 11: E917559625D25E6E5F2EDA, 19295C37A70314CC9A1D11FDE8D23C92 + 12: 1E6DF2EE112A893AB14DFA92, 12C4A89D4CD65F8116A03A135AFD3701 + 13: 47B18CD762E011770E203CF605, 434909A97E118B20D3AEDC79AFE33A9E + 14: 72D9A1A7DA6F33D5E0B927F9F32C, 779C23714FCAA2B2321EC7FB5B03E222 + 15: DA8B830FFCB3DB274807F780D33240, EDC2F1C8A401F328A53392597730B007 + 16: B53DD2BB840AD933D36A7B5FFDCCFBBB, 4EC0E6D1F916BF633869239B672B37A1 + 17: 42936BB9A936C30408660855F4F47F3314, F0DAA6DDA15585E1697ABBB4790B15B5 + 18: 00372E47F5BA016F1B2A1E680B76AB02052A, CDBF3D241BF7FF96D3DFBEDDB872E901 + 19: 8AA236B0C8BEF6F67A97C2DF90628F6E5838FF, 731DCD61F7F26004C03519F9500EA824 + 20: 55338647812FC9D86CBDDCED7120268A4D43F8BA, 0E61B3C835CAD95FD49FEF002C014E72 + 21: 435820B28E52154B47A04D5E635D8FE37FA47FC985, F6A96DCE4917E8D7C610923627E80970 + 22: 0D30C15B6FEB4A48B14DD15D41A4B25D442AA677B25C, 28E15CCB74AE992C68BDDC8D87802050 + 23: D9D701F9AD6B0E13D2CDDA15A5194E7CE8BD2C02137391, 2DB9A15884E9C996C3D6B5BDA44B9598 + 24: E2390AC5CE10CCFBC72106A52C7F180CB477E3C193CBACA8, 22D3F7DCD6947EA4E78DF57A8E1A9A59 + 25: ADEFB7D9500658D34996AF6BE6336CD78891064EA1DB8E9785, F239D67D039A15C620A7CD4BE4796B3F + 26: 89964C90ABF54A6DF9F13C3681E70C702D80A17BE79F8160F30E, 6336F729ECE1ED7368669D75B7E2DCBA + 27: 576B2813CECDA4F905BD5D58349EF070FF41B7EB6BB2B01B061B0B, 125324CBF2ACF1011A44A99A11EC8AFC + 28: 430B957481748519A60494F0B5F698F34B1A8235B00AC0D1F0A4442E, 1E80A7FCEBBB8E1E12D6831906154485 + 29: E781BFE5FCDE0BFC056CC86C4A0B9DD3B815BE8CA678204CF47289B5B5, 190D5AAA9EC1CB4CC86FACE53BF1201B + 30: 78BFAC07A9B7B2AE9329BF9F9BF18A1A49DD9587001EFCA00E9AD9752764, 4FB5ECBEEB0995C150EBC66508FA19C1 + 31: 7D6C20694109DE21F7955855A8FF832347518DD496C2A114DF142C68ACDEAA, B25D4BB34056DC091A7A3950D46C32EC + 32: 3E1E4395DEC1AFEA9212B95F37E679B6E2D14DF23C5DE49018C2C8038CC4AD45, 9A6DE7BD41A21918AD504490EF4E581D + +EAX-skipjack (10 byte key) + 0: , 85F74B6AFFB10ACD + 1: 3F, 604DF8BDD98A0B3F + 2: EA87, 792374FE07588BF9 + 3: 0169CA, 489AB8AF69DA3306 + 4: A7AC3EB1, 428DAF508E24B583 + 5: AA9028D5B3, C0A44EDA71FB2C86 + 6: DA97BA88A061, DA2EC34077F42585 + 7: 7E25FAA41CEBC8, 36D4987551E06D5B + 8: F662DA6C9001CBFE, B7DEF76680C316A9 + 9: 6D3F73EC716E1DA897, 5F0F83BAE4D3513B + 10: 2A300F585BEE9C889743, F4756C24DEB72A9C + 11: 80518B010DD77C82D19106, 50FF5CAA365F4A70 + 12: 6E579A2173C861B6F37B4CD3, 81E3E5ABBA8F0292 + 13: 5B04829880A72C38871C7021F3, 6B26F463708A3294 + 14: 934177878E9A9A9FB4DEB3895922, EBC1C32F0A2A3E96 + 15: 07AF486D1C458AAB2DBF13C3243FAD, 87288E41A9E64089 + 16: 84059283DF9A2A8563E7AF69235F26DF, 351652A0DBCE9D6E + diff --git a/notes/etc/whirlgen.c b/notes/etc/whirlgen.c new file mode 100644 index 0000000..2880d3f --- /dev/null +++ b/notes/etc/whirlgen.c @@ -0,0 +1,91 @@ +#include + +unsigned E[16] = { 1, 0xb, 9, 0xc, 0xd, 6, 0xf, 3, 0xe, 8, 7, 4, 0xa, 2, 5, 0 }; +unsigned Ei[16]; +unsigned R[16] = { 7, 0xc, 0xb, 0xd, 0xe, 4, 9, 0xf, 6, 3, 8, 0xa, 2, 5, 1, 0 }; +unsigned cir[8][8] = { + {1, 1, 4, 1, 8, 5, 2, 9 }, +}; + + +unsigned gf_mul(unsigned a, unsigned b) +{ + unsigned r; + + r = 0; + while (a) { + if (a & 1) r ^= b; + a >>= 1; + b = (b << 1) ^ (b & 0x80 ? 0x11d : 0x00); + } + return r; +} + +unsigned sbox(unsigned x) +{ + unsigned a, b, w; + + a = x >> 4; + b = x & 15; + + a = E[a]; b = Ei[b]; + w = a ^ b; w = R[w]; + a = E[a ^ w]; b = Ei[b ^ w]; + + + return (a << 4) | b; +} + +int main(void) +{ + unsigned x, y; + + for (x = 0; x < 16; x++) Ei[E[x]] = x; + +// for (x = 0; x < 16; x++) printf("%2x ", sbox(x)); + for (y = 1; y < 8; y++) { + for (x = 0; x < 8; x++) { + cir[y][x] = cir[y-1][(x-1)&7]; + } + } + +/* + printf("\n"); + for (y = 0; y < 8; y++) { + for (x = 0; x < 8; x++) printf("%2d ", cir[y][x]); + printf("\n"); + } +*/ + + for (y = 0; y < 8; y++) { + printf("static const ulong64 sbox%d[] = {\n", y); + for (x = 0; x < 256; ) { + printf("CONST64(0x%02x%02x%02x%02x%02x%02x%02x%02x)", + gf_mul(sbox(x), cir[y][0]), + gf_mul(sbox(x), cir[y][1]), + gf_mul(sbox(x), cir[y][2]), + gf_mul(sbox(x), cir[y][3]), + gf_mul(sbox(x), cir[y][4]), + gf_mul(sbox(x), cir[y][5]), + gf_mul(sbox(x), cir[y][6]), + gf_mul(sbox(x), cir[y][7])); + if (x < 255) printf(", "); + if (!(++x & 3)) printf("\n"); + } + printf("};\n\n"); + } + + printf("static const ulong64 cont[] = {\n"); + for (y = 0; y <= 10; y++) { + printf("CONST64(0x"); + for (x = 0; x < 8; x++) { + printf("%02x", sbox((8*y + x)&255)); + } + printf("),\n"); + } + printf("};\n\n"); + return 0; + +} + + diff --git a/notes/etc/whirltest.c b/notes/etc/whirltest.c new file mode 100644 index 0000000..9184f77 --- /dev/null +++ b/notes/etc/whirltest.c @@ -0,0 +1,15 @@ +#include + +int main(void) +{ + char buf[4096]; + int x; + + while (fgets(buf, sizeof(buf)-2, stdin) != NULL) { + for (x = 0; x < 128; ) { + printf("0x%c%c, ", buf[x], buf[x+1]); + if (!((x += 2) & 31)) printf("\n"); + } + } +} + diff --git a/notes/hash_tv.txt b/notes/hash_tv.txt new file mode 100644 index 0000000..7fd9062 --- /dev/null +++ b/notes/hash_tv.txt @@ -0,0 +1,1736 @@ +Hash Test Vectors: + +These are the hashes of nn bytes '00 01 02 03 .. (nn-1)' + +Hash: tiger + 0: 3293AC630C13F0245F92BBB1766E16167A4E58492DDE73F3 + 1: 5D9ED00A030E638BDB753A6A24FB900E5A63B8E73E6C25B6 + 2: 65B0E1EA36CA17EDE2F055E67EAD67B1C282A11A5BA3A8E0 + 3: AB7FB8D21CE3D8D9BB5F1AF1F2FA0D3C277906160DB8D226 + 4: FE2E9D43F74B199D91B9291D73CCFCA0BEA5F068FBA244FF + 5: 3DF6D672FE9DAAB21523EB04705D8A8B72B78B00AD465D1C + 6: E05724353FE29957C3E8DEBAA21D0C2DD49CCA22191D5AD3 + 7: 4056DDBF82AE74AB56720DEAF079ACA2F076ED046D044DE5 + 8: 801FB9BE1A9AC7337A81345B3845E4E7C13AF1FBADB73723 + 9: 430156547A82492CA859385304748F65F2D4A7E2664AE2B1 + 10: FC435137CD652D720A11EDF47ABE4680BA4AD5BD810C9835 + 11: 20A8143DF47F5715FA0905FE6F9D1D2B5B2D4E26FA98930B + 12: E4A2063019FBC034DEB01E2A95296042319CBC039DA69A91 + 13: B5F0FA570C4CD69A3C68448BE42C865BDF77ED68B93875E7 + 14: 802BE6EA2CE86A0B371F2354944B19CB3231AF7FB4F00FF8 + 15: D7C08863B5E5E3D69B5404A116315A698E128EBAF8636B70 + 16: 5C5288CB0E4E533056BA5293440D9BE6F3C461233BF1ED51 + 17: 88D3A94F3820E4087DA69D8BBE2CF415466063709C450C4D + 18: C07B4B155F9F75805D9D087087FCDD28D08A9D022192447E + 19: EE473E569FF3E092CF8996B31CE665EA7D61520D42E27395 + 20: E13DAE8098139CFCEA755D2060F107E3C7581EDF9F4B3B85 + 21: B48A9C09F26B379AA28FBC750B50CEF69D0D0EE37FF765F7 + 22: 574A01456373014F4179CDA14541E2E3C5A1CDDA9F9D071C + 23: F2E2831E5BB4AF05914C4BA61BB8D600D1EF071C5DF02269 + 24: B7808A5B6258CBE718EDA938978C69D3FFC45A222E9DBF4C + 25: D8E4E076DDE78950D51EAC9F97D2D1916A0910465D45A55C + 26: 4EDECFAAE1DE98B7E056E64CA24003422BBE6F048129B24C + 27: 0DE283B5A4953EAAEC6F3FDE50D7875C8EE57FA79BDC70FC + 28: ECDD4BA1936DB9E6F83E2BD7F39D23927A1A17B2D52A8649 + 29: BE11893460E49659F7DF3FB3BD5E3E9A319F85FD3496E26C + 30: AEC0DA0F2CC0646325CC03319A0E080F68B46B33F81920D6 + 31: 8824FD39984F6A52FFFF19016E27C594921452086373F2EE + 32: 8B6592AFBB02E227AA451B5CFDC821B84245D34B96BF4F13 + 33: 960DF9C349EC6619FF37E3F0F4832E19CC6A4E4D68962651 + 34: F4E2B7AA72BC7D6E0CF6DA1094BEEFAA9C55610327C62900 + 35: 05FD1B80CA4C7C14FE5BF0ACBD0EA3DAE498DC391DCF2277 + 36: C5E95F953898C68355B591507BB714F0E5DAB9989D083900 + 37: B2D4E286CF7EA8AB6ECD650C9E48CA23497EADE55485DB1E + 38: 9D51657E11C54FFDF205DBB435097A2BC6F93C4BE8D6180B + 39: 3C6AE3911356A343AE3113735F07FCFB5E046ACD47B00FBB + 40: 664342CDECC825ED340A7FFE2E57107DD0B5F24C24B2C3F0 + 41: 4EF7FCA13CE684D81DE4F566D2897CEB407FBB3DDE81FD64 + 42: 54689FECED63F297B13CD494B85E686680F4F78DE7EC81D5 + 43: AF434BDBDC7EF90BE03E40A033F16E8A57B41840E1E8AB59 + 44: A32DB678F44905C18968F5D898CA7992EBE2E4CC3318B96C + 45: DEE9D519A12ACFB8A0935A368D6E6C75EEEEE6F2B0D5D191 + 46: CBC74863472D1C9D23C526F4908BD4D4234E00CBCC99A9E9 + 47: 6C228A1D4871E802E035C9BB16C5187354841FB6BE3C69B6 + 48: CAA755C55AA869E633CB3C6D93A561944AC7418154E2B0F0 + 49: A6835F7C0C6CA8F4A45787BAFA77478AE9ADDBEFBC3052D3 + 50: E406755957EC21BA6A64B5D3AAF31749CF98DF92F1B1FFE0 + 51: 0C2D4A44A803DBA99B7A467553C9293B46A538558BD77DD4 + 52: F04F011B09D275A185528CC040EB719649C8471A87B259B3 + 53: 3DA8B57FF52FCAE7C32636EC6C80708189CED8113C5CDE1E + 54: 6C6C88B8E18DF5CB22EDB61A2D3ED74741A708BC46576FB7 + 55: 2D48EE2BF85DE234754BECF3C6F5B0E62988B5BF24AEA5BB + 56: 0D17702DDCA078ED1CC51B95DF29EA1053CE97F69395C613 + 57: 9D8C2AD327DE43D5782D5F20881F4A8C433BA19AFC8C15AD + 58: 227BA419B760D9D10DBB09585EDD475AC2734FD4539F8275 + 59: 2F5220A828EF94E327BD51D4DF5C58609F8A93B9FE01FFF6 + 60: 0EED9F91E1A33A50B8E913DBA0B5E248D263E1FC72C6A449 + 61: 766B707E999FF3C51EE01168513BA0DCEFEAB222DD1F69F6 + 62: 85E6710694E7C36A2340DA6A371C0560450F3D44D35AD98C + 63: D401F9B13D39C24477C0AE6971C705C63C067F29508C29C9 + 64: 212DF89C57155270344ACCB19027B0B26B104FA0FBBE0FE4 + 65: 3BEDE767AA4A7507DBEFF83D1BC33F67EBA9C64945066227 + 66: 79FED1FB9F17C4980108E8605C10D9E176AC8FE4F6A65064 + 67: 48D9B7622AB7F8968ED926255F78E8CE461E4C9162FFE8B7 + 68: 6638C83837297B3F53B0F824C087D9A0B8D9FC6265683B8F + 69: 174421CF6D331FF51924F8946E8244555C9020D38E31B6DB + 70: 03E42AFB5FFF9B9C3794A3DBEC99FA7E3F7305EF07BD29EF + 71: CCAFC68D4B3ED889DC9F28CB9225808A40AA8E0D5CA343FF + 72: E824F93B4022011886EFC54539D4D5D51863ADA329FB4E22 + 73: 7CF0DC01B326687530F42040BA0D0CE93174455E8A990D14 + 74: 7A8E619479F4F5C418EC041806850E6723CA56AFBC3D32CC + 75: 083C5CA90F4B296C42040559C8296149D4EEBAB5EF2CB82D + 76: 3581B7AC32FA8A0986FD14F277FB106E112B92D18CD689BD + 77: 258E822D9CC1ECA8B55D925BA361BA2D9FC27AF181F138B4 + 78: A86C1E88A64515FA281A462D467458231494F16E835DF873 + 79: 76E7F06FE9B8B388DB012F8B4BE2FB343F95913EDDE47A27 + 80: 00278B4E5690E729EC7118B5BF63C9D1EB1268960893CA75 + 81: 8DE70E64A31BA1AF4F5C23CF774CCA32FE952D76C3FDD1B7 + 82: BBEA72C840749BABAF1415FEAC343411B89515B87848A09A + 83: C6C3CCAC1B338DF117A61ECF9A280E9BA709784C72B76771 + 84: AE9813EF4429EAE73EA9FDB5E23D263AF1BB87928CF5F048 + 85: 68647CD7BFFB8E530D28C86685A8D2F657EE4CD64EDD7E66 + 86: AA8C35B0E746AF56435F6C711AD0423966EA459087409713 + 87: AAD5C0D5E980B29BC88985C544717B81F58CDB923A3468E0 + 88: F60929D14781DE44EA607AAFC0D25FA1B6EF3C6AA0F8B3D7 + 89: C48087DC75EC43A54A593F24E1B359BB75C581A65C3170D0 + 90: 11D1372FBDFD9FF514611AB20D31BA62F18856C8D6AE3AD7 + 91: F2A8076B9017EDADEED41F409C9E32EB3BC090EAE89F855D + 92: 702FA47E5BD35E344B5B87C0082106337206CADD3D4D5014 + 93: B9E03FED752A560C3B0365EDF5BFC4DC7EAC5E4BBB93738D + 94: 3C84C52BF51077A5819F56E5A5C1C06209181579393220C7 + 95: F8ECCA28A525594E138B55C06617A063DF74FE3469D98381 + 96: 1081C3BAEEC0ADF4980C2EA6593B0906DCBEDE4805754774 + 97: B5152E39DE0BFE8982D783FC4F0CB7160EB2D69F6F3B3E5B + 98: 6A6B760BFB1965C72AC793F9C02FA21B0F1C34BD2640BB6B + 99: 1E6DCBFA8BA8D96C29101768A6A39433D5AD5A50E0970730 +100: 733222D3A033351FAFD68C5CE8A4D833BA7420D44103CB6B +101: E4CD7DA59B215F1DEAA8FBBA850F2C1A7F4C3D495FE6804A +102: 7BE78C790713545754D4C78A9318ACA4AA058C5C23540131 +103: B71C3809A504BE2F57AE9E25BDCC3921DC665C65289EA55A +104: 2B8CA39977535EB692EFBF0DECDA8971A8604F7FCBAE75DD +105: 3CC48B51E4C5DE4F0C2ABE0BE6EE4B63CC564A87C01943CD +106: 157ACDF7B59FC25966F9783207554364882840E7251ED6C1 +107: DEA1CFAECF18D3611CCD0517131A16DDBC97A12902DD8BAB +108: 2AD2E990BCF6481284DF44B961632687C2E64DFAE2AE16C2 +109: 838F3A3B28A50A12B5707490A66080DCFA0230E583B6EB14 +110: C8B20315121CDFB3A91BC0EDF11886F283CF6C480F498627 +111: 2B0FB04F100BE9AD51B7D64C76651BAB4B7D31D1D9195711 +112: B6495B6256FF464EC409A4098B622E8BDBB1003411854FD7 +113: 1741A789472E20E1CC89869A2477E4F2807C22182EA5B221 +114: 07ADC82CB3F27389A12B6B9C2B268BDDFD1D9478D9EDA0D7 +115: D9BD6760FB819A8A3CEE75303F8208FCA3E138B517DAB934 +116: 9FCF21A9236C2C12861FD20F1FB15A187CD7EE7821F72BE7 +117: 73D165769B34DA6F151464E61115D0E09A66F8D0FA049726 +118: 74580BFA88EEA03C0EAE722F81997E400D9CC25FA0311DFA +119: E3C6A369820E267C938D276A858928040C7C25A826501DC7 +120: C20AD90DB0B8BEE0335D069259991060969EEC9F939E4CA7 +121: F3746F4CD6A19CC137C5FCC8F60A4C0A7F56D97190B7A9C2 +122: 63A3B79EAF3DF35180960465059C0ADEE06D45179A56284F +123: 606AFD833D082628D58672403EE6DB348E6F68D8CD1947F8 +124: 7567EA8E10CBF312F8478B7C51D87B00B6CF3DE82B03DCE7 +125: DBCDC2B9B8589F6C7616B55B059B3B3E38D97A9E6DF1F29A +126: 15D9909F8D69689E7E78A0DB928194A59623E7253AA9D400 +127: DE39589DCC0C654867943801946B9888B347526279CA15BD +128: 34FA7C74EE67C1F92C0BE1CFD4B2F46A14FFB999604925F6 + +Hash: md2 + 0: 8350E5A3E24C153DF2275C9F80692773 + 1: EE8DBAE3BC62BDC94EA63F69C1BC26C9 + 2: 1EAA4F494D81BC570FED4440EF3AC1C3 + 3: 54CDB6D1BF893171E7814DB84DF63A3A + 4: F71A82F8083CD9ABA3D0D651E2577EDA + 5: 2F708334DBD1FE8F71CEE77E54B470F9 + 6: E014DF2DF43498495056E7A437476A34 + 7: 9C410644446400B0F2C1B4697C443E19 + 8: 0944DEC40367AC855117012204018C9F + 9: CE8A6E797AC79D82D2C6D151F740CB33 + 10: 06DB4C310570268754114F747E1F0946 + 11: 9F323D5FC6DA86307BEBC0371A733787 + 12: 3C1C7E741794D3D4022DE17FCE72B283 + 13: 035D71AA96F782A9EB8D431E431672EE + 14: 7ABE4067ED6CA42C79B542829434559C + 15: 5E8D0D6F6F8E07C226AE9DD32609035A + 16: 2B1632FF487D6C98AA3773B9D3FCD2AB + 17: D3D894482F7541BC0948B19842B479D9 + 18: CFE6B872AC98304524CC6A88B6C45881 + 19: 1573DD015C8629DE9664CA0721473888 + 20: ACFE2D3BB3CCAD8AEF6E37D0D8FBD634 + 21: F5F83499AA172BE8344F7F39BA708AAA + 22: 1D1C71FF6321B685D26F7FA620DA6C22 + 23: 4D7E74B6C8321775A34F7EFF38AAE5DF + 24: 351A988C86AC5A10D0AB8E9071795181 + 25: 970F511C12E9CCD526EFF8574CF1467F + 26: 0A68F53A476F7499EF79278A4EE8DAA3 + 27: D458CF9C8CD0ABA23BD9A8C5ABE495CE + 28: C8002E85C3AD9B8B4AFD23378165C54B + 29: 0B4788B157ED150A34D0E6E96BB4789C + 30: B14F4E31DE09281E07248A17939BE5B9 + 31: 803EEB99231526D6A33C8D4FCA537A6F + 32: 51FE5D6637D2F0F09E48CE2A7F5030EA + +Hash: md4 + 0: 31D6CFE0D16AE931B73C59D7E0C089C0 + 1: 47C61A0FA8738BA77308A8A600F88E4B + 2: 9E7A1DDE4D280E7F389018A5CCC3ABF2 + 3: E9A4DB2923FAF634CBB12CC1F8AC5C66 + 4: DF8FA069C6121801FFC539DADD33FCB9 + 5: 4B3511308F7E71BF6462CF18F1184C61 + 6: 075582A51F87682919E733C84C9FD998 + 7: 20DDA7535A464D13E1763BA61BDC12AC + 8: 66AE1E305BED186780BB60328D3CCBC5 + 9: 503E90BF2375627262E58D90177220F8 + 10: AEC6B48C10659E3D6E18A2CDE8F8D3A0 + 11: 45EFB3704B6684B0750E3DEDBB2BCDA9 + 12: 7C9443DBCD858138E32604E0D288F7B8 + 13: 95E5B93F4EA79C082BA1745D3026D70A + 14: C913D5DE0BBD1C2F2838E46363732D97 + 15: ABE357BDC413C82C8BBAA380C39CB5F9 + 16: 22F840370EBB1DDBEA4FA3A40243391E + 17: 0A289FEC69AF967988FA40C47960060B + 18: B63D3ADF13B509C95C088F909A0B356E + 19: 36E8E07E3202E6F4F7E885853C9735C7 + 20: 1D363AFD1208A7B8BD486D51AEBFAEB8 + 21: 75E36A5445AD72CF5BF47301EBED1FDF + 22: DA7979688F48A6606D86C762DF0D8850 + 23: 6ACB325CE624372873CC01A4AA053F8E + 24: 94F9BFD6503DBDC58C163E33504B7EDB + 25: 3702CB296784290FC46B82445BF7EB17 + 26: 903510251E7A00415EA21B6AC268A92D + 27: 6DF08DB9C33C86CFE8DAF5E5BB865ECE + 28: C29C5223D89A6589DE9253AF050D3449 + 29: 16B935ACC3EC6C016CA1BBF727C272B9 + 30: 644C01B157A24584B02A32119A424C01 + 31: 4A3C6C73634759420C419426F7D43E67 + 32: 7BD627A6B82FF3D797FFF130D8956391 + 33: 811A69D6A8AFE3C4FE5B4EFD73804F6E + 34: 721BE5F4BDDED885BFF842868F62F4ED + 35: 76956871B22D5BECAD3E9A459B4A448B + 36: 4F2CF372771A13B4C0C1A589F0EDCF87 + 37: 084AFBAE8D22DF83CC760A61138E560A + 38: E1CA123EBA05CC4899731A593833F372 + 39: 9D9E277FA61993C018C1C61AE09588BC + 40: 85E0D0316F0B76578948810039EDE2BA + 41: 27736345D0F2B0A1A9576D17C47D0202 + 42: DC9F788BE7C97BB5E0D2DD49B9F1D2DC + 43: 27F1A9A0D166C495493877DF06E9C104 + 44: D1ACA7951866F58773CD4AFA3D2F5C2E + 45: 5204BE3729BD7D318EA8127BED82D5CC + 46: 10258B7939D81F5F8E0EA70EE6500B08 + 47: 4E699952169098ED3084DC2EEE7BC488 + 48: DF6ED8D604512088FCEAFB21808BF7D0 + 49: 904D0667C94C9C981D59BE80DEEEE628 + 50: D83483A47B64D74F9DED5278EE462404 + 51: 490EC8799A9DE3BDE8708DAF68E6888E + 52: 443E4D2D5F800C22D818927A29A38490 + 53: 48E82AA772E111FCBE393177F3123963 + 54: B72685D042162D5F30472281278C42F7 + 55: CC8A7F2BD608E3EEECB7F121D13BEA55 + 56: B8E94B6408BBFA6EC9805BF21BC05CBD + 57: 6AEC85410412FF54078A9FC72A55ACE5 + 58: 3E69F792BE88478883E46E867F3C93EB + 59: 3B057FC41BA700F0E46740B8FF391F52 + 60: 3E3C6DF9500BFF8404486A3AEFC6F16D + 61: F5AD65BA970ACBBB8335F9C0B9D7139F + 62: 75D45F8E48406E32ABF94D07FF9B9C84 + 63: 54BA4472FCD03E99CF28F90EED9F2AE0 + 64: 2DE6578F0E7898FA17ACD84B79685D3A + 65: 3A4F2CA37EEBDF6DC99A6155517B74FC + 66: E19DC463C01E1B712B9415202A2B5505 + 67: 61D8AA0838DEAEEADE2F26156AF58761 + 68: BE294AFF81BFEA3159564B8B61844EFE + 69: BB943319320EE7B3A029D7BCD101F92F + 70: 36239791A7BE33AD46F668B51D724481 + 71: 21DCC9A32031428B7B02F68E1450A0F3 + 72: 95C1B0832575E21982B17CCCCAF54556 + 73: 24939E25985A3B5620B19D7889E5E153 + 74: 3029C8B005386705FE7E4CBAA060E987 + 75: E8BD97C5C1A0CC9AD1F1BEB3913B22FF + 76: 808EBCA0B0E6FD1B30E4BA499C05EF9B + 77: 55BD20AB87DE2E536DDE22286D0922D9 + 78: 2B2E45FA5628F29DA06462378D17DD12 + 79: B90F1709241EF59F78666AEBB3D5607C + 80: 37854275343F079BCE1639C84D74AE1C + 81: 444AB5A4F39B765C5D67BB433D4CF0B1 + 82: 7E30CFA6363F9AC96607783710E151B9 + 83: 9D9252DFFB2D5023CFE34873EA6C43AE + 84: 49A70634AFCED27DC2DF2EB079F7A1E6 + 85: 4C976C9EF13716CCB468D82BD8C56FE2 + 86: 4EB382D16DDC18C31E6DBAC6CA83247D + 87: B16112D0FF3C6A8ADB19C13DF742F5D1 + 88: F703DC6100AE23D194E01EAC433CF28B + 89: A6527B1B907218063BF196AA91C73F47 + 90: 61F1A1E947F3F542FCF85AC758BA5D14 + 91: 12ADDEDCE418E9444AE34A40353ED0EB + 92: D1C35142C475D44A52CEB0A8FAEA7AAB + 93: 1F89912C1FC59AAB53C983B035661269 + 94: 2E7E19A4A6635AB5958DDA70B415EB06 + 95: B700B6739C0AF162D246AF07284A1AE8 + 96: E2B95AC9F876A38D33CCBBD7FA92D67E + 97: AEB4849953750A10BB236BAC8D5AB487 + 98: 82D738AF18FD4B26FFF61377EE921E62 + 99: 0E1451640E59CE0461A46934F174E237 +100: AE06EA64074E8C07116563E8E0893BDC +101: 562DCEB678FBFAB24141E591FFD471B1 +102: 7DD6C3C2884E483E8CA572C471B2D812 +103: 2A4C8E4EC2672C1D54A8DA8F32F04783 +104: 2BFED22E8810A4658060B95B0ADB60BC +105: 214D8F2DD099BAB68EC17189BFF8A8EF +106: 98E4EB29797C8E631CD4317AF422FB05 +107: 241A0F826F359A21CA0E6D9154D1E291 +108: A3398C0118A3605E7A7794B8DF7CA152 +109: 5B0A6FC8721F14EB8A03E9A5D87F173B +110: D93ABEC3EBD5672350C3C36F8FB00E53 +111: 659905751D1F614A78ECBB56D4398D06 +112: 594691B38126E028352DA5B28ADFD416 +113: 7533FBD1FD58C85D54A712EF218A9D53 +114: 654796E7D2F9F2C2D166F23B5AB18812 +115: 5D25B604FB75727AE7EBFF980F54D96A +116: 426A7709CD61EB6ECF4034EC83E073EC +117: 62E21CA2F8E39C03BFF56C8265ACB60A +118: B7C9DAAA89A29F2805DEDE790DCB9575 +119: 9C1067170940CE8F8E4745D362675FAB +120: C5BB35660E3D0A286A96EA3AA4922B3C +121: 8F3B6351623A0E482B57525474DC703A +122: CCC34CC280340681CA5117477DD86AE8 +123: 2F5FB6B41301F87A0490035DE4C1BB99 +124: A16E28DB3F331091E928F9AE3F1ACEB6 +125: 7D2259C98085B9BF7F5E36B29DF8384A +126: BDDA1266FF3E8FFBA1DE1B2759B58BCC +127: 2067886DA4BDE10A94B971CD740B0AAB +128: E1275970EB67D2D996E6E658270AA149 + +Hash: md5 + 0: D41D8CD98F00B204E9800998ECF8427E + 1: 93B885ADFE0DA089CDF634904FD59F71 + 2: 441077CC9E57554DD476BDFB8B8B8102 + 3: B95F67F61EBB03619622D798F45FC2D3 + 4: 37B59AFD592725F9305E484A5D7F5168 + 5: D05374DC381D9B52806446A71C8E79B1 + 6: D15AE53931880FD7B724DD7888B4B4ED + 7: 9AA461E1ECA4086F9230AA49C90B0C61 + 8: 3677509751CCF61539174D2B9635A7BF + 9: A6E7D3B46FDFAF0BDE2A1F832A00D2DE + 10: C56BD5480F6E5413CB62A0AD9666613A + 11: 5B86FA8AD8F4357EA417214182177BE8 + 12: 50A73D7013E9803E3B20888F8FCAFB15 + 13: B20D4797E23EEA3EA5778970D2E226F3 + 14: AA541E601B7B9DDD0504D19866350D4E + 15: 58B7CE493AC99C66058538DACB1E3C94 + 16: 1AC1EF01E96CAF1BE0D329331A4FC2A8 + 17: 1BDD36B0A024C90DB383512607293692 + 18: 633AB81AEA5942052B794524E1A28477 + 19: 2D325313EB5DF436C078435FA0F5EFF1 + 20: 1549D1AAE20214E065AB4B76AAAC89A8 + 21: 7E437C81824D3982E70C88B5DA8EA94B + 22: 2F5F7E7216832AE19C353023618A35A8 + 23: 6535E52506C27EAA1033891FF4F3A74E + 24: 8BD9C8EFBBAC58748951CA5A45CFD386 + 25: D983C63BF41853056787FE1BB764DBFF + 26: B4F24C1219FB00D081C4020C56263451 + 27: B0AE6708C5E1BE10668F57D3916CF423 + 28: BA7BB5AD4DBA5BDE028703007969CB25 + 29: EA880E16EAC1B1488AFF8A25D11D6271 + 30: C7172F0903C4919EB232F18AB7A30C42 + 31: E9E77893BA926E732F483282F416FFAC + 32: B4FFCB23737CEC315A4A4D1AA2A620CE + 33: 5506A276A0A9ACC3093F9169C73CF8C5 + 34: E5A849897D9CC0B25B286C1F0BFB50E3 + 35: F54FA30EA7B26D3E11C54D3C8451BCF0 + 36: 07602FE0229E486957081A49E3F06F83 + 37: 7C4BBA98253CA834BF9ED43FD8B2F959 + 38: CF8DF427548BBFDB1E11143FDF008B85 + 39: 1431A6895A8F435755395F9BA83E76BF + 40: 30DD5E4CAE35BA892CC66D7736723980 + 41: 8EE247A1063931BEDAF4C2FA3E4E261A + 42: C32CEEE2D2245DF8589F94FCDA0C9F2C + 43: F25FA0E071D1F1CDC6632C6B673BCCD5 + 44: 370491B643E97577F4F74BD88576D1EC + 45: B292BF16E3AAFAF41F19C921068214F8 + 46: 52921AAE5CCC9B6E8E45853419D0C80F + 47: F1375BE31969155EF76F04741CD861D7 + 48: 04605CA542B2D82B9886A4B4B9ACFB1C + 49: FA887BA0FA491FAAACBB82BC5FEFCD5B + 50: 06470E932AD7C7CEDF548B5CCB9D4806 + 51: AD130B245E2DD894267CB0DDC532D169 + 52: A9EEB95053682248608E97D79E89CA82 + 53: CC26A3DC608268B98ECD1F3946C4B718 + 54: 33DD62A2DF6538DAF1CF821D9CDE61F9 + 55: 6912EE65FFF2D9F9CE2508CDDF8BCDA0 + 56: 51FDD1ACDA72405DFDFA03FCB85896D7 + 57: 5320EF4C17EF34A0CF2DB763338D25EB + 58: 9F4F41B5CDE885F94CFC0E06E78F929D + 59: E39965BC00ECACD90FD875F77EFF499A + 60: 63ED72093AE09E2C8553EE069E63D702 + 61: 0D08FC14AC5BAA37792377355DBAD0AE + 62: F3CDFFE2E160A061754A06DAFCFD688B + 63: 48A6295221902E8E0938F773A7185E72 + 64: B2D3F56BC197FD985D5965079B5E7148 + 65: 8BD7053801C768420FAF816FADBA971C + 66: E58B3261A467F02BA51B215C013DF4C3 + 67: 73062234B55754C3383480D5EF70DCE5 + 68: F752EBD79A813EF27C35BED69E2EE69F + 69: 10907846EB89EF5DC5D4935A09DAD0E7 + 70: 5F1F5F64B84400FB9AD6D8ECD9C142A0 + 71: 3157D7BB98A202B50CF0C437AA216C39 + 72: 70E7ADE70281B0AFCB1D4ED13EFC2E25 + 73: 0BB96A503B1626C9AB16C1291C663E75 + 74: 5BED4126B3C973F685FCF92A738D4DAB + 75: 7523C240F2A44E86DD22504CA49F098D + 76: 6710949ED8AE17C44FB77496BEDCB2AB + 77: 4A4C43373B9E40035E6E40CBA227CE0B + 78: 91977CBCC32CDEAEC7A0FA24BB948D6A + 79: A6A0F1373CF3DBEE116DF2738D6F544D + 80: 761F6D007F6E5C64C8D161A5CED4E0AA + 81: D44EA4D5A7074B88883A82F2B4CFBE67 + 82: 3097EDA5666E2B2723E8949FCFF2F244 + 83: AB247A3D9BC600F594D5A6C50B80583F + 84: B229430E3DB2DFDD13AA1DA1BAC14D5C + 85: BEFEF62987C6DCDF24FEBD0BB7CD3678 + 86: BFC3E5C7C461500FF085A66548378E0E + 87: A5712194537C75F0DD5A5AB3E9EBAF03 + 88: 8DAAC097E9044B85B75999D6C3BCCD24 + 89: B8124DF21129685597C53A3F606FFD28 + 90: 8FBC4D795C22D958248582A8DF7332ED + 91: 36D217135DB136B2BDF1617D7E9C79CE + 92: 1B3E6271A3A4B663C509A1255027CA99 + 93: A25F596574031FF9C34314C1B1F6BF34 + 94: ACA7017E5BB62BFDD5BBFDED78C8987A + 95: 8129E53A694ADD0560B1534B32FE5912 + 96: DA0E48224106C7535A4CD8DB2AC7B8E3 + 97: CBD4ACE3D766D8E44F63E0DE8F110F04 + 98: BDC17A0EF2777512CB402C90E9D13E31 + 99: 47695AD6AF968D6F1CDD2D8C5C87A466 +100: 7ACEDD1A84A4CFCB6E7A16003242945E +101: 225489D3D073AC705F7B3AD358EABAB2 +102: 301DA87A7B2EC27514C3A2789D5DBE49 +103: 16222C503718F1420958133C330FE3F8 +104: D778CE7F642AA23355948477DA4CC11C +105: E873C37F8977E200A594B815E1A87EF3 +106: E8F8F41528D4F855D8FDF4055BBABE2F +107: CACF3D3D1E7D21C97D265F64D9864B75 +108: 6BF48F161EFF9F7005BD6667F30A5C27 +109: 42E7BB8E780B3B26616ECBCACE81FA1A +110: 225AFD8EC21F86F66211ADF54AFC2E86 +111: 4FAD3AB7D8546851EC1BB63EA7E6F5A8 +112: D1FEC2AC3715E791CA5F489F300381B3 +113: F62807C995735B44699BB8179100CE87 +114: 54050B090344E3284F390806FF716371 +115: 50482241280543B88F7AF3FC13D65C65 +116: 4C36F27D4786FE2FB8CAAC690B6D62F7 +117: 5A0EDF0B97977EE5AFB3D185B64FB610 +118: 4541055C6675B614D27C537C3BB15675 +119: 1C772251899A7FF007400B888D6B2042 +120: B7BA1EFC6022E9ED272F00B8831E26E6 +121: B0B2D719A838DB877B6D6571A39A1CDC +122: 800AA956EC16F603ECDBA66C2DC6E4CF +123: 8827D2778287C58A242ACD4C549BEB31 +124: CFBC5AA0B61103C1A982D8927B26F575 +125: A1F5B691F74F566A2BE1765731084F8A +126: 80749BE03F5724FA4CA0AEF8909379B7 +127: 8402B21E7BC7906493BAE0DAC017F1F9 +128: 37EFF01866BA3F538421B30B7CBEFCAC + +Hash: sha1 + 0: DA39A3EE5E6B4B0D3255BFEF95601890AFD80709 + 1: 5BA93C9DB0CFF93F52B521D7420E43F6EDA2784F + 2: 3F29546453678B855931C174A97D6C0894B8F546 + 3: 0C7A623FD2BBC05B06423BE359E4021D36E721AD + 4: A02A05B025B928C039CF1AE7E8EE04E7C190C0DB + 5: 1CF251472D59F8FADEB3AB258E90999D8491BE19 + 6: 868460D98D09D8BBB93D7B6CDD15CC7FBEC676B9 + 7: 6DC86F11B8CDBE879BF8BA3832499C2F93C729BA + 8: 67423EBFA8454F19AC6F4686D6C0DC731A3DDD6B + 9: 63BF60C7105A07A2B125BBF89E61ABDABC6978C2 + 10: 494179714A6CD627239DFEDEDF2DE9EF994CAF03 + 11: 2C7E7C384F7829694282B1E3A6216DEF8082D055 + 12: CFF9611CB9AA422A16D9BEEE3A75319CE5395912 + 13: E51F9799C4A21BBA255CF473BAF95A89E1B86180 + 14: F741644BA6E1BCF5FEE6D3C1B6177B78468ECE99 + 15: FB1D9241F67827CE6DD7AC55F1E3C4E4F50CAA03 + 16: 56178B86A57FAC22899A9964185C2CC96E7DA589 + 17: 0A0315EC7B1E22A79FC862EDF79BDA2FC01669E3 + 18: 32AF8A619C2566222BB0BA0689DABCC480C381D5 + 19: D35B5AFBC48A696897C084E6E71AAE67C7CD9417 + 20: 602C63D2F3D13CA3206CDF204CDE24E7D8F4266C + 21: A3C6FBE5C13E8B41FADC204C0CF26F3F214189F4 + 22: 25E480E9E0CA2B610105CD1424B8A35F63FB3981 + 23: 45412D51D3CA7BCF452D1612720EE88F9D2427C3 + 24: ED6A95036E3E046931597A457DB7A78B7309C4C0 + 25: B4FE0256D346700783420E08A4A6F7992B1E36C9 + 26: 33E1799E98280E5A9ACE5509477A2048607C5537 + 27: CF193837F6DE43F8E38000ACFCF764FA8D8FDE22 + 28: 7C8DE247DDA83599AF2EC2EE2D29E20583DAC34B + 29: F38A076F70613FC251C4D21E6435AD08341A8A99 + 30: DCD68E6174BD74BA180DA047A7345E8D111F85FD + 31: 43BBACB5F62A0482CBDB564171B04365CA6E27C0 + 32: AE5BD8EFEA5322C4D9986D06680A781392F9A642 + 33: EB90BCE364635C4C23B49F493F0043579BC85C17 + 34: 2942C7AFA65444C43D0592D0DC73CA71DB729205 + 35: ABF726F5FDA729FB7F3F0484D7C94B3107AA02AE + 36: 75DB4F6BCC05A781DDA9D17C46717286DD53654B + 37: A82CB42D89DAF5FBC1D4A48476229C495782F98D + 38: FC1A69683744AF823CD69E8A1E3F460591714028 + 39: DC68DB44B48521B0700A864896A00E17777AEA83 + 40: CC9AD99E917042381B0F99588896CBF236AA8ED3 + 41: EC7A68484A749C7065C6B746F9C465DCB414F370 + 42: C627C449DEFF14AE7ED807293D30846F061DA5B8 + 43: 4782F2A19B6DBB0882D656DE86C3D21A7317F768 + 44: 02D4EED99E7307BEA39AF5330BF7FB388D48B496 + 45: B3D99B9D90A69E50FD4365704F5AB2EAB7BC9763 + 46: 9B1C07176BB227F73E8A4E173071D39302061DE2 + 47: D79097DDAC552A6E02A52CE7AAF494D2D73B2557 + 48: DF7F23B160E75B9BAE5EA1E62B43A5A34A260127 + 49: F598F3780D8C374D97957B9B62D56106E9E0B2D2 + 50: 0BD98598F9AB29C1359EF5460A206DD1370515E3 + 51: E6C320834F69D81689E1ECD5ABC808D49D9C4E07 + 52: FD5EE7588CD129E12B886974621FD29FACC78E19 + 53: 2A9C28EF61EB536D3BBDA64AD95A132554BE3D6B + 54: CFAE6D86A767B9C700B5081A54265FB2FE0F6FD9 + 55: 8AE2D46729CFE68FF927AF5EEC9C7D1B66D65AC2 + 56: 636E2EC698DAC903498E648BD2F3AF641D3C88CB + 57: 7CB1330F35244B57437539253304EA78A6B7C443 + 58: 2E780486F64BC91FBFA2785EC1CA5C9E3CC07939 + 59: 4A7713D44E97D9F09AE1D786199C58AE2BFAF3EB + 60: C98714B16F92C8A770E9FC229DF834D1688E282F + 61: AACE3DD6F54A2A255ABA920F5FFC8CF04B85A69A + 62: CF8563896A3B0A0775985D8289444C4BBC478DA7 + 63: 6D942DA0C4392B123528F2905C713A3CE28364BD + 64: C6138D514FFA2135BFCE0ED0B8FAC65669917EC7 + 65: 69BD728AD6E13CD76FF19751FDE427B00E395746 + 66: CE705B7C60D46E7E36FE073DB8822698579CA410 + 67: C717EBBF6A2BF1BB33DA6257352D5085BEE218B3 + 68: 86151D140AAFC9A4B5877D3FBB49014FE5906E57 + 69: 7446B5A6BBCC58BC9662451A0A747D7D031F9A7D + 70: C24887924F92ADAC5AE367995D12691C662B7362 + 71: 5AF83CFD42D61967778889CA911CFB6C14339BA7 + 72: 587D4F6E6B4E21343423E434679009CBD3D24DCF + 73: AC65DD946C5CC432D4D624CAEB53C7363F96B7AF + 74: FA71E70750674C0F6B4AA19D0BE717B2936C83FD + 75: C9EFE6DD0A019315F73F3962DE38B6C848A1705B + 76: D1D05649B952C8F6EB016BE08FE1544AAC5D5925 + 77: CC3081AC1D695BAE51CFD5B44B9FB3A230733CC3 + 78: EB9DE332558953792687D9A7F598B5D84BF0A46B + 79: 39DE5EFDC92E3D3678F24D2CF545BA4D172D003D + 80: 399DBC9F721E44A992A0DEF42D999B32AF449ADC + 81: 996A2817C8ACBC667E1C4C27B8F4E9952736DD7A + 82: 3EF8189CE1BCC0D65AA182B1A81534635EDFDF2B + 83: D676714C6A6FF4E17A60C0511C25AA8B164FA606 + 84: 4DB6E3381E1B9290267C1539E1053793C8B81FA1 + 85: 3A34D35B0296FE4D83EDA39B742A9D8F4B13A958 + 86: 54F3B45304EF1287F54B877FCCE3285E154F9D6C + 87: B1EA96216E025377AB5AA845238FC8BC65DD60E1 + 88: BC6C7488145485DEDE1AE1D43B594F0046BCDA0F + 89: 3D9A0619ECF88C84CE86213E9AA91D9A252CBC32 + 90: 92CCAA0B4CE89E2BD80A61B9BAFD5AC58AB7B588 + 91: 3EB326B5BF4440FB3A88E3DCB05C1DB5EA01AC5C + 92: 989C63E819B13D4CADFB33F8DEAFBC57C1992A12 + 93: AE944552C20CF16F07A5C357713832C9D72D0C6B + 94: 46723E982569A1E2D9EDCED5498FC1F46F7D63FC + 95: 3BC5DAE7907C83A0693F87FD8372EFDD1DF53E09 + 96: 96D281BA44EB21ECFB1663C8AC5752C48686A927 + 97: FA0EF18178880A72B51C26555C10F5210DAB4390 + 98: 0C7ECAC32B8ED6D9835D381BF069568722A276E1 + 99: 649E44ECBA85C0938EC09229CEE4BB69388EC642 +100: 1E6634BFAEBC0348298105923D0F26E47AA33FF5 +101: AF2AF2734BB2BAA288940CB62109F4849DAA347F +102: 22D14BC045CC9A3794C99BEEE7ABE278BF24D6D8 +103: C3164CCBED75B82ED3F59F4A47FE09B256025549 +104: C27B5BC7CD24DE4913614A769A442E9CC9FB0E08 +105: F44D48D98CAC77522FF6B9E1B9CBB8489E58E588 +106: EA19A71FFBEC9572F6CD65523ACAF865EC05AB52 +107: CDA0EB9D310247BD1E8B3EA10D9B9DEFF6FBABA9 +108: 449DFCE971B9D65D69FBC72940E9A885E8DDE9CE +109: 96EEBB6B95A9DA99C58190CBD77CD6FBCF638A79 +110: 670F7A869E90CE86E0A18232A9D4B1F97C1C77D0 +111: BC544E24573D592290FDAFF8ECF3F7F2B00CD483 +112: E4CE142D09A84A8645338DD6535CBFAAF800D320 +113: 1C26461E26EB697CCC36A98714EE70CAAA87A84E +114: 51C5B1C25A71FF00394A84AB48B5733C8955551E +115: 84803504181C0AE33A511C49AF5015A5B1892BFD +116: 7CC8BCA120C2635ABFEA82DD203112B5C7E165DA +117: 44E2519A529D7261F1BEBEDC8ED95E1182CAE0DC +118: 2A81372DA39C1DF4251539A9922717B7CF5F0334 +119: 41C89D06001BAB4AB78736B44EFE7CE18CE6AE08 +120: D3DBD653BD8597B7475321B60A36891278E6A04A +121: 3723F8AB857804F89F80970E9FC88CF8F890ADC2 +122: D031C9FB7AF0A461241E539E10DB62ED28F7033B +123: E0B550438E794B65D89B9EE5C8F836AE737DECF0 +124: FB3998281C31D1A8EEA2EA737AFFD0B4D6AB6AC2 +125: 7A914D8B86A534581AA71EC61912BA3F5B478698 +126: A271F71547442DEA7B2EDF65CD5FBD5C751710AA +127: 89D7312A903F65CD2B3E34A975E55DBEA9033353 +128: E6434BC401F98603D7EDA504790C98C67385D535 + +Hash: sha224 + 0: D14A028C2A3A2BC9476102BB288234C415A2B01F828EA62AC5B3E42F + 1: FFF9292B4201617BDC4D3053FCE02734166A683D7D858A7F5F59B073 + 2: 00AC60F30E9BD1956F914C8E5125B69DCC31A179734E6A85B3F702BA + 3: E615202185AABE2ACA924BEC29E5A12384F8339EAE4E64C9CBA9F1DA + 4: D70DA0705EAE42A5C596D92F331DDA2421B4E14F8B3035FB73B8B700 + 5: 98029CB458A39A16355963922D32DACD9439F90E9FD106D42A0D123C + 6: 7D92E7F1CAD1818ED1D13AB41F04EBABFE1FEF6BB4CBEEBAC34C29BC + 7: DDD5BABB1B05D8BCCD644ADC393A9E2303C850DA31922C4DA07574F9 + 8: 4C07070802E21052FB0295AC0571CAEDF219143ADAE0627E2850EDAA + 9: 5D3CA3BFE738D33F841069ADF6DD79B987351CE580ACA23326B3A7E7 + 10: 6B5373C535A4FA5D56D6C4953575CE64968031BB019B909F8F2DB904 + 11: 767D0CDC11079BA8DCA276DF5C4B85507DE67DCE47EDA4CD9196D312 + 12: 02C513977B6242D2FAAC094CAE3C247C6E2745F8A71494A60535A2EA + 13: 1F39482310E2209C10A88C7FD7FC1FD567F36789808C37D30045A82B + 14: 55BA81EBA644183AB2460C234BB95ABDA898E980BA976584E2977231 + 15: 2522E2B35A835436C80A122E4676DE64690C81440D42DBDA40EF2151 + 16: 529D656A8BC413FEF58DA82E1BF0308DCFE0429DCD80687E69C94633 + 17: A153F81C68D9FFFD4DE0AB9111C2FA86E8EDCA9B294376083077A135 + 18: 1EC706AEB2227B263A105EDBE2562E0521C96420DA4558012327661B + 19: 4904ADADF19D088911EE0EFD20A9AB511F2786C8FD43F1E5E8BE2AC6 + 20: 6CE245C296289A32F661986FF1C80E893BBD35EB0B182EDC14AB3A7D + 21: 33831C459A43CBF8BEB6DD50039750F1EA3688A7EAEF68CB2F095E16 + 22: EB4BC2EA1F7146E8274A96E874585C401256FB921FFC7E935DDC7FFF + 23: 09A266C98019B6B2A4318FBEDBEA5481AF01F0AD2AD16F09991A3C3A + 24: 7AF2814CD6105473EE530F2B3DAE992ABB6C801428F33430501F09A6 + 25: C5BD6127243049C4D5E9E3B391E12BDA86DC7A9856910A757004486F + 26: FCA06DDE2DCD212E6C1C11BB22B18B4F5582202655DFB9B6C9960C57 + 27: 0851998120F8CE47482DA5B2EB21BADF73C9F145921EEFD33459D49F + 28: ED36A2092538C5D4769917953E7355A13072DDAD8A6E5E2AF1DE96F6 + 29: 2C4A89C05BFD09B7068BAFDA37B0314EFCE02AFAE1B2C25DCE337326 + 30: 1D552A4D06BB8A0827BFE8DA2B6EE56ADBD17CE4810908D572076F6E + 31: 997D180912E0655445B07259278AAAD424633F5FF6BD0AFECD4F15DA + 32: 71446EA93381BA091F94AFCDC5B938323290A1A027C22A75E88A04D0 + 33: F77087D6F4AE34E88C62597CEC06220F4C694D2E0EB704820035AE6A + 34: 64EE78B0A6C116380A4C16F24489C1E94A578E558453537A9819A2E6 + 35: F39C1C862FDC9AB4ACFA50FE283CB7595C608F8C521BB7898CF71D34 + 36: DB482A26C9488A963359D145914612E34B821CC6CDC11113B73BDE2F + 37: C7C45F3AA5EEDE664D6CCD510F628D4DC3C67F93973FE05B0163CA13 + 38: 7F230E3E597845DB9F8D61B44740968FF55F2DF28CA538A68927F130 + 39: EA52362A9C66B6A5FF3B642FCFEBBF54F793B088D29E6840D7A5CF56 + 40: 84B064EF9C13F1ED54AD0B8FC0CC28F9BCE5009500E1CD92CA2BAE04 + 41: A2702281BD63CA745553CB18693DD70AC9A70CD73C01783727707C97 + 42: 89231FCFFC7022DF20B1846285FAACE44AFCC677685DA55EE02D94EA + 43: 4C5B01C50907D097DDBF0923B885A26B58DFF5761C1AEDFB8D5353F5 + 44: 84E0CF33A7E1C0EAA46F37E99CE5C8B292E81AD61318796D1A9A90C3 + 45: 27E59A0B6E7B9125D4CAA658810AE5054CE40A9A0A0FFE6E36435EBC + 46: C7F21E2B4C89B2A6E64D92F93FC4146EB5886503C1231EE6924B4E13 + 47: 653CAFF50E077A855992990F0C5F89C75FA18D1CC147F685AF2EA993 + 48: 6A7BDEA7E456D5339B7D9C244E246AD65B18BA95E0518E201AAA7889 + 49: 837ADE7F298F8159E6E2408751B0C480648CB6FD6D26C551983F3176 + 50: BEEF3F6AC40A9DED345BE41242BB2CF924B457A45CACC68379B1DC4A + 51: 6D2908EB3B6C8952346E0B65B9406D949B5A340123DB83B151DF5F81 + 52: 9E75A1D6B4A4D1A9F5AA6F8A48AFD6F3FD360D2D8723B53DBB63208E + 53: 436E3BFE94A39359CDF47D35395D34C0435018C88B4E96E68C22645A + 54: C209DF2E99E03D679FBA9E14AAF958AC1B0A22076BB3B532A0D7F092 + 55: 8991DFBA74284E04DC7581C7C3E4068FF6CB7A63733361429834BB56 + 56: 2B2CD637C16AD7290BB067AD7D8FD04E204FA43A84366AFC7130F4EF + 57: E87F5BC938C3B981C197D4B163C635A5049FAC81C4C6467E1251BE48 + 58: FD9BDAF5CC288A603D1623651D5BA3B8801D1602B0B9221C0B48435D + 59: 87F207D9D870EDD7DA61753473A51FC386E2792A3861F949BEA05CFE + 60: C9EFF79F4412CE49296C082DC777118F92C9AC4136D4EB32621E942C + 61: DDBC76D25D9819693F3597D6F09044F8D6CCBD12F081156F1090AF7D + 62: 6411AD13AA3654302BAC8E2BFD1CE76F37E3B3394014BBE260062CFC + 63: 049E8DD7EAB3378CE9F823BFB569E5B270235D4B7F9623606971998F + 64: C37B88A3522DBF7AC30D1C68EA397AC11D4773571AED01DDAB73531E + 65: 114B5FD665736A96585C5D5837D35250AED73C725252CBF7F8B121F6 + 66: 7D9B844CAAC9EC93AE2159ED3D336C55396216DAC6AC5DC5DECC11C9 + 67: E1C799109DEEA117F68DD1826B38B514E1D265F11A8B60B24630FF8E + 68: 029A0D024B6C0B63E1586F3D34111727E37D49CA12E7F520FA91A926 + 69: 2EA94F04A72C770A98E2A495D886EE674B7D0FB987B7B5C2217A8773 + 70: FAF445688FFCA34ED783F948B8F74578503D4845836CAF69DBD5EB51 + 71: 91EC59AC7C98F9DFB869E11C80027F8A4D311324597E6FC6135224D3 + 72: 190DFC9C7BDD954E415E543F99B00B5110ED6A12182BFFDCAA77D8B9 + 73: 8C3AA805FA75625476F3267C211B1DDA52E1810B058EF804E34BEE58 + 74: BFD0E517E4A340A4E0EF1AC306EE2C6DD1288C77531EF0FD5ACB73FA + 75: C621A18D7E09976296CBC39761B020E7E346042FC735FDF106148F3F + 76: 27EE5F7E3FE49EAEC0AE0A93FD971EDF0304A4C0513BCF43424C95A2 + 77: BD9D42F293DA572219F08D4A38081D203E44F612EEDEF93CE0DAF6D4 + 78: 374CFB6FB12768717EFED2681718C11B22588C429DB9C71AFB5EB562 + 79: 1CFB1037FC3943559E9F913183DB71392CD4BC68CDFD47D7DEC9C9AD + 80: 2537E015D5945E0541BC48320AE4DFF7FEAB911227AE0D579DA1CD05 + 81: 012B34E1A530B6889E87863A59645EE4FFEB292A33815D2CE11918EA + 82: 5242DD4DFEE389E668D8FF78DA9B2D85AAE12D0C220E8D1BADBBA845 + 83: 4813D70E1D6BB6232CD9257B5132FDBA05E1A4A858E237C303CFA052 + 84: 0530BBA43AE6393655F21F7EEA67F8E8E819BA225AED78CA8BDE075F + 85: 4F7EAF4A9D0000B0E957DFE46DB304EBB2664A32AF4142EC74BE18D8 + 86: 68CF23B9DC4DC3430835B484648CBF126940AF6BAE51431A66D7F0E6 + 87: A093D2119C7076259F194F107077061C61C792DC5326C3A4D3A63BA6 + 88: F4E883F7FD12ACD36E3891986E4D7FF03F3E150F09CD4FB58A023A04 + 89: 0816862C59CE35E0D78834A221D3BABE21987FDAA81F20ED61D9DA84 + 90: F415933677BB364C589722E30B958F2BEF8670A10F1F5082F79FDB4F + 91: E40C5632490BB8DAD2283B6DBDCA870F4B5AB4271C61127DE999BDF0 + 92: B2D4E6CD7AFC35A475620EA1446B9024D767890B8593AB50275F370D + 93: 948616FD7828F09E8A57F986589948085D18EC3550E0ADA8E0127665 + 94: 2B115E930333A355A82F074EF261DE6BB2942D9DD64F98BA12D92DDE + 95: 6EEAB864B5AD618CDB1AE79C7B1DE31020966A02350AEF71088E6876 + 96: 676AD81F213E037F3C9BA2310F49DDDA4D6476C28A8EFC0046D3F55C + 97: 03A28C9068BC10A6FD87A1E53F00415F8CE994C968DD9CFF60D6B0A2 + 98: 01D91D084F400C591EDD750B66EC2482C834CE0E140A37E6E142CFEC + 99: BCAD899E7C771764CB91FF60AD79BFD629F4803A05FCBCC24E8F3E79 +100: 6E08215B5470DDEB67E44A494E52E259A9C2C4FBED4AF5DC6DB3E92A +101: E5C45BED6F8BFC487FF7190B108AF5C5B66F6D55D365B5A1BA156914 +102: 0DB55D83B38D42D229CA42D001B09758B5F3F032109F2F999C553655 +103: AD4DF1AF973A2747568A1B8DEF15E34A350A93F45BA84596580D11F0 +104: D4905849C8C4EA32159A431B52BAAC092F90037093E200A0C46611F9 +105: A936D0AA091B827BAD86644C94603068AB34A5B59E29D1E3BAB13039 +106: 46D214E9FA8C877C2791CC8E6716868713CB5B677CC4D838242C9B18 +107: AE8D3EB227AA3558101D5E5A2BF6C862C9F7297A31A3DF24E4502257 +108: 4462C366B10326D4FEF46E71930BCF93713F7D45FAC9963520FF5FE8 +109: 05EFC35781E413ECBCC763AE13D5A37C159CE5CCEE6EAA1CFF7CA516 +110: CDDBA09D7FE081E7A39C4017B3EDF7A9138D1CB857559BA9AD2C939E +111: 1AEEF583C448A9AE00FBC931B50BC0DA5BB8323E616B11076CEE8B44 +112: 01E5ABF50619B5C2078E754EDDEDCF4DE8D31185A2219313CB91A8C9 +113: B7FF114CA77757CAD67801E6761AF20F4CBB8328AEF290F77EB612C3 +114: 08F43DF4547732424AC7D0390AD8AB3D4978826462446D13B2B468D6 +115: AC3799ED09E3BD9E770FD3A0073E371FE9A3D4E3D464C3A7023CC72D +116: 795F160C275FF6B575031D4053BA1D1C32744D09F005B3BF10BDD1F7 +117: D2EFD4AC8ABA33151D0399E2893769A6D8BBFBA7B128388BFA65B841 +118: F85910F64FEE2B8F91DEC8064F75CB97E1FFC895AEE912DD3945F839 +119: 762F18C0DF65C3D0EA64126C8A6E51DB4425E76D4D969ED0F83899BE +120: D022DEB78772A77E8B91D68F90CA1F636E8FE047AE219434CED18EEF +121: A802D8B618A503352CDBCC1FBEF04EA36499EA72D0E32D314CAF83E5 +122: 6DE1088DD95C9535849294A8635A44084BA36E4EEF81C6D67B98CE90 +123: 6AA11591302A30EFACF874F40AA017F8545D3D9EA68D479965AC0B3E +124: 3288A475A4817D2E42830C709C1DC18A4BBD59DBD903B43CA702F275 +125: CCEEE7F6EFA60B2F2CE1090FB929D6068F7EE301E7A84072FD163F7E +126: A45B0FCFAC3F05279B7E8278AED93E37B225E6A997664F92C7555447 +127: 554C9C3F7E92B80F4121E00CC147535D377EAEB4FB1FA8E25C7F81C1 +128: 67D88DA33FD632D8742424791DFACE672FF59D597FE38B3F2A998386 + +Hash: sha256 + 0: E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 + 1: 6E340B9CFFB37A989CA544E6BB780A2C78901D3FB33738768511A30617AFA01D + 2: B413F47D13EE2FE6C845B2EE141AF81DE858DF4EC549A58B7970BB96645BC8D2 + 3: AE4B3280E56E2FAF83F414A6E3DABE9D5FBE18976544C05FED121ACCB85B53FC + 4: 054EDEC1D0211F624FED0CBCA9D4F9400B0E491C43742AF2C5B0ABEBF0C990D8 + 5: 08BB5E5D6EAAC1049EDE0893D30ED022B1A4D9B5B48DB414871F51C9CB35283D + 6: 17E88DB187AFD62C16E5DEBF3E6527CD006BC012BC90B51A810CD80C2D511F43 + 7: 57355AC3303C148F11AEF7CB179456B9232CDE33A818DFDA2C2FCB9325749A6B + 8: 8A851FF82EE7048AD09EC3847F1DDF44944104D2CBD17EF4E3DB22C6785A0D45 + 9: F8348E0B1DF00833CBBBD08F07ABDECC10C0EFB78829D7828C62A7F36D0CC549 + 10: 1F825AA2F0020EF7CF91DFA30DA4668D791C5D4824FC8E41354B89EC05795AB3 + 11: 78A6273103D17C39A0B6126E226CEC70E33337F4BC6A38067401B54A33E78EAD + 12: FFF3A9BCDD37363D703C1C4F9512533686157868F0D4F16A0F02D0F1DA24F9A2 + 13: 86EBA947D50C2C01570FE1BB5CA552958DABBDBB59B0657F0F26E21FF011E5C7 + 14: AB107F1BD632D3C3F5C724A99D024F7FAA033F33C07696384B604BFE78AC352D + 15: 7071FC3188FDE7E7E500D4768F1784BEDE1A22E991648DCAB9DC3219ACFF1D4C + 16: BE45CB2605BF36BEBDE684841A28F0FD43C69850A3DCE5FEDBA69928EE3A8991 + 17: 3E5718FEA51A8F3F5BACA61C77AFAB473C1810F8B9DB330273B4011CE92C787E + 18: 7A096CC12702BCFA647EE070D4F3BA4C2D1D715B484B55B825D0EDBA6545803B + 19: 5F9A753613D87B8A17302373C4AEE56FAA310D3B24B6AE1862D673AA22E1790F + 20: E7AEBF577F60412F0312D442C70A1FA6148C090BF5BAB404CAEC29482AE779E8 + 21: 75AEE9DCC9FBE7DDC9394F5BC5D38D9F5AD361F0520F7CEAB59616E38F5950B5 + 22: 22CB4DF00CDDD6067AD5CFA2BBA9857F21A06843E1A6E39AD1A68CB9A45AB8B7 + 23: F6A954A68555187D88CD9A026940D15AB2A7E24C7517D21CEEB028E93C96F318 + 24: 1D64ADD2A6388367C9BC2D1F1B384B069A6EF382CDAAA89771DD103E28613A25 + 25: B729CE724D9A48D3884DBFCBEE1D3793D922B29FA9D639E7290AF4978263772B + 26: B858DA80D8A57DC546905FD147612EBDDD3C9188620405D058F9EE5AB1E6BC52 + 27: D78750726155A89C9131D0ECF2704B973B8710865BF9E831845DE4F2DCBC19DA + 28: DC27F8E8EE2D08A2BCCBB2DBD6C8E07FFBA194101FC3458C34DED55F72C0971A + 29: D09BEA65DFF48928A14B79741DE3274B646F55AC898B71A66FA3EAE2D9FACD77 + 30: F2192584B67DA35DFC26F743E5F53BB0376046F899DC6DABD5E7B541AE86C32F + 31: 4F23C2CA8C5C962E50CD31E221BFB6D0ADCA19111DCA8E0C62598FF146DD19C4 + 32: 630DCD2966C4336691125448BBB25B4FF412A49C732DB2C8ABC1B8581BD710DD + 33: 5D8FCFEFA9AEEB711FB8ED1E4B7D5C8A9BAFA46E8E76E68AA18ADCE5A10DF6AB + 34: 14CDBF171499F86BD18B262243D669067EFBDBB5431A48289CF02F2B5448B3D4 + 35: F12DD12340CB84E4D0D9958D62BE7C59BB8F7243A7420FD043177AC542A26AAA + 36: 5D7E2D9B1DCBC85E7C890036A2CF2F9FE7B66554F2DF08CEC6AA9C0A25C99C21 + 37: F4D285F47A1E4959A445EA6528E5DF3EFAB041FA15AAD94DB1E2600B3F395518 + 38: A2FD0E15D72C9D18F383E40016F9DDC706673C54252084285AAA47A812552577 + 39: 4ABA23AEA5E2A91B7807CF3026CDD10A1C38533CE55332683D4CCB88456E0703 + 40: 5FAA4EEC3611556812C2D74B437C8C49ADD3F910F10063D801441F7D75CD5E3B + 41: 753629A6117F5A25D338DFF10F4DD3D07E63EECC2EAF8EABE773F6399706FE67 + 42: 40A1ED73B46030C8D7E88682078C5AB1AE5A2E524E066E8C8743C484DE0E21E5 + 43: C033843682818C475E187D260D5E2EDF0469862DFA3BB0C116F6816A29EDBF60 + 44: 17619EC4250EF65F083E2314EF30AF796B6F1198D0FDDFBB0F272930BF9BB991 + 45: A8E960C769A9508D098451E3D74DD5A2AC6C861EB0341AE94E9FC273597278C9 + 46: 8EBFEB2E3A159E9F39AD7CC040E6678DADE70D4F59A67D529FA76AF301AB2946 + 47: EF8A7781A95C32FA02EBF511EDA3DC6E273BE59CB0F9E20A4F84D54F41427791 + 48: 4DBDC2B2B62CB00749785BC84202236DBC3777D74660611B8E58812F0CFDE6C3 + 49: 7509FE148E2C426ED16C990F22FE8116905C82C561756E723F63223ACE0E147E + 50: A622E13829E488422EE72A5FC92CB11D25C3D0F185A1384B8138DF5074C983BF + 51: 3309847CEE454B4F99DCFE8FDC5511A7BA168CE0B6E5684EF73F9030D009B8B5 + 52: C4C6540A15FC140A784056FE6D9E13566FB614ECB2D9AC0331E264C386442ACD + 53: 90962CC12AE9CDAE32D7C33C4B93194B11FAC835942EE41B98770C6141C66795 + 54: 675F28ACC0B90A72D1C3A570FE83AC565555DB358CF01826DC8EEFB2BF7CA0F3 + 55: 463EB28E72F82E0A96C0A4CC53690C571281131F672AA229E0D45AE59B598B59 + 56: DA2AE4D6B36748F2A318F23E7AB1DFDF45ACDC9D049BD80E59DE82A60895F562 + 57: 2FE741AF801CC238602AC0EC6A7B0C3A8A87C7FC7D7F02A3FE03D1C12EAC4D8F + 58: E03B18640C635B338A92B82CCE4FF072F9F1ABA9AC5261EE1340F592F35C0499 + 59: BD2DE8F5DD15C73F68DFD26A614080C2E323B2B51B1B5ED9D7933E535D223BDA + 60: 0DDDE28E40838EF6F9853E887F597D6ADB5F40EB35D5763C52E1E64D8BA3BFFF + 61: 4B5C2783C91CECCB7C839213BCBB6A902D7FE8C2EC866877A51F433EA17F3E85 + 62: C89DA82CBCD76DDF220E4E9091019B9866FFDA72BEE30DE1EFFE6C99701A2221 + 63: 29AF2686FD53374A36B0846694CC342177E428D1647515F078784D69CDB9E488 + 64: FDEAB9ACF3710362BD2658CDC9A29E8F9C757FCF9811603A8C447CD1D9151108 + 65: 4BFD2C8B6F1EEC7A2AFEB48B934EE4B2694182027E6D0FC075074F2FABB31781 + 66: B6DFD259F6E0D07DEB658A88148F8253F9BBBB74DDD6DB3EDBE159A56BC35073 + 67: 8FA5913B62847D42BB4B464E00A72C612D2AB0DF2AF0B9A96AF8D323FA509077 + 68: 7DED979C0153EBB9EF28A15A314D0B27B41C4F8EED700B54974B48EB3ECAF91C + 69: 1CF3AA651DCF35DBFE296E770AD7EBC4E00BCCCD0224DB296183DC952D0008C9 + 70: 5767D69A906D4860DB9079EB7E90AB4A543E5CB032FCE846554AEF6CEB600E1D + 71: 8189E3D54767D51E8D1942659A9E2905F9EC3AE72860C16A66E75B8CC9BD2087 + 72: 107DE2BC788E11029F7851F8E1B0B5AFB4E34379C709FC840689EBD3D1F51B5B + 73: 169F6F093A9BE82FEBE1A6A4471425697EC25D5040B472C5B1822AEEA2625988 + 74: 2087EBD358AE3EA2A092FC19C2DFEE57C5F0860296BC7B057C14E1227C5CB9D1 + 75: 182AB56F7739E43CEE0B9BA1E92C4B2A81B088705516A5243910159744F21BE9 + 76: 081F6C68899A48A1BE455A55416104921D2FE4BDAE696F4B72F9D9626A47915E + 77: 5CE02376CC256861B78F87E34783814BA1AEC6D09AB500D579ED8EE95C8AFCC8 + 78: B93E407404E3E95F20FD647365E0E7F46AFABE9AF1FF083AF996135E00D54009 + 79: E81FA832B37BE8ED8F79DA29987AA4D61310DCB14B2859DEDF8FB1DAA2541FD3 + 80: C56705FEA5B110B8DC63688533CED21167E628017387C885423B835A55EDD5EF + 81: C2226285D08A245A17058ED2D24AD095B714F608AE364FDDF119E0A7DF890540 + 82: F9C270DA8793221A6809AC685FDD4F5387E0FE1EE6AAF01C74F1E0A719621614 + 83: E69BEFD6EF7F685C36E343AC1702D87AD6A0E4AC8C0D5C521D04AAD4EF0B7458 + 84: 4E3033562AD74A7D43EB5FF5FC2382622C6307CB10E245AD62DA77C4C63CB178 + 85: 2EA17629472564A59E5EB845A2CDD04F442DF2FF26BCC866E400F77158D612A1 + 86: B90223DF74DD49A8A1461F340F2D7A90F96903CCBB5BC3C74EA3658FC8948B20 + 87: E0209F42B927EC9C0F6D6A76007ED540E9BDD6E427B3368A1EA6C5E7565972DD + 88: 10D9BD424114319C0999ADF6288F74060CD8918EF1228827A6269B2BF0F0880C + 89: 7D1978A65AC94DBBCDC62E3D81850299FE157DD9B7BD9E01B170156210D2815A + 90: E052DFF9E1C94AAA49556F86FAD55029A4875839FDA57F5005F4C4403876B256 + 91: 58D29459B2130A2E151252D408B95E6DAC424C564062EB911CC76440CB926CA0 + 92: 4E4530C392316F598E1BD07F32166380A8F712A33A48E9EB4247131EC5DC05D3 + 93: A09C9D3E42342C7DEA44EDB4AEB48CF6727CACD8032A12CF77A25829FC249D32 + 94: EB978D0F1AC03CE5C3510B5F4A16073A7A2BDC15C4AB7777DCF01030CC316667 + 95: 7D1905A3ACE827EA1AC51C4FA08C281ED3BE87E7F4E928D696BFDE35C8F2DC0F + 96: 08359B108FA567F5DCF319FA3434DA6ABBC1D595F426372666447F09CC5A87DC + 97: A7B3830FFAB0F2BBABBEF6DF0B169A7917008BF238880BBF8C20B8E000077312 + 98: B4F5D9B1555994C5EBAEBD82918D560A3BF82962A171A1614E7551939E943366 + 99: 014ECAEA1B378900F1212898C6DDB01565D81AF1D0EF78DF5E28D46E9CAF7CFC +100: BCE0AFF19CF5AA6A7469A30D61D04E4376E4BBF6381052EE9E7F33925C954D52 +101: 4565D7B898CCEA3139AD260F9273115F806B30079D7683218C4E3ECD43AF3B33 +102: DDADEB660FE8902C9FB2DB9B6CF237C9CE5B31753398085C4367EB5910B9CC13 +103: C15A8928131F6687DD10F3C115DDF8D7C8F2DF7E18D12C08C4FD16F666CE60BA +104: AE8E3D799B1353A39815F90ECEEBEFA265CC448FE39FAF2008CB20784CB2DF9F +105: 98545371A3D9981ABE5AB4A32A1D7B2FADD9801D89DA52A94A4F78A42740D21C +106: 6323DCE2F8B3A04DCEA8D205602348C40403CB200C677EB1A1C0FE37EDB6EB2F +107: 8150F7C5DA910D709FF02DDF85DD293C6A2672633DE8CDA30F2E0AA58B14B0C4 +108: 44D21DB70716BD7644CB0D819FA6791805EBC526EA32996A60E41DC753FCFAFC +109: B9B7C375CCA45DB19466EBD0FE7C9E147948CC42C1C90F0579728CFB2651956D +110: A47A551B01E55AAAA015531A4FA26A666F1EBD4BA4573898DE712B8B5E0CA7E9 +111: 60780E9451BDC43CF4530FFC95CBB0C4EB24DAE2C39F55F334D679E076C08065 +112: 09373F127D34E61DBBAA8BC4499C87074F2DDB10E1B465F506D7D70A15011979 +113: 13AAA9B5FB739CDB0E2AF99D9AC0A409390ADC4D1CB9B41F1EF94F8552060E92 +114: 5B0A32F1219524F5D72B00BA1A1B1C09A05FF10C83BB7A86042E42988F2AFC06 +115: 32796A0A246EA67EB785EDA2E045192B9D6E40B9FE2047B21EF0CEE929039651 +116: DA9AB8930992A9F65ECCEC4C310882CAB428A708E6C899181046A8C73AF00855 +117: 9C94557382C966753C8CAB0957EAEDBE1D737B5FCB35C56C220DDD36F8A2D351 +118: D32AB00929CB935B79D44E74C5A745DB460FF794DEA3B79BE40C1CC5CF5388EF +119: DA18797ED7C3A777F0847F429724A2D8CD5138E6ED2895C3FA1A6D39D18F7EC6 +120: F52B23DB1FBB6DED89EF42A23CE0C8922C45F25C50B568A93BF1C075420BBB7C +121: 335A461692B30BBA1D647CC71604E88E676C90E4C22455D0B8C83F4BD7C8AC9B +122: 3D08C4D7BDDA7EC922B0741DF357DE46E7BD102F9AB7A5C67624AB58DA6D9D75 +123: CC63BE92E3A900CD067DA89473B61B40579B54EF54F8305C2FFCC893743792E9 +124: 865447FC4FAE01471F2FC973BFB448DE00217521EF02E3214D5177EA89C3EF31 +125: 3DAA582F9563601E290F3CD6D304BFF7E25A9EE42A34FFBAC5CF2BF40134E0D4 +126: 5DDA7CB7C2282A55676F8AD5C448092F4A9EBD65338B07ED224FCD7B6C73F5EF +127: 92CA0FA6651EE2F97B884B7246A562FA71250FEDEFE5EBF270D31C546BFEA976 +128: 471FB943AA23C511F6F72F8D1652D9C880CFA392AD80503120547703E56A2BE5 + +Hash: sha384 + 0: 38B060A751AC96384CD9327EB1B1E36A21FDB71114BE07434C0CC7BF63F6E1DA274EDEBFE76F65FBD51AD2F14898B95B + 1: BEC021B4F368E3069134E012C2B4307083D3A9BDD206E24E5F0D86E13D6636655933EC2B413465966817A9C208A11717 + 2: 5D13BB39A64C4EE16E0E8D2E1C13EC4731FF1AC69652C072D0CDC355EB9E0EC41B08AEF3DD6FE0541E9FA9E3DCC80F7B + 3: 4F895854C1A4FC5AA2E0456EAF8D0ECAA70C196BD901153861D76B8FA3CD95CEEA29EAB6A279F8B08437703CE0B4B91A + 4: 80AE432E757826025095CA1FA4F89C06C8BA6754B1D883A8E31A1E65FCFB820BD74ACFACA3D939A574EA408A74162D1D + 5: 561C16404A1B592406301780C0C2DF6AA0555F504F35BFBEAC810AE36A343B776858C5E0DE56BB79607A34D2F67108F2 + 6: 79F4738706FCE9650AC60266675C3CD07298B09923850D525604D040E6E448ADC7DC22780D7E1B95BFEAA86A678E4552 + 7: E6CE1896C9783A70AC4C90276CC37B37687D7E30C753975762F961AE37118D9A610242716E8359EFC4975AA98C632DCF + 8: CFB18F81F4BB672B03214F1FEDE456F882A0DE40120212A1FEBA8FDC48F763C86ACBBFB684D34B70F99F4D8D81FE3A28 + 9: D075AE1178210804635AC02C656309311527FC8190835C8AD8196577C3332AF4D87F056023F235DB893C69AA87B0CFB9 + 10: 182E95266ADFF49059E706C61483478FE0688150C8D08B95FAB5CFDE961F12D903AAF44104AF4CE72BA6A4BF20302B2E + 11: 89BFCF569AE4AF718510DA78C67414109F5739BB5C40D51C9C8C50E2B2CEE86F2F80C8B9D68F7C01201A0714572FE602 + 12: B635441A3721CF190B39D23703C5B77018FF1A56C94F8252EE95C217E3477F093E8EC65C6AE767179A7872C8DB9B2141 + 13: 48DEBF56626CC86DFA47AD6FDEC73FD182434621DA8BC6DB23AFF067BC36DC8244D3071B1F57DE4B716F63D9820DFB23 + 14: 58475B7CF93FECCB2C02B588F1552A359E7EE9AC45D9AE50B2D7C22021466677D70EF24EFA5C492515164458E9A24744 + 15: 0AA75534F0F58756A01E3366F78E7611BC7F432364C649C3F50547F7BCA3E5489531B8AB129495FEAC834FF0A0B45DB6 + 16: C81DF98D9E6DE9B858A1E6EBA0F1A3A399D98C441E67E1062601806485BB89125EFD54CC78DF5FBCEABC93CD7C7BA13B + 17: FDD3C4C0F87EEC0CADD73028A06B01E67696C7E04960936B30C73F004CF6B595D644533F8B473C8E63B02D593A64B041 + 18: 445E4CCA1A03480D149F38014C14D28DF8288F2C6CFF047F45D4F2580AE85EFFB3BE009C9D2ACC54B51467F83A09FBE2 + 19: 8305DC56172245B82AEDCE7F9C7DC88C0E62CBF835A2AA133EB579F415FFD15BABBC30BB98E55DFDA0F9E80275C92BC4 + 20: 8A48240E1C85E80651EDDC88599273444839A952CACA2BEF4400576E65B1EB6C19C47A3067B63AF7CDC4238ADB9A8DAD + 21: 8F2F7669C27A7CB1CF7A84A2C4F050D7141852D8B429291956B85E2DB5287741A3104E7E99CA5D23A5EEA59A68A4DDB1 + 22: 32CF04AE2A4A326FDE2FBB887F47FB7A2C486E56088D85B45F0C7587591F44797FE0A67E36F571809695E05F254884B2 + 23: 713A04A3A6BA8D2FD821F1CDF9FACAF42795E4247C9A26F0ADC5E0E6AACBAFFD8F4E02563733C6BDF1A863A787949B35 + 24: 35D8A5AA0DC9AB4C9A4C62B36E0E1013977C198B05CF6B92CEA25C08309DAFD282AA9A4862958593C06BA46919EA8019 + 25: D3FB60C2E981A5C82F1B1BCB3D4D7AF62C9A32A9F0D87E0532C9D3AAC083D70133EFF63A1E2CCB87360BF032C25FE9E1 + 26: B119F9AC74E58BD081E24C0CC1E090012C192996EED67A8ECA33794FE7E1920E26C0EFAEB866EB5AB82FCA3188A3B05A + 27: 5B29543AB0F76F246B7FDE6E8E5D3DF6017A39342BB08351A4EF609AE00A91ACB7C5D0487B3760B34CEF326F63C84572 + 28: F8E1FAA657BF829C9D2E4811805238CCCD11F0C1AB7619058241BA5606E7BD5E4816163E6E8E82E62A43CB4943A41006 + 29: 0855B919786B5E5C87B85A6C17A46C550B2BA81B3724389088E2B54BA89D82B8F9841FF442DA5DB8D54C9B2AC108DC3C + 30: 7DEF8CAB7C80CEF90FB38989ABEF6F1A5EC18379681E484A1B4DB6624818D2E486FB9C245C1F0DDD85A846D4268344B1 + 31: 04AAA180C2CD24F0FB150B1AA360F445344150DCA13E1ABB8117D42E25DF7FE29246D9F00C7473D20CEC32A71E64E1F5 + 32: E7112491FAEEFD57786DA73F367B25A6F5769F5C98FA7B704D8D37747724A647371989E8B0FE8D3CB23F9EEDD528456B + 33: EA27126D0B96E00E428943EA94F4B03FD22D56C4FF4636EED139D027E6D45EF57AB86093A7342B3B3851FD3BFD1DDA23 + 34: B2BD337A4BDD48D25A5E3FCE3E0948EC67829B835A8E3DD0D9F4881D10C766369B079028C6060B7263603288D8FA4BBA + 35: A9E940504AE6B137BB1BC88CE3A9AE53DCB63AFDFE5FA0C652003A921F582C08662425C7FBD5B1E1422E39E645D4A757 + 36: F033150D7464D49A076C7D4BB9E2A5488132786CB4851A4C81DA5B0FCE66D775D3C1766094AD6CA9482DD9539F28ED9A + 37: E64D999E7258ABBB4CFF6F74AF7D6A1E9B044C17E1ACE0FC61B29E7732763755A9C1D3A380B080AD968D2228DB731DE7 + 38: 9030D47B57ABEA93B51162556FF352DA61FDF501132A9FD94E6CB56690E7A805CDB290FB4ADE36BF90A53F20922C9B6E + 39: 4473396BB0461EDB4712880810A3F7252725AD4FD6092021A40559F453A1C63ACFFA8A02C85CC8DB86560323DA0A0FD9 + 40: 095FDD130278B3C8F574D17283611E4D6199EA63A0F1599E01ED070CD0B115296FE353477582BF279D622355C89A23E4 + 41: 7EE600CEE8437531C6A5BEC313D53371F9B56425D5662C104624D83D51111E5C9F4B83000B8A3EF150E04AEDCF67C237 + 42: 676D2BD2500BC527DCB51968FE8742E40D2965047478E69155AAB9201E0C9B0F6BA9BE85C4734B0DD556B5FA7608BE83 + 43: 09F5FE433D1FB8F62A76E5654B54CB6A9EF505D2465A49DCB9669EAC9A30B2532505E4500F842EC9FBE79A382C8C2F4D + 44: 075821CA8C547E66AD94F4C4ADF866A2A7554E08D2B0F0B3576801773EDC85DF76107E6912904E9757EBA753A77CD0FF + 45: 2172C22E7E48BD0B4A73FF02803D6FCE776CECBD95DFC43CA0763A0B375D57030000B12E59F9CDE81DE58E17489B2C41 + 46: B9A15689BA4F41BE46855775B46A5DB9D6826E0CBDBC3B292DA6D57B2A179A3D393A8E1B55DE79438E5221580C604EAD + 47: EBFA57C946831E2E370A6B1BE46E27C95C512297499B8BD15722622178E00599DEEADD48F1B4B08EB649A137805CB786 + 48: 25866C8288F9FA319FA9AA2470B4FC2595DFFA9154E607444EA3247E81D74A2AE0957D6B7E050F8C96AA7577BEDCABB5 + 49: 3D28682B90022C873CEC78C3A47FD45B5124E49ED07E2F0FB41A112A63AACC9E7614ADBB007D129C0673B08C51210839 + 50: F76D9B7ED868085905AE806CFC5C6DE994999E379922AC003D53F00B65467AACEF3929392F1F2F56C621D2F552544A22 + 51: 324951FA2432B63D1765C21F98325BC4AE2FFB25F411047C53ED5A3D550B50E2B8F6E79BBE65F2C686A5132E5B982AC7 + 52: 320CB033AD533AF8EDB3E664E34BB85B2327AFCFC583CE9202C0B11F16425A58FD895D7435E8953F9506A25DE7BE6EF3 + 53: 6065D55530ED8339B09D7A4D9CB1919004F69ED9D6B119E78E1C39C7AD2AAC029A3F266F7E48350966B845C4D7D92A72 + 54: EB6E866BDC0B5089301D89B870B75056ABA6D5FA6C7406A8D6D97CE5175102479647D3F93325A2CB648A3F40CCE38542 + 55: DCEDB6B590EDB4EFA849C801E6B6490657A5C1E64F69269F5F63C9267F6223DE24CEA7AAA6B267D9BCECC15147B6C875 + 56: 7B9132D597B8873AD55BBC30F18ED3F2C9F340E7DE69FB5774056C71A06D9BC2B14137E9E1C68B6B645FED28B188249D + 57: 0901B1E5B13FCE000486BDA64FBE45C79FCE15F38A4DDD9335A521D98829D267ABCCD84284BEF1EA3C2D4E4687C6D3B8 + 58: 4A9375DBAA878E2C1C7BFB977989E6D39CC00F890ADC425F7084AE3761BAEFCB9384C8B9EB3ADD4C3C838A6D560DF788 + 59: 908682C3E0D97A4943063EA9DD0A0F55EFCA203ACA3004010D3D7EF94593592729B523EAAE4160C3EA2241EBA236FD65 + 60: 24586F75A43A08D6CF116B87B86CC43300FC4132523CC4824B7FBB3F54A5B41C7D598B40639B25A99732D575A5CFD355 + 61: 7B4CFB73E247E941570E70C7308ACC5166F123187F003B1CAA9BCD17DDA8ED5535ACAE443C9ADE93C5567090EACE29AA + 62: E97EF4578822DDC79AF60514A188F8C719E4133B58E5EB134261AA7E89C402EA7219129A06B395E5E1D2738AC23FC876 + 63: DD66B519F51A925814407A449C60B34C553D7652D41783EE903A810A4C9F833B8181C91C7F12283EACD6A5F8A2639DDF + 64: 9F2C9EB7116B3D7A4BA84A74A4D4EFF8A5EFCF54B6D7B662693C38577914C73A214766F0A175339BB0895A863824FC0A + 65: 14B0A9FFCE149426BF5045FFC24C057451D2473186DEB4F150117B855911A7641651FB1E15DF406EB373D71151C46F25 + 66: 286505FF7A9EF81224988A8FF1E423A2AD21F6B339E91B89F7F1540F14CC9A603952564539167465CA70FF0B523BECF9 + 67: 8CAB08A79BA16F3D7CBEB942C7D8676F8D0295B5FAA01F3C850DC4B5FE913AF00F2E938BE0B442187B135BEF1A36C34C + 68: 4D12FFBCE2E770ECA1104BD2F29C65FE95534E390A138C30CB0ECB6436A971116D82C6321D2EA2C0A735AF34E5E3E3B2 + 69: F8617A35FE9116A719441F82F21C79B8868E5FFFC2EA737FDC821246DB7610E9868D870575F19B29F2FD259D9242A497 + 70: 932FC435B590B1E1D49C34EB3B627DAD5476216518250B1FBFE772476437872B8DA6CAF6D2F33CE7AF8648D956CF717F + 71: 3F63DF48C2D87CEB2168BEFBF6B857A415D8BFB7062251E8E1AB0487483EEBDE5E8E8B8B0E3AD81ED4AB15E81FD5E448 + 72: 4A71E4E737DE74F78E72ECB9DDB580EA5AC96E5BBD5E52E11D4A41AB3B8303E3AF3458A8AD89B39CD9F4A6D5DB3C9E2A + 73: CAC3A81A98103BBF08C440F6C8F61AC010DF8AC05FDA77E2ED8660AB73A978B9428BA0458A5C64DFCE35D87F0DAA2A6F + 74: 6E5D162C60A451B6257781FA0E36B3BDD9BC42A7BCFEAEB75C18E541A4DE00967E6BF575CB32374C1E9FE7B36D92048B + 75: 04DDFD71893D0F4AD2A0B672A057ED2795D6811AEAFDB7136BC8C20A55DABB3AE4B62B8A2C722C1F53E18FFA5771610F + 76: 555D5B51C2EA17659516A67D31CE2CB302979F80BD7056908C1A152403FD902EAEBABDD066AB3F7834E7213A6CE99EEB + 77: 44797CE4FEC66B26B52A4249C2B267AF891C912E55221EDB6CAFC4E2F022A40E8231931DF0B19321D5CCB2AB8A4F256A + 78: 51D7AC85289FE7E4D9431414B2BF3760BE65FEDD1A0B34BED0E1562A73495EE10971B5141835DB454C865039154BEA15 + 79: 2E31DAE50A484B7E11E2E621D0552803791E07279752E09EDF4C884EF24C79C33D9572AE0DE6E0B6A20271F1F7AB98FF + 80: DDC65ED22CAE4D159D35E129A1602D8FA50D7AA53E209B0D5442BB121DB0D5D102441054B2B321675F3722669FECD06E + 81: 200E0BC495311E2FE524A1579490D843011A592E4E9B927DEB0727E5481898C557CB2941F18AF0F2725A1B19DE045BA5 + 82: 561E1875B31DEAEC4DB2FF5BFA7856A6F0ABE1294CDCCA1DA12CCB1786D9556881A768ABAE50F7243921ACF993AAF18C + 83: F6B88007732D5B9F75209F9FE107B9917010D5960184FD239854AB4611CC788D1455B113A5565A87326B3CE6CA190DB8 + 84: B4E703169169B07AC61E76A75ED4AACEE4115F6A43842BF136B514824A05F5C5ADB68F2E525D8C9E8BDB20D3BCA21155 + 85: F72E2083B296EB7468C97749D3AA1B08F418EBCD9A2E5CB4117C5A034BBEA5E2004EE1E43E26A98E4F25AD4306AF3A57 + 86: B1DE9ED0D5E5F7FDCDF530041D7320CA7376A64590F6679971F84061C42AA03F0B07C7EBCB806EC8380D9FF0E182293F + 87: 30ACC02AECEA9B91F3C6BB0F4CA8EEA1B84A0BA6BBB8F7749FD29C9BE5C5E28AFAE5A33617DFE3FC28CE3A78D1A19CDD + 88: 5B2DABAF662B86DC4B1DF6A2EBDEB5CFF1F63C65ACE5E1237DB507DD3FA2C27FF46517B0FCD6F32F25DCD55ACDC07FA0 + 89: 33BE80B29355AB16AA0F05A45A8DC15A5EF7F9FEE60BCBE05E106BF6FA0F196BFD9CBB8D79298360F760DA7B05135F83 + 90: 048C648A525FAB61CF81E087047044130E407B71DDD27293119689C8516B19DDC4F276E3B4E93E6AB80A79BB2700DE68 + 91: BF18EA9E00E6C2262D802FB66E04FFA21DC5C13640BBF27B2C22592DE4AFE31C18147E6EBD2D45669C36F9432494A000 + 92: 0A1A114981A785C399E2B21871A532B2A747FC67B4DAA287C14F2F449FC6F7C6925DB5E884E6E041D08BF6BC69295124 + 93: AC6705C373300FCC09A291CFF1834401FC30FAD512569848A05171AA02426B7034EA2E4777AAC2DDFF48089226A4884C + 94: B7B08352FF8988C0FFE3FE0E27278F068BDC88AECBA8D7ACD8919850D7400A2C0A0A8519B264F61102290C9AAAD3C2DD + 95: 8F78C56A93B3DC69ECC5827F8D591195FB683A9951175754926A8E19F81FF859DC1904DE12BC8482A760E998552D28E6 + 96: E606004ECDC6878B5EC15F4554017CCF962E92CC6EAEBE4997BA34EC0E53C67D564C8461C013701A401FE347EC0F721E + 97: AB7D7116F436ECB13ED2EC42347DDF902E0FD766EA8978CF93625F56B2164E2E630D6383EB03602A8DF27F28F580E3C7 + 98: D716BE6974E46F19A606486BE576AC6E250AAE6AC2ACE7CA9A924C874790E6B4C94670FD884A6EF770EC5E5F3F264306 + 99: 746EEE51375E6695BC4B66190172DC6E86C18E144267C7B0133D6C2ECE05F75B862E4C4EA5F813DD927D60C46E2C554F +100: 3D20E33BA4D52A8C374878F1A624A907132264D0C831C64FC51ED8E1CDB75D11C3FC78D4C3CFBF99D7F0BEA9829B725C +101: FE6A6EBBE30EEA13CE04B1C8FA4199331B77566D2AF420D4EACEDCF22C23B3D7AD2313175389A0765AD60A79C0AA85C4 +102: 1806469C58C028D7FBE80F219DD45333D440A824032778DEFC0A89CF704D40745F0F449F7DF82D228E1718391C85F318 +103: 20CD15E37F6371020B78579210FFD7756B42BD01EB829C1320C59AC382781AC4224439F1F820E215EE907091EE4F028B +104: 7967636E73E440EF1F8751441ADE0F4D169167AC270949A758FE0FFE0B90C2773435623160E4BEA5F23DBE0678E95ED2 +105: 754F6D73A11693E07A2E5F05FBE13514C52F04F904131E0544202354D30917C333DC649FF7C33557005BB19B64DB777D +106: 358D83F883166A6D2972C63F2A46EF893D2FF0F577A53830B3B8E2CB28D1EFE8405084C145EE4E0BEE5DFA9AEF739263 +107: D74B6FD707BCEC9419F032A9C21A7C79CD38F42D564057CDB956485FC5C2ACAECE9D86BE8E12B9181018EA7871343147 +108: A517359A64226F2D08B65203593F3427DD42852476A7609C7F6423C304FBA6EA83981470B8CF171F71BF02F688BB2448 +109: 62162975F98C8ED1B74ADE5B2325EC3D185F7BF8D9DE6C08BB3AB052E54C28399AABE2BE4295CBE12003A03924D4EE3F +110: 8F1E4237FBB668D2705FA6964FF50014F54AB6346A7DECC8DBAA282B51803DE20F9090E7AF2E6B40FD8A138AFE25E1BC +111: F5F9FE110D809D34029DE262A01B208356CAEC6E054C7F926B2591F6C9780579D4B59F5578C6F531A84F158A33660CEF +112: 33BA080EC0CCB378E4E95FED3B26C23AA1A280476E007519EE47F60CD9C5C8A65D627259A9AA2FD33CA06D3C14EE5548 +113: F14FC73C4192759B70993DC35FBEE193A60A98DBD1F8B2421AFA253DEC63015A0D6B75FB50F9F9A5F7FB8E7241540699 +114: 72B9E34E0E655DCD7D9C288D11839A4FD96292F76F69BFB2E7D4F848E498B842CD4ED6486E77E30C603D218144AEEFB7 +115: D71CBD531B25BA65E319954E5AA670C8055406A595D006F0DCEE11AFAAF735CB1615EBAB4CC98061645FB70F31CDD9AA +116: 1F4398793AE7B2C4975AB102BC054DCEECB238DE4307B5DC54F6D7C20E066F638A782E33441533276DF9DB1AD0EAA75A +117: CCD908195016DC596A78C6C10C92EF6F272C6251F3C40B2E7DAD3A4538BF3FF585D4E44035B49EC397D1476E9DD28D02 +118: A8A26DDB23032BBD4432AC857383A5DE280202B21CE173D864E19C4A52984E159BDD006D95605A4682458137FE6B71BF +119: 0C8D3031D85CEFA23A09E13CE03623F0E648A030E43700C82AA1C8AA7E3EA9CECEF3029A23815AD940CC39ADB7747D2F +120: 0577AD6090B2A39FFA1C4A25436F9E958890C55A5B23CF8CEE8195A5984316D81D6CF0B5916C0AD8B1F512FB39826C6D +121: A5E7C31DCDEC53D8898DCB27D52A5C1774115D8DB163543A330AB502FE31D6017FA4BA4C65ADE0CD911972C5A1B7739D +122: 2785C149B798E41E6ED600DDA5257E2F31484BA4D14D35C8353BA4BB3BFB47F6E2CD9B64C940E3C1F83AA4587DC29CAA +123: 977756EEF1A7C1D4CA31A8E6936E7B8884968A22F2846F20B38F247345B1CCD47405040F727BBE2E0FFCD159206F5E87 +124: 9E4811F182E5D6734EA097FCBC77892EC48F09DBA138AD5A5ABFE67F2E88AB61B0A3ECB29028B5528180191754231765 +125: E964C5CC45E8356DCE9FFFE715D01AEB3935D644DC9C2603ACD175A04E8924DD84A4D88A1384D6BAA8AB3F7F7D52D122 +126: 764EB963850537E57D0969C9914355C5AA67AA9722644569B7F50E20DA8461CC9C6CA5958ABE10F5469E4DC1ED27619F +127: D5FCFE2FCF6B3EF375EDE37C8123D9B78065FECC1D55197E2F7721E6E9A93D0BA4D7FD15F9B96DEA2744DF24141BA2EF +128: CA2385773319124534111A36D0581FC3F00815E907034B90CFF9C3A861E126A741D5DFCFF65A417B6D7296863AC0EC17 +129: EF49AE5B9AD51433D00323528D81EA8D2E4D2B507DBD9F1CB84F952B66249A788B1C89FCDB77A0DB9F1FEB901D47FC73 +130: D9B681BA08EC0D0598DD3A2A37F909D01A231D22DA52216126534402A58A072DB35FDAE555B99159894BC823F9DACFE7 +131: 961E792C94027A091DF880A713ECBCA94E7699FA392CCA3E4B9988CB95DD46C894AB6CFA3DE91236188F7A372B1C60C0 +132: 779C845CED9623B6558577C06C6F22768E4A01CED2A9722CB8788FCCA89E0B5CC6A8925533FD097F635997A9C191D59F +133: F8A6FA1C730483AE488191E5863AB3DAB4BBDA1722710E519A2B2455273E78A382C60DB0D21E3B497EF9EEB2780AB384 +134: 1DAA34486981474A57029F0B1FF5150A144CEC7939A5D0C3D7DDDC4F471225D98E83E8A0DE880036F1A265E24CA1E674 +135: 769694D69D701764BCF81C053E2899B232344506C08A39DEDE3D838F85870818C3A8CD2DBC8695EDAF8FE34B4A5CC35D +136: 97E29E4AE7C7E461196C1D698B5D1186822BB66ACA3B3E062A3AE07DB9DD0FED83A345014D3E5AD89E9046606AD2CEE7 +137: 6B57593EE18186573F92273A9B722F9FD77A4A512164FE3756BC2D9F665768016EB2766C46D473A103D7D7090073271F +138: 35235261C522612958048B7FB8E48F96462D2B8B52AB2455C7C142E442E4CF643B367ED466A30BA97D91C1C8C0070E05 +139: 67004A5E74598981A79984B2662FFF8C8F49F8FD13C8A841F68DBA18DF68015E9C1EF38D6522D44F89DBFEA8AF48D2D0 +140: 8ACD05F9738BBB176E50C7419A05C8200E1BA84B5797032E025ED4B55D7A61CEC4CE3662432A4E0BA938D8C9143D5254 +141: 9963300C0CE5F2D39C2B899E47988BFA914D2EA2DBB972C15B3CBC414E41DF3A2FE793597243D46CFF937F41C0D83136 +142: FBEE0F5E072237D19170999D02BB95F6F8F48FD0596A982A4FA2D1273872226398DF57A63E1ACCCF6343415DF387D89E +143: 32A65099C47EAE3BCD0F68645845C0171417385B15DB5E5F7BB5AD965F66C98CDC39B7534198AF70AD5739C8A2F2B8DA +144: E936DBA2CED7F65DE3450BA7ADBE1030D7AEFAFCCE0CBA94E671422790B45B49918319A90FAA7692780CAB4301D9833A +145: 1E20D13B4D71ACBDBD5D2AA129E98929510C795119EA8A07EC63917114315E2756B45E7AE42E1A44C5E410ECBEFB3661 +146: 02A0571C5C3076CACE7F061BDB108D7CD9C7EA51D0FBF1D00F202A0B5C87F22CE687D1CB15F798ED164CAF1CECF92CF2 +147: EA07C4A1DF1E5CB26DC7A7BC76FE518890FB8C424AF3B1C76B37AB21445D9F7FBAB73C7DB35E85337A8F7A0D55121F34 +148: 7829712876378DF986A63E4616DCA38DBE8833B14760168897AA808B96D8FFA4460CA3C1A9B674A0FC13E0625537C45A +149: A7CBB3CD50AA663BD2C4520CCEEF123F7D314870806291DA26A59C003D041E46E6B563670F27BECC5F838A273D349AFC +150: C14E7F70D28E17D3546EB40EE96D239CA5EF7EBBBD0DE64B964C145A5F2980D408A6AC248D651E4583E25093042EA286 +151: 19F87BFFBFF4B1E195612F41E67E1D4CD0393E73FEDAC1C36550C2B1A7323D3E7D747EAAB9844F45F150F8DF0FB72E80 +152: 6BFA3BC29FFF3A92FEC377AF8508D4823F4E87072D6F2F16370B7DD30789A944EE5721EFDA7ABFD47A512EA2D4984BC0 +153: EE10FDDE70EB0A11462DC00860AC4756B21C83BFF0066C431B17BA57CCBB9ED018E8058CB9EA44CC11952C3C9BD15F09 +154: E6A72B9D2A0FFCA41C3122C767A6FD9CFA04CB5B1D1D94B79A0B2C592A584F731CA0523AEA8F2DBA35FDEF74CAF165EC +155: 59118A53C4479070DC728D94BA36D211F4ED5D35F1B69E4DFC0543F07326F982D2B81DDB020F2CACCAF1E5E9832624E3 +156: 63778B7830A3AB7421912A52B3CE9303A53C2A6655291042F428691A633FB9FF173937A8D8F59B21F72D490F39A9AC06 +157: A702F15D9483BB767FC6BE9C3BFC64732277CE936AEBADE4022B24B4822BD1B0FA1213AACF7B4506BF8F330FB7643955 +158: A3FBEA92041484F7F46B380462C5114B0243A79FEED89ECF8E6D8306D60DBEBDC5FF1578EE7E94B5527EFC5707D2B7D3 +159: 1EAEA2602E0B6B328D008A5325C5D4F9DFF7AB9BB5D36816D3EBFEE733BE664E35170506667BF5A24D00222EBC5DCDCD +160: 92E4D41594E15628BEF06CA61E644D2A686C113BF8E3F9A8CD2CD8261B11D01B081EF2941D5182E565B70C566D461B23 +161: 2F08DAAA98DE6DB4E85B81E32C651D88075DE18B7F9C3F633BE1F29C89F24968525B1B357DE80C6EA8D9570E003C75DE +162: 5DF64E7960C755D40BE78F0BB7C1A185DF8E505F0B421BE23563472843E3B5CFC7DA0F40908BF56C6F3A6244581C1DE6 +163: DABB5DCBC32FE7298C811CE22025E9B1C0B87DA5E7931CC3614E3EE39112206DD8422A5504F11599436B806C9108B01B +164: 31AE27382E330115E009474FB5AC750A278B79EFF63755E323E3478B0761E5E946DA6D2436DC44ADE9F4578A8FBA9896 +165: 6804CF0314E455F499E73BBDF4FAA22CA49020330E74C55B1CF4A2D2F4C57D7149B41916002B2852ECFA0713BA91A094 +166: 7FAD2AB0972D8059D4306F0B63F25D9ACBBD8FD95EC8199CFA89D4E227EEDE6052AF0C53C703C7E319047DC5734C9F4C +167: 4635E654950B173D3EC81A8212C1E65605C85835CFAD8607C829786855636A660D6C3045FF17663DE465BF2B152879E2 +168: B40764D8F066C897C3A8FE54BF21DA294C6B3F1B35255F68C8AB325AB3B94EE8AE2E5173936C17FDC95C9B7C3D3D3A58 +169: EE7E424C550F79BA82043245C3B7D0AC32A41B876988C322B9997D87F0A0A1FB8263726B953B43B4616285A239994936 +170: 627DCEEACB27F39552AB683330A67A316B2F53842BCE8056FCF3988702955E3BA72FDEEAC2CDB53F13627858C1BBC51F +171: DD13F3B3E9C79958B20D1986650A79CEE1343F9957FBEEDE18B2FB5E543E3B8839EDF7A57EFD818129C4F00F505D2112 +172: 0A7061C0FBF1EE8CCB0F4A1D0DCAF2F200291AC06830F0E38D05E1CA2429A2BF57DE5BF8DED5A7CECC3A4748FBCB880E +173: 3635AEA9152337FBFA4C2824C5499B9F3FD32061297C4121FB0A44CDF5D3C8D4C6EFD760A0BF076DBD1801C416949A9C +174: F9C58AF2259C719B0B852FC68299AC9F17A802B49B34CBF5FBEB85DB3C68767CC34DAE2CCB536FF90BAE49FDDEC0CFE4 +175: 3541EB8602A4C84545F4476749EAD54E4542C4358CC78CA5B7C8B6BCD9E9A3E649CCB243FE0B3D02930CF1CB7A507FFD +176: 4AA26C2565531A52811D30A1C59152BDE4C61AE2CEAFEF9642E7076EC44C7EBD50F1D1853761B4097D985DFE6878A701 +177: 32F1DD0B4AF205B4891E2F43D772EB5E4A5EA3658106FDC8B8CEEBD2D502F8048B583610A419E1A60020C8C2A5A02FC8 +178: DA7403FE3C3D3139893522C5DC8E4F615D36A0F7B7B8AAF150D1337C8DFE70311544E54880D1C575D664E9AF979984D9 +179: 39F8450D4A946ABC6FCA804AE11935CDE846D999BCFF3091F1E6944EAEAD504F77139A919F915D34DACC13757CCE0157 +180: 45CC03085CC3278B8337096BEDFE6F1D645994690660F23A358C4EC728EBAFD6966C487B9492DE217C17823B16589852 +181: A2150F3BA3349E3AA0ED97B1A02A58F31EB5731012393EC68846D95465F3B787C272852B6945B1CC0FC2B3BE999E0E46 +182: BF9392B085B3C5FFBDE70A3FB64AAB36E39BDE4816F1C9B2A608269336906303F7DFC15F4701D3FAFA5D7A8BFE316A1B +183: 21BDA179D5B80FA6B9444AB1D1F7E06F89F670DA4A038E7E83E8A63CEDD44AB6C1D069D12C6F538B45022EF3160D396D +184: B4216CDE6BC1C27A5C1EA9AC79E85776740F93440AE438D4D9CF51BE8A83AD44565586FBFB58DD743782724A440218E8 +185: 5C3D5C00381BCCF77FC2103C262F373592FE34C2B2895F54BCFD1F9B3C87026288130822B2B451D716FA9D4D7FCC93F5 +186: B927E3777D4BE05FA85D0CB707FB00F08C576777840634531795CD3D6818F192789977AD6425018025E10F5892FFE708 +187: 9C6976E1EDFAEDC32378C8D2758D1B0C5B287C500442EC5D19560BC87C75FD2A7379A3E64ADC1421B7410D1ADD6456BB +188: 9C20482AB71BBD8E985D7891499DB526BCAAE11D2A42DD72FFED664D7BF7F254C2F8DDA2E340690FB83E1F5C58378B72 +189: 7899D5AF410188A3D0D0B12D52437313D786CE7959FC4D194D6A3ACA85729B60ABBDC58AC40731B9E833505156BEFE24 +190: 4F958FD1841D2B790A199EE3358F4DCEEC64CB34D0886EA91AA5E38F8600FBE13DEE4D6A55AC1273B3730CC62A3611B7 +191: 66572F61FE6C34B440AC00C8D3992B9CDE3FC465FCBB193CB7716B53E8032C743718D4F8245D94A22A9AE125795589E0 +192: E7AD49861960D1460A77F4F363341ADC2207E205302957250612C7E903802AF5C9423414C52F4C1AD55CC1C8B2922EF8 +193: 62BE3AA3A9D08CB41F2CA3ABCCB96E2E91A248E569FF58F58C8BECDDA5B4B25FF46BB30EB37999E6131D944CF3253302 +194: 3E082F7DBDF5BBA5F52CC870F2C6E9C63DFCD5D547B183F3FFBE392BF0A1F8F4970CA21E5B9B4306792C138D6B2056C3 +195: 5CC36277225DA2EDCC6CB603EDE9C629E5DA823E6D233AB7833F70FEA2878B2F8D08F361BD5B4C7609577329784D87DD +196: 9555EEEE1EE60EE981CED3FB6BF74699E5383436ACC283BDA0F9F6FFE20561ECE75ECE2C5A82C0A158C071A3BA59CF58 +197: 0B975D2ABD0551BA987680C4890F80DF93AF2292FDD1E47322560B0AD3BDD38A67D3A78497D78B3C38DA597846C5159D +198: 016CE0B8AD1628C7FBA358EEBB7C3667FA93566086B99F20EA6F87FBACB320E7BCEEBABF0008550A59AC1E6C3B4478DD +199: 3D138114480946A2AA1E2B78948B6BFEA95F53BD8BED81ECCE166062A67FD111933A696E6FFFBFCBDDF71041955C98A0 +200: 7EA4BB2534C67036F49DE7BEB5FE8A2478DF04FF3FEF40A9CD4923999A590E9912DF1297217CE1A021AA2FB1013498B8 +201: 80C399C975ADDAB12FA20B3C3D04F25218DFEB678B5A87F9963A462F5474732C7C5FAFE0EBBBAA94662789CC10C9AACB +202: C27E28A5B6C7BFBC7ED372B5BD2555EF1370FD96043753015B3FB9AF31D41E7189D4FA8860B183703560A298D90B6E75 +203: B792B021B3FA904B5948AFB4E56BD4C40119AC79E57EB24C32A7BF0A1A889313D816997E35F2CA192B34D2FF9B05ED9A +204: 7828C6235E2B8AC46E4BCD7F7C7554EA81B5BFC046133EEFA0C4E64AAAAD7115B04EE09E33CB4EA1FF476960C64D9A36 +205: 06678F9A2F238953A8D6646F859FCC3BB0C29BABA669D7F891142C2C3A0BAC1220200B4EFF8C17F5D79E261128C58248 +206: 0FD4448A47B6620FE90551A9AA06DD991AB13DBD2AF18A4F17AE4A9A24D9A83E7653D5F5A2C54633C42ACCB0E5915A35 +207: AABBB8857DE60BDBB21742DE7ACF7EB8D9180D5D0AED23B7F708F09006C6FC56CE85DB87D9642CB909038E70C15C1574 +208: E1BF933A4F32AF56C929911284F9B05B79F0216EF3A150483D74B2D4DCD78885190EB1601A320150C860168221C6BA49 +209: 9074B187372B0535738D4606AA0478BECB5251EAEC961699C2795FC028D641D60230532C8F6A096FEF419A46B0DB87FC +210: A63532A684A1851050E2861F7AB94296D131F768A94AB0019A941734E13842EBE8AB1F42DB4D0A84E261CB4707C74290 +211: DDFD64103308F0537ABD8D4F2209D8920CB42FA9ECBC93318D438C1493FE11B6134DDFF95DBE3FC6B8AA31F833E305A6 +212: 044ED56EF3129D29243665545A59FDC12412E137E1F55A543AACE511F9F86CD3202E3D24807B0FC878BA76223EDC6F42 +213: 2E470AB58A76690755AE6643D615039E767B84AE9E68480DD937913C44AC2350A27FDB45D6FADC242BD5F84809D59E2A +214: EC0ABAC477B5AD5F6B11DB4B699283FD4668D84C2BA7F8DF90A5BF83C0E1E224623F0D2BB3F2DC6EAAC5E41436035D58 +215: 9FEBB6C1604914837F6D00F9AE23A3459DEDCFD81EF755B96A3CC1F63E4CD2E67F5AC2605E594DCD2610F4962EA6C277 +216: 3873BF1A102F1609A624F1A096E420CC459C02590600808F7DA5E3FD49F5B491269C1116A2AC74185A3105B5E9606126 +217: CD7E8C16B59BCEE5888DC7FFC28E65B72570B26F3A0C85885BBCE81E5A6B63D781F953E497399DCB506E8C4F5E237169 +218: 3D24BC91A4932BF6D631EB7698549B03E7F3930662B8527EC122FC2C7AA41E330862102557F480273864FF9B06628BB2 +219: F0B21BC919A3C6089BE3CB7CE10B55D76E31552E759F0465086A89D1FA435E2671928AC329ED7B3D7C1D7121C158BABE +220: B32F9A1FD8A97E6E8E701371BF1A017078B26C3F4C58E342ED455B2557BDA16EAFAC00AEAC1ED7328C65D7C1E227FB83 +221: 5468F1B9192244C738EC20FA979F746CF6929FC48F69C79F43E46859AA022CC42E65203CE7CF77A039402093A1552EC0 +222: A58151FE3211C27651693B55E67CDE0E886BB0D8F2B6D9066615124CF1DA403DFA014C6F19C1B10DE7D3BBDBD0AB9880 +223: FE73FD3276463D27AE6A9F54877CD9BD3410C4A40381D25F5A915194538CA8C4F4B6154ECB9CE8B1B7E23953DC64F664 +224: 0D4EA680BA7CCBB9D88C09F6DAA6BC655BDB0B2A1C8C3DE0BE895328027794E223A45969AE594C7A21FABD5C92BA6530 +225: E6DC0E64DC804FEF91563B550A83BE7ABD50F51D3BFFA785A428EF9436775DD7E3A589793CB2717DC6BAD8B531CFC922 +226: DE168B8F03C0CE8143FD14BD2D294476FBE8DA85B09BF26C5D846E2D19957F87D6FE150B278EA4B3BCD36AE52D251FE5 +227: F34472A4DF2D3B529CE56E9D2A721A839DB05DB7B66BE8AB7202B024DEFD46ACF493973DD1FE88D8EF6E70673914DAA9 +228: 1F5E8FFB4678B3889E7FEB2288358A5F1377A97F76674A8D3E5EF39D185D02F6A1FB60E43BCC79C31E6974B37E74E50F +229: 190AFF1D363C413BEE16C78C544AFD20678C7B1141D3917B6942E4D1486EDBCEE90EDE8A50E441219ED3B11BEFA09F18 +230: 66BB67FC2BDC1D5E8E4366958804F459AA689E04D5FCAFA8CA222656D568B23E976086E2BBAD979EA0973AAA1FADEB8A +231: 0E14C70C02205AA29303D24D6491CC84B648EEB80AE9CC2A0997B7BB646ED32C69D2AE41C0DC007AFCEC514D7B04BCD6 +232: E38C413F3FC12764415F39A9F3638AA1204D3E818A43CF2EDD9F2CE01936D36C6720CF5BE8ABA362F92AEC81386A4800 +233: C3ED0B3697A84B388AA83DFF8EAA65F5BB12EF00315AD462F1F6D85D410D021BC32E77ADC763A254F7D9F1FB6EEEF1F3 +234: 8DC2C3F8C13C43709AAEBD408A679CEC524DA8C8F4157DA4BE551EFD687A395B33577728EB73EB498ECD0AD2487058E8 +235: 8AE817F2056903661E4EBF37D7293200D8BEE7AE0CADEA671E4987624A43712FD2C392E37C17D8E81EAEEBEE8E96653F +236: 9A622BC18F3A09C8BC1C8603B55260BADF32AE7ABD8DCB6CDD980C5E7A5B8A38C6D287A63FE88567BB9B0481743C06D9 +237: B74C6303DDF9F0AD7CBEE923F7F7F1C7FA52C84EF609F2BBCC07B9911C12F3D1A9BD818A9F36EBB40D4B400AA4D0FDC1 +238: 5B1AD3420ED592FA3D593435CA6EBC700583AC5E3CA2876887E5F190EC2109A1E6DD06AFC6C9D7ED0E8B0272B7F9114E +239: 2556CF077A788C49BB6D600F4A3CEE635C4443832D169F761537AFEE2980742B9F34AFBC87F598DD0AEDC4A826ED6A73 +240: D64769AD58F5A338669B935F3431E5BEF31667D0A2437BFF78F1E5275075F434FFF675F9833EA04AC4E5C2E2C2C99B8C +241: 3264CAD70D24B53CEC95269B980DAB85A30D24CF8BDBD68F0FF8A45C6208F05723A4B3270CD095FB8B2D9A4167FB3D3B +242: 4D564117E87700C69AFE5A4D90FF50DEF8A54A9BF19382E4290290D2BEE101355EBB2DFB2A9D6D044A6D12D6DDF7BDBE +243: 6AAD71FA5D5D7B63FEA64D94E211155B01F8C9E4B3D86C3B9C014CA4BB6C668037C4739A082F37B2EC5FF6D85F0A58FF +244: B36D529E55B5CF0FD3273F204F798E21DF533BE466AD1AF35EF80082132640493FD89A6CF41CA68AED066E93181A9EEA +245: 78814E883A27D6ED3A5B122260059CC00D31B8A0E933F3C377BB99EF33F47B13B6AD825B740784BEBDD9917879C2DAEF +246: A7978D0C79070B208F070241867476AE622EA887D26B0F6703FA8A455F411649D8919E6E12C540C59DF60CA9C05684CC +247: BDC3E02D31DB1EB7F04CD9FB8876AA9C7CB1852BD3BD62F56E062E216BE648A34FD327B84E3B6339F44697470711F661 +248: 9135E6D4B1E2356C3DE16A85E4AF57243CF6861DFB6C53CA13D9481371AEE285B75DCCAFC1A64499F1B2CBE4A3CD82C8 +249: D1F9BAA4007BAD437509DB6F6DCA22086CB786026553244A6F480C3A6488F7E26C416C6AE85874477BB5563BA0AECF2E +250: 49E5B7521794B6C73004BADF3D039F4185BE9BF8499FB08B9C8FDA2186B6C4BCD280AE2D2051C6775C19ECF1C776ACF6 +251: A7534C1716B59AB1C7AF3DF0AE32F22CD02A1823F61B318F36DFB536B8EF4515116A099F8DED19B00EE7B2D243539960 +252: 0F01FB323FADD9380A5E4EE6371E8BDF6FFB1F70C4D4A1B5E8BC9B281582AE0531AB354EA9F58A96568826F6172FC75C +253: 145C9D3926904D8418B75C8D645D43AF651684AE7FAD885AB46141B9EAD2D9727731F44D5AAA0204395E020D1B52DA96 +254: F663682EF7FA3F300DFF0B4D9C0D2D126F2BBC164F3B88C8A2207C3799464ED2086CDD324C1E88DAA6EF2D53CF7C190B +255: 98D7AC796C4CFB5D98A1C323656A4BE8AFAAAD168E5EE72B6B7A3FA3260461A043E27243120D41584B58F1AE4463121A +256: FFDAEBFF65ED05CF400F0221C4CCFB4B2104FB6A51F87E40BE6C4309386BFDEC2892E9179B34632331A59592737DB5C5 + +Hash: sha512 + 0: CF83E1357EEFB8BDF1542850D66D8007D620E4050B5715DC83F4A921D36CE9CE47D0D13C5D85F2B0FF8318D2877EEC2F63B931BD47417A81A538327AF927DA3E + 1: B8244D028981D693AF7B456AF8EFA4CAD63D282E19FF14942C246E50D9351D22704A802A71C3580B6370DE4CEB293C324A8423342557D4E5C38438F0E36910EE + 2: 80536C6170DD8626DC081AF148D39EC2FD5D090CC578A76647E7903FD34BD02E4333ECE57B0E24FF116F43429B6FF541834BD40EF0C8D3563ACEF5ED0FD254B8 + 3: 8081DA5F9C1E3D0E1AA16F604D5E5064543CFF5D7BACE2BB312252461E151B3FE0F034EA8DC1DACFF3361A892D625FBE1B614CDA265F87A473C24B0FA1D91DFD + 4: 4EC54B09E2B209DDB9A678522BB451740C513F488CB27A0883630718571745141920036AEBDB78C0B4CD783A4A6EECC937A40C6104E427512D709A634B412F60 + 5: B7B70A0B14D7FA213C6CCD3CBFFC8BB8F8E11A85F1113B0EB26A00208F2B9B3A1DD4AAF39962861E16AB062274342A1CE1F9DBA3654F36FC338245589F296C28 + 6: 2F3831BCCC94CF061BCFA5F8C23C1429D26E3BC6B76EDAD93D9025CB91C903AF6CF9C935DC37193C04C2C66E7D9DE17C358284418218AFEA2160147AAA912F4C + 7: B7C0B47F42F7202BF7D28D6834BEE365FC01CE3F0C8C8DF24B4D940406C2E9C230BA88854E946EBCD786C18C748969FDF012362B7C96400604B6058950FEAAD4 + 8: 8A414C5860CF1BE7BC8531442F69A65EF2ECF0B7CAD9994BCB407097EB74CCB92E93AABD24BDE60331123B4D900684CA7BE6027099D4946BF537F4D6C6DF3D82 + 9: 8B5E5E7FB6530CCE1BFFFD1B1AA338D3282E8483319BF028BB674BB6AEB8200DA389647E3D8631503DC5C487BBFA7D074584493615B036849E0242610EA4758F + 10: 0F89EE1FCB7B0A4F7809D1267A029719004C5A5E5EC323A7C3523A20974F9A3F202F56FADBA4CD9E8D654AB9F2E96DC5C795EA176FA20EDE8D854C342F903533 + 11: 8FFAEE0CCCC162851FAF051AE38667EEFD423C0164C50055F8ADE00AFC3705E3CDEB9900004B0E426CA66AB63AA3B99B075273F44FD37C22A3555C6FD1F37CCB + 12: BA51B2A9DA2F26FE81FC3EE11524255937EC6BEC48835EB437C598C55674E15AA50F88922DE7584332A5E4D24787090CB14DFC3ABDB39C55AEDF6EE108F95354 + 13: B6E30A4016029486F9205C5D141344F885B3DE2468EDFB0B870545F1775CE82597C2A40462F385C957790C20822D9E920EF1AE230878D6B23F221B0182879CCC + 14: 79D76024A31CDBE54CA951D264C46E78F6F5AC5DCD018BAF89AA586333BE82B2D5CA2BC64B99CA2A99D95A984F2DC0D6C07E7C96059DD346BB3296ADE3AA33C0 + 15: 4236736D08F26244E75B51614091CC2C2907D5DD162F8497B14D58D0D954A777C8397549BEE468F30E480252D9B893175DF7D2BF415A128CCC79407D9D5FA536 + 16: DAA295BEED4E2EE94C24015B56AF626B4F21EF9F44F2B3D40FC41C90900A6BF1B4867C43C57CDA54D1B6FD4869B3F23CED5E0BA3C05D0B1680DF4EC7D0762403 + 17: 7B9AE840AAB8BEE45B038CE398D15A8679DB92D0BA46FA67D1B8177986E41EACDE915C6552FC2AF8678425B8BE81B57E0F7EEADCC93B56C58DFC38B4D33BF25D + 18: 0EF6A8C19E19A466DBA3139E2A401175BEB9EE01FB56A8FC11A3E53B345F2327959F6DAACF0CE6121987D2491251DCF550C95F6026F93A1D96A0F4164CB1C642 + 19: D6221AACC88CE14EB7DE0F15F2260EBF4294D9AC3D75B87465EF7AF9570C959077860EBBC5C8153000507CE1E39AED5D007F2286210EFFD26A118966ED15C143 + 20: C9AC4561A7503FAB9C6B71C843AF6911438550BCDF4881EEC18DDA06E4D8B820CCA9521DFA9EF47298CCF6308FE4C4F2F5E34DFEC2ACB78FBDC04D2EF0A5A09E + 21: 73C5D58B05E1E6FCE4299F8D9294681416BC3785F51E402DCEDC0E30C0671DD48321A0248CCC13389A012B52513F1B5BBF820E91EB4F616928183485B4F1EB22 + 22: AB1725C57427DDF93B34AAC62C26F3FF1E49CAD30DD41AE7B5FCE23894245E7E889E0FCA5EC076F247DC7E929D72FB965B45688E57D8CD54212714A17480BE0E + 23: 456F6757A82F0589040996BF88F28E61317C358135A9AB6E96E22F5CA68E2A6438D13D176B01157ACA1FEEDCE3C1A6D5C3A9B1D5A471691917392FB94D0834F7 + 24: 5330241E6F01A49B21AB0D01A9C76AD662E97A325BF8E24C4EB82C6F3B7D2538ADD98F62307F36F900F3934861B80FC9844B761BE15460A1B102C26CF0410E83 + 25: D8DDA603DC21C20A6DD3C6A4F380C297679F035D27BBA82554D02E1F95ECA2EB20496164F96DC4B84B9BB0942B96A3796AFF6125BB9E8711E2674B440176E91A + 26: 81E5A3AF460DD2881353D006AF37478C58AFFF16022441226FB04439783DA920D09FD03E19F45BC82F82735FBF4F2E5F588F11AFDB87B69DB91123CBF05F7F2F + 27: 25AECF7D241EE54E668DDD345582DB777F9F631B9D2432CE4D32119BEA3968D9FA3E184B135364DF62247AB74BA7B86AC3542F63D9F18653D86B9B47944AB96A + 28: 8A372F722A922E29CF5CB22BDABC6D284364F376DA355CA65BE36DAE2FA6F0335744CEFA9089DE55D331AE64E9B2F1037E73608B03B978758A20A012924AB235 + 29: D57C54ABB87AD2D518790B81230DA336F551A0D89A57D0A3CFE2F4ACC55B4B210261CD1482BC436F62D3FC96D1536B82A2E93E9A3DB5CD0F1822EEACF307460C + 30: 6092F1E76F04A5926F6FCD149B18DC9DBE8581BDE6D2A1468145280463472B636C711FF61F5CCA84FD2F044697BD1DD18340B3ED0A131F4BBA35F839A2DD9E0B + 31: 0674A3CDF5F7C18C1B7524C87C36037F3D0267512D11E052F453DBC097CFD52BC331950880CF904656C70758B2E25E21FE2C7E0462E861112A2DC9D0636BBAFC + 32: 3D94EEA49C580AEF816935762BE049559D6D1440DEDE12E6A125F1841FFF8E6FA9D71862A3E5746B571BE3D187B0041046F52EBD850C7CBD5FDE8EE38473B649 + 33: 301F1CD7B25B097AE4C79A97E92BCE359D1289F6754E76B71E7617A06E7783A3CC30F5290209BDA3E6AF239D0DC0F3D1CD4C5E866F4C5C3209EABBD7AAFB8058 + 34: A8C7114B292CC6F46D73824CB073CAEB23EB1ED5EBB37F064A0A76AD452D936D1DF41433FFA337C3F7CD53F5CC00658ED0633252B69DE192E61D9F002B0F133D + 35: D2F92068E07C9AD0572693CF546FE75070E574807C02F5483A31B8CB2105CA55CC6AADAAFE74977F581CE90F43E2AB48260BD7E273D4A83C442EC4871CD88AAC + 36: 1A4133CDFA6CC518387D392814029744D6FA71122EBDFB70059512B89469CDB9D9B5E45900E99E67DBA54B4708036298A94835751EF583149F06AB272B2BA355 + 37: D30DE790B4905717C956A95F60D9ED5948F9E509BA27607E1C5C8FFE35ACD83F719AE04D63364C0BCB72BA529AC79C321ADDFBF7AECF7CA3CAC840A372E6F6CB + 38: A25F5D4BFFBC5F0E3D5CACC3A91870866D8C2D22573556C9B9FA0D24E1D68C55EB42726B1895DF8E5E870DA33755DDBBAC130AF2D96D84DD0D57761D25FDB64F + 39: F44001A74D0B087AF2A143B778DCDEC1554BCE5992C9672E3D0F6704D022CA1E78F087543569CB99D249B820E683138A2DDC5DC178D585167FDD269D17396A89 + 40: 692F36EB114060FD04CD38555025251DF985DDF681A0636FBD290EFEA6FCAC5226859373F3E10E8CB07AB5343547EB0A543C18420D70527D2BBD90040F8DAA52 + 41: 4B1CEF875A025624398CD06DB876EF9AB34FDB1B6A75A07CCB591D9B20EA66E24BAF323911B5CE8B67904945A36C28630B36129939D23D26218610CB049D7AED + 42: DB3E80F11517AB797265829371F245A7A0A384E36A8D43E72852C8D47F8CE37A178475EEF44CE8BDEE5AB054F47EED502E76D49B9F4A5AA392077ED1E6F43EC1 + 43: BD08551AEA7759911B37E9D45748219B47C4EC17A2D2A306D9B8FDF982A9E3106BDC1ACF3F47D383B6D16E85910BBA08128E35EE578E7C55F2E9B9B59F611298 + 44: 3BD8A709DB9A4E0B874B113564B11EAF8270AD1DA3A9236DBB16F58F43285070344962394C2231B3917401924A3F688150B9A9ED3B410547DE3F56450739592C + 45: D0206C8577202C617592B47AE178DA867AC7DAAE4E65B912C771C5FB09585FBD10C36782064E83ACE749BE27045508D544532B628F67DF00A6B7DBA9775D3E06 + 46: 745083E5994158A0FEE4D849012F43A822D19F068AFB327B372A7A8BFE8347E579DD29424EC95319BF75A24B4DB4280D9C16CEBFF5D930D61D34909061A478AE + 47: 3527A5E1E5E5953EC57F309C6513C34405531603372BA0DFD5725E68B9510E5090CC6B317B2E7359D2ABD5ADD353AE1435B85535EB5B0B8F2E09D4DD1BAF3C8B + 48: 622BE417916F1B0E9CE8C952171B11B6D2E2932D6197CC17431B9FFDF03FD0ADB69B08DEDAEBDD0F94812BC2C670C894D65165B31D2F2879532F2C14453E6A0E + 49: C2EBDADE0368F1DEBE44F8E1B77E66BC1C25E7F0FCED7784D615811E2C01192DBC21253E10709D0BEEE746DE6EF93CF65AA39BA29551E11F602ADDD27B196019 + 50: 5ACE0640F0DCB25871E1925F96BAB48162D692BA134C9C7052A37FDFA4895B90AC56C7FB0E7FAF155D147A467839500D980E9D4ED1CC96661177ACF0BA8D4167 + 51: 5D43600C04E52BF6524CDCB9DAD89B1C7563912E7C7E2CA3D34B27B3C1D07D85D35EBB7A65AF0434155AFA3102A580AD557468CC23EEA1E151BFD4EA817FC5B2 + 52: 38D7538AC3E51DDFB6724F57B29A5E46D15A8C08FB29D15FB0681A4315B03FD6747B85D0EB2B9E5FCEC709F365DE08D61A1EB363094BF292B5154671D15D61DA + 53: 2DCE13E5882A31F7396D970AE72E89FB59270D78BF7B4579D0855C4E8BA231D23E5566B77E79CCDC1146762DAAA74F49D82F9EFC0D4FCA891E78F9FF86C61300 + 54: 6D7644DB575C5C238DA02CC4259996CF163A3A3B5ECCC4FC62442DDF01AA05EF0C4EDBE3E6D220DF189C984AA55726A4922EFE004832F2D8887F0B8A9267DB40 + 55: 6856647F269C2EE3D8128F0B25427659D880641EF343300DD3CD4679168F58D6527FDA70B4EBC854E2065E172B7D58C1536992C0810599259BA84A2B40C65414 + 56: 8B12B2F6FE400A51D29656E2B8C42A1BBFE6FCF3E425DA430DB05D1A2DDA14790DEE20FA8B22D8762AFFFE4988A5C98A4430D22A17E41E23D90FA61AB75671A9 + 57: 92CB9F2E4EEE07C7B32B06CF4917FBE54365F55247CC9B5BC4478D9FADA52B07D1C302B3959D0CA9A75A629653EA7C245A8FBBA2A265CDA4EA70AC5A860A6F3D + 58: 23417F93C499DF9EAAF1BFD6A62AADBC711BFE56682943DE5D94E0DAC32F732B763BE28C32AD5F01CB95E5B322AEFF8494B111D7CD8BAB50E7C602695EA6FE42 + 59: 4ADFA8837BB499605D38716F8305FD50255DEA2EC4BF3EEB07560B3C93B5E3725C5A598277A32502CD5C8AF6C88D55756DEB03B69CFC278FFE2BFB3CA202B0F6 + 60: 981A245B249111B4CDCD565AE60C9DEB69FDB552B10C932E8D0635685904203C37CC65D674292405DF24A589682B8AA69BD0E16F666652290BD79AC10E3A9B37 + 61: 15DDF1E434A88F27DEDB8435ED837FE4F1F3BFC5B6FD387A98E93D1C83493D326467C7C53EFEEF158F6B9CC2081267D9761A32A5094399754C0FD62F4C72371A + 62: E08026874830E0B911F5CC51B81599A4DC21204F5C9381CB5A0DA8F452EE99D9FF7590B798805C2743822572E6D2E47C2C1F2D428EF3C28D05297BEDC5CAC4EF + 63: 9DC9C5598E55DC42955695320839788E353F1D7F6BA74DF74C80A8A52F463C0697F57F68835D1418F4CE9B6530CD79BD0F4C6F7E13C93FEB1218C0B65C2C0561 + 64: EE4320EBAF3FDB4F2C832B137200C08E235E0FA7BBD0EB1740C7063BA8A0D151DA77E003398E1714A955D475B05E3E950B639503B452EC185DE4229BC4873949 + 65: 02856CEF735F9ACEC6B9E33F0FBC8F9804D2AA54187F382B8AE842E5D3696C07459AAD2A5AED25EA5E117EB1C7BA35DA6A7A8ADCE9E6AFE3AD79E9FA42D5BBA8 + 66: 371DDB96ED5BE6521379457AE8ADD707A866732B629EE00074904D73858F3FAE827D84E503F3779073490B274E29D644D76154FAB18945222289BCA798BA6438 + 67: 96A693A22256D39A0596802319CB7AF997DB4BFE311577E38F8423DE81C567A96775D063471438F0982EFAA6B75B4AB173D9D3B3D4762030B522FA70DCF3B27A + 68: 7D8AB6155AB31F29740042D82788A69E880FC642E600BEDFC89098B9D2F4F98BC11141FD420870958810295100DE66F50C96E1E4F6489DE98F9BF2D4A9AA2237 + 69: CE561F8F679B4EEB1DC97DB0F72632B9DA1C5B5C0292CBF0662CAD981374BF8C9A0BE1355657FB18196F980E6685D52FE601DD45C6B0FBDE7AA5C9D52E7E5973 + 70: 10164CFD162CABC44C56D76D369096D759954074B0547FA7310C3388F0FB6BB2AA295FAF1E22C44CF59959A37EFE317698BC29AA718D57EBC831A14144F4E48F + 71: 658B337A8FA873C73AE4D19992BBAAD10E1325AFB4DC8B5733F870761429B4243A7982AB375E529C1FBE6339A48F9FB9E8FD6A568F9CAFE640E102B9F398A330 + 72: 4EBDFA0E60E1A3E7FEFB8DB424A5C3A52365F325EC7F51389A4955EE3453BBFC94692DEAC3FF6A4E94105C27D632DF26250FF37314C882FDEB65D53534F8A961 + 73: DFE9D2A6B0AD5DA802D695B3B91745852C97B0283D9A033F04D79D2CAD4FDE50048AC7D82BCF8C402B109E785D39FC9FA0203F7CFC620EE43577688BCF3E69BF + 74: F21869E1EAC3774F3878570AF0DB9A94F464373C1A92E097D180A331C9028A18A68BF4624D8E620B2216B03709F03FB6CD10004F77433ED605B0F771161145C5 + 75: F1F928D322E6852301AD6FC901E91F2156A3CEEFA204044DDA3B4B76A63692DAAC479FFC6D83EEE3BE028A1F651D3520758DD395A1B251E6C261B7CCE86D0481 + 76: 37954BB11B0AAA67F803973DDD2709A73B947D0A5FF8DC46C2D3C6918C87069AD0DF907589F3026A94B071E0F00230F00CF74AFE8010C24E489CC8AF9B8BD646 + 77: 140DB04BF46A194E44F07F6ACEE8326573AA0591F8370A79DF320093C45764A2ABAE531E5A742F496544657FADFEDB7F04D4BD74C347AAE237B5EE59921BA87D + 78: 6D0D30BE796B6E1039739BF24CE26D8DB954D25813F8D7F7444617816F93FC7488B71C69D96D77C65007EF6A2BA313AE0739302395F3D9EAB0244E372AB96961 + 79: 2B92E0D915BC7D56215651BC9F769544C55E2A27080EE726AB14FAC0A43AC51CD378EEA356DFA70EEC3C9146E08E98358C61FFFA3D477CCAC35FD6724A44C23C + 80: 2CED9E743D84F8EC5664A99C6DE2238464E61129B3C856A7FD2CE08B185F4D447A829F287870AC5428114A7234E41A78801C19EA5C6246FEFF961DC6A9B55835 + 81: 4462303D052C70DE76296234B72BFF1AF173E7B63D1CC0E26C518D103BF3BA78D9AF4BA88013192CBADAD83801B8FC29D0838A144AA3CB721AC859EEABF019C0 + 82: 880FEF79B74C109F030F3FA6FCB82DCA034528CCA68A23ED1EE4133C10B3E443434A37C436F079F3F3A922A8547549A39854120723791519DBC166936C239AA3 + 83: 12DE996C9DCE152C83BE6C0E69C66633FC4244B412066A5FE7CEAE27BD4A109FEC95332C60E87DF08A1C714D9D2ECF28A8A81F1CDF8BB3CD2CEF71011BF5A5DC + 84: 748405D18FC05F0AF7F61E0CCDDEFD8055D86826038C77F2AB230F7D97C89D0EF09CE82C4352A7491729C9FD704B279449D0DD7D86CD2FA52EB3B5A582DC2057 + 85: 746653CDC44B4C86B29DE5B28254BE9198C0271249F0690615B05F23AC0456DD66CDDD13D2F22924DF530C78FDFD3699E38E29A550E2739A803FD1FFBEB29E59 + 86: CED0B3E4011A6DA0415C51E37996EBBC5041861FD1584E3D948E1D4DBD7F8673EF93910A10797490DD5C62245EE7EC03D7CE8B8C38FAE21EFAC1AE6056AED143 + 87: FD4BE7DCAC6984196FABA1D88D0FFA9F33CAA29FBAB3E38CD3DDA7FBD94866C944F91B405B3EC613044E4AF11BE7187B15D5AFB4067C54FA09215C3BAC4FF080 + 88: 46836D5A579D5158B9F49D6EBE9A43C9F4A55C768869C3D542BB615FDBAEC8DD34FFCC40288567F8C5E9363852EFF44FEF0EFC0904BE178D3F78EA1B61B9E98A + 89: C05B8745D68BB9647E411E5AA1F924C2C9B96E7DDE71D190A3B8709ACC2856ABFF3C2DBD7093B25F81C6B9883D377E721968632FA4D566F7F72E1109BDEF2D74 + 90: 647A0E15CC4BB5EB3333919CC828D68C5352F1FCACE6964F23FCEB46D0D2408AE896D3319B202EC687F3F9E55126C05705FDB909CD8CAC88304A61B69ABCF65C + 91: 2DD1C321E3CFB58C2E883F5DC3D87F01936ABAB3F1F27648B6AE563333E3852BCCBBCBF4822230E8F0A0DFE32AB6D8DE92A2B8B2271E17DEBEEBF00D83046B75 + 92: 38122D8324807E25DC8A74012CA9C0292222604303CE8B66D7329FEA394D85B7BFBE0F656895EBFD26BD60A3B553A6E3E4003276157B31B3A47779E1633D89D9 + 93: 27FFBA5DD09485E141B659E218D2924AB0392163CDE296D4109F3AEFCDB02241CF0952F0A38E2680D5CFA35363391A324E12519B58C04E8ADF0E9C7A8B6E1712 + 94: 69DA55F3BDBB1C7397CB382B7E8075F615794F6F8453313C0933D33656A3BAB07C42FF977850625B11CA302494497B0EF3A51F3D2EC2E4AECD24BBBC661C6513 + 95: EE1270F6FE6223C19AD4814F0549B54C11AE7B43A8F3418B0F7BAC42BB5B093024DD4F3AB0C9AF5FD2025D50D5B8DC3505D8F754F98AC3237344A7C14FA50815 + 96: AD8ED48E056378B1AFCDC0B3D5D3936AC825F96ABE0953E9BB85B00EC16084A4F0BF12A2B0B73F0A29ECB9841A1DC7F003456016203E891ABA1BEE13FFD19BF0 + 97: F6EB6972CB5FB156FA20A93D8695AE1D9DA8BBDECCADBA81123E7ECBE917596B51E4A6CF9E1458D882B76B33AEA8F3286CC7CA1085F09EB3DB9B9263095339A5 + 98: 40C54D468FE760A7094726B9EF12A98A1F0FE5E7112137ECFB3A88DB04B0758EC581603EFDE3610B1D76AA879EC31933CB6AAFA2DFC559C59BA31425B091FFB1 + 99: DD0324C4DCFF798F024A32A13063A05AF673CB5F8F03E08A0D931406C868A86B5071BA711F6DA80D7FD2F7D3CEE1B7DC12EA456A1EBE4CBCB25ABFB27492390E +100: AF216A7122D29D6A7DC7B89C8B41C111E7C9A00781D4A867A1D75110B48A5A9C92A15D1DC2AEABB53B83BCFFC50F44CFDCAE29DC9984C8C84FEBD0189322BE25 +101: 1FD96E1905B024D5FA883B3BF76C00A0235EE6386EABAE4D9602B5C5E5EA81FE3A1DD0D81BFB0F904ABD4DA7FC71EF7A2BBD0DC6A766902021CEB03D2578B204 +102: 31B75B047B1214B915EC56983E284D14C214D567F149EB467A1A324080AA0D80264ED771E2F91104B2642E9A8312C0C001652CF4E55308A870A77ACFA088D7C0 +103: 59B8D11078C8B65C5DF4F39D1C532BDB9C6E8F2EF121B97DC5BBC29CAF76774A7DDCDCE0F3BCCFFD4779E57D9B23102EF596B8B940480079355CDCF7EC52D47C +104: 3F1702458BA7F28460E84A032BA160430126221AB5320AE028387B60AC53DEBC42FD169A23714AAC3009D52BF9F9485C0878C06A98BB42D1568E7D038234AD23 +105: C8DA7ABB93D370CE8BA6F2B58F91ABBF1302F96799544CCABF52D5D1EAC3318AD4EC853EDC99CF86DF9341D6D794B57B68CD1FBC5E37C03AA10297F9828D5D0B +106: E1680FAF315911FB7588AA2F02D5F96A3FB02F60DC3C93117B97E4F00E2CE6862DB06117A6627B14B11B9E4C61BBEEF09134E1684599A370C61721A3B086942B +107: BAEE728FD37CBE1DAB3FD5A922E58111BFBA9BB47E107909FBDEECCB1812DE27D2D87003FC6F9F67977ED592EBFC734470CD1E907858F555F21EAFD6E64F060D +108: 891AFA38F3094E487BADAEBA012F11D3109EF19B858394EECA4C7F0C2E8FFBB3B88A7105C7D73E7252E67BBA518ABB6A312A7B8A11742D31BF53267CF3B09E5B +109: 6E6E3BE3956224A97F813DE55B3594EC5E2F4A43BAB873D902025699AE58FB43DB71DE1DC159E83F7A7EFFC19CA5A03C1EFFD27B026EE9AAAD92D1D58104D3DC +110: 51F2BA331C24541EFEC042CC66398D388348C4FEDC3F77A4DDFDA39752AE2880C68E0465C15B07ABFD93E16BA635AE7CA7D7E144018ADE57607DE8643992F50B +111: A1A111449B198D9B1F538BAD7F3FC1022B3A5B1A5E90A0BC860DE8512746CBC31599E6C834DE3A3235327AF0B51FF57BF7ACF1974A73014D9C3953812EDC7C8D +112: C5FBD731D19D2AE1180F001BE72C2C1AABA1D7B094B3748880E24593B8E117A750E11C1BD867CC2F96DACE8C8B74ABD2D5C4F236BE444E77D30D1916174070B9 +113: 61B2E77DB697DFE5571FFF3ED06BD60C41E1E7B7C08A80DE01CB16526D9A9A52D690DFBE792278A60F6E2B4C57A97C729773F26E258D2393890C985D645F6715 +114: C02CCA2EE8BED9B4AC74438D4E8B39619347922DDA5CAD2BC3EB9E4CFD4FAF7CC7EB9F6B21ECCA2C55CB60D11EC450390EBCFBA18312E49598D2BC52020DA9F4 +115: E528ABD6C315EADE09A981E4861F6148C9DD4F2FCE0EA54CD3E9796F17033A3751FE9A223AA23CDE0E051A10C2BC27C0298BE97CB87C7110667A115B6D30657C +116: 1B0BF23602D272A06BEC3E86FC675E16DFB067B2AB662181315C45733D191137454BA22713B51478B096DC51D3FC7E9730504324655AE8B7BDFC184118933D36 +117: 12D5EBC3016C77ADCD01F1DE3F792C4230DE67C0B50102E03FBF3B6B80BF913CB66C3E72530C644719003DB2FCB15196803812D89761E0B781E8AFED7268A35D +118: A3527C4E62349394274FB15B30BD95FAC27472E1E521514775D2E667A5480C5367DA6EE526AAC8D0D1226C33EDA1358091C93EC6B1B8464739D25AC4795EF175 +119: 43E497279C2CE805903A33B54B746EA92D607F7C4807986C849823B81097A9099B5896AC7CC66DF3A93EDC8A91B6F3971D6C7F5688DAF635737760BD080E27B3 +120: 9636708964C5FF6600510319E07BF3FCFCB1F4058FEC278EFB677964BA1E140C1632505452F802E99BCF09DA3D456DC3868D149A0788A730E49D239CE7415145 +121: D5D17F592D401CB111FA7C34CF5035BC08EF6B2E0D3E64DDAB08430DEEFC8B9C09C20EB4E8F98D8EBCAC6F09AA2C1DBB7C1B3B2EFE792377CA6600F703643700 +122: 0EA053BBE2E72264AE4F54512C621C733120F777D3CF8FCD8A7CC1ABCAECFB9BE93EE821A15D19467D249A27961E474ABFC433B8C7132321198789D5C2A50896 +123: C64291C217E37E754F6F57C1316FCD8A7C2AC2426E86786FFB69797C0645848CAC41DE345FF90B72FCDE918B7CFAEA4D661687E6F737A088E9296EEF4C3B4F31 +124: DEF8A3CD4921127815F4D1650FBF8B3EF16EF724A38045133749B7359FA68BDE3EEBC9CB5190FB6720EE3D24473286FC046DE0646C6C0042EA1968B48FB6BFBD +125: 6F3581DF30AF789E44C7459356E1C248749B4A5A389759DFF37826BD278D293BA2264BB808A71C453E22A2962DD33A9C03338AD060B3783713EBA8CC8B43E2C2 +126: 2681BF910DDFA680B7204037294D00D0FCAEE84A3747F6E302A16704B3B08EFBDA0E57DBB8E61E92348C8D5FC5A59EAB74C77949A74C7740C30412A9FC65BF34 +127: EAB89674FEAA34E27AEBEEFF3C0A4D70070BB872D5E9F186CF1DBBDEE517B6E35724D629FF025A5B07185E911ADA7E3C8ACF830AA0E4F71777BD2D44F504F7F0 +128: 1DFFD5E3ADB71D45D2245939665521AE001A317A03720A45732BA1900CA3B8351FC5C9B4CA513EBA6F80BC7B1D1FDAD4ABD13491CB824D61B08D8C0E1561B3F7 +129: 1D9DA57FBBDAB09AFB3506AB2D223D06109D65C1C8AD197F50138F714BC4C3F2FE5787922639C680ACAD1C651F955990425954CE2CBA0C5CC83F2667D878EB0F +130: 90272B89212C81B9700897F611F13AC1D291C33A437000C1423336B4D962DD39CE23413160F023963E12F4CCF90D2762B31BFC6818EF865E8A7CBF918A94C1DB +131: 325638D30C9F63D7CDBAA689B7AF8D23826BFE8593B361C7042D3293926146C65C2D6092F20DB5068262359860B3E3D502B6034B9EC8E7253A1FBE4B2007B77C +132: A3FEEC20C69CDAF1936795AEB9052DC525A26F5559045FE458D4B24697E260BDAA45BE8C940A06AE39FDC1F9365F32BAD7DE824FE7722A444E469C7BC198B7C1 +133: 3F80B7BFBFC9D45073FDC2ED93F7C19F01E4D49CB912BD2568F248561F9C9ED1B6762270033D9F421C977F8BB8B4A73F9A99D580C0245DD4F64AD35D68C9847E +134: C292EF04844CD7C3E477C2C2FDDEF46FCEF97E5DEA7955FD4F418C7B4114BA0CA2CA230D0F73A585EAAAEA9277D72B83DB74AC5E887439A225C105B0BFB5A38D +135: 9F0DDAB7986DA54E65EF6B536BB4F7BFF468E0F310803DE28D3908492343E4CAA855B8CAC7409E3A8928E63B9C5D1CAEA7A408ED061809DBAE1AB1A67BA1B926 +136: C58867D309CA48AF74B4D7E49ECED514C89FD433F9DD842F9B50FFAA6C7810BEF35348D00D26DCBE28122BA1CE33D4CD00D09BA76F982A598B8F65790368AE59 +137: C8B1D6B4778932BC21EDDBBE4E48F7711D7E97ED5354DCF11BE98E3110510FB007948C288FD2F7AA71B2E41C86330DBBCA2ED472D15B444828C6DF4282815879 +138: F1C0C057C974E4C27E497EEF52A02963D5957EA02C7E1CFE06423048799AAF74475732A7352220A914BF32EBA6A0B6FF28C77D25CC3CA1AFBDA89870F4EB55D7 +139: 092E121F2C7A2621AA36AA9B040EFE4435DD649E3F336BA82788D57B9B164184F5B5BA644DB4076B46FF9F3A6B9F58D775CE94FEB648A372D960471A663B74E1 +140: 406A5382E9A563E60FDE5CC47F52C6DB86CEE271BD3974AC6E274A1B8C5A7EB369A9B7CD312C301F891D4E3A601A80B9CA06303C53CABD5D3B7834DBC5108470 +141: B2D3EFC2390CF7A1093B93C52B76D0DD74BC277F3D67A85F41635F89E923AEBC960B2BDF8A13860CF3083AC3FBA13D4FE5E426F144FC988554E89ED7A0324748 +142: F1F7100636AEEEC8AE93A2CAF1F4852F192E1EC1AF13697765CACE58FB40B9D9AFC3BBE7E52EDCE649F53C1BAF653CA20E75D3E4AD549D05EB33A68DD11E1898 +143: DB604416DFD0A7DC509DBD2C83D5FEDE5E31D641EE6C14390CF599CDC7D841660AC700D3DE4BE35E07006B724B7DD1BAA21EFC3CA6D346B3B858384FF691F913 +144: 87AE00E496649511C3BF947A65805ADB5D237AE8486CBFF01EBE52D5D5062A99DB3434EC22A37DFDB4CBA1A59AF1FA5825EE3DB2A8524BDEAE07F3264989B85A +145: F442BB697D498F2026FA2A5FFFF9AC5ACA0052F6D200E10805104D91BDFC71A3764CE0277009229B9E7C945222BD7C9085163987E4CED02ACC7420A96B0F9587 +146: 1061588877909CAABFA37D4915EEBD6E517B8D3EFD5660F872019050B3C1465F11FC9B44E72610219F3F5F21772933F101D9D58B5C5F79FD7457F95749BF11D5 +147: FBB4C9BD6821A04CF154DCC7A7507A2C655739F3636B69E8183418E2C33D951DE6BFDF2C3CA603694C44DE44057665EA4835281A2773CB8A84965BE02DF1F3E2 +148: 08D54B05F901FE95EA5B56BA19DF9120C66AD004F98BF8FCBDA9DA0874E64978EFC34877B8224A024DE12D7B926B5D83068E8A704EEF0F738A5061E5F8462F54 +149: B79F53A5117503B5A0316F801B8D448079F38CB90CC39BAFD4DFE169E3C931D622AF7E26835C9AD4DB25C0D6A684E7DAC4B88B475663E05601A99EE9FC8922EC +150: 2209CF6BA43F61D7E579651EBBA0890686A9CDC1E045255494DB0BC732C9512ACBF72158D5738FF63B500AADCCBA000D25A521D41AB4EE6D92D38E8077B79C07 +151: 8236F7CFFA68B49BE5C38A7A1BB67B745430D1511A08EF347383C32AAE1EF4AB2E7F63A20C9D8E5CF2198B32B7BC79B470D36BDF12E7263D669FA4AB8605B75F +152: 228BEFE5788090066D493CF87F75C666BC3C75E0B7BC63E80D38340CF9176251C6E185992B244D4A5B1CECFA42128DAE6EC3ED535AFF039769E364048C442DCF +153: 59171D498BF80731E2E35D0A32DA356419E69B8BAA5B1195D690CD8A5B11542087A007D8DE3FD000BFB03A0408C08E92A0C7712924373FD67A65218E4A4E0F68 +154: 4F94A8F6A136E49069C88DFDEA9361B34D68FFC25724F836CCB021BDB74E0AEE9DDFE80B938A5C12B01F0F1CC49C500FE7709C2090F809D9E0256FC93D93122F +155: DE5E17A668F75866262BBB2089C9DD86775100C77974161DF46BE02A9578855E7C81C77263105C473FD1A2D55483063970C0F643CB25AA4B4AB45A40888F61FB +156: 3314001C825DFD2CD1CE08C746F0BE5C451027F0FAA401431AC84FAEA51553EFD9E0646FB7E9B94CBC672DC98FE9870467C176AA648EC72BF61334B13E479E4E +157: 3EE80B1422E3572B46F7CE5841998BD2B6DF3B591FB5E46851B4D54BF572A17DB5963A04EC6AB98BA07C943475AC088B4D201AFD684F30F45C8037400A7C9510 +158: 3743FE18BD6AEF36887EAB7BEBCE36D5D3B69DFC306B58B1E8C6241E81A9D38425BA991A29C3B07D4F4B9C5CC762B2563C9E5A05B199CEA5833D9FA0062D161A +159: 7F9F71B086CC6D6B63052767CCD6D0349C076289F63483241CE105076B7549B3187897D45D7B5FB2147E54F056530347A1F9265E6F37953B5941272A29E2FAC6 +160: E09CBBFD3DDBB24755CBE8E51C8BFF1BFF36E571EE72E6C99DDA6D507AFE3C562D437E8612B50859AD5CD608424DBE625E0162E6CB7B838F20E7B2F93F40ED91 +161: 2E2F91BD5FEB5C79E98ED97C513E17D2D97B02A844780A0190264773C3040A2CF07FCB0E6424B7A0E88C221BA3824C1906FC1647AB40DC13E2D0CC507CBB6BCE +162: 8D4E87F66B3418105CD5583A92A2D2EBE8824E1F9150CB872FD3DA9C93D382C08065C818E1AF9B25875B142E70676D9A525D901EA2142E42D813A221D21EAEF5 +163: 0518E420BB5680B74367F8CFCF7DD32F3AAE009A0067FEC22456CEAD0832BDC2A60D8AA7B0A2FDCB9072C0F1171772BB665C0B28CD184609F63AD53F89597F9C +164: 247197FBCBEE77B8EAF6358F71A49D784CB43FB44D99910B0599E69B29E31C4019E830F322D5A7117A996BDB4D91E5CF323DB354E902E4DAEE8057B3F78ED5B7 +165: 35A7D806AF0C8167D1505B25EDB565E931864C453BF60AD7B6695035D7584E7714E21F377B35A5F3A69878835617B951977C209F5F3C5967B7DD9BEAA75A7CAB +166: CA9B60EA8DA2D0BBF46742E31AE882F5355688B071883F690AE775C4D949DED8077170F26E89A18CFC251662EA8D1FF43F5A5F28E3FB41ADD741AD2E28341A79 +167: A861DC64C745B0F5D3EFB2773C51981A836024BC420B1FCC564E03006163B491126AD8633FADB6DFCB25C2EF92FD82823FE2C7F1161A78C7766B5E21F96BACB8 +168: 1EE6CA0866F227B27678326FEDA4CBF59934AB0EA2E874E9EA233AA5C67141A05C1B4C950044BB6C9B9D146520C2E3779AE44187BE0DC1CC41FA7F72500B249E +169: DA1032057A25DA7EF987A2D7CF28B927D3DBD956979679F5A6BF4EA20FE1080BD8AF2DC8B1C7E236E7601BD82CFD64DFCA7D03A03087475ADD57EADFFEC2CA85 +170: 22E41325474C7C7EE980314D7738947E9CE3A970B2D28BCD69D545D5E795ED50A5A1839021645D000CD4779E181A65974171C15B9B08B349205B87C150688839 +171: 5FC5AD1B8B7622C4D17CCE23679FC7E0CCEBA00C1FD7178245206F866A6BB198F26A05A3D429E2C508DAAC6D0F698FAE6C0DE7FF971EACEEE84813110672F3AB +172: 2264F674AFC9743A46180CE4E4AA6A2BB33D6BF2F62AA14648179400806D718DEE8FE57DA48D88DF5D57B42087BB2FA62F833BFF87B6678606C6336CBCF34B3F +173: 65E9D1187801C74FC23C4F19698F6B93405C681B93A80D23D427D9F2CBFE63F7E2959B2AAD6CD7EF6E987A5FFD585E1BE8E314A1D502FAE80215C5331F8FFC2B +174: E0436B17C2BB096B08698F4CB448287D69322C34814776E0B1B21486A2D5B6906889A5B198FDDF699AB285BDF58783DE7913075F86ADA977DD35FD09AF336E21 +175: 857BE6485722B4BE445B72C7A15A1D0BEE6C7FB2AD541C2B4F0035DFA1EEAA10D4F0BA5A124F985DEFA53D0A0554BB258B2832BC2CB5B7787D812E96A55A93DC +176: 7B2298654B95CD00307D8D983A0079CCCFD89E5788180CAF352B6C965B9BB5153C9DE25C4A0CBB5E578859660696C887280EA378A2E02B7C7F9E6CC635509EBD +177: C7ADECC928EF065C263A97A273CE8CB30485BFC035F2FC02C78AE2AC6B7F7ED20E93897C0994CAB8D584EEF9DD475AA1613159A0C862FF179C67120F6B4C72C7 +178: 041A03CCE6696653ED5F367749AE1AF3C2654E8A9C0E70E467261E60023876C7271CAE545D114C32D38DA75389525CF0CF1FC0FA9A481ECF43FA0B1F61B868F7 +179: E652E4A88EC1A9C4678F8CFDBFB1D758774600255165E2B4DC15F61C18B9ADE14C5ACE7E8AE72D3062B7F1787583C55B14B347F642344E71D6E00FD6F4C56808 +180: 903675FD8C70BEBE9FD0DADAB17A638A2DD8089AE63114E36D28F4C75D951D75B0BCAB5247803551862720713AB45A932DBE141E48E9BF3ED9E76201577DDD43 +181: 6E61016D474D2AC2984E4EAD44ED82B7129B0B7FF0B9AAF5F45CA68B0529A736B846626CEBCAB9E7CE374D744E7A09C51BBBC746D989806F1A00703A002542FA +182: 20085D4717A204E896F10C5F7E1FD429C9AF848FFF608A2C46D3738EE4FFB944381880A7A455FEC6A1A21754D9ECCF3F1390EA22EC17FCFECE2B86E361784045 +183: 37216CA069259BA3244DE3933A3AD5F35712F0AB7B9C81D64000F0B91DD4232B53748B704E7ED0DD682A77D84BAC1B943D2FF7A3DBF5FE33DF455DDB10D11632 +184: 1F2467A57006D96FDC75A8BDAF98907AE72AD330C0418B06513C33D86DDB800AB6A51738DBFDF1C44676038C094EB5F309B5B590EAAADA4DB09FE7590FF04888 +185: C45893F92AC3E3AA3BC86A9ED659797A7C7DB949A66552ABD046DA2AA7DA9E52FF8BA2673CB44B2CB0481D599EC70020B6D5079296F2C19DB162DC8CCD64BAFD +186: 9919574ADE9B8640BB0EF45F98D1DB6FB7242C433D86CF6D4BD67AD14FF15D74A13F796429E312BAC581552E6597BAD2792F31B2488ED300C6118891ADEE9FB1 +187: 034A92D00A172A5F0CE717FC38AB8D68019F500493899401B563845EB604ABE0907749AA830F91B53AA7C89DFFF86664F8B123AFF4721D790A58CC22F36A560C +188: 54714E69859C60B07C7FE34859C855A37A82204D723F1A695F78D7765CE906D109FA6144EBA9E7E7A7D8343A99495E72D160DD468BEFB794D97659B8E2D8F1CE +189: D6CA476F7E68095DFCEF4338BD6466FCA90DF78A17DE9E29111D4645B0DAA0C6E98F156C0EBF9134BC28EF9E0EA67E6D839027DD5CB084E9EBA899DD3413E222 +190: 86EB8C026D6BF090636F01F623CD98B960D08E521E44697F364BC1AE1655B9AD6FC3EA38C929AC9A244D18E697342594F3E7DFE605954579AE4042CA69E65AC3 +191: 1F63EE615E9B809E3661C77B5029C78A92DC4BE3CC4DFD8BBE78DC7B7D990BC717238004969A8B854CBA04B4D9B30AA1A1964264C47F23D9BCDF45C74FFFD918 +192: 0351F475C711D068BE7B0395D65343B5E249FEAA3C3F3B6B87100C50306EF0340F60EF36233F0E6287057EF7BE8634BFC4D46B49E4A8F2CC4839F42F486A16FB +193: 16645F9C0ABBDA602B7436DE3B1C55AAFD1E844057D51EF80A96CBC2FAFF6E3B2706B45069C90A52D779E101793EAF4C9AE85CAD0A5A394164F0BF34C189A2A0 +194: 821E46199F4FEBD9C118D49B1CE9FFE953113EB6E4E33DA9E39C676399A0B3F792C2990A9F75D729E58EF750857C07336526631CBAA5EE0643699C8E7B7EEA13 +195: 64CB83ABF2BB0A94451F2B9C3EDD76E4A15F9D1F9EE32C0607F5E0951084377E484A8259B3C64428293396F78E6674CC3C027CED1BE12F5671D328D131740770 +196: CCC1A68114DF54BF467EC49CB15CE381EBA7E6FF06A93EFC88F442F8A35827D5DC6494A4F39E8423167CC1C3269A3EE6AE68825FE3E2E40EAFB75C8D878FF88B +197: 94D38693F1B1A8F1013544419C5B3BA0CD79B72478A91CF3AD325E4C3CDCE092AB667572233A4F8DFF132401968BC74C553AEEE96D530CA4E5F6D427F9D2C422 +198: EB080E256FA9A5D51C3DF577509B877563958704C0F1DB645F75CE24005D3B12503BDC26FD3A66E8F6882D3491428A4932EED6F5F58532FEAF521BA5FE05B70C +199: 9A43D7D0C42D7B5409963339C9D9805BA59ED8A63DB144165A3C759EB9F5D756E6288308DD2FE460CC50DE26E1A1C1747AA165FE6C8A1FD5B0F7CB1373E28CAC +200: 986058E9895E2C2AB8F9E8CBDF801DB12A44842A56A91D5A4E87B1FC98B293722C4664142E42C3C551FF898646268CD92B84ED230B8C94BED7798D4F27CD7465 +201: 9FCCC4EEF7571A2BEEE06981856228CEDAF3BD412E777F4AE8524B81C373FDBC210795C1E788EE7081BA42EC3FAFACCF2F386A9096AC719E6565B4E384E390E2 +202: E4E8BF0BF40249236FB88C442E6668E3067ED6001189053A3A81EB755798911258E25CACF7282811DD5E5147811844C4B5BF52FC24A6862BCAF9407F2E38EF5D +203: 317ECED703044C1BCE944DDA7114DD1E36244DF6A533790FAADBD0B8DDF1AC0D198B593F0479A038198F4B94AA6ED294168FE0EE800C02E769EE78ED45249945 +204: F5FA1EDDE359173067E463107FCDF00EF227CBBA0EC5EA02EBBABE2C79B12E793B98FD3A90A72BC26240D994F53DED65FE22C6FE87EAFD01B8478D1E8569A882 +205: 6323E2A8E380CE86433D5B8FCC5E02FABA4ED7F9CE5BD194F7CBFA36F65844B61A7BDF8F131CB4B28C56ACFDB99CD84830557C571FD369650B4608376BBE4FDC +206: DC6BDB69D1C6111E280F993635BB59CD6E7B189166DE593B71E194C5F218D67B00EBE0D028E944976D6538DE410C4D86A2B6F272BB94FFA590208C644F99240F +207: 2428590D2043634FB10268435EA90ABD082D45317D2C54D065529F15E180438AB18FE4CCC9129584804EB04EA1CFF646FA881878520BC01AFF392B6D7D9C0369 +208: 1A29341BEF679E5351911809DA190BAB8E665A9375BC2D477742176A70A6BE8ACE4A35645BF8DB97AB9BBAF1F0313004AF8B4CF10ADB26AC0198AB1D45D05C46 +209: 0EF4FCF3B2010921C58056B2BA367B4C09F5325E6AE9AD732AB277281D4BA797A847B1C6A74D81523DEA163AB0E556FB5102C14E8CD94AFBAC0AB0A921BF1A25 +210: 73C65AF2A53E8860BEE63AF0BD8A457B0AC8D3C5D243FBB1BC3D67624727CC175F3CA133B26342C3401D75DCDDDAD9A692D9A2B1264E90CFFD4BB9E6E775DE15 +211: 18D3DE049396E2EA541E15C31C0EF0E0BD90CCC6CA35663856B94F6F18160D616667C55F3ADC1B33E749F60BE50514A4F3BE48ABE2E18FCA10F85ED0266972D5 +212: 34DED45ED26FE224E0C5A66A193C11A2CC0786E61D421034B3BB16175019C95453F20BDE865DEEAC5C2BB5C86544641482B51C4E61D9DDACC238D050CFC35776 +213: 025D211B55974BAF086B139D8FA1AEA75B627CE1AB894D52F8769874557BE5944D27FD4BA3606266BC7F50D1734436C53D4555A1D2DE0DD2AC51D7F2FA373867 +214: 08CD521B1F13440D57001F30BDA0029FD8AA17FF26AFECEFA2CB7EE1812FC79A694ACD0BDA98184154B72FB7CE305FF4897F466CBB3972B4863FC88B3DA52C28 +215: BA3BF464071BDF124034CD122451D3374AACFBBC916C858B93E191006235F4D741564BA1DE70372269C122D360121DD3D427853BA76C6B450BB46F4156EA7524 +216: CB0B3250639B4ED947BE0C83EEF67D370DE76AB901F607F68FBF1BF8ADA15984DDA7BECAA4D7FDD55FBFE479EEE3F5ECC9CDA7BAEDC9DB7D35DC227411DCF20E +217: 8AFA4024BD96BD50323AFDCF92A7F3E7BFB4C927108CF81C01FD378F61C55D850020DBEB88C6528B8FC141C37EA4852481C14902878AFDE51A7F1EA1612D0324 +218: 27057269EEB73333A1A8059D6C9D6FD5AC89EC26500F6F9838CACEC20E93F1713CF5569E820BD80969547D77E56AB0CBF57F03182EF45AC8BDDE114470C6DDEA +219: C79C3D4A4608C7CB4A3D0C14B28CBB96364F44DD8651F36D908AE502E547AD7AD5DFC10DA26CA26C6D9E51CD40F6D7F1BEA0A03358967D867A97333DA8ADF3AF +220: 9DC3B1EF11D85FF8A57330FDF91D5B5AB142FB89A72D880DAE476E020755C2F3B4CA58C9ED36239E8807C059BD66F826EC517B7A44187E7216E48B683B567076 +221: D11A97FB7B967E90C2D39EF42EBE49327CD58EA6977C84275B01698E322DD97024A40FC3EEDD96207310708F737E81B79659A6C7202E96BE7AA34D18D4026F63 +222: C9BD62C0FCE47736ADCD9275B46845E4ECA23B73678693FEB8E21909EB8405D4B057AF2AFFD7E667E047A07E6ACCADC2A58D7360C17689769DB009F0A7795560 +223: 7FAFE6ABE7CB8C109B18A14BC4FC2E4FFEADD55A43AE7DFC58D89B9CCEBB4467FE4CC163FF6EB16C8C71B8EFF12E7891D11D3DA2C6DFA8152DEC52B232267B6B +224: AEC37B2A1157708142BDACFE77E5204174F539D86A12730BBEF6386FCA098AFF2A5C31EA1AB21D3B4537531DDEB27CA9DAEA22F5CC8C9956B2F2595F53BB931C +225: 6B005CC923D9AFF56334CFC7A5E3ECD70E97C4247EB372A3180E7DC5BEBE676E72E2FDFACB74277B70E15D871819626F46661285DB04B3F825C49EEF42391B5E +226: 509B5C993CDF61F8F507A84BBD7D6D7AB090970927400043D39E5F47DC23AC289F5BBF9D3246EDB174D9C5D72BA7A066DC13171EC15FF9508911464F8730D395 +227: 00A05302C3A60E58C4C52847F47379212A918060931A72BC660D88E7BF5599DF6C38DE92452B4823B4725BA3EEE866235CCF4D5903E91714CAA230C6D6EEBE45 +228: C4FA5EFAA31CA205A732FCD5DEBED53C09A4F30C5BD9ADF27F8C1DCD4B2730925BB6AF176E2E680B2BE325F7DDEFBC9EE6C1CBC4F0426ADCB5CBF18D1437EE6C +229: D125006B8107FA63C375A79AAA0EBE82017372B7CC65C3157CE078DDBDAEE8C569BB84FD8490F2D66D15FE73C6881245761AB2B1D4F056637ECA70641745CDA4 +230: 01C7D098DCE4E40A69DE14682587FF2A40BAF9833BDCC6413AB54DB0E64262F290D584CD5B21C6558682C50E1E27BF53A18A16D72ABDE878C3522156C9F04DE3 +231: E863DA51CAE09500F589BE05CAAD5788587E2017907444D76F547D6F30632AC658EEB8585733BBB815D2E19EA046369ED3B81AA773FBFFAC316162389E015A71 +232: FD8232F7B79BDF9CC52FF0D5DE1C565E9D659BF19769096895D182A88028C1CDB7387DD240128A7ECFD2708EBA7E9E3C676D6E2A036E1B993940F5CCDF1A736A +233: 3BF8572CDC7B825CE7F3222A3DB87F1C52FBD1A8229B957ACFEF2047C560567483C479603A3C0B0F1B2DD265BEC257D1A32C651508D7A4DF501BC015657DCAC0 +234: 23FC530B031136A17B8B2FCB55046DE7271312EE3E77851FBDB05F78A294815CB2169079168E07647A2BD5D05C1BC2B1EF1B64B929DAA1F9CE723D448C936FEC +235: 83D10057C7FB494FAAD289B4FE5F093DB2A0C7D79A298173DA735CD5063232BF9E5327A7B4AA795C99F323045790B554476F37EB9D04FE3DF40C047E4113A720 +236: 0AA201EDF4124F421D4515554A1A642E3B9D18C70E09E83A886D6F0CAB0750D9BA1FFEB9C587F3ACAB0D8B9C1D83D789102F0E2A6CFF885C50F485929DF4602D +237: B85CC52981751513B917F58305AFFDDC7D901CB3BB1D1BF5DAB058DEC9B8CDCD2DAE543D73EC6AE0889C9D785F9178D207059D994E1C80706EB28AE65AAA100C +238: 068FED72E55444AE108EEFBDD59A96DA4AEA3D81A6642742C38BBD4EAAEDA6EE21FB8702C2F95152F1F997A5F40F06C54619481F2EC343AD33400913D6FDB4FB +239: CB4C7FD522756D5781AD3A4F590A1D862906B960E7720136CB3FB36B563CAA1EA5689134291FA79C80CCC2B4092B41DF32EBDCB36DBE79DB483440228C1622A8 +240: 6C48466C9F6C07E4AB762C696B7EEB35CFE236FCA73683E5FAB873AC3489B4D2EB3D7AFCCE7E8165DBBF37ADED3B5B0C889C0B7E0F1790A8330D8677429D91A5 +241: 4F663484EFCA758D670147758A5D4D9E5933FE22C0A1DC01F954738FF8310A6515B3EC42094449075ED678C55EE001A4FB91B1081DFAE6AB83860B7B4CC7B4AB +242: 81A70404857420638D72672A2DF5A49D52B9F9F38B385D8C5129D6A2B82A682CFEAFE6509266E4B00F6B6A07341C2F64E4D4F2152583ED143E3DCFB14C1C216F +243: 31F655A1334E1A45584F12A22E03B09E3C69ED0E1D0FD573AD0D56F9C86862299E333ABE78590E97EEAA5C2FB14DC9F34FEF6DDAF6E7A9BFBF68CA6631195CE5 +244: B62C5102F97E5C4D7554790A4CF53A58D3EF44C83142D6E009BD1F6FC8F3A19AA1B89DA8DD9BD1310827A5BF662BE7CAC750C48E6ED91313E940D7D9E5EB9C22 +245: 380023C0BAC4C9524FF6778BE80CDF195E36FCF460E8CF1BF04E5C2FE08E38C35F183FBCDC3726FF26423F351C507279F6258F2319EA1403B6C8A3DCB384AC7F +246: 473FC167C7C4BC40B17DA039EE09FF3DE884879557E40C52C1981AC419CE021A090BBAE014822D05714077008988D74FF151C927AA43E88CD63FF2CCD2012AF4 +247: 006086E61959B1D66C72E754427EAD5E1D6C02D8409F5C32B2F5AE448F54682B504A1ABC0346CCF39BF66A8C7B69081E886B47A7D0B02291462391C95351EE40 +248: 3828B2ED548CFD0B74BB34A1FEAE030E267222198D7E387E7FE3ED503905A25D4C3301A9A47E78372F685B05847062476C507708CDD75580ADB579E4CDC79AA0 +249: C26A7D5BB103EDFEAE2F1201BE58AAC127F69AE378DB04156074E991745D4AA5AAB3BA064407DFDA8D34E573B7EC1F9F37CEF01ADC17FAF393C262A09F2C4736 +250: DCF82307195035A668097514FF1A10E0BF0E802B4945A702D2E17AF6DE1D3D9BA49616DFD16D802054B5219CA37884385E87A713B4EF5C7FCB69661C7F56D5E3 +251: 46049EA0DFA5C49429E15626AF4AF2CE0A9DD2F308B99BA6E6E3F3088250A146870FD0B53228D5A1F1BF9859480E1B7A3D3DA180AEF4D5D41BD2951C4E19426C +252: C0A1FB6C0A65A0D1AF46A5FE86C8A88E8A86F83E36317F435542927C98E74833C887CA3AB5E792CE5E3E21CC6C6AF437349F5A66FAFC4DA79742491C643901F9 +253: DCDD20CD47B7C7D011E9DF7855B08336BD5007C4435208BD3B914D7E503B8399164A155697E68A1B88A0600BDCF847A114D98FB773C81FEC817B92057A6998A9 +254: E2DA07644DAA73B66C1B6FBCDAE7FF28E3B9024F0BC5408FE02C18E3744CF9BD6DD54EA7BFA1F6F3A81C8560FB938FDFF9A38A29853A3A819B58D10213A290EC +255: 15025C9D135861FF5A549DF0BFD6C398FD126613496D4E97627651E68B7B1F80407F187D7978464F0F78BFEEA787600FAAEBBE991EDDB60671CD0CE874F0A744 +256: 1E7B80BC8EDC552C8FEEB2780E111477E5BC70465FAC1A77B29B35980C3F0CE4A036A6C9462036824BD56801E62AF7E9FEBA5C22ED8A5AF877BF7DE117DCAC6D + +Hash: rmd128 + 0: CDF26213A150DC3ECB610F18F6B38B46 + 1: F069A435C14A8D4B02A7BBAEE02D0BC3 + 2: 48456EA1CD4C51DD8E1130F625DA4F8D + 3: 6E41F2AE95605779C74CB5ACDFB361CC + 4: 0C7A6C73E99A5C65B12D3EF47ECA9D2B + 5: 3B80361C079D1B67933455D00AB1428E + 6: 0F74C4BFBFC740A027B1D5BB9CAAAFA8 + 7: AA54ED5DA34CE9205B64D138538C0C1F + 8: 08445C3C3E71434DE375CC2071430EBE + 9: 1FE0AE641DEC6F8C172F0E27E9E73B9E + 10: 4E8152B7EA8F7A31D8649A51389260F9 + 11: 0F851C98C2B997C2459B34CCB209E481 + 12: 52D27461FD7E095EE3C6ED43BC24EF23 + 13: E9F3489135F3D90EBBADF9F916C34920 + 14: 36D527B693D6531A5E4E15BDE9E4A670 + 15: 57433A07CC200953B7FD440253D5E476 + 16: 4A91FFF90756026A90A83927066EC911 + 17: 5A247C26BB1BABDF1009B6B4951FD76E + 18: 002DA29AC9F51F065A1E371660BB67BE + 19: CFFED09ACF01DEC9D3891033C0973953 + 20: B78F28AD3460C99D428AF24E2787EFE7 + 21: 5E203157AB6BAC57660F3D25FF615C95 + 22: F128F5DEC3A24AF34AD3E7F3883C8051 + 23: 2E05AF10A6CE9AD1E0C0FBCBF69B1C9E + 24: 67FAFD9A5CEA5D41863D03AF2932C5CF + 25: 5ED7E86651AC4BD0EEA718C773812977 + 26: 6BC74F78256A98761981882C3CF7AAEB + 27: 44CC573B964002D877E79B75E4433E41 + 28: FC02FF53665B52B58DE38784E2C28E92 + 29: BC4D69312DFD24EEA219F29FF2AB2072 + 30: 0355E82F130341EFDD997EBDF4469221 + 31: 453D500D997FC85F6AE16365D83ACC05 + 32: 42DF4C5A3844F00F77ED84E125237113 + 33: E782D7162BB54E735F7B9FDD75A3F14E + 34: 78993013EEEA7B14999DDD3979191D74 + 35: 27BFCEF540F0782E9A28328E8DBEE59B + 36: DCF00356DCD264B7E359F02D7D2CDBB3 + 37: 9EE0BD7F55EBD844A8D114F83B3E8FC3 + 38: 01EF8F3154BA9B9B817AE717FEA00A68 + 39: 4DCBC2AA56D785CE7249761791442BBB + 40: 10282C07B870BCCE0C8DF9E68B4C5DAD + 41: 0757B359AB2D1D121BA01BB345A12A87 + 42: 450AEDEE570A2E9B1A19D5B4747B2AC9 + 43: 2C45713898BD259B10E2352BECFD6DE8 + 44: 3E92731175E510FCD07D28AD47DDA0CE + 45: 6A8E5690AD4AA2180966AC1503A81A18 + 46: 820BE195E2AE85C115BFE3C341567030 + 47: 9C97E1F0E7DA29A0527AC4F59D520100 + 48: E1257842EA15216543BFE84521B9FDC3 + 49: 42BA484CB70A58EB3EB5DA43F1D5D5D1 + 50: 2C674397A81CA35EDF1FE77B442BADD3 + 51: A3E07C012A7C67D2B6557F4A8B4DD031 + 52: F01789A2E0379CE16D87EEDE671171CB + 53: FFF1657EC846507BDECD2DD829DECDA2 + 54: 1673DCE23D430948AB818D47E83BB5CD + 55: 37CEC696967031AB2122155998A07F51 + 56: 320B7D4DE17A731B9BA5CBB48956D605 + 57: 1EB07088E5F563DBC5DD988ACB84B048 + 58: E4DFE704E4C25D06224D2560B4650467 + 59: 6C072AD491BEC80667A6D71D9C8F2FF8 + 60: 53DA8AE3F36FA8F85072A89962F39B76 + 61: 40210D1C7A728A27E1B5F92057DA4765 + 62: A4C4E5F271F3BDD74C560787718E8816 + 63: 4466033447F1E1C9BB107D152BF06051 + 64: 406C6EC2643CCEF38F964864D12C9191 + 65: 19F725CB43B171DFE18EDCB90A9DD900 + 66: EFAC3C9FBF1AB0C0F3601C18FE3F0212 + 67: 9B9BCD32F735EE353D33A657C2292475 + 68: 68F4A4294C640BBE4B1E90FF107E05AC + 69: 3630FD1C9542A56C851140A7D76C0D00 + 70: 21AFDFAACDD8FAB91027A61F8DAB6C91 + 71: 2C7AAC93B6CD1F8E23AAFD49F04C69DF + 72: AE4C5124059CFFB3B823E68FAC8CFB33 + 73: 79E95CB7E752863AA87A7693D0677D89 + 74: 1B491E33A96D9838398A4F624E773DAF + 75: 1F3986FC593D8A8E927C82DFE1F538F8 + 76: CE64F09024A907E76726E29E1364E606 + 77: AC98817981B59789E7C7E9CB9F70FDC3 + 78: 3827B4B077493B289C25EC3E91B36D26 + 79: 75295EED68F750E506C60A780B7F0285 + 80: 4FA47F32992EE6C96C3B96B6A69A6656 + 81: C52E142B7838D731FC036517003FA73E + 82: 3451812871ECD1C09E4A95CDC80369B2 + 83: CB5261A793A55DB33016ED27A35A20F5 + 84: 2D06368ED98E266E81A3C6491BC24890 + 85: 677F6509BDB3D44BCFB088A81BFD96D8 + 86: 6990256193FB0697862AB5A45FFF082E + 87: C88D698EAF83E446C025EA915998EA01 + 88: DB8F672EE8129BF4BCE25704DD57BFA6 + 89: 807F491456D7E28A36AD6E934B053EA8 + 90: BBFD55A483CBD0F9DFE18FEC5070A166 + 91: DF7735106411CC29535664D85ED81603 + 92: 24FE3535DFCC295C2F34F3F88CACDC88 + 93: B80CDE220C4199DE303BC97FEE125048 + 94: 8C252310E9A71C7BC40C3D2011E24EA6 + 95: BBDB705F5660C50C5B0C87CD812B76FD + 96: BD517928591240C7E63C8D9F957F6A4A + 97: 78A534AA0F4250EE83D752F3E6940148 + 98: 3346EDA882F00D6073D133CE609D3B83 + 99: 51EB1D3235CD35A2386E314F815588C1 +100: B4860192E79C1233A08FE595C084315F +101: 79EDBE3E80887B4F741199295347117E +102: A2793EA5F25492D32D315B3923E945D3 +103: E398223EBEFC56D3437AA5FBC5345CA5 +104: D3E6593D69B24069AF0374671E466930 +105: 12D63F5AC48F99BD59EC863B61952C1C +106: CC99A81A22B62A0FCAB4AE889112A8DC +107: CCC82CA5D35A421FFF313F90B9D1A675 +108: 5B4A2912071CC36CEA626F9AAD34F257 +109: D21FC82D78AC98C5DA436388AC9AC6BE +110: C2F22C7C16DD2E1BBFDD2BE7915B869D +111: 2B5AE5D14DC053558A1702959367760B +112: 7A6A3A6553B2C3387BEBE119E80CFB2B +113: 7E2206BCF666B89341CD7615D0291E3E +114: 93D87A658259C7E9FDD0BCDF93A24356 +115: BDBC0B062FA3D743C1B070F2AB43D180 +116: EE0A575AFFC966F58B91BB66CC1E6B6A +117: CC24CF8DF0798ED2CCED077B06AF1BAF +118: CBAE264BB4AE635A15D8FDCF7F9A6852 +119: B879B9BBF61B6F291A8E4645B70EE06D +120: A6F88AD4A16F789A58F178799279B40E +121: 3DCB6B1674608B11F496F45C9828F90C +122: FF34A1C7748C5B5F2F014ADF57241C43 +123: 1A77E2B20ADE5F286705251495AF04BC +124: FD47EE73738626733CC63327D4F5EB7E +125: B9438B50CC80CCE0303244713853A0DA +126: 040BC7876B31E22590F5898068B19859 +127: 16ED82C338495D067BBE1D4AE73345FB +128: FBE1AC0EECF0AA2671A6F25733E9711B + +Hash: rmd160 + 0: 9C1185A5C5E9FC54612808977EE8F548B2258D31 + 1: C81B94933420221A7AC004A90242D8B1D3E5070D + 2: C0C355CA556CFE356ABC0A5595BAB1364BD86444 + 3: 6D8D360567AC2CC8C4EC11DEEDE0ADCACDDA388A + 4: 04DE53FED2BBFA80FA79698B4C5627536FB620A7 + 5: 9538F24F7432E952F030BBA82C9F744365035197 + 6: 817ABE77EBB7EA159AF7BA7DE1EBBF034FE6CAFE + 7: 340835AD791316DE50DDB59838F3EB13F5521228 + 8: 64B7269FA971B162612265C73B9911F53EF43B63 + 9: AFDD1E7F8E39C63DEE7104014AD9EB32B855E0F0 + 10: CD2E472470BE8FD70A306DAEC5C59F485EA43929 + 11: 550844206034AA74E37D813FF29973D3000C1DBF + 12: DC24FD5F309A7BEB9A7CFA7A354F2DB2CBC15AFF + 13: A814B4CBFAD24B7B92AF0E16794A793DC16D10A2 + 14: 6C316617808A930BD29972B1142C0AEC89EF00AC + 15: 3286BABC7C4635FEC52F67CEFF1471E122D50258 + 16: 696C7528A3545E25BEC296E0D39B5F898BEC97F7 + 17: C87DA6F87A65CBCBC4B02BFD6D01E26F8047B5C4 + 18: F1AC2E0951EA5875B71723BA1A2158DB49EE073D + 19: 091A39765126ED406254E7F810F02E0A6124C6A3 + 20: 4002C0305550C5A726705DCF8D3880C54FED0453 + 21: 2B59904E1585334B1298AAE6EAB06526CAE5A232 + 22: 0EF94DF816593728611664F4ED6A0C4DA28C5AA9 + 23: FE7AB8A5B0CA3C86B6524E3333490D0430E9A4A0 + 24: E748023DDA7E4B77DE8A4424744331EBC62A6590 + 25: 96147FE511BC64D9493C795ADE8FC71A78FA8C23 + 26: D81D7D3B46D5BA875EC2604814616230D7A075A1 + 27: E8245E6537FEF146A2CF6AF9BC54472BEE6213F5 + 28: 231CAE27B96A78767A0915A529ADB6B72A8006B6 + 29: 4D6BE5BB6D29A15A259C8B7BD4827EA82F514425 + 30: 3B00599329120E535A5D1A46F35AD03CCA27F9D8 + 31: 2AF4160DADBB84707F7355177A4644E4CF577DFA + 32: E6BABB9619D7A81272711FC546A16B211DD93957 + 33: 1E374AB924A652FA36B395D654D226BF901B6A04 + 34: 67281E2EFADF2EA6211B549426D3A598B5E1F291 + 35: 993464E56DC035716064577245BCE99ED175356B + 36: 298D2CEC0A3887C93501307B51F75BFD5CF0AFEE + 37: 2A0A02BF4D63CC09978EAF3B3B85A4DE8470B025 + 38: 6236F6FE25D5157BA95BF49EEBA8987A6A301D2C + 39: B4DD7121567E8A428F16BBD5A8832FB2EE68BC0A + 40: 5FBE6037F8D8EFAA9A315C070CE3373080244496 + 41: 04D5E112C47EA03BB60CBCEB9FC8ED7D92A68C0A + 42: 658797C7756256C98E04E6718D9F8952F90DA672 + 43: 6A27ECD40BDA4CC81C599DE94D0D2904716FD457 + 44: EF5AC5B8E7A00560E79DB54AAD4B97E996D2745E + 45: E67EE5275910B48F7D248A8B844DBC041257D695 + 46: FFD256BCBBF0F3BB4DF615B4236C147FD09F4F1B + 47: E83A4B18C347F188301DD3AA78265AD3AB3C0311 + 48: 13968583BC017CF0C5043364A42EC0D97E923711 + 49: 39C33EA7C4F393C4DD4B882F73FDDAC2D7FE1EDA + 50: 50B0068D46AA025615053132BB53F88DC062DB2D + 51: 434198200766DB6CF48C993906FEAC2B47224A3F + 52: 004FBC3820002357434D6B8ADCF79BFA6F9E3DD7 + 53: 13F7A8CDDDE021BCA6227EFF1A71DE19AF399B66 + 54: ECAB85CA0C2AABF18F5359F94AAD7578A08AB5EF + 55: 3C86963B3FF646A65AE42996E9664C747CC7E5E6 + 56: EBDD79CFD4FD9949EF8089673D2620427F487CFB + 57: 635B0D05BE254D82503A9E1DB7647DD1B5D5D6BF + 58: BE314B818A657DDEF92DF123FCC17C1DAA851C04 + 59: DCFBF0575A2B3F64B24DC203BDCB46290B21791E + 60: ADA425E87A8DACF9C28B67E8BE4B204A31960004 + 61: 35691DD184E08A80230467ADC6E68599B7295A51 + 62: AD1CAEFC7ABDC90E7877D376957532B7D91D7434 + 63: 6D31D3D634B4A7AA15914C239576EB1956F2D9A4 + 64: 2581F5E9F957B44B0FA24D31996DE47409DD1E0F + 65: 109949B95341EEEA7365E8AC4D0D3883D98F709A + 66: AC745186C82DF8697458326051A6CE7E4E9C1C1A + 67: 5DE50BBB11C62ABE22E7EDC288B7D1B6A1CFCC60 + 68: 7DD54CC4E8C70A4AC55F4C0485A4DFE139253757 + 69: A5E0EFB95E6162F9637D58D3E4836F9661D6A34A + 70: 6C77DE7607A361D22852385E663171148C0499BD + 71: 3467662275B136AF096D84258B17CA5F23BD6397 + 72: 1C56A69A826F95B8971635AA709978A441E75836 + 73: 9094727596F086BA28956A6BB69CCBF3B2B29FA6 + 74: 8C0B6183C33E902C22F17D81D18144ACB7B66FB2 + 75: 24ECF7598894FFBBC7D30FB1EA47092F03C398CA + 76: 6A02FE0041D98AB7AA6916A5245BFBBCF6635C2D + 77: F3021EDB24459533488660512660DDFF7F451C3C + 78: FBB7561C0065C90D7B8182018EAE73A18288E968 + 79: 32784F0E354A20688359B6EE7FD3874714C48677 + 80: 8BFBA0972D36739EA808C37C07F2E320ACB4114D + 81: 74EADA88C8ED0B649FCCC36DE338CB538242FE10 + 82: ED812B77C12856DB371E6F7DDF15A59FEBDD6962 + 83: 27021F491E923CF0B191E13ABCADDAA72586B769 + 84: 47664874218C135C09ED40DFAC26E06733AD02CE + 85: B39E492616FDAF2480F13D6E46CEBECC1FF5CBA5 + 86: DE967F65BF6DF26150AF866FADCA58C45DDC337B + 87: 8F2E2D23CC6A2B52B904032119CE68649406033A + 88: 247FB8B2BD1BDC35D0C07EA10FD9686A19E4723B + 89: 9D1E80D5695569D0DE28587D37103BBB0701E462 + 90: FA5C338E7506AC5418C4FC2C04AA933588892D4A + 91: D6BC93880FEC0163E3F223C8A64BA0879BBB0AED + 92: 8F27EE9C8A923C9698584786B5227CF17F0F557E + 93: 4C10ACF2F404236E2DABED0BB48DDC6D00AC4B16 + 94: D5166CC6B779EB2D45AB3222181064D05FFB5E23 + 95: 13042EB8245A8C5DED69CFCC1F1DB264889CF5CF + 96: 07136FE8CC1A03673891BC614E29BE79EA02D627 + 97: 73C50B2751C502572492C801C28B02C7E9F61B76 + 98: 8BE4B71D50C2D2895B9CA359ECB69F90CDCB1DD5 + 99: 36A669D7C1DA8E23D07B29BD6769DC324EB6D6B3 +100: 8AE5D2E6B1F3A514257F2469B637454931844AEB +101: F16396E005FE5ACC34EB53E6086F477415794BF2 +102: 907CD2922CA5F62F79E17B28AF389A38066E2C9C +103: 62C9351A21A50F2150367F25D4C166C63E771C32 +104: 8809CB529232A0CB22D384B70462B64D93B0EC1A +105: A85E4B4260A836BF0DA50B83BE1080D98CEF8A17 +106: 21D2A0D78435B2590B2C6366439939B9B15246E7 +107: 204FFDFDFCA5D46CCEC5FA96A778BFCBEA70BCE9 +108: 01DC05D6006E12D2F63A8F061B00D18CCA135D41 +109: 30E67D3FC0A0A6D2F257AE24EA8C168A4B0E0F5B +110: 9B9454E2B42908E57403871A64EA5E930F35B70A +111: 9F72DB053BC5370C786E34013FB8DA5958000D5A +112: C1BFA4009BFEAA30ADA4D940FC40F97FFEA3FC39 +113: 26FC30BF64087DC3FA4CA394637D15F73B7687FD +114: 36106E0DF24B7DEF46E9AEAB7CE0D784FE619D9D +115: 0D82262E443C3C56565EE35776F95978E16F1757 +116: B19E6C73E94401020B14ABBF19A15A6F0C9061AF +117: 68ECB5552C7B7B26940A82B6A67B0F4C62EEB871 +118: A834797B79DBB564AE587003EC4B74914A1580C5 +119: AD430B4283203A7B7F338B9D252DFDBF807402BF +120: B89CDC109009F1982C8B34FCA446953584D3F6C4 +121: 8030CC5A4F55566958A5BFCA97CB6F40B9C19279 +122: D0CBD1EA711E2D405DA5ECC2905DD8A3A3E83C37 +123: ACCDC924549D314019C4FD1AAC6AE3CDFB81BC84 +124: 312933643FCAAEBA4DB9BDE6EF7D6EFA70E37399 +125: 47F11AE47E2E693EDC0B06351E935C9B5DA42A35 +126: E4C6AA211767C15E90935DF552E4EEB89F23AD50 +127: 2BE8E565E24A87171F0700ECAFA3C2942C97023E +128: 7C4D36070C1E1176B2960A1B0DD2319D547CF8EB + +Hash: whirlpool + 0: 19FA61D75522A4669B44E39C1D2E1726C530232130D407F89AFEE0964997F7A73E83BE698B288FEBCF88E3E03C4F0757EA8964E59B63D93708B138CC42A66EB3 + 1: 4D9444C212955963D425A410176FCCFB74161E6839692B4C11FDE2ED6EB559EFE0560C39A7B61D5A8BCABD6817A3135AF80F342A4942CCAAE745ABDDFB6AFED0 + 2: 2661D03372ED5C961EE23F42ED9498B451030EED2FD01F29178955529B2F8A758F0444087C82AED85540C8217E959EB8CB43EBBBB77A7E0D2980D6406AA2190B + 3: 7314E8035788304E57E68AC9EA89544ACE6D2379035697D91B98B64B105130DC814B67A4B46B4DF6C103016B8F7C7403E0B943F0291ED6909E2219B6E18E89D8 + 4: A6C01D8CB93A5CEC17A9BDD270B24C8EE78686CAFFC454F253D9B8DAD5398E52304CD57F30F2111BE78FD98338DD3A41FD8A45124C940C4A59F270100DD6CB6F + 5: DB22986F9FECA154CCF0E7DAD914AE8C0851E170D116E9B550C39B373F109FD073395C0711745E40233226F96B5FBF6C8EF1D7F8E2E4AF5375821C897EB18514 + 6: 793498B98970BB3CF187B0A28D353AB2EEC8F6CDA12E6D484CBCCDB96B2BFE6B5278CDB38C9BEDAEB59A8404645DBEDFBE1FE54227947E226EDFD36114067F34 + 7: 052A7C4EC5AD200B6B8131F30E97A9A5DA44899E1C6C31BBE078058630D5E208FD6F2F51A796F814F8AD048D759F8DCE442C405D96D6E1B1A197AD908B366E98 + 8: 219B01987262C597603DBC495792F2423E24A4BCD38825A74CEE8ED91D55935296D80E73DB43A78FDD6119233A31DA5940C6E335EB22600729478A20F61A56DD + 9: 4BBB8746D1D754CE91C27F3A6262ACBBFD4A38D100A65ADADD3174ED6EF8F6AD343F0ED2DF28309A6E979E02B12E732A3E70371EF1E0935E8A30B7C55146D9AC + 10: 81BE2AD26A90BF502C9514F46681276F927E916A630FAC442D823FE4D8EDE0FAE2E8384F3C267B56126F0C009BF8689D475C53425322BF8CD7F6C80CD2C725C6 + 11: FCDEAB03C0FAC7939E8478FD152EEC2408D4A6C0D829B55AFCC5184C50706C253676CF68DA3ABC1C1AEEB5822898C5194AC801881B8CBCC8DB15930EAAEE9373 + 12: F943E5CD2DF74699913B25EEF0B08FCA6BAE9E66BC073DF0BD950CA02FF17276F4A28393BCCCF6E567024CBC6C05C94EA912F1B07034AA375009F594B25D9542 + 13: 1260728E085D172EE82065B3F878FE21F550748598E72A40F4FAC3F54B72A99E6B3CFDA7141C7E5BE123757AE4332C8320786408523DFC8655D7E1F7010792B2 + 14: 67EB4E93961EF18A82152DE2882CC5AF4DD1254732A8FC1959147268441A80EAF0E0B68041F7CF013313ACAD044BD440F1E06D3E449D206433F3B52BE2C9E7B9 + 15: 9AB90A3384DA32A03B31DDA21732B398358DD40D7586E836CFA047961360CEA2F1E3DD0CF2D90CBB57F68C4334110694A6C1BA17B1E9E533E6CF3A3ACCEFF84E + 16: 112C2ED4CE732E21334D7248A30E683246BA602AD3681BAE365E857AA840F1F80FCEF1B9ADA33AC1F9BF6FB75045F9E61449B26F9201E482E7F2ADC8ED9A1D80 + 17: EF574EE7B498AA64F3ACBE1972E42B873C6FADE053A1459AB52D5E5B49C0AFA0C62FE901ADC3FF07A7D0ACC459C3DDB3F6D499C70B63F68B60B02E2784BB9AC4 + 18: C6185B5836DD3B160695E5E27058AB266EDE91A5417DC086988EA5181DF5BA0C51DEB11F6BA14AF2847540BE368B6C561CD976809E2D9982F4D49F96E0AF4F7C + 19: 8510D305A5E1AB3A0832B242ED402BEC2D70C24B41BD840B8D2DE436A6B4DBB7CB5F7F9F1432E694F0CB1239EAB0DDD92E6D0C7E96FDAD5F8E465E286D7588EC + 20: 926800FF566CAFAEABACA9990772EFEC8AC956C3C572A360194F95AAAAE477F98AB7750B2710E262D039D8584BE79D93E9E6405BA25DFF6DCF29C54D748DD655 + 21: 0F0B98CE94E2CC67D36086D153A2DF48F20283413407C3CD0570B619871DAC188AA37BA30BD706AFEF475BDA7AEFAB63055ADE8B792F025D088B51A08E941B01 + 22: E6538F3479D33979F046FBC88D4BA785B072EF58877BFC9D1214FA8374B78DA6895D5A4F4E50E6AC6A237E48A73EB18E4452E7C8AD50C82238FA9B323C96935C + 23: 378E83B88847F234A6A2FF7304ABA759A422E6823334ECF71E9C3C1F8B21B016D9A8A100B6B160772FFF12482A50613BD832EF534DBD1D4D055F3227C7513F11 + 24: ECFC0F6C168962197E181C27FC9AA1975FED01E655B3D4A7857872451D6AF810783184534C401709A63BF6BE6CDB1D1455C382CBAA6F68E8180CBA9E0CDDB9EE + 25: 8523B737250579A3787BD83E5DCC57F7038B393F003223A7BAB98EE4D040441190622290B164F32FB96682730DF62CC366FC33126DE2F7DDE3A38C818C48F680 + 26: C6BE341A28878B733C30F50D67F6933D3A15A0950CAAB96B9F3D7D78C95C61874A400CAB65A100302D9E2DCEADC4A0C043834EB0433D5D684C187AED93B5EC6A + 27: 4AE827A36DA140D2271F74DF1AF4303DF4B1C319428F8BA94EA28BD3765BE4535275053DA49B630E6B754097ADCD7F17DC7C16158F43E2C1851951EC3016CD8B + 28: 6D3F01856A8A28E28EADF60401E84253C3F7CD13F3A9FB8F94D8B07B74F7416817F274903C135BA0DA4509A78D004388CBCCA75B06132C7CFC0156C03803E85B + 29: 07CDC2BDD9CDC49853384FB647736B50D788AB80A0A54A0969B86603B683C22A1C5FD32D3AC92E73D378F379C4BA30A48E7D38FBB867E981271FB3962C745659 + 30: 9DC875BF987C55CE646A709E89CA89E226B0F15666D5174771368FAD768BF3318B8BC7D8CA80AFB5E6BB7FC0090B5559F11DA165DE51B940C9DFE911D4790477 + 31: 58BEE92BE003CCC34F9CE8C0B323C6BAF1297460BAAB4998CB3B52D2BBAA24D1B06CB597EB2E609A008572FF93710E3A7F42AC53E3FF09D4733757EACA41E20C + 32: 888AEB1BE2BECB28598556A128AFEA037D0689C8D13D9894F1416B2C48B2551CB2FDA321A26CC4D7E1C87332D7A3C18FFB455C92C0E7AAF829FA40B8A28BB656 + 33: 19099B4E8ABF225DC7BD1C1DC6D52F54E8FB7E4EAE0AB19293C686E6FD2828221A1153BBA4C143795D1A718585D9255B6DC911C0EDA5E0042A10565AA5D6D8E7 + 34: 22B3ED65F64C8E51257A922FF90DC09447224B9A8C7B5A6A94D68601F3D4C7C1557BB90B91DF318EF9F8BB367E838D36A3CA82FDCB85721AEA20A8A2268D90AF + 35: 0D2B24C6FD5D772704BC17D2FC8C011F1511F92491104F3C22470864882656AA40DD07C0C329C8BAFD90ADEA7F473349038CE475D352DA41E24FF64723070566 + 36: FEB43F7DCDE56A2EE963236C234E5800C011FC54D14396288DE5A7AC7DB2A72D1E8F63F04D1DDB3C55CF3BF19F4E0FBA4B79405A6B45ECB31254C9F1951C632B + 37: B8AE2C8427A750F34647C3529A05D44691B8DE0C79525D9145665BDA5C0C396C00E936BF2493F12945899B6FDAA9F61E6E7B22846023D140F873EE7D48D76BC8 + 38: E80C49D1E29F6FAF0BB5C7B47F5A85B3A0EDDED84418890748724792CC83B53AB044B051722F1ADAAB713E5069E883C1D172CE0EFF6EE6AEBE05B1FD77DB652B + 39: 1FED03FA70436EF45286648ABF39057C33815E6A80A19E22009B89C809DD6F0099C944B882FF9DF3DF08DD51295F3F02FBAB40F606C045BD4395969E27647D24 + 40: 2E3630EB519F6DD115B3E4818DB4429CDDF1C6CC2C8548F8CCA226A24F87A949A27DCBF141803B87B2A2C0F8AF830031DB1FE084E3996D8834F8E7D29EEA4AFB + 41: D54509526805DFC0871CBD6E41ACE395C64373E8F57146A657C28BB3ADBF7E57A152D27BE24B8F30F08329C2E040359B119690D9A1118BC14A3B1883D093466E + 42: 0AB062968EE4D71DCE807EFAF835EE11588854ACA0959B5341DDFD10E70BA9AD427D92168B31B8E6EF81F58615AF9215A8708CE1F144EE29901D1FC282C3F78F + 43: 45862B0D0F0AC5CC1C5769C29D786FD3AC788CFBCDD6CAECFB120D05D71F2575F4174CAD5E5A00D2D740D0714E92822427085F044A72D66631755BC55E5BCC8E + 44: D3A9EFFA759181346D8FE53130F05B2C65F96E1D5908A61DA8FA3A9BC551A7781ED7B1A6CFFCB2F742DDAE8D22B0EC99D82B14EB85719253693FF920FD5071D8 + 45: DB53395A78DDE62A406211955EC56C6F7BEB9EC2275501C35CA955268C3E2D71BA246B4286C76FAFDE012F9E2CAAC8601A74699B466023FE9F8B1BA26F65042B + 46: 9426FFB7B70DEDF1CFBCE6610583CDCD91AB421FE39DDC31F4215CF7604B9050C84A3BA29C4B236F1CC3B09F53D29229132FDDDD9B468CBB6338BBBA6193F84B + 47: 3D74F17DC6FE057703C72452BC7A078EC019424A89783F1FA40003657C323997DF30BBA38CB4B16BAD8FDC43260956090F765C26AB1FC88BF7F87EACA1821B52 + 48: C6EF119085EB17EC1B9F74791D95E366FE916F5397C20857A8966C52512F4EE16E63B53A28F7632A867EFC7FFD8080B173D5E2E33A2063FEC7D1181ACF8C7824 + 49: D878B30402FECA5EC93362105D5E183D658DD2FD38B8173FF609740CC84239C4F8F533AC3451D369001CCD4AC78814058DE0F7E1F93D167A46E85E3002F4F386 + 50: 948C4254AD2C5658A28D42DDC3CB4FE4CF731B4180B8A4A183C23C54CCEA045307422547600598CCFFD3C6229DAA6CDD006D3C782ED91AC61172059D016970DE + 51: B74FDFED0388D5164BEE25E37C6687FA8D5C069D4FB0D42A7F1A270A676F83F24FD1C9048EC0D49F7BE913D893E0015E0A3F724653B3F0AB0017683948712E46 + 52: 497EB803D053D5DF498369BADBF8AAD57ED1B072CF361D3DB2A528D3DB16DD962887916E9D21FFB439DC2C025CDD8C21ADCC98A23C8C5B0245F2D71CF728F10F + 53: 63F4098F650820EDCEA3E7C10B65D3B0F1949A28FEA323702F27C7D311C7E6BFC82D4C01F4FAD06FE0288E410EF325DE192F78B88E04075FA9581AE2B031A68B + 54: 337914B013B8056D7849E42ADB47FA761B5AB05696CB8FDA6B87FFF88B0477902991AD81664727164053E4E47ACDF880DCAD0E0E67F7141123DB494450CF0B61 + 55: A385FE66F8C852638F5BE44503B680298EBBF27DBD9F20B1A0447215C0E2C1078926002113A71C78148D5019FB22C8132DD05356C78A1A8D8E4EEC5A6442DBA9 + 56: 218336585A419E9877CB63387C5E759FC93F0FE1A7BA717B8BE9B2302393E0D14DEF2F749D138692D0A0296F1C792B567F40037DD2B8787F1F47FF363CF34F37 + 57: 7EB842771A61A9AF779C8794CA055518E7F38CD13F61638900EAAEA000B12816D52C593B62B9DAD79DB7397A463AB99A9D0035E7A1369B0556D593DB41EEEB6B + 58: E41D1492D3472FBD42F2460650F9DAF2ECCDEAEF5F4516B452D940DAD516F5168439154B4BA76610461B343BCF1E7DD7DD8C285EC0CC46C17CE3C7E14103042A + 59: 88057C0B8442BC5763283EA17FD1FE1AE011A988E1D7E0F914004CD3AD2E06FEEECDF59E309B9EBDABF19559954C37F71FA98C14BB19F7B91CE5F827C1DDE1B5 + 60: C5DE99AA273D1971272263C740E689739B39725A0B7C48B41577F05738A24F5EE2C0B673F93BD52A083798DDDC6E70A209213B58C95D49ABC5BCBABDD6AE7D22 + 61: 68296AC346BA3B14C038CDC629C5F5700CEB9F5DAFD94F948C6B991C0F91813BFD02660A2A05A02A61D8EB03BC93601F9F6A38196650047E1D7DD1071CC6974D + 62: 1CE0E6793B0ED59C4DB7D5F24FEF75A4ED2F28CE4AA7E5EB25919219C2C04935E4B15841821FA92FC7537DE2A538871E5A043A773CB1ED061333113223248C18 + 63: 37BF321F66ACE827B66ECAA651CCFCAD30AB627E717AA4FE441279C4FA48555CB7784B0AF25A73B86375BE71A1E3FDDEC661E0EB8115E0BB2B9A7FF81DC75DF9 + 64: 5C3C6F524C8AE1E7A4F76B84977B1560E78EB568E2FD8D72699AD79186481BD42B53AB39A0B741D9C098A4ECB01F3ECCF3844CF1B73A9355EE5D496A2A1FB5B3 + 65: 85A19923268414DE6A10A2CDEF7917D7AA01E68DF9D028CBAB5C5236FAEFCED836BDE9CF90D8A214013056202A1BAE5CB73606078C5572D8FE85C36002C92D70 + 66: C2FB9763A6F86225F6C66F55ACC8E7E17C1A2664416B2704D64AAC2CC5B04A626030B5243CA61D62076DDBDF3C6B3765C38D0CFA01D4D45C124EA28DA593F84F + 67: 5083280300FA5A1B172D7B5CCADA5CECE1EE5B7B5D382EB4A430179EB133970B0B89F6BB6DCBB1F38EC9F13F5B7D1559F114DE0EE26178EBC56CBE31BB26A91D + 68: B3571E8C1CBC0C58E23094B39352D554B43F9E7DD0FF981C12A01E0D8BBFF06A39875D90BEDA7F345550E6F67935A49E0183456B9967BB319D74AAD87CCA3695 + 69: D11537B780D458D37279D00621F646EBAD3244A22E4D45DF11AC5D084FDF70E7A32F897DF727E65EDD1019DABCC05DF0B5E015FC5CC1184129C5DDFB14F62154 + 70: C146458EF40E6F1944BFD863B2862A97145BA580D47C7ACA67E797EAC6790841C57D68A74930AEFCD49031819FBED806A0C033DD529A203B4E460F357BA1BBFB + 71: 660F3E1D5CD3B2AFD95DB0D8C258F6AD74DD40DB688A37AB4A24D720766541B1CB928001EF6D67CE5429039C9C1490613DDF90A27E6152BE7D42E1614C590056 + 72: DEC468EF73E98F44B60EB994935921F920DC0CEEB7498655F0FAB7607A77A7A3D9462DD8BAD46CB408EFA81FF08D7E9508BC565C1578C37C2B87D41A0A32A549 + 73: 070D4C36A0934C5C12E6B65FFF385404E49C3871DA8674D93D26E3166A7EF9693D946B419F0E10C9624964B37493DC8A46D26D8AB8942E60143036659CA4C91D + 74: BB8935CC84E08E6B4E7C6233E41D880D70CC018D1668EE64F19906A83730495D01AFCE1A4EA8129A98B7F9E074FD35C0BA6D5667625DB63A867BAA67BDEFC190 + 75: A0A7A0B619643115C582BB6953D2A3EAA942451F631FC56C0933B535313D668FA4CA7D6BEC4DC9FE2AD7528DD6F8DBE68478A040FBFDD2F3DC3AD7035DB67371 + 76: D6C57C3FB08D07A30A622B25985A52A6E552499345244725B1084E41691B11EB31D3B9776940A9A7E6115D2D1A93372D3A7388D87B01D13BCA726E8823E89729 + 77: 413CB26BE2B1BA8ABE930ED1B9978BA4874CF32B38C825CB6DFE9C21A87C0BD115D3357198FDA0A5B7CDEB4235A354E9C2F37D11B33AC6A257DEC67326830E23 + 78: 748E4648FBD009E4848E44A284D0CB2088300F50CD5215A285826E968B9DA59B6322E1987F78447150AF72CE37E516BE9E83B05A9817AB7A924ED8B09557CB5F + 79: 0A8111FEA824D43E0991C22FC3B1368A191D0C73308283494309D0762AB1EE5AF0CE2DB8F0562DECAC636128688540E845D72BEA3852A19CA2ED22D6C1E82CF1 + 80: DB1067879F014EF676471D950A81DA073D676DE52E85F67890C8471FE6144078DAF940CB6F9F097BEDB8FAC94C737C5B8A3B4217CFF4A56DC349B2AE845AB25B + 81: 6165F19F569BAAA3A3ABE6D6108D07E1ECB22092F66227DC27173DAC097118C2D927F2E5F7D20C8CEF0F99C6FE6C7AA46BF18FBC452F6FDD733728030CD0A4A6 + 82: 1D4AA14617A4BB9E48DCC1A7EE5DF65298AE45FB193F077FDB6D1C2B3252E1633AF86A527C29861661CE155A47E5BAC91D9B07715E0FF7E08B39A3128891EC42 + 83: C2C22B53D6BA460954C2D826FD3DEEE60E33AF2EFC87A61CBF2AA021166AFB90967ADE2C564D037518E4141BE9C0D0BC0B4F95498D5AD920BF28CAD4F5FE700C + 84: BB5E9CFE19C6A2D14EA4C1F6BDE51855DF61D650B23330BAC30A5072EAACF86CA02AD31FE4C146176DEC75C56A56C2B868177E0E365414508D2E7606AB9E8921 + 85: 6B40A13C5486396864608BE7285BD4D1205180BC41E10E537042A1CC6CD12FA7737B5E73D768BBC5D687FCCE41880A8D9773C26316ACEA2D78DA26FECCC11E90 + 86: DAD0DC8A7D78E29B12182D36F47B93CAB562C44FD6C5B1718651022CDEEC30133437431D13C43EC1C02DCE776F459A57C29355B3FA0D67C6BF84AD26194A8854 + 87: 8118AEE5DFBD7FD9F94403FFD3C6BEA08706D4C4DC78CDE72F751A6C4027ABEC7786A62732819ADC036B787E25E151AC51B60BD2381A64F05A326800D7514B15 + 88: C64737334A61872EC00C8A3F1B1EA931FEE8D80203CE6DB9F1ABEFEE2CD3E652971615AE4F9A23400B9E31D861BE6B7E0F6DED28ED74B45D6AE90E70AD49508B + 89: F927B571B03B892B46C0A16148F13A2E6B80630CE41BA7DBE311F9ADBB5E8F23923CF0CA527DDD20BB3FE42BBE805066BEAD569F6FED12A2722A8629427ED841 + 90: 2576A445CCD8977F24F50EE30EA7A51F0F3F49D41BAA663BD1C1734E02367A382E3D0E8C07EAED0C6A47CF662FE573BAE5593D9C4BA8FFDB4AF024F6064F7A89 + 91: E85C73AEB638F35565BDD2523AE2A86B573C339B4D5FF8498ADF71BA587CBF146AE63B8C920B2F0A166F802167A04CD0D7F7A842D7D058165894CF9188289032 + 92: E74E2ABDD6AFFF851EF78F8A866DDE9B9F86D906B298DD1E3630E1D4A30B6FCD7FF91943A57367A00E2658A84346F53ABC896EDAA395167E5EBD12C954E0B820 + 93: 6827226985276BA731A9AE2E4DBF2D0187C05D566F06D098E05E3F425DC058958B50F09B4CE0741F1375E9B522F94A61F1ED8A43A8D03A036D2ABFCEDD4F0C1F + 94: 19A71A12DCABA1BA185BA38BCC0D915584A801EA49F975393B25AFBC456571CBF1A6F9121CBAE89A9B438092C65532489A95A0864320102EAD9A2EBD30D41F6F + 95: C70F19BAEA7420A7482C9C54CBB689A9AB93E4F8538EDC2371A1EDB3A103DFB7176E04DF170FF71EF46DFDAC1E8F9CD6FF96115BE1EFC271A56BDCFB67D29E67 + 96: 8BBCCFC8815786ADD9F108F4381A2B084179002AE940ADD4C42AA2550C353CD0351C2F7F1BD544D8F268FA332B0E803838318A39079E9D93269A01EAF9CAC967 + 97: 5266FA966A04B8A2450ECF3826C9E1516FEDC33EE81D4911A601351564D27C8BD4A11BF00E0DE237E50D75421CBE475E38967F28E6A1C5D311A2C95B84898D1E + 98: DF87823E1E02AF34532C5F3A08CF03CB9B2017B835525B3E3C448B1ED15569935D9A1DA19A6B1E8D056FBC868447ABE6226B97F256F6B638B052B4BAB3BD4808 + 99: A1317CAC2364B10EABBD3540B6139D337C0EB3F7A740C050988FF9B3584213DF5833AAD81D36C30CE6CE76962A9E1D45F08667A314036A299454F25F73EB067F +100: B752B6EEB497A8BEBFC1BE1649CA41D57FD1973BFFC2261CA196B5474E0F353762F354C1D743581F61C51F4D86921360BC2E8AD35E830578B68B12E884A50894 +101: B0BB23AED2CFC9C58C8BAB019CD10DBE75717EE8F04AA45FD8D84748E3F05C523FD2F70DCC460F7A18DF7D28A224BCB86CFA4C8164D081D51F3487A7BD0C8109 +102: 0FA46C6A759DA9A3649679780A28FDD51EDFD3F99A4B801C5824247B270A137CF40006609E149C919CDA0A6C856A9A8E855A670A2BB2CD5211FAD42E84F6E365 +103: C4E350267BD335848D00151AF2C380E49A323E63AA264D534EA1BF7A860B764A78993F7FFF34ED93ACB1F5A5AB66758C462B4D2F2F4E14225D29FEC0C102E772 +104: AFA0F1DB8A321FC6C4EF7C65ED2ADC4B094E928E230D27295699DE68FB5C1657FE0E5C4E66C5852ACFC45DA94BEFDAC89CF0D4174B262E6FD51CDC3E7FFFA5CE +105: 9A86A440FF8A33DCD38C69D7564EF827F614629CB699B7F45E7FFF1CFF4AD5E27EFFDD32EF1D0845987A6A273EA34C19374E9FB606BB2E3B909157CC6666D29A +106: 1FAF8C564575D654133B0A452EC43959C9F9E20C044724B74EFC90D2CECE4C49A0512C9F4DA2E999552E3ACC04CE0F0E2FDA9826C2A1FBBACEC4330081D5CA43 +107: 8B35FFFCD91E617C8A49B13CD0FFA2199FA1F20E5633AE6E95881BBCA02B1E047392DC9A4C0F0A4C39D3984E78ECC4DCC1B5C94A26ACDC1F69C7ABABFFB45175 +108: 6C8AB69E946FE86DEF6F14B955B8F1977686EAFF8E384CA45F245CCC0EB1C80AF8E62B0E7387C0DA52BBA31B1A01EBB00CA26CBFDA9D8069A773C3B62F989A2C +109: C3A243B45B7C3C2002CB197BADBD84C4900D504FCD277D2DC6C06D34B1317B41EF098BB980800FA9D011C0363D074308835AEBCF3393B1C925045E97E14831C0 +110: 803E065AFEFC6C48EF9F701233AF512465729E81B0DBFF99A2E7FEFFB542831E1D3B30230BFA2F30343695C060AC8140C37CC8D1E25E95E6A1139C5522F4ED28 +111: 86618429B8720ADCBC8B9FEAED8BD44E0848572CB6137213273563EBFDA859240E17DFDAFF68B09953F1853C9E7EF217875E7BD6959E76DC3A1CE5F548B76CEB +112: 96439A93295B5C479F0310B28377FC10DF81B593AC233556B15897F1FA3886C940639AFF2ECEB29894DA884626B4811254FE2622EC7B4577087D9046C96AA556 +113: 9F7BAE13DB80C72A434BC4704998A73D7E546CC2590E0D0EE511CAFC63C622A8B2A296426E42754606D02B6EA060892E325EA1AC13EF0B523A3551F4D25BE241 +114: E999A862E5C479B7BB21EB52E4BD301571A8A39B712EBFEFAC720F28C515025E98CCC74B950D57CF3C3B34D788D62CDA0339AE0DA02C8A107BCDD797C4751FF1 +115: CD00EC5142CBBCA87BC15D69EBE96B5222F25BE1576B318208178679B13A9A8BA4BBABE9A488BB38C4EEF327C9A4DEA4225DD30C0F70B97C18C5C2FB19FC2134 +116: 1289951D2B62112BA590D8C0CF9EFA38AB77737F994060596738612E6BDC41EC8672F50A027A2C049299FD39E1776BC3EEBFE3E66CCF4009615D63F0A4C43ABE +117: 451A46FBDC954FB76E744AF3DA8429C881197F6BC12D22412438729288AA4540843B9FD4CD1BDBA5E864FEAEF0CD6CFF045A37510B3759FADFEF4697E9BF9240 +118: A267FCDF72D9160DA2A01E781E07701478F95A38C262ADEBFA194EA6D5A50A9CF3E04D32AA4B492580C6E8D8FAE1F813F3C17F82B7F47D8CE0C900F0F3052F98 +119: 3D910AB6579455653EFC939BE1B22D993537408086361008EBB166724FAFE3C8578EF4BE0378BC28ED883FC0FF3DE5A9310CEDE65FAF3AD9590A13B3CA4F81C5 +120: 47386DF4D41775737BC4E52D7CB2EFC11BA335A5D59597B5DEB3DD0A35032461F5DB4779D48BD6F3A10C5503AC563C790235E6F54EA79CEADB6A56AFCCE890DF +121: BA59044EF3A242974F074337CBB6840FA0506C2227A429498F546B2CEBE0644DFF1D442190C48CB54BEE72F960670F71AF1F8402AD5ABE8C1482DEFA881FA903 +122: 89B4F35E5C8C19AD61CF1600BA80C1A1BBCFDC86AD9F8066C967BA10F62827FCEFA1EBD07C90C82B48082A5B7D6A72E0AAFD230DE05955C7E8C081286B0CA96D +123: 0C7F94250F4EA7647F91E7EA8B8612AE8E7BFE4F5BCDD90CDCE564BC9842F6987AFB4C3661D8431440FEE18EB2EC70BCCD34A6B61D209CB72BE782A0808C08E2 +124: 2C8B8B17820085795BC6A2720B5D0BDF5407D9DEE1CAA4270FFAD010AE9555DFD2B74A742512BAFFAA1D5B4F14ECDB2BD4BF37838D5981A317C7287805974019 +125: B464C5A9D040F11DA45D98C4BCA9295D0F589DB11EE5603410C62BDACCC329B9AC14567C3A6F3BBA4B92CD3B95BE58AD4DA435199CE62D8BD61269F8BEA38FE4 +126: 2F64554FD54AA4A04ADE3793AFCC5C968B1C3603F4F71E1BB5342BA4E951D79A4580BF57736E7FC13A43604A057E9C360C099AC5B3403DA8AAFDBBF417FF6ADC +127: 3C9A7F387B7104DF19CF264B0B5821B2E46E44ADC79262546E98FFA113EB3D45799EAC78CCA4643C937FCC3C1D249A212FACB34C63D45EEC81069095D7CDCE7B +128: 803A3B37C89E84FBBEC75BEE3D00DD728FFC4246B5A5E989DC8DC2CD0F7937966AB78C79E1D4648EE6EB40F3D70491CB46B8AB42E155672E2AB8374FCF70DD79 + diff --git a/notes/hmac_tv.txt b/notes/hmac_tv.txt new file mode 100644 index 0000000..3003490 --- /dev/null +++ b/notes/hmac_tv.txt @@ -0,0 +1,1736 @@ +HMAC Tests. In these tests messages of N bytes long (00,01,02,...,NN-1) are HMACed. The initial key is +of the same format (the same length as the HASH output size). The HMAC key in step N+1 is the HMAC output of +step N. + +HMAC-tiger + 0: 2EF793765716EE48A671BDB5F002103C43734304C8717C85 + 1: AE61B56C82BE9FF96DCFBC20DD02B4BEA4FC6B6D5F4EC412 + 2: B54ADBFB404457E6C5AFCCEC27199D1F259EE1994FFFE99F + 3: 08AEEC38E88403BB854935EB6F1464CE95B044F4B4202524 + 4: 4C9DAEDC1929E22128F2A7ED5F3556D8A6D3A8315A7B556A + 5: 764794ED9EE1F94891835CC3A361FE75C600C7951A07F450 + 6: 1A4C447A0FB8826A0881ED2E7BD89499EACA4B6C49F96060 + 7: 1396A21D8B465C6B898511DF94846588EE8E35C0095AD90A + 8: 7552EB03CE26A8F079AC96B42F556FEAEB756014B8FDE622 + 9: 835B7CCA9D9F13BA2A36CBD746E5C92D5B2D123CA2EC848E + 10: 7CF4EA88FF8B9A5A57E5ABB6B35278EE9D8653F624D662FE + 11: D588D953C6F438D077A1E302F84E25EF31AD99B9C5FC9DB4 + 12: 86EC62CF1A08CEA9171AC742E8E615B3F0C7B6FBC95DC3C8 + 13: 6EE7C51E26187F86370A26811C75136E28B0C39A113D80F8 + 14: E1326D54123BC26CF41B30F9F2BA2E732203836AF8A74273 + 15: F211E4C46862E3AC8B8E69976A705582CF6D1B34A6D342B7 + 16: 0C6160FEFE70C81C71B7465F42F070F30808CDAE448D1974 + 17: 492FC6BC091489F926F0F54CBF3E3F6C8CEC6ED14DF2DF8C + 18: FD166027ABD1BD9DBA13E3908D16C403E1691FF173328CA4 + 19: 28D99C64CDFFAC1E6F7B33C8E675E49749CE835A177A1C63 + 20: FD7BD55BC2A684F4875C811143A2997356AA87A300345843 + 21: DB8968E787BF65C00992ED9DDE974EA71BA947395111FFB3 + 22: 4C31B2FA4E6F7F40DECA589F85BB69BFAD1815A73CF9EB23 + 23: B4D8D7FCB314942F171F85EA0953F7816DA9F07D72AF48B5 + 24: 9A6A70BAD76203A7A1F64D1EE34375EC8BCB21810ECE0B68 + 25: D21D7E5EF6F1579C84428AB5D574468933BA037C9B0C34B6 + 26: 3C5292C87B24626241693F0EBE20A96800905691C5945E65 + 27: 350BEEC075258BA7FE0314E6803152B021570F067AE0D4D4 + 28: 6881F892886F9D66E68B937BB3A71FF5CB064611C722996E + 29: 07831F1B2D00108386339F192729687B2F57B9DAB2B1210B + 30: 38DE8DE8398EEC32939A239BC0198B0CFB18D12E4F2A3023 + 31: 5B683578F81867054089AE2E1B20E02B3BD92334CBB01FA9 + 32: E30A80BE07651BA17E2DF0D43A583A9DB268DFF3AB7393ED + 33: 42341B1EC4F61E90571188F5599FBA9ACF884B1E15694921 + 34: 7D98297D65F5FEA85CB967F22AE0707E03F305BF1D2249DD + 35: BC8EE5CE0FA8F9E6694406009EC9358BC420B7E5DE07B6F8 + 36: B8095DE6770CB4CC2127FA672F93F39CA4AF0CCBB9805DDB + 37: 20C0E981DF1B763B6BB47D43F66765AD434127C1FC55F829 + 38: 59795328D40D2CE6CFDED8DD5089F2D5B796C9438E7646CA + 39: 0789CAB229AD54416C82CA5A2E667EC7CE66019FCACF766D + 40: F7C81B1AE705019FF9A9905972AFD72484A70E11FB81B278 + 41: E72F52644BF5EE59BE87DF692EF0070D095115B7664BB53A + 42: B9A5DD984358D0B0F3C2781BA60E9BD3473C1C89C7982F23 + 43: F7BA22269249759F1A87AEA0A125D4DF9B58E93714449008 + 44: 5D2257317F8978576CD7D2CCD346E861A59FE949F74A3D82 + 45: 199D8D5B0B5C5B61E046F50E0E389DA6F19CB3A7A37C8588 + 46: F489CC6CB2D3E9F741D6C9008265CCA97E7E54D62F5EB85F + 47: A5E7CB0787EB7E62A9CFD8486390A6628C9876654B9E85E4 + 48: 22FA78EA17F0D29E16276C70A564D234BC4ECA7302301528 + 49: 4422534FB9EEC601CE7662345D6B6FF932E54BB0483C2F62 + 50: 5D2E2B90B460D393F36BF32B2F491E224EF388FA72A48501 + 51: EA5287BCBB856BF04FC785541079087CE24783E9310F3090 + 52: DEDA3920899FA69F913AE50A4F0D7119C9D3CE8F4E6D5BB2 + 53: B2F55D8EA64C9842BFEA4FADFE616664CD44C57D53998C58 + 54: 3D2C72F26188E1EF5C0F0FC8B541224066C4DF455FEE78FF + 55: 50BB36BD8A8D97E4D6CA78DDCDAD0690FBBC93DC9A66BF18 + 56: 48140E192FF8AB74FC22676AAAA186C1A7E2FA0166E986AC + 57: 40AFD540C40EE7E598D26AE3FE5A47939299B5DD46B0B4FE + 58: CEBBBD763B077342BA16D4B20412C9EDE0F0508ABCE3501B + 59: 0FE4DFE539160F5924C324B8B43DACB4F220195D286C6FA1 + 60: A06D135075F943CEE74AAB1B8DE08B772055551B1E73ED48 + 61: D4E1B5EBBDA5CDA5040DD697BB96DD702C6730CFCC012992 + 62: BD5E77B67B42C507C4912130C8880A9DBD66431DCA0C0038 + 63: D81F583A9B4DD1F48028CA602CC0F131D60561FA34F7B3B4 + 64: A41F0481EE52842CDF676177F8E43BC1F1B00A5682C63E15 + 65: CDB29E274ABEB20EECC8378D5BD806997502E4271AB56708 + 66: B8366ABD45565BB3D26CE46B6F419F74B34851863FF4C336 + 67: 5AD2C193D6D51C9C7E56C5BFF55C1D61E045366B51E7F619 + 68: 9948E3AB7D121B15A6CA8DFDF4EE5377C957F0DE891C3575 + 69: 095676D61096853635128A80570BD1CE803AC7249C0A0F57 + 70: 354F4CCC1E5112770B2AB035AE07200A6CDC0280AD088AFB + 71: A8723395E80BED25DFE8F9ACEDA942A77D225D00440302D2 + 72: 0D2BCE0F8CF396FD8277C8BD9B19D54965308D3ED04D2F27 + 73: 54B1939E9944F499798B3DCE3479AC315F2C42A1EF231984 + 74: 5CFF726EE4B2596240E6CBBC66D7C737A4D12A702B40E81E + 75: 82996D7F3F27B473BDA647BBBA7230DF217288F2D1A38B99 + 76: CB95F63E0E7A2EC4F26E94B81A3C8C757E04EEEAB35A8C2A + 77: 057DEDF45207EA885A0BAC5B64240DD21CB9D99CD8F38FEA + 78: 27DCDD1ABA459506EF98E5C8D567692264C4153F91FDB269 + 79: 911C83660F7EE8CFB5F54890AE98CCA36C4C12B8CC771DF8 + 80: 67CD07209988C517FAEE01E64AC4B5CF261B6035069508FA + 81: D9A40C407E2BA852684770A5EB08D8502DFD264F2DE5A5FC + 82: 9AAC50A2BCFD74BE3DF85237478AAA833484FA3DF912A3AC + 83: 38078488F6183B5A94B655F24212FC9769450D93986C9208 + 84: 2EFFCBFA4CCCAFCA66BF8B368FB1FEFAC280C20416BB90EC + 85: D626FD6D285C49F20E99B88B9F82640D93D9E765CA55B5B0 + 86: B1DD178943B26AA241D34031D3128344C6955F6A942CC5D3 + 87: DA0C850E2067F9FDAE433C1230E0F629700FC8896ADDBDE9 + 88: 58E393E353BD7DF75A591904AA99526E94FA45C98D095E21 + 89: 323D0E04D239BD70192B2ACCB9ACF06E2F8C3B07565893AE + 90: F9C4147C6921640C097534BB08020540B420AD569D03665B + 91: 5171DB964AC815B3A6D058419FD47833DDAED71039966E6D + 92: E7DC7C574AFC2C9A59E46CB8ADBD03330A5321B237DF7899 + 93: 97074CDA9FF8D40B0501E9F632ED7335D6A7926101A34C0C + 94: BDDCD4D007DE39680B80F9AF9803A9F21C836EA971250CD4 + 95: 0DBFF45E3155098D4B4C13815FB461D3C4BE41E9E1A68757 + 96: FC16CB95478E4D23A7AD15CCAE3C24BBB3D0FBDC8A00A144 + 97: 93A7CB506481D6A72EAB14A2BA544F8631542B55903CCAAE + 98: 9CC1FFA19736AB6EB36EB4A2C1624FCB6913B255D2346795 + 99: CE3526A088FFEDEA4345AB221707848823B16DADD19AB487 +100: 1E1D790323586DB8A306EDCCAC8C64A6F29A36F772B8D61D +101: 8C403515F2B9014E9519EC04769ACCF23E522D3E22DE7F41 +102: 6B6A634607634804988301240CA5AB029A9E86E51281D64E +103: C7C3483CC8E6B58520B554259EB08866AA7980B53FFB6B86 +104: 96E429611C9E411321947469E2095CD9B0EF29578030E40F +105: 5C5A7F2B7F1F9BCE730BE2779304A443188FD3B31DD2BF19 +106: 70933F999325353277E0AA1F543B5CBED3F28DAF4FC70A57 +107: 5CD6D136FDDF4AE9CE42F008301FB6647096D5007E79973F +108: 1162BA742AD199AC17FC707285301A82BA9CB12C09BA229D +109: C36615F6D5E29E6CABB7EBC44A6D3F7B024DAFBD338FEFFA +110: C29FEF051D1606CEFCE3417BD571CB9188BBF0FA8AB98679 +111: F925144EDDD27244E19E4B6E433F312C6CDE43EF4F9B84B5 +112: C4230A59E54A34D0709F3F1DB02C18EC8AA270078DE424D5 +113: EB1699CAEC36681CCF8A9144DFB5050566042977D15FD1F9 +114: 9FBF0D9B2DD9A6E87240E538590E9799B76E22604D22AB75 +115: 2657EA06D69A78A5895A9169F849B3DE111B31E5673A8E17 +116: D1F9E1BA4F4E52CDAAFC388FA4C366EF4BD5F440608D86B0 +117: 049196BFFD9F77175FA936066C3119293EAB79D1E0028C8F +118: 9CC1BD2CADDEC1D82FFAFA7031F2E5C9B6765CF1727A0ACB +119: ED00438670D68A70CE2E0729997CC9648947EEA35809B8C7 +120: A520A0089BC16C84CB8E05425B330C6D261108EE3049FACF +121: A55B470483E547D2752EDC3C4FDCF3B4C48A1990AD857941 +122: 46A78E772C533EC8EDA60EB4A127FCEBD35E7D0E7F183241 +123: 5EB9A774124D571FCCC83D1F36C603D9C387390DFB3928B2 +124: E904066FC77F73CA41166297A8FC631FF59634B659F0AED0 +125: B85B66AEF7D9904356F1CAA5583757D1D69EEBB8AB1D1420 +126: 6639F85214BC798D71B757FCD480CB78D325881781A3A073 +127: C5B72BBE80917B55036A9AD6908D59293C49373F0BDD104B +128: C0BD695F6B9B42DAB543C31BA73C9497A6AA6419A007A9F6 + +HMAC-md2 + 0: D39AD9DDE006587A8BE949B11B9288F8 + 1: FCB21B5348C95E8A8DCBEE50A80302CA + 2: 2F26B6ACCD0E03FE9B21A1B0E75FF665 + 3: 17CF85D985D0D85F545897CD42C6EFE5 + 4: 1537A6943B4F5AC1272E4161225D987B + 5: 83E17165D62CA6E4B9ED67DF1E599954 + 6: 7A3195C863DFF86A98968F254E128E61 + 7: BD05057AEBFCB92FA4B07456085EC6C2 + 8: 23AC0D307BFC2E87760F8BDB21851DF8 + 9: 2CD26A2F2994106A375BEB0433575BDE + 10: 1F63BFC44FDBE9A966CD90DF82265EFD + 11: 72735FAADC3819CC24CFCE1D589BA311 + 12: 28B589C3C8078B8FFEF1C8297E33C1E6 + 13: 70A6DC014CAD2752931A47C0879D2371 + 14: 81694317A37FFBA816504974F38B4829 + 15: 72F26208B3051F1B938EA7E03DD8C107 + 16: F945F57FE0696A4C81EC59AE69384FAB + 17: 54D8DFCEE33969486956698495B4BFD0 + 18: 508B82F88A234E753A9E305E15A14D82 + 19: 527D77D2AB25131693B02F653ACBD90E + 20: 4868AC540FCC3A896D5A89F7A0444D36 + 21: 6189807C5FDDDD68D20356ADF3B90DC2 + 22: 0356362F2BC4206F2B930C4282213758 + 23: 2F59956F19B3CAD687C66C4EC3CC916D + 24: E30CEFBDA3FA1A8EDDE3B72614ADDEDF + 25: 33E0E6BFCBC9581BBCDF13F4D3F26724 + 26: B11C6476F9775219A9F18B5E88857790 + 27: 49C7A9D7F56344BD405E53BE927E3A58 + 28: 99A06874B0F0CA45C9F29E05D213195F + 29: D21A60A18F061FC453AD5AC2A519071A + 30: 2F735E82090144C036E3D12DEF2E0030 + 31: F9539EAC81BBCD0069A31E2A3C43769D + 32: EDCAA9C85A614AB6A620B25AF955D66A + +HMAC-md4 + 0: 752E874F35085E497D5032112CC65131 + 1: 6B2CAAEE210F970AB481D6D8EE753114 + 2: 2162A41522C2DB0B8AF1F0C712C19A22 + 3: 7C2106C3CB687F35FE2658BEEFB497A5 + 4: 3715333CA3EB74A15B4B1802A1A78921 + 5: 403D9A691A130AFFFB81A655AAE1D956 + 6: E697C3CB42716CA1973DE0D15486068E + 7: 99676F34E42C61E396F0E76BCB77BEAB + 8: A2B2CE8CF8AC151C5556A36D58894C61 + 9: B8614BFF1DAAEA90BF319F333024976C + 10: B8759E8B97DFCBB2DB94D8CBE2C96B20 + 11: CFFE6119EB0C649831459339C1B0C82A + 12: B2FC0DBA9C4830CA66423728599D3660 + 13: 454749F1DE579F1918FF046FC1CAE7F6 + 14: CC625178FEFD46481B7D02618AF6194E + 15: C26D523EFCC42C4AF7EEC2EA4B45B719 + 16: C352DA2D077FA3F493A5CE0E9A79CB87 + 17: 570DDE9FD220F59867F17484605D2061 + 18: FF5954A163CBA61CD3C8424CC71682C8 + 19: 1240D12E3D6C07F6FE1CD595C847C038 + 20: E87A4D7958C43CA71791B13E16301036 + 21: B2CEDE4A15F8D64C53D243F8C5763C05 + 22: 54A9E9EAE155E7AFA6FC8A7E05D7FA9B + 23: DF0E79F27CE25E56ABCFF5E74D1212CA + 24: D9BE454A95E5D9127990577F7EB7183E + 25: 26F9221A8B854767861BF0281303B89E + 26: 92BD4CC81A673B254A4AB493864BB014 + 27: EBC3851E0AD28BE9876BEFD6B0A88B44 + 28: 1134BC8A40E1D2FB038B67548AC2040B + 29: 954700135C4E7F232337C84130B43360 + 30: 8C3EF2D8F896C8D252851A1543F72493 + 31: 52817E79D2B0B3A37DC08D18D3519F92 + 32: DA661A428B9659DD59545E3B09162F8F + 33: 3FF5BB67B48F87B4B642DACCD2E4001E + 34: C674F95BB622D7B8281FFF34E9EF3E7B + 35: 3A4D25E3BCABAD8CD4918CE650EF00E9 + 36: 2D91248C51837A8B80898E2CE42CBCB4 + 37: C0B3BD2B36493F0EAF9AAFEFDC37064F + 38: 9B4723B091102B480B2B59069317F292 + 39: 0F8EABB489254491FE19AD0E328A483C + 40: 25469BD482E1405E51AA021752394C4C + 41: DF1DF50EF9D95892D08DFEFB79D6552B + 42: 707A546964CB22710482C478E58C2E0F + 43: D1E243DB14E2F946D650C811030ADE9A + 44: 11A1AEA678E98A65420747DD6CF9293F + 45: 66E735F658BD689A9F1BA0B526827CF9 + 46: 98170734E67F576CCC3D01D83965A6C9 + 47: 399D99CB7979E80F6D3B5D5BBA5871CA + 48: C26651C32EABC76289CD0843D3BCDD92 + 49: AE0F50954C90E8897BCF504592D0626C + 50: EA3AB701136862428EC326D2551F8AC8 + 51: 4AE98E5A1E6B1BA8CEAE844E34934039 + 52: 7C9826187053186DDC2760AE6FB56DC7 + 53: FE0F555B851CAD830BAC9FBB40705671 + 54: 221BB509584BCC7E10F3B4FAB2AEB1F3 + 55: DD93EAFE25EE27C6FDC2CCDE7D273267 + 56: 535472E1ECD49FAA75CC6621BE7E6210 + 57: DA4554FF7D5B289A03D195F94154AF47 + 58: F15A3F547B5A3844BFF713CBCEF701A1 + 59: 279DE06FD5644C520BADD3B97D96274D + 60: B933E929073492EC1E2AEB78071C7B83 + 61: D1DA2335654AB4CEBAE5C2E78CF27553 + 62: 06FC50285F4BA5C8B5A478E9C02D6434 + 63: DB66A5D55224DDB50337B7FEF9A808A7 + 64: ECFCD0385FB49553EC89DD94AB084D23 + 65: 4187B0B79E6CB916F747B857AB2F75D3 + 66: E03E14F5E00B2DFC0614308608B929B9 + 67: 5F61FC3005167EB3256DB549DA8BA562 + 68: 21A4D14DF8E934A858569D8BA7F151E8 + 69: 5955DDA4CEF16ABADE2B551841C69B8B + 70: 8E77066A973B60DF64C27DBB93EF204A + 71: 2101EE9DC8221FF17D9D887FC39F41BA + 72: 6574A9DE32B7A673B5BA20FF18EF8C93 + 73: F571B14C9F5C5C1858D48AA944A13050 + 74: 0BA4BE0A5E853D07F79B2D29BCF046B5 + 75: F240C8C38D71131F510369D79FA32208 + 76: 920C294DE37C28803FF3C49A4135CD65 + 77: 38796D25822AD8F2AB4D64E4A65626A0 + 78: 65A203170FDF794397FD1090E318C5DA + 79: 965A767FE4A75BEECE26BAA79D816AD7 + 80: 0F4B30947B790C47924657648FA1D88C + 81: 74B05F7B7D006F7DDAB31DAE251C3BB3 + 82: 61B0366B57A8F46C2F6C16F935DA768F + 83: D4CB13CA922B542980F854C9780A1951 + 84: 039B2F23A1CE410FF4696D9C35C40C08 + 85: 2D734E28F995C2AA2A7AE2412EB99A10 + 86: 1A55FE47703ECDBE446033F492412812 + 87: 6AF4CED86D0181D6E99EE6AE57F295EC + 88: 69C239A875E0352D20BCFBCF8D5CA19F + 89: 62723FBBF0AC6F397438589AF06625A1 + 90: 424EC9353901795251AEF7D7BCFEB8BE + 91: 9BBE4ED6C8BD14F85BA86E553B1B8152 + 92: D7840AA82F788B7D58712E29003D1239 + 93: 4AA55512DCAF770FE4D9428FB318B0B0 + 94: D040BA08BEDFFB20D2C499FEB35EE12A + 95: 0F295EDEFC85546547860B7F7CDFB1AE + 96: 720FCD871B7D8824EE6A7DE9FF1A62BE + 97: 2FE3AD14E24C441C36186673A0D60767 + 98: 943FD502136B66D0313951198680F746 + 99: 4EE6829F3EFFD0A87115512ED28C85BA +100: 6EE1AC28A320246CA5C37F981E22D294 +101: 36BC623D6573C3ADB164F8A6F02315AB +102: 08B3AAED34FB0A0F99C4B22714B9CEAD +103: BDCD10B66096AB992DEC5539773EAF23 +104: 6DA36A53A79FA2C68E5060C0D2D43E13 +105: A3E886199532C025074D4646113F9C23 +106: 00D67A1D2ADCA77A20441CBF593FDEE5 +107: 2E4399F5FB44FF5573B73D01C5B248E2 +108: ED22A18A8824A30B68EE0EF9907B2B91 +109: 36166824634304417BECCC9519899CDD +110: 0757DB01193BEEE90617AA8CAD0360A8 +111: F7691CBEF4ED2E9FE4EB992CB3939970 +112: 09DC2FA975CBE8CE828919957D110EC2 +113: 7DDB74DEC57AE8C318AA5CCFB53872F6 +114: A26B7DD0AA30EAAF1F4F8314AB7DF16A +115: 088855527BEBCDB67A40FEA4FDDCC061 +116: D0F8ECC0C32B7060CB6128279F57FD80 +117: DF5B79D3671CA5E5B44CD395F6FFA551 +118: DA8999EA059C463D5F05D04020EE867D +119: C0EE404DD8447AA70D3725D5634E2B53 +120: D19D1A725F5E9F0DF21871B31900CA73 +121: EC202984BE149C93CC1D440CF6D29E1F +122: 422DB7C21B1348983B75498E270FE6C1 +123: EF136334BC30C92DB9082A9654B391E4 +124: 0B3526430AE734054873B14DD696CB3E +125: 3BEB77C0F85F8C6F21790ADF30EBB812 +126: 4376F8C8EAF5A94871822DBDFBB5F88D +127: F7DEAF52378FF735B2D171B17EF573D8 +128: B4FA8DFD3AD4C88EABC8505D4901B057 + +HMAC-md5 + 0: C91E40247251F39BDFE6A7B72A5857F9 + 1: 00FF2644D0E3699F677F58ECDF57082F + 2: 1B6C2DB6819A4F023FFE21B91E284E93 + 3: 04B0ED3E73FBB9A94444FDFFAA530695 + 4: 1557A22261110DFB31ACE25936BDE45D + 5: 54C5A67A9CB4544CA66BBDA1A2B8479E + 6: F803D9E43C934545AF078FFBB34BC30B + 7: 32F56EA655DF36D845E430D637C85D17 + 8: 14BD2095F4A478C10EEBFF379DE76DD3 + 9: AAF6867B3FA01DD26312B0DFD6371A2A + 10: 0FA2A6FEFEBE7CE3C31A38400F8AB260 + 11: 54C37BE13B7333287D0E74AA9D9227F6 + 12: 385D75A58B0C95E5CDC059DB168BD1D2 + 13: E73003103ED65C08E62D46AE1E1B771A + 14: 278ED4A4EBEA1FFA5EEC874F198C0CC0 + 15: F65CE9EEA7FDB90B9CC603329D3FB9A9 + 16: 8640836944EE0009B2CC6FDC3F5C39E1 + 17: 7819A99F82BABDF060AA51AE109629DB + 18: EF26336668486C76921D1DAB67ED5673 + 19: 13ED7BC140F1496E09AD29C644586957 + 20: 5FDD337CE9C4AC8D910833FCC2BD837E + 21: E9470246ABF7CF4D37FD378738D8F763 + 22: 384A75C33EFFA12EB69187BB80DF843B + 23: 63866A5406B9EA0341032FCFD0244A4B + 24: 8042F8572C8A9B88E135ACB83EF1FD39 + 25: BD1BE6AF2D022F966F612569E191F0E9 + 26: 9F70C839533EE4C7B3CF20C6FB65C94C + 27: 800A5CE92CA4FEE6F1D353F496113873 + 28: C35E93E1E54C84C4389D2DE71E1B9846 + 29: A130EF5F91465F5A56999F450E63F4F9 + 30: 5F16564E05285A099F628245DF9A3C2A + 31: A34F7E3DF06DD84CC67E8A922240D60B + 32: 945E50753B6E6C920183822D5F280F10 + 33: 2DDD269DBCDF5C21A1C3FD540FF4ABA9 + 34: 212FE3E2CEF7DF74FC01CC2CC83119B8 + 35: D98B2930011649F16C08BC8C0178D838 + 36: E39E21026111C1EFB0C491C0FDFA841D + 37: AE46DE06C3B0D2CEC35352C95A1003F0 + 38: 5550EE50BF88C9DE5ADA34567FE044C7 + 39: 6BC486627760373EACFF508F7032BF31 + 40: AE6E0B8DBCFDCCA4B3449B57647D5AE5 + 41: 6BE5A0F140DFC4B75439630E6F9A36EE + 42: E3E4E735BFE79397D4653A6243DF1925 + 43: 68C1D9E8973A3F6B92B588469D68A2A5 + 44: 956132D512118D5F446C8CB912B924D9 + 45: DF5C2AD650B3CA7A89EBF92EE618C845 + 46: 14D375CF7E4294ED99135E4237414F01 + 47: DB966D40B447692E2D13CC0C09C1B495 + 48: 53DADCF1C6B99BD403052A1CE1ED0D14 + 49: DEC4A3C1DB8F6AA4515C512C9299C4DC + 50: 3B3A51DD83AB1DC56A7F0CBE1C71923F + 51: 03C73353B3203EF9CDB95F9DB8750AF1 + 52: ED9E15FD86D66DA2D546D2BFC55041AD + 53: 81B649338F9DB1C6E592427D38221C7C + 54: 92E170E13BF40FF65E3B4C665F222DD5 + 55: 00D5E23F5F829B21D454C4445851AB53 + 56: 39057029AF0B3F4391A7BDC6DDCE4D07 + 57: 2DEACEFA698F9CCAD5198C4E17E69A93 + 58: AD35FD52EA199E26948009DF3546D3A2 + 59: 4C42CF2CFD4D8FD9A06E3F73D02FE818 + 60: 4D7C893E4313FFF72103854463414277 + 61: 3F04E8B32AB56EAF216503E46BD7AEBE + 62: F015DDC3EEF41ECC93E944FA3577DB52 + 63: 31F77A50A2ED96ED8E4A3CE04B9DAA23 + 64: FBF481373481756E0C88978F7E0809A2 + 65: 7D8D793B287C04E7D2896D76EAA5CA15 + 66: DAC74AEBECC2385DD9D0C3147CCA1F78 + 67: F6DDE50D37B460FF5E8B4C03A0854BD5 + 68: 5710D6A54A2124E06A6DADBE9BF76119 + 69: 19DB5D13A53E57184759F33976537AA5 + 70: 848DD8D32130626FBD11B0133C2A29E3 + 71: 4F75BE04BF2F6DD85D048DB82F19C38C + 72: 4AE9436540ED24BCB5EC62977AC90789 + 73: 859D1A9FC2B795AD60F24A37EB9EF890 + 74: CD45865317FD17B652DE9F9EBBBA16B6 + 75: 52313319D395F453BA2C0A0159CF180B + 76: A7B190C0EECACCA4DFC5B45DFB324718 + 77: 23E85CAE85B50F45F7F48EE0F22FDE85 + 78: 6A80DBFF139A5345235EF76586CFCBC7 + 79: 850E638FCE5A2F3B1D1FE9C28F05EF49 + 80: 797CDC3F7E271FC9A3D0566A905D1CFE + 81: 030CE97A9A0B1D5403E253D883FCAF12 + 82: 648FFFF44E416D9DE606BA0DDB751194 + 83: FE15098E0DAC65FA8EE45CAC67121CC9 + 84: 17C90ECD390A8B41046B4C7FA0354E4F + 85: 7D149DFF5F6379B7DBF5C401DB6D2976 + 86: 8D055A4701DD51CB9D1AF8E2AE59BD21 + 87: F3481CB07B034EB4A023D00D4FDA9A86 + 88: FEB22562FFAAA9CCE5CDDA34C29E55C3 + 89: A620AA447216709D8CE5C5F23474ECF8 + 90: F25FCBB2BF7440C5E3C5B53092B8C828 + 91: DBBAE1CF60BBCA0B05EDEA0B362F0A33 + 92: E18E85BCB4633A797FAF7975CEF44B84 + 93: 1BE27EEC72C2EDE151978705C7C7DED2 + 94: A15D36C5C5BED77699838832FC225DD8 + 95: 08F31E68BFBBB420742F80B20B69BE8C + 96: 5E9B4B5B3228F533BA8EFC3C0B9AAD3D + 97: 1239BA6D941D1D8AD2ED561BF517D4B4 + 98: 5233F50218E0D097EFCC68F1536F30AE + 99: 340B47C78B003272EAA4B9D22C3B0542 +100: E7F11759FE8A897364C21767570885BB +101: 054BD6ACBFD5421C0290B0839C0A0ACC +102: CC0748F7B2CC921CF5FA019F955066C9 +103: A4DF167697949B1AEDBBA3226A334BAA +104: 29893B9776BA5E750A9FCEA37B0116AE +105: 2DC25C935F006F7965FAB3256D77004D +106: 24089811FFF2189FB9AF38651F43977D +107: 0E048569D634BF652CD8EBF859C9B69A +108: 00386B569DAB73844A708BA5B48BBAA8 +109: 8033E1AFFBE1218F81C8331343FBE5B5 +110: 9B82008A34F3847C1204ACA89F3D57D1 +111: BE1A529F88AA05A42AFC40F663E97849 +112: 5237637AA645E83B0E56A1361AB80643 +113: 15BC4405E891ADAF48FA56D4356705D5 +114: 0820087438832B63AADC479CFC88BDBF +115: B1E3BA7E96605D5FF614B1BEC1F57AC1 +116: 838A096D64E6C0DDB069DC89E4C3F839 +117: 934BCE159F3959A933C87AB497CA8D42 +118: CA501F1DE619A570DC38FDCB8B3F7722 +119: 033B27D5994A6F5D5F6800539B69E876 +120: B447FC68FEF4E3CF9290B06EB6AECAA3 +121: DD3D3F72F0F1FBCD030D839DCFEE457A +122: EE73C4C996E0150D93B3144F20FB2C1B +123: 5AF9679D2441542391C6A903FD8C1626 +124: 2BD84B87230511DAE7256B62A46AA45E +125: EB159E5694C191F7708951EBC0AAF135 +126: 60F02EFE1DAFAACF65F6664A2321B153 +127: 14E5A0E90D4420E765C4324B68174F46 +128: 09F1503BCD00E3A1B965B66B9609E998 + +HMAC-sha1 + 0: 06E8AD50FC1035823661D979E2968968CECD03D9 + 1: 0CE34DEAAD5CF1131D9528FAB8E46E12F8FE3052 + 2: 23924849643D03BBEAC71755A878A83BD83F5280 + 3: 6119DD9A7024A23F293A3B67EFA2BF1D82EC0220 + 4: 379DC76AC2D322FD8E5117CCA765391BC0E10942 + 5: 7897CC86CFF17A3F95C7AF02CCA03546F5CC2368 + 6: 1FA1EF3980E86B8DF2C8E744309381727ED10E8E + 7: 03B2B726D71DAC6A2BEE63EAA09631DA78F5958B + 8: B8CAC4C104997A547374803B5898057B3F8110A9 + 9: E165E07F8D542FB288C7D367198D0618DE3C9917 + 10: 18125F046C675F434B3C53A28C301FB2D91B5D34 + 11: FAAB993F2FEAE442D28FDBB613D2C768ED13342D + 12: B657E7EE3A65C6484D007E21484813D9AED1264C + 13: EEEC2BB7BAC158742711ED13090FA20462A5E5C0 + 14: 12367F3A4E1501D32D1731B39CD2DB2C5DF5D011 + 15: 57DD9DA36E7A4E567A2C5AE9F6230CF661855D90 + 16: E37110DDD295D93990C4531D95564E74C0EBE264 + 17: B2115C4E923EC640E5B4B507F7BC97FE700E12DD + 18: ED20C67345867AB07E9171B06C9B3B2928F43188 + 19: 6CA7DFC9F8F432DED42E4EFE9F2D70D82507802D + 20: B39EB4D2C190E0CE8FA2C994E92D18CFBCD8F736 + 21: 91BE5ABF1B35F6227772E36337F258420CF51314 + 22: EB957199EF666C6D0EACC64FC4261D11C715BB23 + 23: 2A18D8D4AB1F8C528C9D368BF5A7CFFC2168D067 + 24: D4DC370D482D82932701DF8CEAC9337682C2551B + 25: DB9665A6A26DBDE20238F04E9F1A368D26564E4F + 26: D5AE212C9E543F2656699B59DEED54CAACA9A071 + 27: BE8890F9DEC6A02AE2848D8505B6408E884E6D1A + 28: E8D9DD9FAA3080560B0EDE798B745FEE2A1E5479 + 29: E219219D2CB8C363C2687F578446ADE1C0404287 + 30: E8E7767B35ED8D0965F68272ACE61924CB044262 + 31: 1B26689C1EF55448A61DFAEF98B6E7206A9675EA + 32: FE850390864E98A17FC43C3C871383169741B46D + 33: 3F63068D536A282C53E5C003BCEEC96646CF7455 + 34: 2962C292CE247F11ACB7E1F981447C51E9BBE63C + 35: B28909A2B7B2E0E13FDCB1124B0BDC31D7D2FEDE + 36: 8DA0FC30C8322DABD67D61E82FC92351894789AC + 37: 543DAC6D449FE2DDC3201927D08695F68F832905 + 38: 371540F3092F77867F0CA9DA69318C7673F68388 + 39: 7EAF32204EA5993C87E9A12C67ADA4C85D253281 + 40: FC4994BAA05F592901085ED7DA188EC3A9BF36E3 + 41: EBFE77592EF34E81BDA05305876411484DC0744F + 42: 25F64E8F076305D6F5741EA58232F68B725B8F6E + 43: 5DBA03F7E4B4226666F0D8D5BF49FEE77951D121 + 44: 98E1D56D723DCACF227D2AC67BF2D6E7FD013497 + 45: 53550BC55A367D87416FFA25261362E7D4618DA2 + 46: B18434BCCCC5F08B35397C1A6684D60F4F3A452F + 47: FF2BF38DFC6909B46A01E055D173F67A7E456341 + 48: DAFA445432ED37FEC99059DB8A0BC528E788E95D + 49: 7FF823C570F8B4C0E483165C076AEA7B5E727632 + 50: BC4FC948AB621FE1419CF6006DC04E7D7B32FA23 + 51: 1678AFCC3FBD1063E7C82CACAD5B6A933A93091A + 52: 97DC2F9F56738FDAFFD555BF09274153FC2FD009 + 53: 74F5CB4F0900441B7AFFC278C01A3038DF3D60C8 + 54: 021F66143270C9D58F26AB193DBA81A811917CBC + 55: F486D1C8127813FEEEA8A693C4B8ECB5BB53C3A2 + 56: 8397CAB8EED5B2164FEC6BE688971DFA2138934E + 57: E4477CE9BF8CC5A4CCDE039B4E3000F1A0F4153A + 58: D6D2D1E3EE4D643AC4B38836AE54E846F99B376D + 59: 9545B2C6279371D4D928AEE24328121D43DE1E5E + 60: 947ED38EC087C4E53F417E8216408863A8EBFCB2 + 61: 32518A2326ACDE1E962B3D0D2BF950F318894E83 + 62: 5D21D368FB9D879ADC27B341D608BCF860AB14F4 + 63: E2BEDD94D565A51915B1EC6FA9DE18C62D12533A + 64: 15ABF657DB6473C9E2F017C7A2F4DBA3CE7F33DD + 65: 0C9DAF8D959DAE3B66FF8A21A94BAFC523ABC462 + 66: A36BE72B501D435CB627C4555A426C4ADAF3D666 + 67: 1C171979D67A014A0422D6C3561C817A354CF67D + 68: B75485B08ED052A1F4C3BACCE3C563DF4BA82418 + 69: 17297624219C5955B3AF81E5ED61C6A5D05BD54D + 70: 38A9AC8544F0EF24A623433C05E7F068430DA13E + 71: 1E9EEEAD73E736D7B4F5ABB87BA0FABA623FB2E5 + 72: 4B9D59879EAC80E4DAB3537E9CA9A877F7FAE669 + 73: 7F76F2F875B2674B826C18B118942FBF1E75BE55 + 74: 1716A7804A9A5ABC9E737BDF5189F2784CE4F54B + 75: 168027EDF2A2641F364AF5DF1CB277A6E944EA32 + 76: FBC67DED8C1A1BEBBBC974E4787D2BA3205F2B1B + 77: 33DD26C53F3914FECF26D287E70E85D6971C3C41 + 78: 97906268286CD38E9C7A2FAF68A973143D389B2F + 79: 45C55948D3E062F8612EC98FEE91143AB17BCFC8 + 80: AE1337C129DF65513480E57E2A82B595096BF50F + 81: CEC4B5351F038EBCFDA4787B5DE44ED8DA30CD36 + 82: 6156A6742D90A212A02E3A7D4D7496B11ABCFC3C + 83: 3040F072DF33EBF813DA5760C6EB433270F33E8E + 84: EE1B015C16F91442BAD83E1F5138BD5AF1EB68E7 + 85: A929C6B8FD5599D1E20D6A0865C12793FD4E19E0 + 86: C0BFB5D2D75FB9FE0231EA1FCE7BD1FDAF337EE0 + 87: AB5F421A2210B263154D4DABB8DB51F61F8047DB + 88: 1B8F5346E3F0573E9C0C9294DD55E37B999D9630 + 89: 09DAA959E5A00EDC10121F2453892117DD3963AF + 90: ACB6DA427617B5CD69C5B74599D0503B46FC9E44 + 91: 9E1BB68B50BD441FB4340DA570055BBF056F77A2 + 92: D3E0C8E0C30BCB9017E76F96EEC709BF5F269760 + 93: BE61BB1BC00A6BE1CF7EFE59C1B9467D414CF643 + 94: 19D693B52266A2833ECA2BB929FBF4FCE691A5C9 + 95: B99816886D9FE43313358D6815231E50C3B62B05 + 96: 7A73EE3F1CF18B5E2006A20BB9E098E98B6513CA + 97: DEC620F008EF65A790A7D1139ACE6E8B8EFCCA5E + 98: B6BA0EBD215CF1B35742A41EB81A269ACB67C9A4 + 99: 3A0FAAD14D3B64BE4EDB9D5109DC05DFFA7680E2 +100: 12E62CE53283B5422D3EA5D8D00BC7F0AE8A127C +101: AA36F0CC6B50AB30286BA52BCB9BB5C1BD672D62 +102: 55120C68B419FE5E12DB526D4ABFC84871E5DEC9 +103: 372BF92A9A2507509C3D3932B32444B7BE1C9BAC +104: 7AB4B04EEC091F4ADA0807DDD743609BCD898404 +105: 20CB412425E88482E7D184EFEF79577BE97BAFDA +106: DEB91399A7BFB8323BC8E6A5F4045125277C1335 +107: 6769F41624E553B3092F5E6390E4D983B851C98C +108: 716760E4F99B59E90A4F914E1FB72A6D2C4B607A +109: DA0AA5548B5C0AF0CC494F34CAB662A30372DD11 +110: 17A0E2CA5EF666EB34E2ED9C10EBC5DDCD0D9BBB +111: 1B3614AF749EE359F64F3BE3650210CC3C3498ED +112: 346E604622CF8D6B7D03B9FE74E7A684AECCA999 +113: 629E46882D214F9BD78418C2A97900B2049F1C83 +114: 765F86114E942214E099E684E76E94F95E279568 +115: 002ED578F79094B3D7E28CC3B06CD230163F1586 +116: 52CC9748778AF5C8E8B41F9B948ABCECF446BE91 +117: 9326190BF3A15A060B106B1602C7A159E287FD4C +118: 18A5DFBAE6E7C9418973D18905A8915DCEF7B95B +119: 6D25BF1E8F1244ACB6998AA7B1CB09F36662F733 +120: 5F9806C0C1A82CEA6646503F634A698100A6685D +121: C3362CE612139290492225D96AB33B2ADFF7AF1E +122: 3D42A5C1EAFC725FF0907B600443EEF70E9B827E +123: 7FF97FFC5D4F40650D7A7E857E03C5D76EDD6767 +124: 3A92F2A18E8F593E6A8287921E15E2914DF651EF +125: CDE6F2F58166285390B71640A19BD83CA605C942 +126: 21A227A8DA7A9F5D15C41354196D79FE524DE6F0 +127: EBE93AB44146621BAAB492823A74210D3E9FD35C +128: 6560BD2CDE7403083527E597C60988BB1EB21FF1 + +HMAC-sha224 + 0: 6E99E862E532E8936D78B5F02909B130AB09806B2AF02F7CB9D39D12 + 1: 1D1D08669FC34CDC5FE5621A524E7181CD5B5BAFCA3DA56D2E15FCD9 + 2: 014A21F82D0CAAD15EB74DD892187D7AD93F2BEB549A596DFF2C9AA9 + 3: 5F600F19EDED821AEED09781792F9435458A32A60FFC1B678FE2C905 + 4: 8D933E18052E7FD1F98E5E7D02384DA60F3E743801032256282AE2CA + 5: 21362A65B49C33568251CD1366EB13A4E683359855C00F3AD6710896 + 6: 1E1814B72BFB185265AF94FA622E4A1A70826C06F2BE2EFD96E4E168 + 7: 118F2E1C2F1AB8AF2BD17842FCBFAC966F5B21A81996E3CBADF76442 + 8: 2C6C72703E33A20EA0333629503EBCC41B64DB829064A5C7897C465B + 9: 794046ABC3BD8165D12C2453FFA3FC518D1A6498A48C91053BEA2966 + 10: E6C3B6E2DC215702960633C976B86B8378D7780FF884910454032C7E + 11: DE7CFF6E85D9411FBD58B28FACF72DFDAFA115614BEF3119F6527104 + 12: 11CF7495ADC07EC29EAA7B3464F772D49999A5E1832F71FCE18CF7F1 + 13: A7541E63945FCAD62D2570B015079DF0422E96075986B45772860F38 + 14: AFD3EB7EBFBA79CC68E4F6F6A2D758969B5C5C014FFB53CFF21C2841 + 15: 28D942E37CB92EDE2E6F994E9EEE2BA01077D099F3562FEF97A8CAC6 + 16: 34C7562962548AC9661759B4FC347D6A82CD47991EA06E855571CDE1 + 17: DA76FA12D69D1FDBA5E544495BBE45F620BE147B73D6AA64D3B3C298 + 18: FBF1911FA019CB7ACA20E3F93ECC0D5E8D60DCA0A1A7420C63BA1864 + 19: 565FEDE0EE20842B82D59644929C2A1A426E397B38FAA772781FE018 + 20: 7B9C2BA77B2989904F194021D308089E23F00954275AE9AD87306A31 + 21: 66CBF93ED8071FFA36B61F3AABFDBFE714C3C055B2FBDCD3CF369025 + 22: D96F10ECBFAD7FDDDF60BF1511E94869ED1D992051539E50D5F32831 + 23: 5473F93F0D979D77C3C6B9CEEB2F3DC1058D81401669EF4AEAFA17E7 + 24: 5B5A75A7D99C1B40961533C345B95FBF0AFA916D6E133967FCAA15F2 + 25: 2A1E50E18C37AB7BD928AE14C206FAC9B3E869173CA337FB9374565D + 26: BF2B241659C96007ADC25D9567947BAA740555D066636731EEAE3C97 + 27: 6E1E7B64A70B190BEEBDB9DA82C8E4B160CC73B8FFA224A6B92180B3 + 28: BE36A5F8DAE9294B3995D278CBE9273E66F04D46890B44EC55028C3B + 29: 9983C289CE2F806F41182752A753E0A890217DAF3778B3AD2ED6685E + 30: 8B0F08EDF2CBE25E8F9EE4D2948BA6BF81672BF4F509530328A8BAA2 + 31: B65FB77E6CB86E5F409EAC2F1B5A05E1910213563F816121AFA8CF14 + 32: 5D15E17C8C159EA5DF5F126B12ACE777EAB36A0082C57DF71E4D9609 + 33: DCCB3D17C8756F2546B3E5B24B1678438959D83A56524415666DAE05 + 34: D28DAB7CA715AC86BF4469D743A0005AEE0101F339350661D46A1684 + 35: E7A1CCC4B2B300457DCC64534152119390B69610C7FF9DD3A683439A + 36: 29380148DA403AD5911C7BD52C783EA97EC306F2B32BC426C4D7FD35 + 37: 56DF59CD635F025925A968591E60DF2CBAB22F98B67C78122F3CE868 + 38: C20EF10AE9CD99CBB54C94C971780E0487899D7A810FA51A6553DCF5 + 39: 5B78837F366097CAB6D31624C06B099BDC71286E3AD8873509ABF4CE + 40: 8DA09589C44E710B9F84014FE553074E72E0A86C9418EFBBE420D2C8 + 41: EEE18FA2BB5A5CD16017B4621ACC4211EF7CD60613A8C879B0AFC0D0 + 42: AD9670FCD043E6F91CE986E6F55905337248B72E7B8551AE72ED32BF + 43: 97FA4FBA4815DA49F6127C96C969574AA9543B338F93BF9171D2547E + 44: 838D5AC81EA6BACB827327E8EFE96CC2B14D92C55B40CE58F4DA181E + 45: CA99480DC8480FA07784EF02074453664DBC92257366514060F07C93 + 46: 93B0E493D272470F9F274DFE4B9DDF183B26011090E15861FA21CAF2 + 47: 770CAE487AE5890DC0B931EC17623293EFA5B22EE1ED496A37EB9FCE + 48: 6F1D5CA0446E7B82DA02847ED1761CF02D646E56FB0CAB9B120E5282 + 49: 2A8A1254F6CCC3D656397A5F2D64C266412FC5207866B073B77DBDEF + 50: E8CB788AAA965ED87FF2C7B5F3107684326DCBB0E667217E0EA62C51 + 51: 85BDB6D1486F27827D5870812BEEE2C3976E0DED4BD2F994BBEC12AA + 52: A14E0343FAD6BD78E0A8E3BCD6D0B6C83B1220FE6C89F57F44BC805C + 53: 2C60D71F2D4BEC90CF10804DCEDB9311637B34D62E9CB68B8503162A + 54: 36397D66B434BA744174DA541F080CF6582F10322C7FB1869A100141 + 55: F612E4EA307F56447112CAB5D2EBEA7D12C7C4427D9155D4085687FD + 56: 9798B420980748993BC78E3601B8AEEE2D2CF6E59799C7B07B88435E + 57: 50BED37F1EE78FAE16D178FECEC2EBE4776C8E5FC738F9506E8AF676 + 58: 2755438A9AC457B81999D9E1E479C36DD9AE1F920F5BE6D109ED7431 + 59: F3DC2238B13BA706A048253F86B79045B72EF767CF25DC62F96DAEA0 + 60: 11900A3154C4DFC49B941258A134C9201DFD280728BDB3F8BC7903F8 + 61: FC584202454DD7C9258F72A6258E42F3C2669FD138FD7AEE6200C4CB + 62: 185355C13E146EA89387C332225DF31CF114AEC0BA3A5A5B53667709 + 63: 8194DABD2F7A02DDDD7B752AB5669821519640EE3B0059FD333F3401 + 64: 2CD6946C6DB676ED1EC272AE34735A0546AFB8D996323272C39A814C + 65: B7A344BC5EFFEA97AC49894A85B96F9B570E680DFBB28C76F7F9A180 + 66: 9011B80655A9CC7964CBC4BEE1CC03074003CCCFF5DA553B289ECF6A + 67: 6BDE25371B7EA9ABE31A524E49CAAE40DB220E405463D93FC7F66904 + 68: 35694194E10D0EBCA6758099D09C99C3CAB37AFA52FC4F4361C510F3 + 69: 4E7A79F362D7AE5B1680F30E6770CA46FE6264C9FCA566718C01EF67 + 70: 9DD18D21E413AE12112AFBE16684BFD4FAED7467A2FD5904EF0B493C + 71: 7532D374B66B1E5B17EB49810DC3C04264553E4C36F4550D1E860B70 + 72: 35EB09C82A624B1E3ECD965ED8522E9572EBF26791EFA667B4DB952C + 73: B9C17DF6F2A6506FB1DFCF1A9089974C45760A438330AE7547DFE685 + 74: A7DD0267C15B36D8BD1879F879E894FB9F33F254556B87BFFEDD71A0 + 75: 68A354D120CD63A5D34EEE84B7E5E5BC1E5DF6E021F712BD4270B781 + 76: 441DC4884130D48BA134E2FBA86AF643C8EB79CD1AA4688F82E0D3DC + 77: 17A3F16DEAFDBC1DA00BD14D9C24497BE765F41E2EC79578421ED8B9 + 78: 8756A267D0CAD54BFC848FCC4D6B6C94D39CAF07831EE35324DCD35F + 79: 004EBADA70F19BAB48E6072E2090941DEDB5CC0A7B624E4BBB671382 + 80: B7F8D35CB865977423710FA1E0F939808E68ABB54BD7EB0427DA03DE + 81: F3D0AAA2F912FF95251D3CF51EBF79B940DB56839DEA8BA5872D1FDE + 82: 0835B2DC376BEAE873F1FA337D75C72FD1BF0F72A81669AA891F2722 + 83: 7CF9A7D57CADEC3F013D4BD87C00B420CBFF73670A9CBB072D18EBEB + 84: 68AC0A34930329F5AA40137987208481E34D8B9C08EF7A85AE3AB38B + 85: 00492F706D84B903D5355FDC0B68C2C33B484A95A173FDC4AC945028 + 86: 6F6C509CDCC84CE1C36AB76C9BF30E4422C90C869C164C64696AB5B7 + 87: 4C0A35D512BD0DB15915DE08FEA8E6027063A1780C104F6273CAD5C7 + 88: 27087F6425878D64A56BD5ACCC0E303F803B7208F20AEFEF75501F03 + 89: 4EF78140430EF60F3CA12AAF8132674B0DDB154F495029B4051C2A36 + 90: BCCA3153EF93AAF21CA02D235A23D3013976295E704223CB37E860BA + 91: 20CC8D4C64E09B00ABF23864BD7EDE542F5BE480AFC4B9551B301EBA + 92: ECA3F86DA00098D91F866C58558BB7B00C9E4239CF83C5A3E76291B3 + 93: 7AD9AB198858820D20373C45173D76AF8D68F829D9A250ECADEE0DA1 + 94: 3E1C202F2D589BDAB015306AD063784E5BEA48AE8D1DAF45D571D2FD + 95: 990C44330D56EBC9EDD951F8CB92D5847F4BD3C6442906F57A828FA9 + 96: C92F9FCC6220EDEF52B6F842635A83914B236862F6CCBED16F4899DE + 97: 0E41C85D5C6D625E1884EF7438DD9EBAC818AB50CC265A73165928D0 + 98: AE087D57F9CDBCDF4DD68A3E8D5BDFEC709A532A4A646CB31785506C + 99: 4CB03AEFD24C833B5350996EB261E803F6DB698FB81F37F8A5C3D891 +100: E680BD218AE972999BECDC905F4D39251ECF49B29CF0A13AF5FB09A1 +101: 64326D6B692B0A17045434BFF13282ACB91E7B690339F7FCEBCC9AE6 +102: 20CD91504AB04E2D3CD849808F2362943BECB310F4A0BF6E3BD47751 +103: 80F607E2D79E1EFB0458E47C8E5726CDB8387BC05F42D6EAE3239A20 +104: F83C023D6F539967AB24309DD28321599782ACFCFC76B77186307300 +105: 70164A250799DBE6C5BD3EDCDEDB16D2516A9FC1BBA294C49F753824 +106: 1883397C9C4C9D33FB9E1E03325EDCEA1606D7ABF86C4387DABC449E +107: 1355DFA06822CC1F216C131F2BAA92A10BBF109BA3E648419A35C0F3 +108: 9E35B9B307990B7D664B9EB7F06EFDD23037F859ACB6B96A5287A846 +109: CCCA26C8F8405FF62421558255F2DA06F73F17D1AE1763A0BF8430DB +110: B4FAE909368405206333491674559B9094DA4C48913D9EACA28AD75D +111: 3A5E7D9273F91E10545FE6861D4FC223A5EB0F7B4FBFBC9931634C25 +112: 96553CF0C5C6F6A17FEED04024FCE1D292C392E60B3595FF53007AD9 +113: CA9B79F403412F71FBC10E094B35088576EB3F7F8B5D08757D89F45B +114: CF60CC5B1822E4A12EEB3E1E5F4AA79E345D8C8FCC546D57DCC7C784 +115: 807D65C33E74DA0E2D5E3788084C61AE3E8771FDFE643D1269A7901A +116: A5418DBCA94A1F9692FFDB3F7AEED75806CD9FD47171A6B67921C0A8 +117: C2B880C9E9D78B0C397D72C8B6684276E8C22A7F4D6821DB7C998775 +118: EA447EA731673E5DEAB57012CC9E0D3A7B2443165B665822963FD6B5 +119: 0F6D50C04357DF9240802977779D7F2214FBDBAE95B6D8F59B414964 +120: A3B24B29B29BBF32A01F21FFF13F44FCAA5FED50718803AC3BAAC548 +121: E31E36C38A7F2525ECADECA047533830A9C46D609E297142AB3DACAA +122: 592FF0C399A6CC1606FA3F404DA4BF8618A4DF159CBB7E05DCD30BEB +123: EEDD6A5902091ADB8EF491F820613740DA73A160D825121912613DDB +124: 3A2FCBFCB007F45CB0EEDBDD5A765EA0CB7A142CE3C024114D6D61DC +125: 5D29E1732898854AF468BBFA5B87065BB811AF8F55C91E82E888E842 +126: FD1F646D021EF31F634EF5FB0506620686B9F7D9B5C672734CA10FDF +127: 5E43945BA9DE62C364E34CC1361FFFEE9BE8974D7CF5D2E06428916B +128: 0FF4DA564729A0E9984E15BC69B00FA2E54711573BEE3AD608F511B5 + +HMAC-sha256 + 0: D38B42096D80F45F826B44A9D5607DE72496A415D3F4A1A8C88E3BB9DA8DC1CB + 1: 12B06C3218C858558CAD1DA6FE409898C31014D66CBE4ECD47C910EC975E104D + 2: EDBEF6AA747C951F25AB6AAA0D874648CF18FFECC4C9159F8FC71E971FAC6D21 + 3: 03436338A166E9051599AB268CD74867C6159378069A9FF46FC07CAE375EDA68 + 4: 634758DF0774A587F3AC6AD7988D0965524DE24EBE4DFF07EF622BCB8DA71ACD + 5: 0C08E52C7CFF8B5F70781197069DC8F209552D241687BA0D24661CCCC28D3937 + 6: 749F473E0D934694AB9917569A61591CA50BEF18CABDED51666DF243DE879D53 + 7: B1E12CFE0273F5D27192D1A4B70EEC4DDC714B66C8BB1921C63381F78CEC5219 + 8: 1C60F13A1C539788E989BAC2EBD4F8E126EE6ED82C2E25817C63B2B633FABD33 + 9: 5643F445B2C0656A49BB3DB5088C9E2E4B2082C2B611BBA0DAE5791F2FAA5D43 + 10: C467F47251DAD4694C9C7A6758E54CEBD68FC933C7C57458020774A2A2B4288B + 11: 85C90CF2719BEBF40EF8D501FDA20C342BC406E728551BC0275ADA1747BD981F + 12: 06B72DAC895B008DA249B7B1D8A5133F09D86BF82DE2C4251BFA6C3D8C4CF03F + 13: 49EDB6714A556DF324E41A3CE5B57006E38FD7CA8B90FEEA2ACAB429204747BE + 14: 7411921D759DA0B491D6D4CC372DB79CC163F146C345B4A73D93EEB4C262A1DF + 15: 5C37FFBD1F0512AF443265B2F3E8B6D01AD9B45FF6F373D2CD0A7C6E48D03E26 + 16: 773165FD16D51E51CD8A958E548902B47BBD0A6E156C31B6FEA036F6D8C4A90C + 17: 5B4BE909754EBC8ECBBB8B5DA6298B8341B35D92E17CE7281909EBA1EF568347 + 18: C6EEF2D12F54815561EEED3426D7AA7E671E26D42384B9478D91FC6B14CC76F8 + 19: 4C9FA0575CD96BB1DEF6EA79F5EC7A1F0478E86352812F690C2C2BDB70028BCC + 20: 7F87BA45FC41EC30E76F61E4EADEC013CE2B4C49CA6FE6D2FA525F6BBD45E103 + 21: 9B8CA1D70339A0894E16CE4E76F6655ADDD3EEB598F3DD80FECC5EEEF3F638C3 + 22: E4608AEA430A638799991B748BB858C91AF58F56B226E1901D28336B30498279 + 23: AF4F9C52079B28546FBB44EEBA20C7AF0BF493D34EF6967B07CA32FC4DE25ADB + 24: FE51F3A9313EEDAAA991350AB4D1D7045D42AACF3AC7155DA3AD9A2F1DE3A73E + 25: C1F5AED9D77F85404A4B308A139D33F351B20C91A738E698BD8182F124D96C82 + 26: 3CAC12A252B93B7D724AF9119FD3C18E85E88401F93BFF42AA05711B9833B1F6 + 27: E61D4E94C212324A64B1A0C04B2237A9A1C5CC003D83EA80BCEB45452DCB42F2 + 28: D01BA47DABCE4704B6820EC0ECDBEF137B9C4ACB80DC99B7C9220CFD9F9CE363 + 29: AED502C53A8B2C76F671376CDDBD0596376B3664B917CD9C9ADBC489543D4721 + 30: 3405AFD96584C5E5963362948D112A70155877BE3B5EFD479F226B73351ABAF0 + 31: 5FA0290DC68B72B1FA27DBAF157923C706B3F52CDE9C4EE38CDA31D376B0BC0D + 32: C1391C694C985CCBA707A8C78AD05E2180AF6B4DA5BB877AAC5E2AB33B4890E2 + 33: B018E7B15F92DBEC58F767633BCA3BD0D84B6D5B9443784DC1757166D7AA1C16 + 34: 8D9E2C84967004E3957DF59D502BC11CF8C8959368117EC5DB56AC958A3E791B + 35: B0EAF9C0E869D7A304DDB30061A73C580B0A6F9D49E15442ECFBB3B5A851855B + 36: 0B48B0D8C3ACF7B4F9ECF8E46563C921B1B6720B6C650D72DD1126B6763CD595 + 37: 8879D239EDB09F6606957D96A1F4BF37EAC0F3419881EEA79E8BF1364FB3FF6D + 38: CC663E436DE42E32EA110F9D90EB990D9151C9F06D51243D2076B0CC45361736 + 39: 732DC3B1F809E55C498C53FC75A23966CAEA16BE984F795CB1BC94D026FAB30E + 40: F1F0EEC77D97A0234D0F19B2FB12A96B6E2FF8626F79A74D4AF26CDE1344D838 + 41: 75C9D8C7344668C478D8AE6D9E2C41E336E7A2504CDD43B73CCBF78B4C05EEB1 + 42: 4B149BCA6429408B242E76C52C4D3A0A5F5437EC0AB6D24D71EB1AC5496D75BA + 43: EDB65EBEBC0411B4FDAF186033E306AD500711CCB80E770E99523BB2672A237A + 44: D1BBFF5A48346A0DFD5CFFAA7A2AF08C27F3FC2908D7A5D2F575E07CA9E72474 + 45: E8EFB6373DD3457610E57750738358A50026D2C6704A98148CDD69BFF7B70551 + 46: 8E3733B729CEB97444BCCA405044B98F45FC59BBA86444A3FC0F4DF4854B5C4D + 47: 868F3EE8F4D4DFEDC3FFAEEE1FA069F5FBB2CB818E63C28151C1566634189234 + 48: 3F5396115DC7F17AAB19A3A9779CFFCCA57DE7A7C1A42F748FEC49B7D8C2B82D + 49: DC2A5E3E176A693AD8CAE551A505729B78FBDE778B526E28953BC1A56B54840E + 50: DC91FD745E9A7A9D0B41C79B3B3939B84BDF78BEB007F9AAF8FF82084759223A + 51: E73DCF5413F17D4ECCEC813DC060EF907C2E952AF92DD247A0AE2BE798E6A40B + 52: 696B5EE4C1E1D8B60B0015EEA2389C9A35088022FFF10034D0D09FA722A2A3E6 + 53: F86C07265389512B2CE240A89EA29D61C6C79C2738FACA157B0DE43294485682 + 54: DB31CBBFD28D6F8564219911EFB748A5663E482DBA26E38634E8E27E3CF65707 + 55: 2F9675313AAB7A940AE77CA906D0342A448FDBA3F7589D14B1344D586EA157DE + 56: 7D829FD994258EF2AFDEF22C8CD5CC1D29A9A55B62847B3B6F5DB630421CF999 + 57: A6CDB9BC9AF75EA4680E895E8EDDCE76F536F7CCA571D62781A06DDB3424FA50 + 58: 1B4186A34EB07F5B3127F2BE0F3943610679DB0F6BABC7DA03B416FA577D36E2 + 59: 7B5DFF3459DC10B9B7AA2B2829094F97706DB5B2F133B8BF9F48D90253D68359 + 60: 2ABB68160300028BBF3B5A414970D11DF4FD6F4B4A35029DEF8492ADFB19A480 + 61: B1B13ABF9D20C42E755D63EC63C016126259C8A6C3F9AB3F0F6AC5D0BD44ECA2 + 62: 9ADDD17E5CF407CDBB12E5E52A50CE134F1B48A2A2AF90D7308344FB5A70485F + 63: 6A4C06DF40BA515C56476471D4A94F87A2B91EAFF6C66510892F2F20A342B736 + 64: 555D424206C003BAD0B08BEEA76DFC81B307C79BBB6E4F15325B2ECD37E04423 + 65: 8A58733E0B990D0D82F93F77DF36E30DCFD03B3181B73C544BB097A3A73B6AC9 + 66: 6FCCCCA4172E30A281A702E36E7BCA07370D4B57272385077A44D5F7933DD2FC + 67: 3B1A91E49AF88B1832F8E91109C7CC5DBEE2847D9ACD2A57404DBB565480AC75 + 68: 69584075C278763CB0B09D4C9E15E9300A191BF99907049F14EC8DE24D86C121 + 69: 2EE24340D13E68B10B95C3F77D55027F98BDE6BA5328D0C02CF89965687C062B + 70: C04B37F5932F427D40E21EEAB7C9594B16BFCF4F5FE2BF175CD63C62F2CEEAA2 + 71: 058E1AC8971ADD2617A4BF7D02B46A8B74A4D52B25643DF9729A1E7DF6CCC86F + 72: 18001F246ABC760197482E25F3AC64B14A795E55B41B505D6027261BFDE7C52C + 73: 4AEAAED524B173E08E54A83E2D9A8B8824E6E2F1B89203D698E9BCE7C3242F8F + 74: 7D82CFB1D7427302889CADBA23A99154CBAC0C9ADEC94EAF29EB07DC86B0B7E2 + 75: 18D42E92BA532A409CEDA8E3A07E751B430800827F5A9F14D93E3ED231BA08AF + 76: 8CFBA378D8595372DCE5D9A6E726C23512F84C0C1EC3C66ADF6B6C55DF63936A + 77: DE1A6E280A9054C91B826785928F37A16E1D2A9A3CEC831185B26D2B8EDE158C + 78: 920C40B4204C7F3D4775176BD245BA0276604C568B3C29943C9AEF1A1C93428A + 79: 935BB39E5FBCE5C4A15AC2A854475578CF80308E531CA86818DABE69BED8824A + 80: D608E561471CC09EC0865C826242CA26AA1C90BDF1625E1A38B96E3EE0CC5F04 + 81: EFE2A8D806A1A71596A05A2F5F48D18CFD4A742247B04E8089FAB27291A8DD50 + 82: 80235BE35DDEA5D49F124D8BE3D143F87CCBA7D0608C7E2CABBAAB01BB95E477 + 83: E9410E0DC14F3BE36A49A5CA673C12E18CBE4F0817E0C1CBD2069349F8A09BBB + 84: B2042A81A36F27B4CB96DBB52A61F701A815869FF5AA0CDCAD0327E1ED1C2F22 + 85: E9E5A9501B24952DCFBB9D59CF95A9A9E6A27FB7315EB472D1E2B7F523D06D42 + 86: 99193B4FAFEFFC932B261EF169250B96901ABF877424FF667CC0DA0154C50498 + 87: 1D9C7F7E681D20E1E0324EFE71C8B6913FE8CA87EE52E443335115AB2C458E7F + 88: 7308DB7E2591D2342109C5084B1174F07D289FBE91472FB2D8C06DF39F826B84 + 89: 90F06ADC29070DC50A23D3F093007E273E783491A70A2F0AD6BA40E34F02518D + 90: E676DEEDC972019F10FEC24B4AEAC0A97870E924F7B1D6D3ECF91EF38A2AC544 + 91: B5DA3B40FBF373795E67A6338F9AC3AD742741F34048930D9336D429D02EE78F + 92: 6FDE20988863CE157042EE52065EEDA233BB2E6EC0464B9DCF2AAC1F3A18971F + 93: 428D4CFF477F0F0379F634D1E7C15E4CE6DA067ADC45221A860C9C3AC4235753 + 94: 9EC80B57E921DA3F81D13B65AA851F5971E4074C96E0D8B64E50A7F5089C1FC8 + 95: 9088151BEF766D0896A48EB6DCC8A09D151C3396FBF3A9FE193C5E7BF9030B01 + 96: 86D853024A762536666316F363BB867EFE25FBD03BDD28EA7522973A1A1BD95C + 97: 007104BD935B532BA4702A78C505D67B41358A61DB8069585B91B1445DC346B5 + 98: 5C5709F6202948E805FAC25C454ECFADFAC693955864494E511F0CD1FC9CFDCF + 99: 0B010F71C5323CC96D3B8DF71170968096E44969EA55B4C3DAC632D30D81D529 +100: 54621EC4F31CC7F6273601D81674612B44726B5CC4A76EAD2BBC3D32DBF62A9D +101: 28EFE1AB745BE64E5DD7286C97360FF2D287F862ADBE44380F85E1388008079F +102: 831BFA684C25542676AD52819249A10D9EF9C2505D69CC1397D0D39D08B39E5D +103: EF7922C40CD96A47C5E7AE4D958B495F1D6954EDC20596E303CFBA43190A9EFA +104: 3A0262EBC746A7C044C1DB043951F7EAC645C40F554898D3D7B2B7AAC4EBD396 +105: 1F2CFBA7275639A12DA7CD1986F920C47850DE3FE13C931618C0FAC765820ED5 +106: 7AC8913C0975101E187FDADDAC5B5EC467A25869C4E630EADBB42DD2DFE4958A +107: D386591F326C91D274FE625A667B6F9F6F7D99CF56ACB365A218F1CF8E167A70 +108: 66286CB1B61156B005CBFC94C2CAB1A6694D7F123411B8A123F2ACD821C291F2 +109: 844D1038E710690050DA737D56FD6B17C261C7BE512713E62033384B53C40902 +110: 7EF970C40080F554851277F4E950C6F378B0A3DA3CD1BE250D976162F8A4EE79 +111: 9BC20A2B67566688BCAC77FCF30259F11D9B2FD2277D033E6AAE19E36058A353 +112: 796C72D95BBA1A4341C6B0397E165DD21CFBEF55555B35C717CE33B6C6ADE490 +113: 1E6A9C1F78AFF266EF8FB25C32C1FDFB4A0F64AFFD046D257470BF6DAEF61D6D +114: 0E1AD927AD658C5E0321333AF8AE4ED69903B4F22C5DFF90AC93268507A7C86B +115: 07B7A778E2931704E7FECA284FF3B14071E255A2B824AD0A2272D21448579CEE +116: A8D810DF06368A0E825D6DB4394916E43E217BEE9303AD4096A8E1CAD37B8703 +117: 6A9C7D302CCA1EE170366F355D8F40AE3A20D28BFCB2BA163DCB68E08DACB748 +118: 40C3A8B08FF9F767491E4243D1808572FDAF1D8CD21AB47115849531513D0750 +119: F26EA6760AA80360398371855783815BCD34431E0CCEC58A34A67997ACE43CEF +120: EEA78D68A509988ED6D7E3F27FC22F3EBCD570EF0FE242A0251457EAC4C3C1F4 +121: AF977819B87F2E63C0E131DFA2A31C555AD831ADCA6DE0FC1BE48D21A1E7E666 +122: 846A75DF3691B2BF224FB0E66E360A2E8BB1DA32422190F2B319B73E6900AD42 +123: FFA997FCFABC9FCAD4B58B0EF848890FB23B974CD57FA07223037450C371B116 +124: 0028C776965A0AE5E9E70D9B833BF328BDBCD06C5A12A2F1C510911E60AA304A +125: 7FA234C59957C214A7BE8D1B909C540B48E54414EE5FD1081B4C339FD2204515 +126: A840BEEBF2C2E80AF2E4830BB26F71AEE48A9C65DE4A9425DA9F98FA3A37DD84 +127: A95332415EA29A8CA6FDB0F771E3F2262C6907DC45B0AC8BC229F6009323C3A9 +128: 8B185702392BC1E061414539546904553A62510BC2E9E045892D64DAA6B32A76 + +HMAC-sha384 + 0: 44BE81C415D283AB7A62A45188E5DAFBCB97DA606BD5B16C92C1FC36F198C0B3A714921848D5E03DF1C4849BB8310C66 + 1: C1E1E68D864F758941B87E30C262348B373F167CE4629E4117FBA208773CCC2E6C7797AE5D6BBE2ABE6BAD4DE2E1052E + 2: BB27A0F06A1BAED5AC4FC2267C36EAB663E11EC5F0FCC0BDC09B9B0E803B0ACAA2F39D2AC73DE489FC7C9AD6DE3FC9C5 + 3: 70A273A2E9E5092EF8D4C58E99734A911B7CADD48954FD518305313B0B682CFCE192018D4847375D7E311470D05D97D9 + 4: B4FAF12B325B486B67E38A855D18B45D1BF6CC60E4D00AAA6E58268F524CC1121AD3EDB64D6E0FA524F11C0F139D0BBD + 5: B509A325F561CDDC539A3A4680380759747709D428B77E69C4CFE926F65B147D92D2C83692F526EBB5CF606AD162559E + 6: 9A1E678A743BA285CE154ADBB555CFD097F5839EEB2DE4147986464C1BF032BA0D80473293467ED0A0AC59BEAE736598 + 7: 1DF214529464666002C1AF094BB36F0FB14A4923031B108C21825E8C55BF6A0BB34C9AD7D5030B2FC7C83A2CD4C79C1A + 8: 86D8BEE44CAC35CD3946321796599F20F3A41BE28F161FDA062E4440CCC16E88BC7FFC714D525A6420CDBEBDF6AE9E12 + 9: 92417595F9974B44BB11EB9200B7560FEA3382CDCB8BA4C2CC5CFDD019C2B5956D3E78D5B186633ACB765E822B3D4E90 + 10: 2E87CF886036B7A66AE6581BA0DBB9AC2A39E1C7C7594319184FF3B612A165DC02B3A7133E3AB3D29634B1CD5305A46C + 11: A5CEDD2B54657832F946BFBA14ED5106E8EB5937EAC6C5405BE5CBE7C58053514E784E3F6668C20466A242D25A44462D + 12: 74475D913659C2C304BA49DD2B39B0C7AD7D537BB2240D8611876CF5955B347694525396C43CA73951E711DA38C6976A + 13: B0AEE82D70411F1A79DD7012421BAC1202D7C3BAFFA15B4D8B868A3E6F92B513F6B026E2E8FEE45DB2AE70C15E11D19F + 14: 7D06EA64FF5B9139662FCF9318589E8FF1F783754A9116E090B0B7A981A9EF1D4C1BF582C8EF5E71A49DEA2834447287 + 15: 8F52BB9B0A2B1066AB67603C552C17E983D15114C3B9776C548D747F7E24AC782253812802EC456914444DD67C0CDD46 + 16: 9DE6587211FE4A232F01D6D20554102D24D98EC140A05303C1893F232BAA2C07C81A10C25A95A50B38E87898900BBE1F + 17: E0175EB9DB2649801EC2EEA9DE2C1E950C129CA249C14326614E0BB8C32AEE67DF1DFC6320439DAE4FCDB4B037A53868 + 18: 0606A848086DDA50D031A585103478EED0259A9167959657050F8D7DD21B4D6B62B93AEB0009B1E878EDADEFAE9B2ADB + 19: D4A45DD1A6B613E3D2D72B35E6030E1531D75AF7C3F100934CF27EE9D0E0F0C236581EC8EE74FF759D7A19C5AA6DA9E9 + 20: 3E0FD11AE4933665EF30E10035B0E686DCA837F6D6FE2D5A10B4EC30F183EDDF3558309905F028DB93323D09A3A2F3E9 + 21: DA2A204C7908FD27A29415CAE3BD16A0488FA1D42CCFA2E2F5A1EFD6F99583EC6B3B36762060F547C629B9A332585355 + 22: FFE8FFED47933CC941A8E9233C037080B9465B4F9C25DBAC790825C013545D2344930E953187C77466437BE226962F80 + 23: 69FE734D5C69F34366E5CA6B095DE91CD4DEA29AD70BEF06AFE9BB232162E6BBB1349263087212AE3AE5D74A3B060F50 + 24: EFCF1B825AF87FA5199FB3C76783CCD1769E7DC77BCF145DB76FDC622BFA2425CFFAA40E6376086B2DBF6F5D9D97A534 + 25: 98C3DC50FC08D2A87ABE3FC16871ECB820D530B453C41F83FD304D51660FD29BEC6A7D1C63E3E12B6E80E8C58CB129CC + 26: 945047CD723EF4F25AAAC4A19FDEED463EB04CCB78EA318989143298DFA70D793391BB7FCEA6BE0D79187543426AADFC + 27: 2718D89F835037C94CD6378A3806614B85365A888B48FFD08C09F0B93360C04E43B7E7A19C79BCDC5DB9F5944579AB79 + 28: F714F16238075796DD43960E17AE0EDF9990132D690F44957C3DE9EEC2773683172FDCC44ED2104320726BAA7DBDA1A7 + 29: A87A96ED8FF0E7FD1F235F070CB5F14B41B2C4438A6D7A0A39D038C74008FE9C52497CC506498414835AEA1192439379 + 30: 31B029DFA85DF545B752506E80675E617549A6725A658CA8123D8C837FB71D8C9961BBC2460D7CCE0CABBDEDACB56C37 + 31: 0B1A9DD308E5E6E65E4C60861D42B628FBDB2C2280370EFFAB736A77A8004C5ACD5269D090B652B1D8F146C1D518D288 + 32: 2A160E0B2EC7BC927FFF813A2B56AE61301AA14933C659B3398C7A0B3CA506DD00FA6F1DE9C6D47AB0FB2BF2E7B4B83F + 33: 6893C0205F3F4ACE906F2FACC97E2B1624D40997370419E5981E6041D5CF34C77EF5ABDB1AA0D3C8C3740100C2711555 + 34: 95BC8C72DC8C70ADB7CD38311292ADEB9D7BDEC6A9580EF4E11A18317CB65667D344D8D6603C044454E67F97F4DDFF40 + 35: 3DD892A4E724376814DD5A4CBE96E4317AA8AF72478D53379247E77C35461BB92CF493851FF1FCF57A6704923099DFEE + 36: 3A5DEAF967BFA3EECA3F259307991F7DBFCEC1F354DF385CF0EE8D93291721553EA954E9D6593506E9F3E330E0A02574 + 37: E00A883DCB5460AAD611603614C7214EC4A566E0580FCAB1CA4ECF1386A42DCDA746D3AE1B0D54E0B9AC1FA336FE787B + 38: F437CDEA425E7A70CB4D197C0CA01562532A7C51FFB8462B4796A4FD0A7EC880CB0E5EDDD5F703ADC179374416592256 + 39: CE69E40F5B5F2F25E0B53281BE76ECB0E5B4558292A1C1A5EC56F2CF11B01BEEB1F0BA01E6A9B3D03BEB69AE0511F320 + 40: 41AA84D15342CD0675C8C0312C024352E99914C3E01C98F969AD04CB5705E9184F3821CFC6A22D43A77C928F6DB79D8D + 41: 74001D972353BB45FF3F7F405FC727CB5D0B00431BC76A57EAF17862BD52949AF884403ED6B2A002D618EA33523DE200 + 42: 968BC28223799F1EB92F1432B6AAF5CF6953491C3F959977B065BDB800AA438CC8AA7EE1304C18999CB5ED709431CFFE + 43: D067EC03F14D2D639C4423A311EC86B3DDC3693A2CF43C259BD0358F8D0D68F41950CB705249A59072A2CE7DF155F5C0 + 44: F41EB77179934884DDB56DCF83DC90C606D0226DDF94135FF8E1E0AA56C9A90881C4C380CC0AD3BD0DA45A6352BACC05 + 45: 27BF9A98F9E2732972FE2F35ABC80AE2E5A2BC1D238B9B1D9CE605A89144EE9766987384EBDCD63533E64BEE094E4503 + 46: 166892E106BBD9D16819D9BDD3601D24C0C11860DB13799F0797F204D07DBE914A7BD286B380EFAC34DFE3C940CDD3BE + 47: 2D85DBCFC431A94F8F50132DC8C10B25001EA10AA9DF7C53AEE9E8383EAADFCECC21202EFBCA556BB4E33CC68156B190 + 48: 086007E2874E779A5EDF0E176AC1A11D241F4AD8D02AA99DF2BC1AE3E5CC4775AAA92ADFE772CEEE89D4FDF1B601D05A + 49: 2ECA3144F4F9EA0F37C2CA5943F458590A1D4D19C0ECEA6A55CDCA648C99CD457DC57EAA995042D7FBFAB598B8AFEEDF + 50: 9C1F31F5D3A589631D8B7EF89A507011736BFC328071513D64E5432D24B1BCF47EB10139B6410A3103145AF67B5B6C46 + 51: E0645EDA004D9005399A2C072ED9959E4F8905D15C57992553202A3B53BCFEA0098E6B28BE047A4B29EED7B57602C0E3 + 52: 6CE5CA92F0B1E84D7578DDB86C96A10924601A3680BAFEE5A0B27D8390B59752205EA483832ED3E9343DE7175601C03A + 53: 47F50844C897FD910C5C228DEA1EAF456882C1115AB71DB15E6832D96607CB79C8B7AD1CDDE01966FCDDAA0B0BA9F264 + 54: C0A7EFA24590833E4788BB117D3AB3CE00C84CB4820AD9FD7F03CF1CE1A8983F9906BDD138E1943D75ECD9B98D5AD8D3 + 55: D056E9F831B6DBE97FC751453B1C52C8C6C4D18A00050F5AF2427C1123706375A918656D6755A4C950F4E5B5C318CEBC + 56: 462650CE3981EDD13D0FD2E5FDEA93A9A18CF8FA74CD6142DF4707E604D1F72745D7EE08AB13AFF3A9F8D166EA90CE3E + 57: 2BA5249841412584B161063087AF9F5BAEEFD97989BF8A0455E65C94B0663410F0E1BB22EA6402E59CBC5A23F24ABBFD + 58: C3B1E4B05A7593CC315AE15F63CE8D91C4B30E0D846A97B7D8F01FAA1B6BD7C9234EB153372F6CC7799A035E22A77EF6 + 59: 1E652653B9A3CE862DBBAF2C919E86891C5C03F54ED5970E8028F8D5EFB533B9C111DFD88ACBBDE516F0D4D636F5E821 + 60: DA773D5AAC336B6266D27A03AFDF3A151FAB302E894CC1D09B6E4ECD07C4AF4BE06A2D28D01669C7557FAE8E513D01D5 + 61: 8C8FE648A29D4BA78B3E0B944597E392A31E28F98B15280E1EC0A721C9ED5E3639A6A457744CC5AABFB3600501F5054D + 62: B443DECF40A5693F67B5BF5580A665DF6EB98FA9F14A661CD50D6635E0F78FB2943731AF363839FE6DFC0B4C49F9E849 + 63: B22EC4AFEE3EA69364701E5621E453A0C3988C1E2FDA54FDB99353F285327A534F7162BC54D701652744413B9A5D4CBB + 64: 40A22B7881AE8139941540540FB37C9AF27BCB164B6D1A3BEC709730BBBB413D1F2FD6BA4A7B7EA747FF45F3ED3336C3 + 65: 246E426C57E414575DF312223272819B0F49FF94953DCB94665FFF74FEAB049AF15160706AC5F702AF66478CF2BBA5BD + 66: 184E6E6D5FB55454EEB6DBE323BF28DB8CE60C271DD0ECC8BD4D3F1C2339B7828C1515F030058FF37BD53568FEA81378 + 67: 10B23FE1616AD5609F6F6C1D9266F702C1B5E6F7FA0B3A81406B5A766E2179D082854687701318A7B46E21FA67D2404F + 68: DFCC1280C5206F99A555E291AA1DE6F0A3AE4B49916FEED4337582B91D7EF094159556B01AC87BF7A8E84F9F53595938 + 69: 91BA9A641616449084A57221647369E2E69525A30B274EE5403FE95A43D0A7C2B301B61929D89222A3A03303550521B4 + 70: 94F59A7F5E68B942A5D66D3C642A78685F3BB400F4FF971BA576DECE94A353455277632B70D06EAE38329CC2298ED792 + 71: 21A9F5C4B1290D95A1F3F051A0158F7DD8A879E7861B61CC757FB5C729FE9A8BD46BC6DCE595D20649092B31AD27433D + 72: E4246F7DE67C3A08F18852F6159F5DC9FA4C0129A9F894EB610C10F1FB8B61B1C9947D742A418F03A00A7E11ADF436F3 + 73: 8D2CE8209B8362311D99D68DC2AAE6BE4CC8E52C03A97D99D0C5C15D8E24F1D3B51738BD27BEB6E773472CD22A1225C6 + 74: 7EAAB124A3C900F33DE06B84E7831FE327FD638C4E68DC8648EB619E3C7E5736A26BCDCFD3AA6AF34EB137C6A210746A + 75: 8B60F61A1AC2C6528C8DB07B6874F19B8D474859F98AF03503B115EEB8082E19D53F63D397647BC2D4278B8C2B741D19 + 76: A48D92BA646DAFF7D0F8CBCB1D574E9C19D396A30573A7404F6196FBD7E226731C8AB05138F7B1936986DE6C1F1F7B52 + 77: 2C3ECCA6E7AF0F9587E5A03D462C98F18B8C13C039D02D2D29E06B5309EDC82052EF72C94E0A5EB7FD35827665CA2F92 + 78: C9B659AFAAEAA8778E9E4E3B725F758768963C55151A54BD9DC191E1302ABA1F1F085D5443C46441793682A8047211E1 + 79: 9A76E83A301C14AC6AB8CFB29D2CE39E0E86B335F2B20C3C889651B4E0B94C5218E910B1DAD28474251D06D12D47072A + 80: A526CFAA2EE981A9A4D0EF12A6FA363F562057BB75A218F4645BC5E9BE7CFE7EADFD87386AAE1C607D812772498ABBF6 + 81: B747819B54CDFEAA751FB9F5C22FB269151028BFBC6650BC518692944C5F4195D26AEC45C9B4C987ECF4076B3871C5CF + 82: D45968D452B5349CA43A0FDEFE4A5379381625825A27259AD9BF5A80C46CB07BF1C919FB3ACC250D73238B11C3A07D90 + 83: C0B8AB0F8C497ED9562C65091DF1D80C32C57A018B00957BF53C41DF81A2F6371FCFE82624B2E84859114152B36B6AAD + 84: 30D2BF3DA80C0F37807F042FE7B878851E0BC4093D987438FC2B993F4CC4AF6F704669938B9E30E59BF8999883639F64 + 85: BB782ACEE42930922A98F65F319089E9B4F5D2DD2374DD76035E3178DB4468A3C04F5EF878ECF9ED757DF14DD89BDD49 + 86: 157424F30A10748940BBFAFB6D99B1B06A897E7DAA4F03387E5ED03F02D39AF59F96A20E4E9F3A4C5C07C20A8FADC8D0 + 87: B9ADED711B1E1537A35AF882F1F868D964B5898E85B07F5677DBF183232F36C14AF4D9959C2108D9313F8BFB14830B02 + 88: 7C4563BAC3C05444C3682039EAF9F9EC79B96F0CD36245F584647BC444B81734D7ED4380CC1F0A2BA876020E55660BE0 + 89: 9811A4A45CB28A780C063047EC6CF94328102DEED9971DB99E11C6FBCFC046EE38C1A00F290FF64356B9A304DC0F340F + 90: 09A69D3255EB08E9B3CF7CFA73D86944CCC91DEEEFC04214F8982836726CAF006A3FD83F8FB75600CBD060ECD639C388 + 91: 52D6D0943728CD2EED671736B6B3BE801B811410992E4A3BB50AB4269EB21AB945F6A9F7036DA654A7F2785869335395 + 92: 8C0E1052EF2B06C0C20F67D92E51DFBADF3655FC6475935426AE1C88F3096628EAB9858E5470FB98A546EB11C7B752DD + 93: B21351AF8400B9756F104599BA4BB78C2904959E2B24AC3E15FD0398627E6C8D57A7F9FEED63D8638A206BC1683794A3 + 94: B9F7CFE97C79568D62B07F1EF887C4391B48CAA669AA8495B71A326B120FA49652F02EC0D53441DABA1E104AF091E0E4 + 95: 69D2D1773208CE3BF02B38A7F14910187F3476817ADCC7A1D9830C9F25F112E604AEBB95D0237AC8795DCB23ECF52927 + 96: 57A9FA7CA61FA2FDBF0BC3E3E6463901B3B26E5D9AD79DFC0CC77F79EF3AA1AE3949E7D71CF794E067D2E38E7038EDEC + 97: FEE9196A0A1199DA8697D00AC8084D6CA1F867D105EE928FFEE14E5E36BEBEDE5C79509CA5BA05E36C3F0BAFDC9A755B + 98: 0E8DAF8BA4ED614B38808B4E468CDF88EC9B148017C6BE3FE593410D37D9B50ADF0913B7844FFDCC2F1917A27A58B352 + 99: C7FD40463E26D6A21373EAE14BCB7403B127A1E23E4583B2AC727106B07B849F74C0907804AA799C05D9FF324D04B182 +100: 16E899F4850512FF3DB0FCC58FEA960831364E5FB077CD8DA3F5B3F0F50AC626601917E8355E4847A00E0A5166E786D8 +101: AF2DADB17605DB3CC471C00D63C42F75F815594C1B49D9396BCFE7ED4D4FBB1CF15B542675DE8C9FF50EF81B72FF72CE +102: 1699A1EA2CAC707205A6BFAD8DFDAF09C8D6FCDDF2BC14A9678453463AC80054627F2C39B713861734B0974F442D707D +103: 186DA71D7E913DA49D8D97101882B1282841D41CA12F514C1B2DD61543E330B751E9F97490E18A4A37FF1853EFDD757E +104: D82050038E6DF6EAE9D2D4019827025A25BC8CB15812E0ACF4B676C799A3D80ACAE5706C0FB1FF72B2C4851DC9232B7C +105: 1657C99506EC8B28AFC1684C4A9EE4970F8F426E4BB0C3FC2795CFBA82913B453C87D84AE9B32897A4CE26FF4320CF23 +106: 9834E936482592BAC2373AA64806FE0D5C8FA92143070C61E594004F0D3B8516C2A5B0244F273124E83B20FE9A2CF5D3 +107: 5C4856A82C8E6E49BB81E89C26E355AFB75EF921E579EC4B97868BE2CFB4B1D93195ABA0500D774C5365C2269FF333A7 +108: 67B88FAD5085C8BAB8E194DF73153A5B1D334431227DFC619D5CA5D5605EDC7BC95DE33512B2F5B714F46F54E1E61B0A +109: 90C6A8F36D42C5F21A89417AA04D822A53110DF1D062E0C1A6FD9AE59C6588CC1C78469B94578B6D7C05EFFAF7FEC26A +110: 817C0E7ACD548BD3733792F4F8D845D7E4B3CAA0F0EA943B51235EB82DA7C8B77A733D756E86D57EA303F34BD97BA1CE +111: 7FF397FB43DD909AB80BC381EAA4BD50B7278DBF10F39FE718B421D6C07324F398BA5B1DBAAC64137267DE2C62F19F7F +112: FAC12B732122E18DFBCF8DC7382AB1B55353134F07E07723608825C907DB05B4FDE40FE550878D971F8B0B0953C88C54 +113: 4DB0FA3C105D64A9CAE84C0B5D7AF0955F6F58717F68366935FF9F478E94D3969B1264B1F37F8F5538BF116DE29438AE +114: BA6E693A6C3C5B048FB7F232CC5E12CA71662332EBF689AD75F6F2C54715A689CB1F75525313FB8B2713909EC13EE0D3 +115: 00BA656BEA25DBA36861B92B356C3DEE0DB1C86D4503C7FEB0A88A3541A7018EA456C95224EFC46AA31CB625421BC811 +116: 812622078CA3B4F59141569A0E125B36F7CC471F76B7B65FEAA1F1F656BAB6A3CD61A4D2456E2F5109274B2090C1F4CB +117: DBDAD8926A811DD0295C31D55AE0D41672C7F22B5CAEABFDA2C1505B084AD01440E9B8FFDA4DFCFBE281222AFD547E29 +118: A32EBC13D689B31617D24E6AC03CE6FD7B1AAA2BA78CAE2E24C36A8CA7BC74ED9BD4CF6C74E3C96DEFF048FE3964F0A0 +119: 095D2C8DCF88F69DA4CC49C64B03B2A1D2C6922CE0C6EDA12642480AE0DF35152B4E4A9AB08D6642DDC313C0FA01444C +120: 578A4BFC0CA83F1B38A0D2EABE2C7D3D67436B559624B92E4FBD9241B2CA8C1AB679B503A754D5029314AAC3AF225F38 +121: 25E321E63E4AC8994FA464B3E2B687150007D83ED8D6E1B217E86B0CA0D163B0B9686E4FA2F26C1839F2D778EDCED86D +122: C761BA17FAC3CCCAF2CACE92283DC5E5B8A6571958FC59D0070FB21CABC88A80A40DCD56318988F3AEDF38AEFBB84EB2 +123: 5EDF5D71D2CF85E7ADF9C7E964FD628ACF304C4DE3483F672666A583E3D9B1D86E9E096541ADA237D69A140571F5B3B9 +124: 401702CD847ECA2BC9208F52F27D84D07B37A86CCA5C3A877F24366CDB9719DE63670E850F02CD02C6227B7214D5DDA7 +125: 362C899156DF70FA189A66DAB6DBB3CBF80B629D1E90D9ABEB007C3C5010277EA589C4D73009C81F94AFF3FFACBFCB1F +126: CA43387C71B8245B822D3085CF029004E18CEBDFC9F78C276F3559D962635601957B6D2287089AD43F3179D077F37686 +127: 4CE8504297E21812C901E77C6680529103A017553F095913CFF06AF20E3D6DE7EFE911B636DCB5791B292C60147F6473 +128: 2AC71958C77E39D4DE4DACE92FBB6A093EABD191320A5ADA7114BD201DD026567D2B799EAC78C1F084BA9FAEC2FC8BD4 +129: 87487060C273FE18A2CF1DFF222658E1B50C3BC5A3F1F4575B3A4A6EA2F42238DEB68B3A2EC6A325E3FCA504B2E20E26 +130: 4A79A1C3C798D9F26D54715108279948EAB246086EBFDF0EAC9152216C0BA3A77AADF82A230AA84A7C884063960419AA +131: DB0BA43960FA6B763202B8BDF3FE4ADA0BAD78EBB3E6E8E57C2D5640D1ED4CFB4AC18ADB1B9770DB49A4252CDD25A369 +132: EECE296E258EA3583FBCAD1CDF2B91F4D2AD1FCC1AA339D8F591F89C7ECB5EA2FA644954006F0A58F2F3BEEA1AEAF7F8 +133: 7AFD95C86517BB6050D04BF3BB1448A0608411B612A7C2A939BB44B984E361C40569E5E57AD7DACB018689C2B8E2B3A7 +134: 7FCE7894C8E8D1FB187CC35CF5758269E286427A63A522F4BC45F814B316C1DAEF981917642C50EC693F3EF4DB8E66E3 +135: F67F56C98221892F64E2AE4325CCB80C2846A43E1629D40BB50845184E9C3B66480B3E9F792389983F2FC48FD2508F09 +136: 1CD915561856936AFCC75530DFF151F49A34D0DD0030766FBC1BE47D611F10502BE86C97B91D0E8767D4F38913EEDC1A +137: 80D9CC8B1B2B883C4735B3C0C19AEDAB78A0771753EBB4688A7E584BE7366B3C181C8532FB3A8BFC484C9CB0BBC1B4F1 +138: 8ADE2B8527C994EAB0807A89CABD5B075CACFEF42381DA3CC3D702316842E25151C65A22E80885E5CD5FB5870FCE501C +139: 2B403F2188D086327C92169871FD5A7B432D2EB999FFB0F2369B2B766E799AFDC1463CF4D9941F828FE42591D6B966EE +140: 4A0C18CECC0641C28C4136D42FABD0BC27FEC27C2587FE8A57CE0D279ADAD70F80C1E812E01B26F2BF3ECDC7673C349B +141: 8906762B63651DD5948C98DBB1B39BD6095C1438B2E4CA4B5A581D451AD3EF76C8A0FADEC9C0B0036A833D8F5C13F1C3 +142: A363BF2A479F67F949AFC151C36B052062CC2CE840974BE2F5E79C0BFD7BA29008A6BFDB55B46527D17F61531C953081 +143: 4E2AC5D6EE56567902CC1E02F119E33974762C03885EB7DFF7C58ADE22E56BC384FE74BD491EFDB2E6CF4021E3016E81 +144: BDF0AFDF17F7B014A61ECE257F8C7E0B52384EB7DEF60ADE785F273851D645E5D3B4D9534C0E6097A12C3CFF5C11D42A +145: 0CDC61FF0B3D8510C319020B82C1C5AA12C7B6F257D7D4F118A5EC3CCE03C63FFD38710F8A3C621DD8D66D8BF3790B63 +146: 19E35E1E785C7A41C523F88CDCD919EDC45F63783330D9033768546CF59D10AEBC77F013057C0E41D6FD0FE77DBF914D +147: 8AFA5DF52F6581794FF014A2E1ABCB05781C7F44AE6F37112B363AB13FF01FE1E8074F14466A365374C29FEB048C5B9E +148: BC9ECD12706BE5ADBA04DCE84AD53AE1B324F99C1F5937774DFE19C5EB4D6A20982E97B8F8E4E02EED13B25B8B13E64B +149: 8D02A1E318DA1EBFD1CDDBB7280F3603AF3AFA21B3D4E0727C7CFC576F55640B7A978B179EECDB8FBE896AD38E82F12B +150: 196929CF0849022CCE9CBE4EB2DAF6E5D8014C5A25E119EFF799A82053035BFDB8B05F6C125B1DBDD4E7B393C684FB5D +151: 58808D04067FAD72BBEEE4F6A355E80A2FF76EDBB5366CA43FF358A842FBFA2F9E1AF5FF266BD2E2DAB1D286AF5BBF92 +152: 4A548031093ABA730D8D99A2C1C6EC2A986A94167CF8C1EBE83D52B34BC2068A4C95665988FA93F5246D0FBACDF85FE2 +153: ED949965036F16A0B5856EA4CF69CEDA35C653BB56FD0F0B397E73FF4884B3E679ECCB19B07D6A93504E82A1613CB87C +154: DBA644B20B01E4AC5CD0A325CB063EEF53AD77E5A9E7095C1BE0EB0E6B7CFE60BF25F38CD57F2AC055D327EB6AECC7D6 +155: CEFD6165F70D9019866374AD7AF9C73F3041B932D61A41734E39AE8AA9C7A4FBF1DCBAE9B2A4E979C64352E3CD4E1B95 +156: 732C3B457F78DED89390BC461380760FBEF3CFCB9BF42A6C86ECF120C821CAC79D4D51C71A955309E33724742FE2FA0D +157: 54803568BAE2DB4F143C78FF53B85E6A9D42EC3894FCFB39BED8EE611B36BBCBED834D366A1F797B626DFF3D83CE963C +158: 35A1858E567FC8A11B92737E369069B12502ED3F44DB50434506F2E540FE643655CBF806C06F15CF2428FB408A65C04B +159: D1F9E930418D10043D0E83096CF717B79C1C9234C741C59436F42737AC73BD39B3F4B6D6439375E0D44260131B25FDE9 +160: D5B56A1A70C47A3F88C519668097B54C989E119EE9DD5B8B34F0DBC092FE7108C9D396CFC62C9322563EE72A0E324010 +161: 1578BB76F87DB309A5D3A2229A2B346DE39ADB623836EF0561348ACA7E315C16C6E31328BC70DD0B0D7D9B7ECE076CE6 +162: F8DF4C71F3623ED00EDF8EFC4E0EC154644E21E78B06C9C5ACB980480732E17E92ACFA059BDF299BB6C8351C6CC6AFF2 +163: 090DCE25595D7770753B78C410F10E830140B23D779E0F52FC451582CDE7511A390450F8B65D7BDA77A18CD95EE3DD38 +164: 5D3A56D23BEF1324B1EAE33B8255F904F7DDF131517200A505031D41A2EC3F2AB03912DEFF6BCECBFEDCB8B948CDACA2 +165: EF712AC1E6859F70D0D2CACE7AEE120A666DF9F210512F5C94AA7FB388F1DDD913A12FF92CCD2537675EAEC870203411 +166: A0E6443505B193D89595A51BCBD47A46E1B5AEB239D68B8B18A119E5C9EA1EB8863B373F91B9F22FA944C29365406A79 +167: D97DACBF80BCC76335C187DA29FF33F6D35EA8A8925709322EF3C0F6FE35D128D9D423F911EE31F1C38E1DF36046E507 +168: 67FFCF0A9F88F84B3EE85000B2DE0B7DC12A06160FCBBB57BA291DC04E14B6DBB3CDB81A40C2EE1859956DAD097C1EE1 +169: 7AE82196B46DE3E6948D7FBC7383A6F080903D6BE6E357700A87F82A964581D375006DE35169446B447537B4F11C5702 +170: 502E0A4CF125EC0640DC7E7264D9E47300814B00D4322F2F62BC1D5F1D0D77173B0E7C2874CD59FD8E056B8F38F78D99 +171: 74FDBC4532534DBF24230ED5677A920B12E328E3D073364498D80F0CEAFBEC774EB53F28F0934F787C56AB794B60BE31 +172: 3C9BF5EEC652F40AA0ECB82A834C836E495E841D337E1299AAFC067A2049C540AABE92CAEAE02F099BC4D3A383D541B5 +173: 105AC61F2D4E586E376524C488C33521C4D49D1F95B752D27F49ACD7181E8FBBCA2E0F0B543EFC0CBD32A5EED2CC08A2 +174: 5CA49D8B554D70B3FC467604661DF8FA51D9987F2A77B13DE44D7809FE2956D21485B36F1D17B59F2261B1B40553FBE3 +175: 1DD075C696DB9B07510A0D276F8BAD12225E00515D19E3B85583BF97CF82B5FE3F685502F64D91F4FEEE1848BCD0502B +176: 11A018C4B213BC67C09370C8A3D0B720428BE71C01C6EE9EF6C9C9DA8B2E1FBAEEE42FA44EE54D0F526DCDCD3C2BB2FD +177: E188EC519C6E0B8A89DE68A7648DAC6D9F84FDAA678B431794EB4BFE077901C95FAE25CA3D39D48EA0292F3F6C35FF73 +178: FABEE0B0A02BA622931A5EB82CD63656B47A20D3C0E703D5A69AFDB92C0A7EC5CF6944D9D7A141C1255D60FF9532B089 +179: 3C8E0BB55E099CA9F6E436BB3CA39D511AB9CE5674469DF8BEA4A20193084AF8561D5130FDFFBE62193A712D7C2D4B48 +180: 914BE8F0A58082B877AF0DC077ED146CCD8245339A170B4099B146476B0A580749D01F83FB52834A033A3822D12041B9 +181: A1B31ECBF451571437DE10330A6E9AB4484576AADC4DEE0B31D9C3AFE59FC6DE028275126D7882A2C225EDFE491305E4 +182: E4DD2E805A5BDE3DCD329ED9D35CAEC2D5A97082966186118DC46BCA7AEB1EF52E0C6007CA28131790838DD8C00E96FB +183: 785B81A972DFC6A4982E0BB76F90F26DBB7BCD2D06E872304CCF6AB2D639CAD85FB29124ACE411EA4742468A6663EB2A +184: EEC3CBB5AA129C7206A32A176482C9BA24FE60E71B46F7C3C11FEF8EB57682A3732680E6541D5878CD6A715A48D75F12 +185: 254E279B7C4F17B911712BF7138E2C6933815BAB18661CB47388FEEBDCCDFFFB6AE8B4B88072B90074704EB7EC567843 +186: 9A8CC3FF0D9637220CF2B4AFC9A8A6CBA4D0ABEA6A0BAEBF151380848E92DFED8C0F0E57B6D05095EEAB0A58DFBAED13 +187: 349966E1D59BC9B32E1BEDB050354177868FC07257A3A1800F0E711AD00AE388746DB1E4591E3ABBAD8F418E1AE627DD +188: 84ED950BE54768557475E6B1A256C30F444E12340C29485832439BBB9CBD219050D184624D6282728D4AFBB98CE4BCD6 +189: 2A7CA4EF1A9356E853329D336B6E7E033F2CA13677BEA67CA669EB7C78DBDDE67F9E7D9099C68F34E07B96DE4155AFF2 +190: 7C7020B0528F1B3F76BA258836A89BD27429110F0AB730FD741FE9EA2714AF827E71B731AFD53A293328788292ACFE23 +191: 91400ABC089F8888DCB22880B87A380FEFDAF81F237D424F057E5C4C8E3C8EE4E423930C1D3D9E16199ED82996BE4232 +192: 412979E13B3D143270BB41FEBC12196B981E99BFD6687B780812F409C78A5E2DB7AE828994B60D26CA4A1F7A3A44C64B +193: 02BDD417852D9B03A37338549DFB6D765EC4CFE4C2385002848BA4D46F88053FAD2A39DFF615ECFAE0D41F02E5877251 +194: 77845BA2210971E362DC117B1BB13D7DFBA62F81EEEC7068D3CB9CD093DF535448CC357ADBF0C2394351EFB07C3E7DE7 +195: 0F43AA1739359C14BC5702322F193AF89335887F9175289933B2BB3F00A777D1D1DA74F5D45FC43AA90C9FFBB0CD580E +196: D1D9A7B995B9BFF09252566D2079121AB12B0A5ED06014994464FA1AA18CB1BD8E7D5E07E1C71E2EED9CF081A537F28B +197: 67DFFE8A168B7408B7DDBD10BDF14F4F2244FC904DEC5850F5D8302FE35AD1752BAD2DE50449F9C12182A2AAB8FBC9F6 +198: 030B5E833F6D8703BD0C5E36354387AF833F466AC812D4E1FAB6CDCD3146FFE3B0E56722D671FB85EAB22CA5CB0309BB +199: CB992B3785E51EF3A32DE88073586DB045F356F18A09329E82943E29A12B2D1490B386D8CEBF7D90FB492966989A73BE +200: A1D337D363A0BD8A0F2342351519C62318A120FAF88F9B90330845DA682261C64627B67D2F533FC48D2BE394DF8F4F61 +201: 319DF6326160C7277A3D3C65995BFB729A69B71B40C149DB1241C0B2376B4205837B5770805C86104677917EE5E5912C +202: EBABE3BCAD828A9A3D5EE05C5EBA9605A67E1ACE73AE69F20BF435C3A14AC63E43B61021CDF3FC2245A14FC14A7AB32B +203: 1723D844C0558D58EB3EEE3286C48C133C5F6C1D8CA512F2BAF1FAD7884D4FD5C3000A6756DD1E34E83DD066AD2BEBE2 +204: B048BED188BFFB8FF1B14CAA0BACE82605AEB1C666283FB7A6FDF216742F9F64A89C50B9852B8119B5FAEFE64615C241 +205: 7FC6E8633CB9B16F553ECA3C75C0C0F7B610010853EFC94AC330D36977EA8722B970DC264D5FC4D69F39105E7AA0EE3C +206: BBC6F0E0158B6DD549C5BADE0FDFE415747F1FA2D2A85CC9DB758F34998FBC8C8D99D573CD948EC768540B363D67C4F0 +207: 5073FA9E162BE773AF5BA1CE5E6FC21F2F0F902C80F09BBC3AECAA6CB1867DAE4DC011D1DB987642949E8095909CB984 +208: A641BB0E1D20D5DB0C5CB33D35B73ED83216F2F5DDD5234A0BAA3B209A39E015B7245C40F9F372E618EC73450487B54C +209: 948806B7335EDCC7C4BBE751844DF5717457B223C7A3B81B57AB3A949D0A726BAACFBA228BF6C2CF94E942F9B2F1A7AA +210: 0451CD5EEA206D50A7897F495D648425CA333158C126C4DBA44ADC06447A51D3C7BF2D4D81779535CAE29792C7FE5650 +211: B4227FEE0A32009D60C9C30033C12B7143D4C7A1C25F39F3E4A076BC4943992AD299DEB2C15E27DF867BF948DA27C009 +212: DAAEA18FA433CF3E117F2D43303139D3F1D8C3BB8AE8EFB30B44B9D5D4BD4E553B9B6EB9019CC4E1AE5D0DBB6C23A102 +213: 4434C818BCCFD92189A3A466D2757AE2655BF0D6CD954706C85220A33B95B184EB560FF3CDDCC4DF557E427E60F9FBFC +214: 6AA3B44FA507B6D704A66B4D7F26CBAAB2B400C6BE0A8B61B50EE617A16C2C09CB36E72FC309C6E4DB24961B1785CE3B +215: 63AE9C02B96B4BC456FE5CB9BA35366DD69E78DC9CEEC376C6780703883D609333D45CA577A982A177515674B975B658 +216: 3B5DD4CCBE8CDF32009CE29FEE4F6EC7CCB1471A3F8E9BC9A35E8CC37F6C56957B757DA4C3204F9014977B93F9E30DCB +217: 04A6528CDE6BB9F425132CCD4AEA1EC6CEA482249E5F3782B000FB071A4EB2434597A7FCE2A364A9BC9E0643A8403DDD +218: 69275CA1F9F102925165A568C1F152D25DF8820A6F34595C4359159070052FED260C55FFFAEA2116AEE7A63DDBAA0160 +219: 584697C23C63904709BEA89F055AC592DF48034F908C9F06C706A51C3F6BE5F0F2A5B953AC2119FBC0855B785326C06D +220: 04221F0A6C4799F9CEA3C1D9E65B9F77F77C613FD114135DB019D8C497B8899513AA4B499E720CC11AECADD1AC071DBC +221: C7B878613C2F2ED10C8EA413970B124838F11F0414AEC89A3825DDC588629A8049E82B461A23F25C4F93E5BD11C184AC +222: 1891E7A51768E05BB1D03A1EC1B844C7C8EF77C433F700175998B2D8E2EEEEC4618F00003793C5873655E093048B674E +223: ADD2B81466BC727AC85DBE258B566C4DB56F6F7D81D7A4E43F86C125F2AB2E08C648E628B9CFE440F8BC06FD5D861D3C +224: B3684BEBA86D275745CEAF0922473CA581CEB7371C5747EB87B407468006BA50D69F9BD8BB7F214185CD0D0C548C5432 +225: 0C783882FC826917619C07FD03FFC46DE6CD87BDFA87F1FB872989489C32FE74E8C5660748E1E8E9AE19C68B075B0EBA +226: DF52553B4F7BD148574BB47F61BF8F7B2FDBE5B6963E29CD559F236BAAFC3DFD6A7EB5EC9968E0C2B3A453F982F16AAC +227: 45102671440B04027B1F9966C1013AA351CAA3F3CF42C4D98F5B2D030FF37836E9F5865421D7DC8B037644FE53C6B280 +228: 247396BF60C0FBA27B245CFCA061D1F6EC50CB87CEE54E8C4A7186A07745D255E4EF9457C0A329AC9E3FC913DF86A4CA +229: ACC5998C464A26C1719E9B17E1B8F5E3657FF0364C46FE87154DCD1C95A84734214D2B81CEA8DDBA501975281EF4EA9D +230: 163F5AE385500C1A6EA212D6925E48CE2189DB1DD47F7F2D2D889272D17449A1C33EB3970A5982EF2FE5F1255367C33E +231: E8BBFF2C5CDA88CB60BEADB8D04B88795B0CCD89057CEFF1FF588A169363AD453564FE7528D1FB7148845363C3E17824 +232: 5F8671B7C62A5EE9717FF80EC2AA0A03E557A2840C0FD0B59027AFC834C051CC9B7BEFFDEE3478165DB9CA303E2D874C +233: E0E4DE22993E4A6B4884163C678A23AD6349DCD4C16B9041D01F8B3FAB1E8D8B07DA78BFEB57F8C235C173B2D238C4B7 +234: AD6F58BFA15FD0DF1191171F86F2B4C8729FE407128ADB4FAC3404E15C04752F2A4B5F4BDD488378C56FF8D85A38E583 +235: 90C5A75642A1811D8FC1ECB84AF4904C6D9E613353C1B9ED0FCA37D20974CC2425052E2300738824BECFDB981AFF06FD +236: EF73A9E6D23CE43508400163CE6F3E8F7076CEFB94E549EB6116C2557F740D66A1727AD51CA645A7F9022912058FD262 +237: 99FA424E413A57DB2B1B851098FAB1B6D3337AC7FA85709121F0BBDAFB3EE291F44092EA7EB28E9BF0EA0691AA531BFC +238: A1E0A088A279E750CEC429D0AE320B638ECBF9EE387C65C66D2231C884D844DCD438D4D4E052B8D76998A444E0666629 +239: 0657FBA0E7A73F7525505235120C44AAC6D37CE974FF23F52872D6ADA50DA022D417D8DAE40E80336846E8CE211D5AC5 +240: A72ED7917F0F9D0DD888DAB10AF9091A380F518D5DAFC005D1EBF0013F57A7452AEBA98913F509509A02665F332EE255 +241: 74CC959DC6CFB31CFBBE9CE8ABF32D1629E0F578F9199B9A2E90889A2F032919923142AB32E1DEE0A53ADAFAEFE0EBF2 +242: 9E4D463D2E3DC2B98CBA40EF84B022A76D01926D8DE6AC05F995C07C5F07D01742C5410B240240459280D7D278E8BFEC +243: 0D74C427EE654E4790C7118272998C131337D0D0555B68F488AC7CB8DE3CFB461B0248E78340D74B828C80CA28ADF478 +244: 952F274ECBC66B68EA74CC8534A5D7EDB219B755C91266E5A779EC22F52DD2EFA9C447DD311E71C90E1419B4B2F3DAE0 +245: B845B0A56AFEC2FB399559FA77C4835D2BC4C3F8D62BEB1C45462BAC661D2E553B43D0A86073F0BA5AB85B129ED20B1C +246: E65B931E25101224A6933FAAE7DFCF22FE84759937F5F3BDAA90D9C8E8ECD0BFA1777B99A77E3232E38917F9432CCBFC +247: 4F69FE2CB97E9233BC873D153ED9D61B88C20FA333BD4137A532F4F703A323FAC6F8675D8B44EF5FAD2314894F7D60B6 +248: B36F43A6DD2917A1AA0C6B566599C274701BDF03A5B7DC65E5E9F0ACF882786F07989B106A50D0D89629136EA0E26EB1 +249: 8DB7B80635C53DAEF891B777850487E72B67F57576EB05F708786F7665F1FDC2A78F441636569D1E84058A43F0243A1A +250: 14A43F1882AE0214F56819F4AE9276499D39DB4A4A939275DDDCDDD80CB6B70999E6178C4EF295E69A807EE5FDBF9AFD +251: E5AA44CEA67F0821D4ECBC981F258837A243FD901653D484BE5C24EB7F08E0BF33525EE3DDF9A89E1263A853485B5A02 +252: 0191F0505CE5512FA08500BDC090570F0C430161595894528FE7AE5DAD8726E110B0676181A228A7A90E21B7B055361A +253: 76FA1230972E771661485546D6CE556FCDA23B6DC0FFE94DD3BF7FF13FE9B46DCBC8D8FFC617F35687903B972FA7EA43 +254: FE280E1191D21CAE12EA3B53D77E03EA4D96108D35555CBFA9B156253A011ED91B857B82D644BB94BAC8E4FC4E0142B5 +255: BEDDC3C0E168A4B14B023DFC1AE07BE9A418678494C2399695EA9B17843D373077A708F8C82F37657BDC101950FED664 +256: AA5D7EA1126BF16DA2897AE036E94D1F96875AD306B19910EFE3F17B7A98F9A4163E4032EFD17DDBF78FE3321047509C + +HMAC-sha512 + 0: D29B9E3F87809686F34109FBC718D6ABBB09C278CF05A206ADF21463E1170362122E58272A31679720B254CBD63A7C6D696BF9283F9C6897E7D792483BB0388C + 1: 5EC18FCA20788348244720D58E9532B4B699E78D48CF7D7BDD1A4E5C61CD09C075EA7F112DE379FBE953332C6A7D6273B3F6360BC07203A5175FAE618E4A2F55 + 2: 293D275FDD5021716117D2B85E6D38F8D60D4984BC73E2D8D7EF5942CF1287B65C0675E566794786FEA18AED1192A024FC4B3E0505D91E1F91833B210590BFDF + 3: 8D9E222D6B16C58B3862D6BFA556BDFC2A4A152BB2574C2294D5381F6E38FB681500A6A19D55525B337A467A2FC30DD1684832FFF92AD071EEF05BC4F4399FE9 + 4: 71E7028F8C4CE9C1EAEFE459771528D26993E180E616D68355B9C618153AFF2C0E9620B151C8F733E71180EB87BD773A512B945AA353029A8F807FB2A8FF2264 + 5: 589F462D37095693ED0C1F3E0DCB892BD19086FE033718911931509EF6195AD17C79939A87665889EFA6DC19A69BEC6E7058531552832CCBBC06F1BEC70D1736 + 6: D94FC6BDAB3613271522BA05C998A6D1C57CAF0E6EE929651762F257E7EEBC07F5CC7CD3D4064A2755E408B347939B3927434556B4ED49CA406C21D1024E6D80 + 7: 4D8A886A89E9C60EDA3BF0BC512A295196C3F62018936DDB24BE9F6AEC7AA9511B33CBEC8A22309B6389417F4E7FB0489981CACF03DFECF7D9FE5B91D62BB719 + 8: D0E00955F0FFF98ABE885970EE44F1B5D4C23C205C64B681381FA13C543106B2AB4E762FD71F47008B4C429C39ED3D66B3EAEA946674F08684AC99F957F50416 + 9: 4F623E52B5FA2D556D25754FD00BB8429356FD75FE2EC57EB4BA4E25CE03C5332D3A632179C9FCFFF140E6B443A4285F4A7CE881E6D3EEC4FB0DB26C0E2DCDC1 + 10: 5196EE8D442E5308F9D8911C87050DD3C4842D0CDCF55AC554412CF096EDA94BE1A251743AD5BC5F8AC902A38B66D7D57C90C29200984572D57C04F64166B803 + 11: EF77019B0F93B1598E38D3B1B703B52660192547353E7FCD5A7C8525DBB516970D3A6F2A94729D90A5A34CEA255F310C1F46546C2A08975AF477DA2F3689F17E + 12: 0A77531D7081095AC0D0ADF2B379D3F820DD20CD89610917E287FF57BCA5DEABA750E1E075DAACA9CC4DDC74732E6F7BCCCD3671B6DD27503CA855EACC63FFB1 + 13: F1E04B1F7B09DA270A44B62DBAD2FC0160BA1D144D7721010D77ED250A00986932CB6652D95B4A977494F11AF7E7FC82A70DFDACFA11232D653B1A052820185A + 14: 7BE1855550A49FF66D6D395DA7DEBDEAF674F1AB192DF82D74F6BAE8088F83EF1471F413CE00A404486213E41B42CF6C4F7FF1BFA17A1E28928B7179F0A966EE + 15: DFF2CDE8856D811494F559E9F4159065A50B1E82961628E95F04D595F670249A2B71C2625CC1CC2B1F85829255DA007F0374363EB749E935BB72BDA24B8A3F70 + 16: D2F7FE57D9583EC1AA733403527DFBB118DFE07B2A60C43039FB238A7205A053E0496AD0F3C1896090AEAB3088283C8FAF272D1D53B5F9F88281E0A53FE7F8DB + 17: 963F629ED8F0E7D6D4CA4DC8A8B57C825F726380D0BA9A9857459491BA82F64A929EC4ABFCF79374CA68BA812E3A83A643D05454E146E9F4103D17E20B8350F5 + 18: 1FDAE69CA4A9FAACDDF30A56B23F14768EB7D5616F6666B6F01FE5E216825CD4201A69CE3D2D1D2C3D03246BA7D32ADCAAA4A7D03B9AE6AF4CFBB474E1717BCA + 19: 2532E98B6D91D8D658BC1A1FE41AC719D648D47BACB423C031A8E2E9C25CC6650D3E5DF8046BC3532875F0C8DADB38AA911F216E6741E9FAD700D31269EE5D46 + 20: C81E6E9F4B75A4EB2B903C4DE28CC437CD87BF789F6BE60EF521491CC7E44AF26E9EFAC55961135F79B3591F5F7B92ECDC9917641BDC34943C6759AAD9437498 + 21: C0C2B9478F956800B64FA408BB0E077FEF48DE4B146926B3C577C00688829FFA6540AD7C211A807286C546F7D146F95989E77B62F5E14D62FE0C77C85FCB6CC3 + 22: 980D06C1B27EB2EB15069566BD1BD838FD3DA453751BEC564C05941C9BFB9EE8443EECF84CBF8AA7DECAA294C7D1A3FA4A39C20A4659DF332CAFFCB2863A769B + 23: 70FB10E482AD19447CFAF10EB9FCFEE67F9DF7164B2647F19CB220E7D83BF892AB7B5C5ABB73B779522012BFD464D9D1B18C37C3F6CB70EC4106FA94F8CEFECC + 24: 7AB19BF67380012D3A53B93AC15E353D477FDD1E2E8851CD5AB5F36EA0C8B128D3193934F837D23D232F44009AC60DDD358AFC8D3A201BED3EAEEF74C03617A0 + 25: AAFC1227AC42CC27BBF78FE26B3FACBB7B15360891C8EAA8C737AD42C00971D02B3A07CA751774D02F402F7E76BE08E2C1241EB66242DB5E11B342C22AAB9FEB + 26: D8CC3BE5B48C7BEE8522BD8872419932907B78392B7F2546788477C858D0C7BD772985C0B0D202AB7E69AB5F4E1A0BC848A512FDD79EC29F19BC4BA6D28DEB07 + 27: 6133D836D68C82658F6263F794073CAD9029F20CC11D0A6CF589335B023CFD66D708F09136546C6C08769139363AE5CB4CC2CC86EC6911237ACBFD8B0423E377 + 28: 833DAC9CFFBD62FF0749391A42324E2848670913890754E24ECC29D4738AF00A78134660A20078FE59C66113787F4A3E6C0E783740B2F2B2BC8D36FE4EDE39ED + 29: A2F3BC0DF058506805DCF5CC3006CC4FC4085FD846C7A7A7DD3A06CD6DF635359F4FBE90A676DABD7F9AAF42577C8E3B07B63B9CEC8A9AD05B38D16F56214E8F + 30: A49C3BB487C561E5AADA4FBA2D9F5B42681486AE2DF56087DD65B3D5E03C625F709299C84C64A68D87C92A4CC90246D608E692D1FFCE2C099348CD0A19407C2B + 31: C8D7B7A7FFAEDE88963B09A09ECCCB4CAE77DF9D8D242BA19F6485BC7775308E5D11C78FE9C46E609F3AF070F3DA8ED929C103DA1F25BE7867FD4D3E4F2757C9 + 32: AD4627AFB02DECFF956E612537F011E82CB0C202A5A11AB7AFF55A201016C02CD21EFB4EB197BC2D13D272C6A830FD77F534E800B0AF1E79FCFB626ED6A0D6B8 + 33: 8D4E232D9614EA1194E60748496CFD32A4AC249BB8F08E55A7C9DFDA708DE90D067FC433EB9DA2A6833D43BBA8E8DBF31137A3C9B26903060EF9217471E9F945 + 34: 4CE5E4055F10F1D2182A7892F98206D9A120FBDA3251036B7EFEC835C95B4D1FE0BE3892E2363087D01948AA426AA403ABE1CD79F0AA851E2D1195511C7A85AC + 35: ABD65F8E9A2B39BFEF6EFC9A9EDEF6572489AE82034EF3BF2AE5F380026FF4CC40AF093F0408445735C0E6EBEF5D7E7ECC13C98B59807AE01FFE1BAB040FD14D + 36: E8C687D7AF785B1E547307875682ACD82FB58A8259551D81F309C923C2B1FBAF5935EE059B89070B8420F71EEE3BE7B1E3B55B196872F06DD1FB890F6FED11CA + 37: A344BE73E6585E0CC31525BD6D4EC3345D7780CF180D0D5C2D5FBDEDCBEA050A958FEB13C21924E311F57FD6A498756146AAC58412B98E4D2A3B29D9B77A9F53 + 38: F0A088CC818F76A1FD6B5D707B114BDE24245CD55E48611ACC6AA497A0CEF93768501B5F280AC518CEE48C15373118BE7B72F8ABB2E9FD3526DD1C18D9CB2545 + 39: 4D56D5C9222BB78E04DC9346FA9C4ADC27AE08DA3E34F490A13F674264896E58F9E9839715F633C7195B40DF722441275C84AEF162B513E673809F7874E7A124 + 40: C4B3C9E8140F0D5589E326916462354827E491F3444E0C361512E6E761F5E24AE1873B238B73F32F6BF8F1D1D8FF9437A01DACCB749282E776FF66151A4F7E19 + 41: 7B4E07BAF338DF6479E169EB6CC64CFF88167958D44C5CB6606964B7F9ECF5F3F1B1F695C63F2BD66354722F81EE4BC90B9FCF5345642E264C66F6950CC8C481 + 42: 8571A8F76A1D5DAA0900A03E236FE965D085BE6035B7C0601EAD338106BE7DAFAEC82F7C3D8AD346FF749B6DAFC69901A6072CA089B7A5724C75CB0818640F7D + 43: DF516D84392E571C3FE39F4A0BA5D16D866553644B4C4627D3513F0A1C60D22FC5AA4276A71CB37BD6D6AD05A12BF812A2D5388A606583B78372B84DC567431E + 44: 535AF3C73B479B61B8B70E590E335DC4C1E22DCA656454213E1FDD46D026B6D36133BDD372FBFBB27B6DCA8E487F4A54BDA8C5F67B37C871653C656DDE9524EA + 45: DBFA27964DC6A80FF76112FC6CC02C87811DF1ECA3A8620A5030C600561032FC374A6B060FEBE0ED67421D9217D2719F5A55621736FFFC6F4F26DD4C6049FC09 + 46: 6F69BFD2C60AB1554023A6A2094D30CA78D364501F7813A2CB73DEA94AD4B94A0EDF3A3698D6A30C8A5E764B81F51CD0CAEF0F996B8C685A345AA630CD10570A + 47: 2769DDB3AF3DD650BC381D7B10CBC4353699A2A352E57FA5D5CC4FB610E498767F49104ED0F4E06E2BD563F7F8045212F5B9C49CBE050A1662F2262BAC4053CE + 48: E50169B15772017CD9FF93D1B46AF273B375A39D174E3B8621EAC8EF968BD967E1448DC3B2C72A667EFAEBF2B90D4E6640698CB866075E95817719E0EE61DF30 + 49: 4212648E8F9ACBDC16D48CD7B355884E0817A95DB03BD9B8AC5B28BE6371D8AF83546DC82550B8B23DC77F6D06211E3AF3B25528BE686CCA1672C91117DF9762 + 50: 33C71EECDBE503A6AF72EBA8D2B9AA7AB8FA8DE536C87643ABF1BC3EDA535BBA64A8A7F4BAC90ADB7D8C926DCAB1D7DCE15D356C5074BB3EBC7B17516671EC8F + 51: C8EE9E57EFA859DC5553D03402AE80B84B1E0032CE3F2CAC43F8422A80E3EF59126AE7AB4893735F9C948CD9FA8793571E4582908DA19FC723A93C7C36F79F9C + 52: 7CABE0F83E90CF9A497DCE45F14F9926DC714DEEF05A1A0603F6436E134FC7C8346A19CB92DCDE69D794B38FB22233577BA3905C94A7020841224DA888B9BE1F + 53: FDC20554A15B71BA62F896DDC4F8B354E5D2434B0AF719CCA7DC56FBC9BD280B0F80136C4336D605C7C26208649F38C1DD0004C6E0E787A91FAA6075051FFDCF + 54: 87387F89646B4068038E011D7E02C353BD5649F6DA1C4C46CD9F7D69EB3A2F6EE84DD42D25B67BB81666CE8F92A5B1A0F3EA58D4F0B5B6E59EDEC86B43BA0CA6 + 55: 6D0210417671B66D59B8F28CA0EAFDB493C30A7D7329DF29194C53887F05EDC2C3F35853898ED77394CCC650E8D350F69598E3AEF3DDF540DACCED5BBCBAF6AA + 56: F14085036C69398BC7E0CD8A9D4451A10B080E7CEDA5582ED396E5D54441125EB3EF6EDE4534E788DFE6DD3DAAA204814097987981EC8BD8E39E8E8B35AD8FAA + 57: BA67FB4D7D137531D3F4CD3D91975255FCF8EABBEB97EF0FC7C21C4E25FD034658C63881B0AEBEECD2B7D15357C14542D26EBA3ACCA944EB4C4D7E44E9899D42 + 58: 4546585669E343AD40792308AB456DF623A6A23CCBE64B26B953D6C461460BBA7A3FB444481BDB3F7FC8D5E825F2527D2DFF193356CB3171CFBB56C679AD1BB9 + 59: 210F8AD68FCD10BDB8773194FE57EFF566C7E65BCD82BE6196DECB40BF39774691AC6BA718E4B5FF0DDCF2C0510182B9A114C6F0117A0BB0E1AD585C69D38D0B + 60: 29003A048ECAC0613CFAE8EC8757F5E5CF80E9B0BBF538D7460765FE2D6B56D6251ABCFD42B56D64B56D8F219868DEB42B968E88D3F3BE3A161DCB43EA98349A + 61: A308F9E2B60D0093A7278B0645A471408F58B45B3683531179F34931D06A15F4A502F2F7E1DF8B47830F65387BB9F102646058AB456045267F2DC403A1D9A6DD + 62: AD484DDC270FE74E68620AEC882E86320D0D0753E713D9D5C9C7FEEB894DD3FD5FDF4995DDEF87B1126B36E92618331126F5852AA8C0D44404BF9F77B780595D + 63: B4BA7B2F08BC0FC901188B50493FD165F659D3226227E2E9892BD70B02312C12D195A73AED3A4009618E6E74799DB158D9AC27FCCA9BC682B09ECF53BD368C46 + 64: 0AF65ED93646AE826C79BB6E8CD193D5246BD00B0BABF8425ACE03C845B9AEE428045D5F8267F3EA86C433F1A9DBF4AD1883AF164EAFE02C07CE43079668A248 + 65: 65F899BE2C5E9879F6A3BF7B60E62591B5DC5398283229E4FADB1EE78FFBF962295C427BA0D50BBCB9E2F1DD9694BD36CA598BAE7C2EF1F4D0700DC95BB66C37 + 66: FA9ACC46F0841962D6DDCBF5D47BBEC43A0E1E9B2A8F8B7970E2E73C06612FD95044B8BEB58C71B19AF4169B7E6500500445490F80EA4E305B6BB00C7181810D + 67: E9AEA6E12F881A7AEC3AAF428BBF0DA3138EBF69C6B8E52621609AD340D6537E4A03E2B099B735FA82A3D300F782606EF58598683D4ACB0870D5130B4B3142FB + 68: 3558ADBFD411DB8436A1A8B40420EE9C274FA153AEF891290F79DE5714130A50C70EB87E8A901D540ADCFC37E40EF44592822F6ADBBE8E5CB4EC89909633DD7C + 69: AF3852A0B4E846B59A4EAEB7A7A451311B1E8F554042CEB2D253F10FCB3067F9CA927C7DA3E57BC9C99E4E7997856B35DAB0645C194AE9F1FA0A92BC218CC9BC + 70: 6BD90F0F8FFA39C2A483E8349D2A29A96AA7F3CB4B4C1325FE5162988C9DEE849B8E56BF1423B6905ED3FC6A82A067F850372414E2A4A7E5CA379AB80F1C4F23 + 71: 6433885A8A39F2E4CBB36191A038EC3E3227BDDDAEAE24FD396481332A9AD7BECCC4E9BDEA0C8A7F33180ECB1EC1DB49218D17C4325B661967ADCBA25B341649 + 72: C3235054A1FDFF2C0D218C3B54EE6A58FA5AE99040A64A90B9C8DE601B80A7C130168FE7484CE1FD9FBE22E6E794161826730B63DE794EC4ED1D653E40B27F7A + 73: 89F4DF5AC626665D9791A1E1C30D1F206D89C4B0C59916DA295931539B0A607A1261B4EF022CCDA6ECE02E99449E252EAFC8929F5074866C3FF59CC58268E2B8 + 74: 3F1AC15A90C38AA964518F176016FDC73A85B096EFD1FCDCCF38F3EC692635BD4E610F1B3314E068164D02168F73A307AD549E1E7EF07DD374F9697DB6A17447 + 75: 4FE16A3BF0534DD2E4DACC43E221179C9B61D7D50DAEDA4DA9C45CCFDC76D6FA96EB3CC1C184DD5DDF7DAAA413D05B2FE518117E2C9A880726148C7AE6052160 + 76: 1EA870E13B7E59B97045F662682F29DAEC4413566DA341468CC9F5CAB733D1897BBAD8E9520B85C43DE33B9B70880AB774EA636248CD0A1626C9CDFEC3F1835F + 77: 37AE3A9828B08A055B2E47A613D25A8D43D5A456BF741E7964C0DF4AEC6D8E5F3EF874F2B20606A38AFCBD307C104DFA5BF40BFBB3078771436276E777F645DF + 78: 48CB9B779D37299162D2674CE2C2595B2422071917C28AB48781DED5060E76EDABA56E7C538C3182F9D960DC21928E6B3069D510046608C976D7A113DE54DCEB + 79: A565459CED6C996C04A21FF0DA10A7F24B1DE22EEAD7FA7FD2CEEAF522A42E29395F771140573D684C94F61F19C771DF68FF8EA0FF727C55294C70E701C8E426 + 80: 3A0ADB5479E65BE1F00462E60C8F7F74FF5C996680A2A4CF787B5DF65BB2E82264004E396AD7EAFCF8A201E03AA950D42B9A26EF2D24FD2AD7CF57CBD08AFFAC + 81: 6FFC799781B2E9F3F573651EB2DCB0771073DA1875CCC3D2B4C6C06F43161195610617007CA9A943B1F2B001E62518EBABD4542E73CA131E20A167FA6E8CAE44 + 82: 79C9E349F1216FCB295FFFE5771EF54A024306CED9CA111DA3DC629722DF7FA5F0927152E4401E0358BDC16D9ABFA02C709B1C21F6D86905B0CF0D6EC9FD1952 + 83: 6876CC513300CC83BAFCAAE5DFE4C4A0CB962079523ED475B19568243A63B208301335BDDE10CEC90CA816960013E08271F02111BD18FD03C1B941543FF4A579 + 84: FB5392BCB60C1329D3FBEDB4DE1131E7B89326A34F34BB099A7EBEE42B985682F52412D3F0628AA72A8C2C46BA3FEA08D5765264E48DDDBB96CB598C9C0BA93C + 85: FAE655D7CC2FDB54349870B199FA54CF47BEF2AD98021FA27B968AD4C3AE477C6B2DFA9A10C75FE275D5A32C5E9FA06B03D4C908184F49FCF15ABC409106E951 + 86: 9B15DD192392017E2F4DDFCD30B7AE58546AB71EC44DB94EE66CA3419D580AA05B5F10E5D36D9E60465FB8F56665366824B5B6E9A63A13F6E83A026F5A8E0911 + 87: 1A0EC6F024130D24D9740E8037C78A176D9C5933C4073DE3C6B0536E9F7CD20E0E89705953DAC9CD44C85EA059ADC496A7A0EFC40F187DF676D2BC83F80BE983 + 88: 5E9683BD68FA16BE904FF617510AE99249ED3477276A0B410B269EB2E03A3505EDF653C725811AD9DCD7FCCF6F2411980784F4BE7407D68C02CF6ACD21FA1B52 + 89: 47CE3079037E396A5B5A1A3FFFC3C60A138AA2C6BF4FFF26D846C7E1E84E31A26270AAC5C688DA7A29DED589018BC349E3247B073B765FDBA4C8BB271CC6E233 + 90: 280FE2B5B0B72FEFA48A9B6A1B0A3529CAC9D6338E2083816930B14FEA5B21088B1009DE147D81FC7F29B00BADAB32B57E15322A6180D713411F559658FAC715 + 91: 527C2E33018CE9895C3F84BA5C072055730AAF767DC82AE236F1F7C5511FBF2CFCBE32AAEEFEADE38EED4C0895290D0EAAB38E3A5CF7B2462675D1E6B26CE814 + 92: 8C0E22F5BE099CEE31C816A0F5DCF9A548B0EAB55AE7CC127D172AA5243A5C73B5BD3AFD77C89370D51460CB7E84F1DD15774D1B8442C07AD21A3B128688E1E0 + 93: 6CF00F05A9DD7EBA5F1A755987F5678F80AAAF9B5FC44D6199100C062DB50D2DA89096389DB94A6D68BD8337640BAB60AFC8793E1A909624A4E149AECBE415C5 + 94: 8452FD4AAEB1AF4ACA8192DD59926E7B0D7B295B8FE18DF4DD21E7C7ABE8F4ADE7391753E533EDA2EFA13CBCD96948ACF26B658F1E72390BBCD7C1BDCE8FD650 + 95: C4DBE8DC875D00FFAE2AAEB3E0BF1F01529A364454D56D329FD493D327287F3E34DBDF2AD54C5BAC5E6059F5897D18157C7DC846F15F2CDA1B2F0A6EEAAE58D5 + 96: 6C88BBBAD961E9DD1418E9F8EC69FEB443176108F56FA2B0B686E93B0E5F505E56302994FB190787EBA7CED5EAB69DD24CEC39BD566D18ABE337A31414991735 + 97: 439ACC720E8CD0C4A119B9C318FBC543CB7B35FF12DA190D82A951970248BB47D0DA2171A7BF850A881E8767FBCD542039E483974F18532FDB57DF23CD18B1D3 + 98: D71EF6284984442D05E8B6B1AB636E0BA013A8D70029F9F1B9BA7927A582D5AC6899B9C8EB990CA93B49E460AE140564D40467A1368FB4A9EFFED4A467E174CD + 99: 8B5AD2DDB4F8C044AFE2B0216B7E7D830EBDD285E4D992CA022CA2F59644806D8B7599CEC51DC73786D98B7B6F7C10C3BB7D4CEE3740FA42DB21BB51A1269611 +100: 28CA7AF155E9E7E1F5EB64F211F254D624C6C42935E27A91745F2AF2EECFDCF1DBD5896F60520A527499432DD3D0F3981F0E5BA72EF113231A0319467BF5271A +101: 45B69480A77AEE3D83D39A38717EC1CAE1634D2D50D05FD78F70309DDA566DFC160FDA967EA6ADEA8BF45B74557DBCAE4D6187DE1BB82A053CF84B4217F9CCA6 +102: BF46E03CEAE3211FEAED2147B3F2909D406A767005F9C8A5CE6139133D41C2812D3225123B3BF0792288E4BB5C8B5ECE9BDFE0F8FF097DD64FB2CCB964FC9862 +103: 3CA25AE24E0D847D9552FD74E1D6FAAF91736603DEE98E51922A2923630D7CF35917916A1DB23A758E7F067F26A5DE9135871B3DE508CE4ECFEBCBBA1A958C78 +104: 2C4380BB9F29041388A0F8292D97482E1E96429B79162A19F01918DBC2DF0B36244ED9E7D015A20290877ACC4D2FFB14D236CE7FC92ED16C7C57012B0CF6DF70 +105: A0020193ADA7F57DA648C1474731F145E6A8E9E7F9550ECE1A841E2D735B18769738AEA78E7AABB8ABB51EF08A34C187478B4C5AB5BFF4932E97F4E246C60C6A +106: 60E81090C365DA5E69E2FC12256131F134F561C7A411F51F72B7649727C9D7E99795D18D1AA54D09F6B2DD7FC556512F49D582BA6006D951D474039095F3ED07 +107: B213DA3FB3ABD16B1CF5CA81574D78649382A6CFEBA5A88C0B8DD40B1C6E18520F145968C342DB13A2B4B2659F4F865E8CF50BCF2138A7B09A1FC190676E1895 +108: 6862BF8F73054DEF42EF38C4A362ECC8F13BE7E705573D8E9AC6B347EFE6A218950A5AB5ACAC3607C0C94301E0A085BFAE7DAD5E1863D469C113B790C234A947 +109: 2D7D3040A495F8C089C67FEE236A07C7D3361D35271B4DFEA5F17C7E80B888EA339B936C4475194BBE35DD9AF3BE112201AC21C9F5858E4F4C39A0FCFF0EB31C +110: 1F995515755C98C5EB95818DAF0C55B51192BD8D752FA35EBBF51176F05ADFDC32E2FA845C1821B6110F7EC1F1D1EA963433194BB978285CA4344A5F989113EF +111: 3F5855B07A4288497533924165E7EAD3D91A16F5E832FB341F5373C118D5ED7E0EF8D837FEF594C2039F08A7870EC1C2770B7C4E7185246908976B62A416DE5B +112: 1541B5A9C84B684BBDB543F77CF384473D007992F37498F07709EE68033E41829E29109E7C77E252C241C78AF41C790E40696206D58B2FDEE768E5B321362F4E +113: 6DA9AC8390F4264064947684F53A1ADB49314E0619509298CFFEA1729A944990BE2D4C0988BD6E8BD1062D574879218ED8FC4801877D637ED3B5383C069A29D9 +114: BA0A194D5078019B21910C37AFB81A890C4FECE7B1F4E722CF855A6F2F8B82E4EAD37B7B58C07ACEF1EA2B76B146811732EBE1BC0F76A146207B8213802DFB28 +115: 20631BF1D6555C7BA761B0581BBCDCA5A7B1BAACA1B3D3E5B4D70D0C9B0A279BAF00DE093AB1334ED5994FC17386D0B2BE9E0FB67AC1038704891769AE530BB6 +116: F31F66E176DF632694A6F7E16ED8F15CE88908EF1D1F0067CC8A5C805370B9CACE0BDC78B1CEF06630012B3A35D129C4E2AA4F7302E1A122C7E53C51DA7F795D +117: 18B5417DC4CEE4387338C63156C34BBAFF19A2BB962E4248B1A1AFF1FF145BA47D84C6C8570D072BBC57D912C8048E0ED50060CA33408A00722A65C194178387 +118: 2AE09DC52D7BB9E692822A6FB3D582B805E5ECD2C1C4813F94F555BA2210429B615A2301B3EB7C491153D68AE33AD9D28F2FC11B6C61700D79BC7DDB251BD15F +119: 534390ED2DA55D45402F828D6035819C4528768DBFFAE1039CF0D18F89BEAA867589F78871FBC746E43B59E7886FDF734364DEC4193AABF56E8BEDD801E60D89 +120: 231597B2B71E6BE567C86DFE31ADD7B31332BEDA930C4921C4817B7DEBB0282A12D23B076F4783EA840D890F6C571760E70E143F8565561062877D95BD0FF941 +121: D60A1481686AB8F889EACF2E9F66BC32271E70E3E04B91ACA6CFB90375860E0BFC5AD9A627BA0C763CD7576811CDE2921E9A63C0F0A7A26E763F7EC7902308E7 +122: BA65BE7D1EF697281736B3AFA97FF675CD776C125CB01028EC2894EC2EFB9908835A3882E5E57BD44ACA09DC3B0580145EB2265E1724DA6F01AF5F93022D5774 +123: 0DEE2EBEBAA770891C14346A26834CF40212531EDDD64A21EF9FBD62F4728A16E18C673DC8CE3883156F51854A0ACC341DDEE6A0B71C4CBF797CD5327056AAD9 +124: 0717C9EDCC2FAEE525A684EAAB79653DD83BF46ECB285E6B154DFCB8A0C9F8D4B28FA200A6C224B4620CB0AB5B33B9C8BE77B2B5A04DB1A3EF8A5951EC46607C +125: BADCAAE4F76006290B9090AC81B807E7251EAC041E6CB10A2C5B58C4F4B2386E065E6D55C46CD888396C86606FACC82DE2F3F88904E15D549101AC7FFBA057D3 +126: 751F6366EFC97218AC2E0675E7F375444C8D82AE7A139E78305E14148E07100F5B7EF93B576DCE546A7BAFCE24FE148B248BE072031F89B6AE7BA9CC559E9C9B +127: EC0FCB3E124C482CC8D86BA2CDDE931E521F0B6F3E7F333C4388E7448A7F196D95766CEB8A49A90E46B592958BB85BD7495747E71508877975EB1454A4EBD57E +128: CDEEE6EC4D67DD8698B72C13735657EE9F78BB0E1DD37D0CF06063717DA9DCD617C5F4FF7656AA48CB3F697E36B3904F496136A2B04E19726DEF9D3406F8A84A +129: 81BB692EAF7F5176B6A0E5F2DFC01A045A917649D0B23B22C180BD78672F37F8E562FD006A00AF2D7AF0AFE15C8D191339AE28FF2797E64A3809400E2E73A785 +130: 04A8456D131499586CF7B9FC45C2EC96859F3F4BB8240ECD93E439EFD5DDE1DE7B67B688B583598D7FD50CB179D318D4C05EDE04F6FA318AA1E9DD7D4E279307 +131: E5C9D55B686DD9D7B1819A6144F6272B1FB5BB3B3034AB9D1BF34391283BA614D57894925C3D589A7FAC0CA1B1E98A12E9DFDDC2BCD85D1E7F2980709EF25719 +132: 2C6EF2E1C179BFA8295197371C474081790A63AFAA194E459CDC27AD4453B3A8C0110F9229BBDD4BBA5D6E80F2CEA71059334A97EA34F96810A2EBFCC3B177B8 +133: AAD54FE02E67080851DC84E20F7661E42ADB610D0B105B3EA6EB6654DAF64458B7E0F756392196AE2B40626CC2B0D82E47D74D3C50A607F4402C6C6A62999324 +134: CF210EE9A800943EAAF4EFE15DB7DEB696233A4DD62206D46BD9C84A7EB13B5EA43FF3CE15ADD8FC4BCFF022196197D1D097B7A893A79C6640135929FCEF10F6 +135: C81761EBF3235F4D56697B19F62B4F7445C8FDCE3D7999F3249493D50C19CA57C5FC84CD35CF794F58DDB6AC86E8BD53350BA9676AB63B88214162C8E11C16AF +136: 8E56EB131EFA286A92078F5A3667BC6669D6A7FD9746CA5F208EE38D5265CF27076C1624ED0F98D486C55C28A4FB89C7B667AAC505CA1CFE1E841184615B7602 +137: B6CAF44F87688E9E3651C2C98E840264464DE9DFE1F3E4CE5C1BEAD46C7D9D747DFFE282D775E101591A7254112C2DFD543E44B41E72EFEE30B032E5E015150A +138: 8E7851F56585595ABD2B3EBA5AE713672093A3120798506ADD1ACAA3ADD92D737F9AE155B8A5166C0F047801A93731D4B807DFE15F08D67DEF31A7B808601D6E +139: B36B6689A5F391688DA3A0756A15AF15E6E66701E2132CF6F06326AE9C91A0BBAA35664B28BC5B936D2BF1E6653848C5DB57654685124A08C79FD03ACC0681D1 +140: 24A23CE3A90C8EC3D10330EBDA47763B1B03035F9E4AAE0AD336169A2F464E067B026D94ED4B9723E969C8AAE7F404F7B4481C48EF7545EAAE4E648525A68751 +141: C7ADE61F21133886EE0E0B14438F070DA398B3A5387CABF98B0802662F3BD3AAA8738D36CCC0D3EA25BBE9DD3B59062BDF4BE2740482BF6D4C21D0E0FD7B0679 +142: 17EEAD5930DB3A1F8E123AD2E72C38209824F977674A52F380843442F0A5C82B55F8A362527BF5324124401648BEF5E9E26E08050B1FE80886E3856F98AC1EF8 +143: 9DE4F43CA8F7E528FFF9F4EF5897652323AEB95DF80049AFBA189C3D142CFF55AE340358A71B01797A8B72F478276E6353421E1C0C22EBDEA0C044EA60865784 +144: E259BE34C467B471C94B612EA6BD99A3F7EDE58E237DABA6A6656F7F7EB5466DAF908B7759027C277BD9234ECBB23C5C62DD2C9D248C1AE52865D66B5C256756 +145: E49099FC970994F8293E71467BFB1D241FE99322075795FCACFDBFAB396392E37BA09E66BF492684642FF2A03F8CF92E0ACF4677C21AC1C236DDCA103F0B5A69 +146: 4338E438D419D8694FC40383EB1045FD9DFEBC6F18A9A03B4914687A8639322E3B050F48E872BB7E2AD9013D374D68BDBBDD0B177024C1185320D04598515ADF +147: A36238A5C795B23F42D0833A5152770A4B0094BC19DFA72C935D32D02FAF5D136BF55D92B022D01949FF04B78507FB203302833AA7103729771A112E4FD1584F +148: 47180F9E838B129A7732A8DAD763B8CC5437BAEF77EFD34D3B33C63C09F6314B87B3A1436C6866614C3B3A693BC7926E9AE876C7BDE9D712FB5198D6417FCEF6 +149: A87064FF5DA177F3651488A139E568F6C75722ECF97507316BDAC36393724525291682776843B8563A6B014646F6B19F040B17B62BEE4A0711A7B06A67DF75C3 +150: F358321DC6A376ED500A2DABA60096B817D13B59AA02B56C1F51E2C6804F5D2DE2028409964D5755BFC6424287504994C7605749A5E5D9D802BB42922F444D76 +151: AC4A9999133546B8452047EE31B398F623E01DCACED7BAE4CB0B4DF0DD53B8E4921109308DE53C0924E0006361BC8A480AACF798D6B403F338357E8DB676AFBA +152: 0E73ABBEB68982F163257C1145FA2E465FD6E720EEAF5E532DDD1ACCC690B37A8FAEFF8D7D41564A9C86C2F185E0FBD0FCE75259D34A5E96B8C514EC83CA1382 +153: 094503A1B90D71960F83C91D76754BA6B05D670EC6A8EEE1D3CDC652DA6E52B196E155F3BCB62A9E4EF8C507F377AC1321C4C0D7A03F7D8A5286C0019C358E92 +154: 12803349F15FCBD53F2FE11B67DABCF3F470B8E3AFE8A855D7A918E611A2D5F4DAE8FE847ED1FAF834BB3678C6253111636100A991A80C1EAD0D35E28DB3AC85 +155: F489665F4D8A4AAA679D5E5A1B7C501DECE2E0B228630AEEAA1F5643FC4BCCB9E2F018FC2D7C44ABC4AC0861EBA8B7700A49B42486DD13263D978F8A7C9CA306 +156: D9DFBC3DBF0E3D247C95E16D376E7098A92EC59A54FAB482C330139EC6E06ED514D5C74F9604D1171A127502811A16D1D3039BD03C4DBED20BB765EFD34C5F0F +157: BA56A64D01FCF392A6E2F73D791D6C5A57AB40A376E73388CECBFDB910402043B4DB2F2D2B86E3510986CF1DEC3880E3C739175D5C0AA1DCEA18959135E2CF48 +158: F4B07B0A063AB240E5A64F1C494FCD9839276FD9689AA6720A94B83E579EF1044997F6506C1AD82C2CABB9384CEEA0B77D3970C1B7E13F8DE98AFA869F1F4D2A +159: CB4F232024B2D0C48E415D73193CD83C1A6BB9806CA336AC4F3B8FF7BF992B200504ED5E539CAAE68B1E47D4D8ACFD2E6B4BBC1B518689BBB5BB4311C96FE06A +160: 1E67E36D2EC5D0591C0171E7426A88919EA5A17470DA305CBA7BAEE90002E23043FAE1F4BE003EDDC2520A404E639B03880E3CCC68243C60E243A0E7A02E2CA0 +161: 40E46A8F257265A1E57A09B43890FEEFA57F56BB47551BAB38BE2BA8D143C176749484ADEB2D833EC9D6B70FBE872FA53618E64CF0AED24D51BA982D29E730C8 +162: F399712E5EFBA3FDF6B7D04600C16F69260179AB79545F44EF5849308E6FA589721CF7E6FE384461D05EF02BE51E50FA93C5FEEE9279A953C57EC07CFBE53E1D +163: 58DEEE13BF73ADD8B49EBBA90A8EDCE7030C17D6E6C449726D094F90A35A07759A3BEA031EEAF963C4753522EBBED1482789833D15D6EED7F5214E1AB93C174B +164: 13B2F766E6B796C44429A747CB46D99A9866115C78D2E94DAB52BBC9269B6584D26676CFECC2A9F026AE8E0162B6BB8DCB2242659EDA67CF793BF66963C69021 +165: 992B995865F57633665483C7C3ACD34BD108B5DDF151CED97C0D7AD134A8D9250CA8DC17C5C2A76C1C07989228F8B474814FB116C98D25D8F291D10CE259570E +166: 1C5D5E9C29DD91877E279DB679ACF0EFD8464B0A58EC9A3036EDB2621E8106FCF2A81719FDD1B89F13FCBD20960387754DD0F12876DAA911E793DF8F1991C043 +167: FE7F98A1D7839BB417CFF65A45E2DE806C74ADF2636385FEB16A34C890B524A75452EC096849EF0F905FFB38A0319D31A886DD840FE2FA66E16AC7C68B0D7FCC +168: EC67530458F01366BE95049FCFBF65465CEC9AD7D12332CF898DD72ED4D275F9C9EE96AD02603E8032F9B3B12615329CF0FEA564D278B1DC3B47EF304BF901B7 +169: 77BB3F5E58AF174DED0B31627648A1C7B5B8092C829020A6FE4CFD42CB51143E9DE20E3D827FB070DEDDA94D39BD0D330604DCB190E7252B12B03F48072B7E27 +170: CF33E5358E518807B70D6DCFBFB1CBAFBA7B2BDD20931B2A3B08BF8C6755367AB3BBB2FDCAE305F04812460FAD37E9AF70F1905D2F0D3E7628DD1FA453E5AE63 +171: 0739D32112107994BF3E6EC3A107AE3BDB9E2BBDA1D7C10D9AD6AE32952649007F68D28BA0DDD1F1C45F7128C1D3C42EBFDB1975A143A42949C7D97D9F9D3BA1 +172: A4F0B775988038E50429428C8526793AD8B6EC1F0F3AB7F6B33F716C61B7DFC49E254EAA01FFA422A31D30A8268E1BE99D385907479C7E2E0492681B6851DE1B +173: D2472E93989E1F29BE0DCF991A65BFE0E772CE77850A2F96FC6114EBCD78252DFC17712AF193FC5ECBA371B8FD27B0DAC44AFF6140923885F403904F1664AAD4 +174: 6696E09A153B0077D3586705E4A19FA6B3B2DD8621F5D13D7003017A0C569B7483C8CD9218ED1A252EB160C3620FE96A00E267DA0FA8996B417F64DD4A22153B +175: 2337E38B460CDDB026CB81B59B99572D45BCA4A43949440AA5C9F2502DBD8906453FEE23AC0AE47AB77214E52E7CF06ACE73DD8565BDD315F49A460996E08DE9 +176: 068CAEDFA329C1FB00BA02C80877E0E2B1CB6127FA2224BD14FAE5AD0AAE6FBAE052A145F5A8340B446F54AC9BB2108CF6582AFA0FADE91CD3568B604F68F470 +177: EBD69C96F4F2DB05350B74A475CA8C1FDC671B018A47072A11A8DC082C418EB20466720AF12E113C2D507F02596CB022D2BECC4EF8486CB54260020EB6C36481 +178: DB0770922005DE66FBC2B05B1F863ADA569B76DA9B8CA433C99C2F2B4AD60BD28B19A5B3820C0D8B6B2E443CF54A942B961E5EF1D53BAC4CA379964D701070D3 +179: D435D7240B8C6A6AABCB026EA53BB8DE58C5DB471EDD8173AE30C81BEFA9CCDE8E30758CBD7DED822410576115C2415D9DA7FD8A83CBEAE337E5908A012AE1E7 +180: 838AFEF97BBCFF7692C731D55442140D58CABFBE81BE76D41652106E215AF4E934691DC20F181C2123CF091B6D7552115F59937E165F1645CE0E14DEDB864B11 +181: 771815708A3D7BBE5E00FD677E4EB76B2B9A03A09412284A236401E7FCB19B340782C81D1A49371609DDCD7E38F9448FA657533D53280B3D6B492984E9C9CBC3 +182: 649EAB3244AEDAA18CF0A1FFF6619D63BBB66955C5D58E3A592E53F537FA74C60616B9E4483BCBB08AD7D1F5B6B91ED3176E89C03C224F94E5D3893FB6D01CFB +183: B4B6C653D90EDFEC3BEA0FE1FD766D5736DAFA184C360C8B036B7CC842E8C76BECFBAA7046AF087831E322FFC181073C19360A269851FF4DFFB4712E68560C3A +184: B0C0061EC50BBC67DA4765FEBD4033B8A204260177F9CFD451E97B93F19736D4B0B7478E29FBE76BE17AA6B0DFE9C4CB9C6E4734DCC8AA5EA825F101E5C9B02C +185: 54EB4D2C9B26B8B17818AD702E065407A19A711E22C8E66163E7311D8ECFA54448453890194C3EE892A599125AAFE1CB230C6EA268ED68ACD86DBBD17432352C +186: C049743F49D57D9226AFD26B94BFE9165BE5A8CEA9DCCD101F837F29C63A4201B1D4478EB5C4CE9D8F5D6E91BF89D09E6A0D918EE7A6D58CCD0A46D36963BCAB +187: F11AED8EC2B1C003B8E35F8F2A05861D9DD6B7DED02E28EFA4EDBB0BDA0DAA76EAD810CF1C78F50668D50DBE2AE65009C2E12504DFCE9F9BFA9A14969E1D0622 +188: 1CEB4106BC700F76F4825E6790959CC6EC85AD93D6FBB9783098E367E5C9676AA0D6B8CF9A7DCC67565284E71205551650557D556870B421273772524463245B +189: 9711275100A787D9678CEB38981A2246112C2FB1F0EEC1F844DF1703DE5B0FAD995FAC983526E7E3336B8CDC9DCE56FD66B73811201A2DA6783309AB6B9C0546 +190: 81E9DC0CBF71797104A44E72841FAF7F9CCF35C18EFEEF873450A25AE56564B0E9DA98598C527D5629EEF7F0571D9AD929BAB87A27539CE9898ABF4C57C9EBB5 +191: 28F4214D1C8C5B9291F2E1F7FCE732C3290A691432A65A01F7EAB1A313B83936DC98A3B39B5F7712DDEEB8968001C93A102C7FCFB8AD7D49B29661C9A9867109 +192: 78C7A025ADB85145CA8C6E417C4E68A9DB83FA78A23D0CC3DF20AD1409B936686FF756EB51BD8901157B1D031DE6848D97DC2E0F137BCA1D49EE3FB2D5A5E83F +193: E2C25FC61AFC794F65AA57DCCC4111D4B15331842493F93E9500AF01E2017CB226444E208BA9C841DF6D7ED28955B318511335F842AF3C2C0573227AFD790739 +194: 50D768C744CDD318B950986E305BF74B77396FDABCAF63AB786893B5F4104C2525F2F69905955A35234BD6BD85DB17B94AE7008F2E2C368E9639ABE8BAFEE4CA +195: C4F1BF6C56C494351A880172B9CBB59BB0D1A5955352E10A868D3C33BFEA0484EDF6ADDD009A20C8D7B59B7ABD5115D595B026CCA6442921038D9BE860C44CBE +196: C782CE6A141EF9E6CAA61853588B8C75B3A39CE191C161F43D7C5F88FB77BD5055B21F37D4A49D65CCDBD0E6BFD98193FC0092A34C21D5ED0CAA5F129D462073 +197: 1B2F68D7DC7563C286612B3D708AA725923FC9A2FEDCD4B1F1E2557CC70F3BF65944A2BAD9705303207B00F6DBCCE245C6E653C38EA0896DEF4150DA118A699E +198: C1248D0A6B75BEFFFD70EF17F2D0F3CE3628BCFB6A634C93E8F0ED97BBFDB48F6E5608511AD7091D7B062B795EBEDEC67696679EA092F7B84A64C99BB224D387 +199: 20A3D3F3676947173C7FB824B40069A202ED3A5637DB41C97ABFE9E7036D6C009BDDD5BFFF97FE80EBC40355A535D7D3A4B2FDC09B809D3BAE2DC31803413B27 +200: B85500CB777B14592A4562A26B13AF3F08CE74E03372D9622E29C1FB7988A86B8C00DDB2049C1395B43B17CD5C415A5AEDD71E05CC0980EB9520D4CAABBD6FDC +201: DB553A36A3EAABF7BE6FAF85DB96D3D0F207EA1E5B55DE589A116DB80C21AE5B1826A5FF3BB9D84C26A403A1E5C00BC7D2F6DE3F6A9661899D6D75373ED76B71 +202: 5580422E6393475B7C1F5010FA7F4395B969E190AEA056ECC88783A8B5FAB8ACF130DFF39DC0175E9BA8B63B4FABA7E4A36FC55FA1504468727086B2D26B5818 +203: 1CA3DD194E7BCA2591AD1B95D0CD4CF7938334C95A1EBE2C8C1A9B75E6A85F534C094E652248048923CBAB97CB1581E9A2D1AB8375C506159B724F74447A3201 +204: DC525D0EC1E62EA68C013470D77B61377398EDCA82A91C1C3E4D7E5D910A9D556B3AC810FB1457BDD70A18B063523C39BD806A2227C7E057CC6B018DDABFF73E +205: 2F0B9523725B27245D2A1B635DB5A3A3800099546ABFDD95C8E86C67C378D91E4711AD1927E90CC9B50A1A7BE3D60414E487E72445936FD0FA2BBF541F1394EC +206: AB6EB21BC802EB0854F61346F7BFCFFF738EA39829AB2785976D869830DBAC367D59D50C3873B960AC5185F3DBCEABD4E4E594C5C2916A8DC304207E887473C5 +207: 8E1C160A334D41F08918EC084BE12872DE79D00473D1B6ACADABD67E2A6827FB1DDDACAD9BFCF27430AA84F3F7A0D6CF2FFC91E7758F471F2739D51B60125D46 +208: C135532CFE84849FE9F40799E1F2CA05568868C0D44E6832A05C29ED17C5F6D0FB844485CBAE5E50A67F2319C30526DB444F4B45CDAE01A9D0542427731DC175 +209: B1FBEE68843D42FB558D1D9E0B759C168D6F84D07B2E90B646F45F1708B0D6AFF7BA8959EBB6AE4D5DF9A9951D139C81BBE602671CFDC618AA1EB63288DAD72D +210: DC11C3D993F59473F64F16F87D5F085E834306FC1C40D12CE7D6E44C59C31318C694282B0FE53B4B60E1E5DB546D930AB741A8DAAB8ED67C3D87E8E76B8C025C +211: 85BFAE07EEA80F939D52CB18C970C8ED9D4035B57391739C44D7973223C51344B9BE28C16EA29B35AF74A2F8F7581C766D61525DE5922A83A1BB600D97F7A3F2 +212: 26E52AFEE0F11DD79061EA3E4F97205729E6B61E50B69CC2894CABB08CFD3A10C41662CA6F6FEC9B5B80ACACBF968C5B75BB8CFA31D06C82D9CFE97F6E1F43FD +213: 74F18E92D85D9AE79BD62C4B8FFB2116DA8157E17A6927BE2B2D0D79CA101F7CAD6A25CD623C8756D49B9CBB903477B9CAC67734F84F0915ACA9025A9D5C6DD2 +214: A51B45BC09382F85334EA58CF7E7747457B517118042D53D773C66668CD6D5059B9997DB183B1C0F2900AC9949028D8F76DD8B7259149388FBF340834A3BF4FA +215: 59DC88A518FE44A7FD0F316BC8B5C865D370A8BC82533037C9872B24390F7969ECA530911463520218D00B415409AFA90A63F88EE729A252F1B747C414414091 +216: 146FBF362ACCEB8DF79A761285A0653484C38585817E26A7B8906FBBEAD70031160C7B924D3BD3A9ACE28A5712ED0E6E89CE4E71493B27F87BF73BF592D80600 +217: 74B6738B2F0904FD59F3A680CFBFE4E466FB5094037AA1942DB3A0017260D75AC5916E044CAC6BD0E25D176FDA267542B2C7EA201F7237E18B9D00723E98A239 +218: E821A4033FAF0FEFE525115109D0B836A22C287E3B157EC302768BEF7989AACE853218E5AF7DEE9F6E234AD50ABCC8A9658A0EE4D9FE050235341C94308D7A4D +219: C3EDD652D2F831B1C783CE1B8BB8CEF9453FC71F519A4800EC2362ECDBE9EC142F768185D55E322A32AF421DC84EF84615F7F3DBE6BC6E702B4BC8625CEB5BF3 +220: 6A3CA0B5A43EF42A1D6526C2F1507785248374C7D2602079A923C841F775A652724C29E788695B52387778CF2E2BBE2213B2FE212D729E3718D946238FF0E57E +221: C425148335AF813E36D072DC64C7EF6782D7DB981C5142B5D32D6D4338E06AC64363E86E88DF018968FD659DBF50A4B77BE2A02E71B243D65024B36CD71C1796 +222: B796D1F5AB11389EC7EC8DD4D1D5AAF17262C8522A4AACF454B44A7ED71E20F7028169F3164AABEE4C716B38271D72D7ACA3E54B30B9E05616AC51594995F61D +223: 113A56E96ED6F8613705B5CCA6CC4F2138204D7BC0C8965162597C1FD2F6E8143F57FF1160F4B482F7430536A349D20918064AAD2BB38A9D4403C16977B9616D +224: 9590A3BD7A0613381159E1E26342C150DD9B0A937855BF78FBF625648448B540158196A2855E7FCB967F22F5AE927D60E97D0C1C17A01E8D07284FF985F54B8A +225: 74B11968CC7CD925E21037DF011F1C93B2EC34C34A3224AA281ACE7D6F1B10F2A755DD6DDF33F1A4630123BC1CF875894FBD8D8B70AC05F8C3C1076E346A45B6 +226: 85A08D6993B7E5C014C3CA957D6B53EC1B8A5CEADD5060BBCC350915D3278F28E238425DA3A95AEF725A23B1BBD43E5D8832382BF76603F7E2E4FF711D540980 +227: BEFB08F621281473943AF153124256386570261916E5238FAFE44A72801D7C204A974B38696C102748CD1DF65BE3EA8C45A40021C28C7E4BB143800A3F38A93F +228: AFB97494318F31A4C6813246D125217242247D4EB6CF884B244E59655DF866B2820A8E1A7123DCCDE98ECBDF1F6125EC5B95A0D9F85F05CB09537B3FCFC2CF3D +229: E8C2E1D342E6503D77328A2C1336F95939B0E8855F75CFC61D4B03F4AF2305AB57C7DB383055A51E61AFB75494C222B01967BC74B4574B8208FC337E09E57075 +230: 0B396D0F15F49E60994DF4FB1E7E526A272A5B41FAB67EB8A41547CA6CE5B7F3FCE404B6A46BE79AAE37B4DF2C2EF68EAB71F39D5908760FB2124C7C83B0AAFA +231: FE86580438E8EE3459A62E73AF0E14F00F4F0FAD0447921FAEB2B77A0D8786784659B1F6D3044538300C759EBEF7066F9218F9386FF6C8099E6C71B5EC6B721B +232: C7E45B1737EBCA62C87A8F0C46F661BF7D3FC020C3B4B91988FC36C38BBC8DE05A22D4BF148F96D31115605D7B04D4CC8AB3F8738B652E933D76CD6966604CAE +233: 2C43F84381FB618512EDA0278FD382AABBA41FCF5546312DA565F4503CACB86B8A704B3B49C0C86B2207E4641F71FB5E72654B0AEE705C52ECB2E8FAF109FDF0 +234: ABC4EED8635DDFFD9900F5DF8C6246CAF12D8CD9333F38647255DCC52A20B6DE8D4109957CBCC2F48F52346579E008091628FD7CAFA092F2568828F424EABF26 +235: 14672F19BEEF8896F751B0BCF40FEED78A8093AA4DCB590D7AA588DDEB3170460381FDEF3CFB608D55F9E8A295A36DD64DE058C9EFF30B1D1F1A3671388B0AB8 +236: DB87424F975B03F925D8B99A1DD0967D2283E408B6B0155851DCFD53C0C00B05A42CFE14B10408E0F5985809813D35D7AA7C70C1A7BC852C7F254F0303103628 +237: 095D34066A6E202C896EF29F3481EFACBBFA622676F58E90FCD5A0591124E489BE3804AFA9BD3E4C92A9653EBE878A88B275BF9B5C8EF8EA0F01C89CF40E5FE0 +238: BB5BC80C718B85BB3C3DCE95D186711D5B90827B2097DE63C647E5B6C14B4766BF8EE8ED395103030F72ADF0C8992AE836086571908DB4A6258616EDB4BDA878 +239: 9A18D6DD0F97B7407DB0F17896DB2A2751B76C69B6F91E821A0DD717DFDEF630EEC1427C2D190C095DDB07601DC0EC8687B7411D735A9A6EF0EEB84A60948BAC +240: 60A614BC40A7DE580B6ADD05279A68DDCAE79EC3DDDD2C6FFF7B77BE9DD0260DA5241660982B77BA9C4B904075F39612F514BC86DF6F68E189FAE2C84A32CCE7 +241: 5CFCD44DECBE3D74708C620C70DA807C5AD58072F7558D950F519691FC96F98B760B02897C3A85F68EE37B2735931660106670C4DC7FA98EE2E18B6DED532A9F +242: AFBE6D9871AFFE6D201E2E61435703856424301ADD5152DC745D96D1BAA3ADD4C78F2D7C5057F1AE8B21FB91879562050C84144A2042AB2CD273025FA03839F5 +243: CE9C1B19D0E0FFD3085D28C5B2176A741A3034C1B76C54740AAC3470C1C8C6E77BA765AC4D6D90D4DAB0A89AFB17A8863A2917674F5A189A5CBF721C14F5D637 +244: F2F065927839C22DF56960845E27868BA8F272A464619EFFD9AEBAF1E40A72DDA81CFC67DEE13C351736C407F59DAE8EE6F2BDA17521CF66F10C73566B7DA891 +245: 24CD3AFA2218863437C5518021D1B96E0A80EBD14EBF2FA161A5E7032FD985BF71EA59DC5E35DEDE5EEE3098EAF6A16698F5BD5903C4ED218868D1E96E4B8096 +246: 1C6AC311730640FE427C1F23B60E817C25E1318109643A8AB51DA74995FFC3F156F098AEF97F37CD9746002DAD22FBED1A1F222511B92AB5F39DA9B53BD62AF2 +247: 37609371EB63AEF0CA6EACED8388D187203A88C379F24970434D87950C9B7DF9A68B618E9E83E3EB10376504F8FEE2505830EFE3FFBD23EFBE081325AA171482 +248: F0C06F6A2C7AC3F0EE428D7D1BA893E73D4D2F417999043BEFBB3CED51F95F7EA3CA882B9E8C1C973DD8A7F450CD60BB5A0B30D44A574E43E71D2533EFAEC6B5 +249: 3A9D1BD43CB3B7D3E9364F05987DF4CD99D573C036BF1337988751658EAF2896244DF5E4DD8984DD494709E587A75EA8AFF93681787AD738A95C5E98616115F6 +250: D42E2D57B36095F0CFE8F771A9B198C7B7E0433763341D35033F32D21C638CD948D8DBE75F533391347C440F208D17F20614309DBF1091DCA10801E16F5D03B5 +251: FBB964B7865A889433E99C4B61D3CD069DEB99E44673068771030EB1B8F1FD3B3ECAED1DCE8ADFA44F9A625472CD4D987EC7ED7FDA0DA912C8AFF5B20BED7F04 +252: 13F67CAD96C3304FF3C2E45D71A2D69301695516EA384F6001850A46A7F93CB74C5A4CBC1C56544166ABB6C9BBF90B9559320F5F75ABBBDE34C7B8B45C783BC1 +253: 78A609196BB40EEEBEBC04A8794C840A6F831680864D65FAAB093A499A3CF152EAC96865747ACA28392E9F102962C49247E0EDA424A345C4AC6F4B60CC3D2597 +254: F199515CF806EA25237EB93D658BEDC994E61EF70F5665CC2F230E7A40EADA14BFA00D56C1249F2E5C8920977A6C85017F8663BE9422762CF88487B76EE7EF9B +255: E8702ADD4B9034BCA0590FF897C10022C56D08FC4EEE0A43BA85E9E9C2086616B1BE7B6F928A3C53755506ED2D9D62DF5BA4A1862FBCDBA20683931A2244AFBE +256: 6E6A3CDE12F2CB3A42EC8A5D21B435C4DA4DF6CA7E41537D361D8169158287BF1D2241581DE07F88FE92F5AE4E96EB9C489FC3B258EA3842EA2D511CE883883E + +HMAC-rmd128 + 0: E9BF401EB338AE9ECE9F2DE9CC104A5C + 1: 9536B19B029E60F979B3A6B3052685BE + 2: B52F90B48846959EF56051CB6ED21588 + 3: 0811D2108413D9B64ADFA78B05EDF1C8 + 4: E06414189CCE13B61A2FC3CE9BC11938 + 5: 8BA02647A4914BF4248F6C799055ABA8 + 6: A3D5D44CBE30E23D20643E865F28B7CF + 7: 459DC8A812BBB840CA10A49E10F240E8 + 8: 26131CE4DEA7D66E5B3E6ECB1DDA4329 + 9: 5EB41B6A8F140E49BB4EBCB76EFAA0A4 + 10: C5E076890071C872B071E2D068EAD1E3 + 11: 476474365DEBAFE39DE7830A0BC3ADCE + 12: 3E9E0D4B41D740310572562E5F7F0CFF + 13: 9BA99B782F7B79C9C19D40EB27033941 + 14: 8E9931A75435B113C7E17E94E22D0B7C + 15: 1977BEFFFBF378633AD22D9E489FFB90 + 16: 9CA06536713225F3A5F67CB6510FB165 + 17: F46F54B012982621E33BA13A871F82F8 + 18: 73F925BD50E603A66B17D8D926CAD1FF + 19: AC74EC692DDBEF86570044E1B5F31EF2 + 20: 4F4F95BC7487A8F07B23C11F700F9C4A + 21: 02CE78131B27AB77474CFAE5EEA37055 + 22: 1D66BAD41487BA6C238BDAFC04E9963F + 23: 79058EE7D70C9D19058BE2E1D5383F39 + 24: 773EB9C677055286C84B39D2344C43FE + 25: 414A4816C124BB62DBA3BF65B6276208 + 26: 350DE5DF46801BAF8B12D4516E82EF43 + 27: F31C58CD73A3D8AC050BFFA5FDB6200C + 28: 5D7489AAD6537DB3DC27D43F698F6E79 + 29: EEF7FC37DCF2AB96328E62B8097203B6 + 30: 8FD428368B9B52F25C47E74C0327DA52 + 31: 923B6ECABD0337E39E6D068CC98F71A8 + 32: ECF2239FC767105FC69F46FDA5BA37CB + 33: EAEEFEDEC3B1E74A029683FC21F03B40 + 34: 9620C4913123F3A718D61C956673FB23 + 35: 59283EDEA3804ECD6471EA41EAF89A8E + 36: FB5B60685DC1DAF0C6557325DBBB32C4 + 37: DB71D12AA3B97C421FCBE45F8232F3E7 + 38: B0849EE5F1F9484514F5512BD928148C + 39: C73A777E20CC49AD33DBCBB16DC59A84 + 40: 600BF6FB779EA2F7108D1F7B8FE89F45 + 41: 0BD76F07D4C433E5BB9FC98B7FE49A2C + 42: 209E2124DAAAB3B5C6D2DD9A79A36E4F + 43: 907E4E2540A6794D6526A44FA08CAAC3 + 44: BA1BCEBA60F32ABD0EED0A1A56748248 + 45: 31F8527CCDD022CB9439F8B39ED70D11 + 46: 05F429D6AA9FBB1723D81AB268F95963 + 47: 7B91D5409357FF13F9B92ED2C6D63B66 + 48: 30AA88DDC6D49AEF0D4058616EEFD9D9 + 49: 16C0B4F46936AD501EEB5BEC8C699EB3 + 50: 782DDC3AA9B3E498767AA310D7C32CDB + 51: FABED92C454544588965E4CBBBDCDAC5 + 52: 7B04EC847F160BE26FB4A7C6B111EF91 + 53: C20AC6220BD352F8D53F0DEDBCA97862 + 54: 2EB8A89C854AD2412E5E2DB8638550C1 + 55: 390DC3D1C6EA4CD7A381BDD9F0B505A5 + 56: 1D86B9AAE5246182EF76456E9A8F2CC3 + 57: 1759BE8033CD082D771127CC81435696 + 58: 4F230D4174BBB11231ABD4AB58D6FB80 + 59: 9FA21699DE8CDE39FE4C9DF25271A87C + 60: 7658883C002D62D33EA21AC43E26C355 + 61: ED1CD4C63C40453677804FD66BE3E068 + 62: D715E8E09CF4C5A34793FCFF0A7EF0F9 + 63: 86C450794C4F920138A8CF2DD9221826 + 64: 2AE1A808F63CF7AFF39FE9595BE540EC + 65: C8E550F520B0662100FF767FC0FC38E4 + 66: 1A4CA5249BA8BF8E4AF50BD01B89C13C + 67: 25A3566CEE5E0921857048F4A54BF745 + 68: 4D76448CE2C08EBCF6C21FD304973DB1 + 69: 83BBC6D82633974D76A1B0994DD8891E + 70: 9F322885EB927B8C4F93AAC081C7F378 + 71: 7E0DFB22C9433A0A66A673ABB3E81B4A + 72: FD3DE62829CCF2AC389581D9932E1B94 + 73: CADF66BDE69903E9E3117DFE75EB1C6C + 74: 71DD9BF191A5A1A0311BA19BF0568727 + 75: EEC05781AEED255A8DA730399ABE8929 + 76: 07E7E6E57A239F659A6B17B695161878 + 77: 6E7DC67642EB72C295EC12C009902577 + 78: F6AD3BF571AEC27B2C99AAD4A22B9654 + 79: 0F38A5596BC9BFA1ABB7318A35E5841A + 80: 987BA29276694A84DF6F3448D2FA36B1 + 81: 3661D8F157DCBA761D1292FC2FB332C5 + 82: 81834820599DE6624EC116A651FFA2A4 + 83: 59E556C023829D31F76ECB5D2D5050FC + 84: 9389597634228E243808C1CCCC71627D + 85: FFD30A17850DB17BBDE7C3EBC8482A95 + 86: 0297895965B8C96F95A77E6A1BEB5FA5 + 87: 46185FBA371A282AD8251A8DA93E7A10 + 88: 34940377228A73C2CDA178635B8A4827 + 89: 0737C31BEFDE68780EB3A5504F295809 + 90: 3DEE2B38EAF96BC620785551C926E9AF + 91: 719B32410E625DC65AB4E422E24C8663 + 92: 5B9AEA802EFFE00D19E746E0684993CC + 93: EE96F9B8F8FFC084C0EF8C28ED0EEC4C + 94: C6575E5F4CDEE50C0C2F41ECC33BC9E0 + 95: 000DCE0FA82C1422ABF37EF1971B4B1F + 96: 83D1C6EBEF52D1B9DFA3F439BF8DCE25 + 97: 657AFE5CA6D54F9083F02C257CE7E3DB + 98: 9E65239503BEAB92716D5B504358352A + 99: D8375320E32FAE3BBABD4620B1231315 +100: CC8914472A9B5862287D695AD0A88BE6 +101: B0E0D8EDA1BDBEBCD0A78678AD7D6A64 +102: C8EBE9364129E651BD4FB491FE035433 +103: 2A6DF032E0D615DB3BE890B0B6D3349D +104: 975F0E184517902F1C239684EBC06314 +105: 5A86E403AD3D0B9EE5CF87C32482C6FA +106: D3E986B5231A204C88D7C2FD1ECA40C5 +107: 891ABD274D024F8B04143DE588A02AC7 +108: EA619405003DD17F13ED5BFB29587568 +109: EF5CD5EF1164A2E5BBC2D96360E55B87 +110: 07C74397955571A7E4025BB9EC555846 +111: B5F20FB0AC1C1DAA0DEF8EF78A9BDDB5 +112: 88D91C18A4AD272B4C1E2C76BE217BFA +113: AC548888F0E5E559777568ECE71E2007 +114: 816071E2B807CE6EF526E423BBA252D5 +115: 0585A675BADFDD749ECADE66BFFD0546 +116: 964CA97939664EE55B8B973D044D7695 +117: BB8FAACCE9D3238714C3934E6FEE2386 +118: 2BB26CD61B24CB5CB9E2C5FF40C51A00 +119: F5332DEBA64EB35CE3B5C7134C4C8495 +120: ADE7A5C99757D216D10E1F13E3A91F1F +121: AE98C3C4FD874CE0B8501FE4C428282A +122: 04D7625B67AC3F9D117AA45FEF6C6AC1 +123: A05D3C933DC8C8A1CF48290A5D52644E +124: 078F882264317B0C00383FBA7E079301 +125: 44023F3B109763A53FDEFF1822488855 +126: CA535702BAAB858D5FB5B79895E0E1E0 +127: FE1C2C02B7665895DBD2F4D2C22A7232 +128: 75A182DB4FD99599022F5A03F1427289 + +HMAC-rmd160 + 0: 33528FDB4FD0640B4C4363CEF1DE795719EBC7EE + 1: 514DF566C6204373EEE6020054AE7DDE2B0934DB + 2: CC8A5C8D2EBA02BF4474A4CC05CC2D863F1AA392 + 3: 27D731E218C369A32BE4B2BB29D2F1A0988BA583 + 4: 091245BFADF5C6635298702F233ECB3265E85460 + 5: BD2C07FA2197201DCA309063881F2EAC9D925A21 + 6: 480886856354E6FF34B3AFAF9E63FB794BAC4521 + 7: 258D58532BEB5EAD28E9BCA52AA4C0444CC2467A + 8: DB7513F824B42A9E1FFC1369F22F61054A3EB7F0 + 9: 3A4A258F23675EE02E1AC1F72197D1A11F32DE21 + 10: 9315ACAAAA8DC91A9AAF8DDD4CD000AE04F70E1D + 11: 57D60D77E1D78D23D3F184740D9DE392FC6C3C40 + 12: 950395C815A3D1A4A8BB25322333FECA15445BFB + 13: F8201A01C30F3B569B7497B5191AE16D1705085D + 14: 08DEA1A0CD4BD6C9031C84FD2005F15810FF088B + 15: CF41D88EB3921FA137F0203C2CB8BC5200FDE7BE + 16: A07100AAACF5253501A6643452D07C7DE2EA824E + 17: 19DE22082D1F4535A733F16262A135358D651737 + 18: D50BD92902AE0127AC8DD85E9A81ADB7EF3F1E64 + 19: 3FA34A3C02E06DE451794AB87C4FCE6877458CDA + 20: 5928329E4D830E8B2F7608A4ED46DCCFD5798425 + 21: 2825DBD7989A8978904A654E6AF125608B0BEBC1 + 22: 9C812424417D47ED7C78C7A049D4E6CB906DCF3C + 23: 9518A473A902DB6BB56F7A767ABA13C8DF306D37 + 24: 439C444C7AB4395C4DBA32E4F8CF4F76207E5BB4 + 25: 9021FCB087269457ABAA8105D4DAD8DF8904A2F6 + 26: 8B7B686199BC73A175940686BD57F45B2329D895 + 27: 0F50FB7AA9425975BFBB6AD65CF96284F768BB75 + 28: BAA1B7749A9CCAD7105E9ADEE499058A7BE4BA70 + 29: FBD3413CE89DFFE2F0A869036F5C4265D5B14743 + 30: 7CDB257E051ED0EFB761A5A044ECE5B0C1F12033 + 31: BB1E5D495074594534AD523987D8438CF1632425 + 32: CE6D7BEAD1496190F0F0E99B0B0C9BECFB7D9173 + 33: F8BE617A3256EB1C4BFC04CD386EB7FA46603926 + 34: D1A1F489434C458344239A75DA4241A3A94BEBA2 + 35: BEDD951DC98BD5C4138C1F8531D8288BA3C51B87 + 36: 9C2357E832CE87A227F6919B50A0A9D3A29B7CAF + 37: C9FCBB9A1AC48B71B2AA20AC992821531F1141EF + 38: 0B58D56923F9620BCD072703FBA71EC2172EEAD2 + 39: D97480E09FA6473AF9AAFA14FA9589AF65E62328 + 40: 4D5C56D0EB0BAD64FD0B0FB7F87D05EB551951CE + 41: B7EC2D13EDD3603D1BBC8CD29F32B43AEAF6EB4E + 42: 9BD5300B02C9432F686842E7900F3D2A085C5008 + 43: 7E8787C8780C64009216324802958E1D845332FB + 44: 1A3BC1AE95380D609571B01D8C3458B2566B74A5 + 45: 9672BD12EBBB12F398CEFA089BD3282A2D2892FB + 46: D5D3CAD705E2B0B6E0CBFBB0E8C22CD8EB1DC4C5 + 47: 408D84FE0B28A3B3CF16F60D6207A94B36219F81 + 48: 0B7E3D35C292D295797E3ED1F3D8BD5FD92A71BF + 49: 18AC1EA3406D69CD9E9C801F471AEA3A31C69D51 + 50: 98E40CE293ABE4ACFADE7D81371FA92AFA69248C + 51: D95E38F2D0C5ADB478A9BFF9F8E7B10064455C31 + 52: 6246C69FF502D453950BFEB5DBEF68CE76D70F12 + 53: 9D788F02EEE675F47AB4498B1337C6D83A37F64A + 54: 139387D749674D0E84F3C2BFBAFB3F0CDC4CA273 + 55: 09406CEDC1C37D275EBFE02CC707229244086CA2 + 56: BACA138E6EB6E5BEF150083CE0EFC64FB163EBF4 + 57: 87CF4CC4500A691934C2C6607F3296A0BEC980F6 + 58: F8E4DB4FE6879870E9F47BA29F0DA843342953CE + 59: 52DDF305014F1C68A34ED514B10FAE3B1B91F383 + 60: 0D568164C300BB14A4571A73493C02E4165383E4 + 61: E1DD806961D718F8C085CEA11A140900FE8064A4 + 62: 6470CBC7FE079B684D108550698B7C5D265736D4 + 63: DAF83273B2F16DCC69FD55DC84835931E75FF5D8 + 64: 47F4D7724BF49DE885D23D84D582EA3A00E1C2DE + 65: DBD6BD40F804E38963EBD2E81CE5196F6E69AC48 + 66: BD96E9391148957BE64FE6DA89CBDFF45233FBCE + 67: 20975680C2E31D61D7F303215A25CFAB4479F646 + 68: FFC321ED45ECC1A9FCDBC28ABAE0DA1FD27A628A + 69: 99F90008F139FA442C152706E522CEB349EABB00 + 70: 288C57DAD9D1174F4EBA92F7815B93C0916E8157 + 71: 8380FD083E742776CC32971B9E088B894A6A0071 + 72: B0F44C66552ECE94502597B6B100CC64561E6F1F + 73: AA0465458FA1F285F5A4530035F84F844D545A75 + 74: C90EE3BAC92FA4986C850DED11D728A78BE85543 + 75: 3E525BBEB158B246A3F4918B6D634CE8EBE4503A + 76: 7B42675AAE1D0DA5A84623E47C618744249384E5 + 77: F50AC31B43BC93D1BE2A4D9C40FC4D3593F2551C + 78: A31AE398E0D6668A52DAFE37D019F7571E0F681B + 79: BF10B29B4DC7C848C5192631E59E0EED32B8D81C + 80: 77B214EB3617C372C191D1D284FCED04F5AE17BF + 81: 1B17DC33F5966621F4BFA93961B1A8FFEE1AC820 + 82: 5A07D9861EDA6D8698E12FE5250CCAD882628B44 + 83: 176F46FF2202307828D7F62D39330444D688FDAD + 84: 59E94CFA3AC2BE8DC6098840E888306764308DE2 + 85: 679F243847C647FCC3F4589CF87972558350DC98 + 86: DB97F5EF492C7380472E16E3B055567DAB630153 + 87: 359CF9515F6B2192BF0E85EDBBC81D51232210B7 + 88: 30B59B3CBFFC08DA7D9514AE7627460BBBDED722 + 89: F31D5E2866D9726051B6E5AC9B846DB36EB705FD + 90: 860A58DDB6119261646907E251D60760099CAA07 + 91: 22EA0278EA053175C2F12BA4ED172FB0B518F3BA + 92: EC68297334F421AB3F2EF3518684E8E1B548BF56 + 93: 5C1405CC33D9025DA265FF4F25942853721489E2 + 94: 8AEA8E9EAFBF3BA597B65BBCCEE59013C8E6AC8B + 95: ABF7CCD01374D5DDAD6EFFB19412EE772E663DE2 + 96: F7F28E05FAB93A3D089BBFF56D4E462F0BEDA41A + 97: B6C4199D504E72793EEB49611E28A82DF5CD7905 + 98: 0B0916C89F1D9F1134E9106FEBAF4169DC49F752 + 99: 4F18AA0E88A01ED162D08F35300B1C3FCE1FE8B8 +100: 5D4F3C473D5859C16F70C1566F9800B3DBBBC643 +101: 02C1A5F34232B8900E6C7DF2BED957BCAE529784 +102: CDD46E434331D7869A27EA096CAEBF586D93CC2E +103: 492C04E69F0204F150B63022C7DBD28116458F97 +104: CDDAB90168E934E69E942B1F1EC0D0AD7BFB5B43 +105: F433642FA8091FB2517F3357DD30308B4A2AEF53 +106: 537B2118792B6A419C438E58CBB6C5BA887AE257 +107: 753728CB39813C27498033A07DEC03D1FA720FE9 +108: 119A6C5BF3EA8F7A78DA9ED2DE7ED9AE3942964A +109: A501EB611542A2A2CCC68AE754D2EAC17942BD8D +110: 158FB54E37C7DF54B29928B5DFA53A560DC09A5A +111: 15F5380252E23B5C37EE7E8D1F5963FBF8788577 +112: 735F2C3CF7680C63F33AE2D4F3569FA8EB45EB93 +113: 67AFC501C6582DF2A9DBD713F206041E5F3E1DEB +114: 7CAEFEC1C6E8232BCB90E3FE3523EE06496F36A3 +115: CC90ADFCF3F9AE777B30EAA6206A34EF54F74C02 +116: 974E0E85B47CCB870A511810DDEFE81CB85B28D3 +117: 516D6BA01E0186CB7D796FCD9DD169C45B63A93E +118: A1CE534BDD6591AF4EBF61ED75636C7BFF670658 +119: 1E4B241D6EADD77E046BDCCD25F70AAC969262D3 +120: 7F2F1B4B77C3170A9E015DF4E8C6EDFE736DFFC3 +121: 89A3BF181EF195464DBEF9576873CA2DF7D16268 +122: E1F96A7C9115E3DBF28E10D62F2D6EC89415B6D7 +123: D75C1081B3C2720D030EC5DE13093357A0EE6E51 +124: C11603CDAD8DF271093CACDFB5AA4E113A270EA5 +125: 39A9E659DFFDC2ABC88ADA2B6A7445090C7EFBF7 +126: 4132330C5E3344818AF5C054AD55309FF7B767A2 +127: B107A8B0C7B68581969A0F6DB95DB2F790098F1D +128: AD090CC9A6B381C0B3D87035274FBC056012A4E6 + +HMAC-whirlpool + 0: 5C36BE24B458FD3713761955F28353E433B1B818C8EF90F5B7582E249ED0F8C7C518ECF713410885E3FA2B1987B5DEE0FBAC210A007DA0FE995717F8FEA98995 + 1: 30C66EA7CE95764F4CFCFBBE4C166E80A1F23E8C88D2DB7FAC118BCA9EE28299778610D94CD545C18C114A2A144F9E933CD80238E9F1AC737F7149BA232FB846 + 2: A61FAC4DAAADF3DB746DCDC24CACDD8C2B74429CA812D86091B5E7F8186753B34532047B3263D2E231074CCDFB18188747B657E0B685693901CBBEC524949244 + 3: AC3BBA8D998C234F9BCE9A96643E8EFC342F4772DF5606A812C1C6CFD644E8F2B8F9BD724CBC8D769B74C52669705BD3AD390CA61DBC7EBE4438726A91FB2455 + 4: 59AD4171B4C33E09312A01B97B3BC2B7DA43F8791561E32A9186C9B0C418BBC31DF54D6A9ACA00910C0F3DF5D7C2DD7CF5634B76506646B7D4EE5C60AA7C7950 + 5: EDFD9FB5B7BCB39811D87A890171096AD2237B78862C4921191F8B0B137DE5178BE8DA898B6A895FA6C4F401714D2AAC743F512F8989E39081F02A2A0F9F6137 + 6: 6BBE26824C7582213F89F773C520710AE400F01B99BCE126C5F3ABDE79C8B304139352427A3E25A313A5F753A94B55F1EE9D3A0300E8E987E98004F58707F73F + 7: EB89DDACA2BA68940C4616B3B1BDFC25D94A78B8C3A533F1231A259BAF6A6706E1B90CBC2F21A76210C0322C7E4286E393B167A2455DB24C6B52B0CEF3EB78A5 + 8: E8AF385440589959D67746FCD40E295026E942E44259169780B3954D20CBFE2586D2A8BBE408AC2D707B0FE539DB43B3E9B29A8D26D09A41FA6F191999A45186 + 9: F6B9CF6E0A337906517DB09EFA31E91D57D6B908ED5116C13B49B8F1F3C3A872EF42DED53F939CC4EA4122FD8580D528AD2DA72BE063251CC89FB52741E2AEB2 + 10: 274FEF3E5EF7AD7AFB1161A29492F0DF44BA9E1C30E1E88CD708A5D27F2B35C45085A200E9F42F340B0D9B3A1A354B1F5F6D0D1A754D51DFC39CB2EE213112DF + 11: E2EF7A0A64A3F384F95823201823BC95060707F273E395F46F3C0627E1CD2BCE97DB2984C0EE7A11B22E617F0CF64A3F44BE9FD6B38C3A07A504DDC1D33C73B4 + 12: 681D72B9BCA446200BA7578E038A8FC418225BE5F02D8DA3CF085182628B7BE587DCAD4851863CE1CE8653E4916047F8E92E91A6B0D7FFB065F316DA93C4F44A + 13: 2CC82F237ECC1B9B0B9FB76E6B9651C56AE57CAA072A0C20B968F2A74FCA6A9749FA264331F4F2612AE0DF32810B0CAE95E5861473F4675766459B7380F7B9A7 + 14: 1F3818CFB04AA3882442FDF1F5CB0DB2FA9604228D3CCA1F14DA16B35D9B2071B372996A176AF0592F00175EEA4C16A6E0162DE62DE30E8A80FA669FAE9A33CD + 15: BFE4BF868A8AFED289DED5F6E7B21E6856107EBEFAEAB5CD644FB5634181D52D8DEAA203C468ABD279E9BE73507A690C0B715869F6E722C4512E815FA4EF641C + 16: CCBA3834AC7BF06B16675376ECCD96A0F91E3E3C588C5BEE1711A00C107B35D603B20DA8E5CC5FBA6937A24DA53D8F55C907F3E53F0F255E080396426E7ADF9B + 17: B09F6898640E5CF77B6DD3D5A8A4452F4F1D25C90F7AA55A205EFF2C319EC0BE245CEB4190F11D85C2F7234BEB899BDA465C95A1C59568987C4C020B9A7AFC00 + 18: AA7FEEC56E16AD79990B003AD51626C87C9CCB90EBFD748DC268C0C8C1DEE1BDCA1C8064FE7570A5C624AA0CB6BEC163E63680377A16AD49D1AE166090DC0D80 + 19: F755304A4694DBBEB0E59B978943F3D4E429F8123B3D6CE27AB400D3C4BD81A13A8C3C0BA0FA7E5F13BCB0B48290933A05DCB49A5907C074039427F0EC9004FC + 20: CB8B5804EF0478645400B1655DC6E194C8DC26112EF76C57823A02F39C8ADB42F1225B130FF0D40F580DA8CA95D82C0441E3A82C206D9D8D6DBD63B4BB1BCCE2 + 21: 4EEA4AF294C458BDBA7F49AC0826BC295BAF5B16D16F40D379F6B7C3456EF4145B5EC7F7CFB85638F641CF4D07FE3904DA891E68288FC11C0C72F54430915024 + 22: EC52FC8CC0F849E633E3F7339031DCBCEAB69B6634D3E54E7C153CC63DF7D3D3F93B13C8E751E79290ED4845FAA3D5A79A7DE6B100F538E0FFF470A51CD630E4 + 23: D44419C0A36FBFD0FB441B596E8821D3F543D80FC7EB5A3389037BE0139921027571502B5C53BA30D31D4A053E830E610A394842229E08485A2376CB9766313D + 24: 3F4BDBC8A4C86B3F646CC445E2CD54B4C786BAEDEE9FD91A879640B4085D46FEBEECECC95E819ECF6AA9085C2309E79DE1A988C6B68930ABCB9BBAB90F1C2F85 + 25: E5EBC015269E0E61BBD1717618C15D44953AB6F854D962A04FE88865626DCDDEC5F094AAEDCB708D947A9547A985F0B287CA0FBBE3FF2ECCC4C0C4FEE4FE74CB + 26: 010C622DF84E677805108A2C5FB1E8BF5922D35CFAC2408F2AE174D353AF169A40169709C39BFE90E51B095C8C0D2886B4F10B37BEFF805D384E29CECE89C4C8 + 27: 3E9C7BE96E03C48DEA773204E1EC3721EE817ED2403E3C8F950A4C447949438037E2AF0A030CDB983D3FBE5B82226F510FD91CF8830F59212F8CF26C2B5E4DFE + 28: 8797C9C14CD2DE3CB1D29808DA9F23A5502A7BA579586DE9513B980FC06990DE0E29837ED06E24B15DD0000697666B8D3DDC556D818E87F84D125697D5E2F8FE + 29: 93DFA3DEB3258FC7C4F5362D36C2AE21AC0471AF8B895B5AD1C407E8D50DDCD0111AF76EC500D7BE035E6F9CE932190712A3F52FBA4BB0DFCE74400C82D1BD8F + 30: 5587EF7A31353C0E9C346C837EA645770BC5F5C541B72886844B4B0789FF1D95134F558B29385B35960AFDFEA7E3AA40562C12683CB7DD9A410873565CA10880 + 31: 052CB0FAABB263A49516E39525023E2A02DCDB2D5FC78948E042E59F89363FAAF1869D42EC9D7AFB0DADB7D4E99544BEDA92E3270544900A5641F059571B6238 + 32: 2FAEBF049CC4C9C2770E859739B1774EB6E6AC2EAF1AF7D3EB55774C03ADC4C865A65C82E795959CBC4BF00A64AFD2AE0CCA16D58AEB874E253FB9FB9A266790 + 33: 82FBFD2A46F2102AC27089B6889024FA9172FA691C1E3BA9B44A394D52EBF5A7A8BB2321708ED9AF2776D8BAEA13A5F2E9EA4AAF420A24B6F59E2F583D54A797 + 34: B306D18161C766DBDC734FCEB08D14248EBCC63FCBB5B9CC0AE9D690E20E7152D771B3D623D7ECA1CBD305A31EE10C220FCDDC2CE76B578E2F15DE4741E9C9AE + 35: F527D57F0A5F13D7FC6A30A84BF414712044B56FB8F6C1E1375A09783968A851DBD495D51C693590E7A8BB570A7F1C0C9ADAADB74EF8EC71A0093D8D1A4285EE + 36: 0D9F9DB43A0FB4BDF70487002943A6CD3BF200518500B6934BA518B3B0958095930EF59BAC48C84C1E1ADB815A6569FBBE7E61F039BFD8C2F727EF4636542A5D + 37: 614CFB257400128FBBB7B56550E86198155A5647FC11111FB4D36073BB57AE4D9C0A54BCF0DCDB8B54ADE4FF8AE5645821CF9C83F7FA9468FC2CCB552E30BEDF + 38: 7032724503FA5B0765D610D3FA4609F4537F6EAB75D7CC4E2A15D2B1421293D9411C9E8F38999F7D64D607EFE95224331E47FAD4F9BDB6AC19CD3ADE47C17E7D + 39: A8E4316126475B429E72432073CBF26E94DA450DB553D46667D597F0AACB99325C9EDDB94F8CE33551857827AF3935F2DFFE1EE69A20884D58E095390C04B925 + 40: E7E90B19E76017EE80E4979FE56A488AAEEA011DE9DC068DBE53AF06ED44DA4CA3BF662358F191FE2842B083BC5DF2D4183668F4E7FA9E2750869DECA7302202 + 41: 818D734A02A0AE76A0012D7BFE983B17CACE37D4890214C7C53A81CA9F42EF0A472101D609BE5D3DF4F0A55DAF154C20A1A97D53112E22D136C03004FE09149C + 42: 0B9F5B2D4BC3DF781F55ECEE149470F3BF68FC51D121D021DF0CB8D4A5EDA42EA6840DD735ADF8DED72B325662BCEECC6195AE831D169A891F6663F8D7C6E0D3 + 43: 7A5AE42C635B250598C536E531FDAA1746DE2EC7984DC1BE488DE4766D0CD544AB51AB1E62A8A170D120999A61CC6920DB96935F295817851A4CE285D2755112 + 44: 95093085CFE52D746C54DDF8D2FBE33EC00D71C39BE0865B896C331C7E5682FBC0DD84ED15B3F790166D537A9A68EEE5FEEC63FC761EB854018CEB68245CCB90 + 45: 8BA177C495E9832CA8EB55E67E5D7F34C59C4C59D56D50BF6982B36AC341CBFDFBF5A98BBEBC26A9509FBDFB239312DF3B3D5BCE70386EF0E593E17A621F41F5 + 46: 6DD39D94235D012C89FD030341392AE42BE7702C4D8E725C4229940BC273EBB8EDA7A6893B4FF86D1EF84DFA119058BC6C8CA47675492A0D37C859E6D9BD5471 + 47: 13A2FBE3DBAEFCAC5AB8BBAF91BAFDEF5FE38B7F2EBA8BFF0F44B4BBB236613B8BB122BECAD9852BF7638E48F0FC656F9C432D9A66C1188DF3FD1D2A88161139 + 48: 33B9B7EF63B302C1C79E0A43D77487C55D38C53F29C800B4CC287A99A440435121C7ED78BE7406349E65AAF991EA0EF19D06C1AFBB814FE4E0BD68613AF0C760 + 49: 720E1005ACE28903D9C2B6EDE02A52F89860788AFB35208B4B7C147E43BAB3D06445DA138606F334624C606DFF288B0C70B487679685D1DDD26F1DA0A5F6839F + 50: 2A742F1E8CE6CDB501E8AD9BD256786A42E7F1888D9803AA8D5750817B3EA101331D7266298962FA28AF2232BF956FAC7C1C0B1C3DE4C5B3FDDF8E63BEB02185 + 51: 05CF6361A4A238091A1FD011336F7F53B9ACF78BA1B96997EE49B99FE36F0F1163E04B446EEFC117B377593EE078B85BB9588918C76612E2A6F9515E0CA244B2 + 52: F510C877546FD2D022051364A09F2051523F8E7FDCD3E9D2AC5158205FB36CF25A9E0FC394ED2FACA7CB4F0639B33B706FD4D072D62F6EB229E4D7879DFB45CD + 53: 2664476D94776DB52BAAF3B2DE05A36D3E35EF44ABB6F09670F37EEE00C2C54B38F70D06359B20F7E40E22B42901863864EF89EA473A1F3C834D22176E87E617 + 54: 62620CBDA92EC8241DD3A6A0EFB28254B0CEBF3E2351B10CF93029244A6A3D1DCE10D9A895EB6E8A33108DDBAA897DFF2703757DA3706209A7871F4274901E3F + 55: 51282A90B63998F7AE7ADE4787D957992A81D3009D6AC5BF824DD1507B53F6918E9AB6AA1F36373D5E5D3EF8D01AF9D05FBC224781C62C1DCB4A2089BFF5496F + 56: FE1C4394AE26E4B85752045DB14E0AD378726BC1C985C8805222B614C62721E40B2A0D21983FF40AACE8E5F9CD57BA62C37C8F0968EE12FAE14267D6AE906A7A + 57: E570E1183CC6AD7A2C73D7D0E96D3AE0605039603B6F6467FA5CA62E4C1424BC14B17E9614F0ACACCAFC2B1B39D8C081B05DFE2B9796F32C0C742FB09DC7B8DD + 58: E690D667A94344E267A6EA7F3F7A6A5385C961BB6139800CD5257BFD6C4A672DB576B52335D22160A372987D652741EC3AA9439B35D8975AEA49698F8D5528E8 + 59: 59FE977EC1D9927FB09389E3D31272E625F089AA75401D1B541DDCE8C6983A363622CA4F2AA9741F0D1484195CA31D6D315DF6B66E74888D111FEFD249FA0174 + 60: 2CAA990D06814CA73ACEFE0D9A815589958398999707BD52C3773F61B2DC2F20EE7AB7F66D643BD9686C4C460AF45D58BE9F8DFC1B5CFE3A5C2DC2C93D9491A3 + 61: F198E9238E9592A97DDFE1B0B56DE5DC05D358940672D84F15E1CE71ECFD3854CDD38762DF11E1871EE615EB6080E329495B37B23710DCA9F4179F5F95F3E2A3 + 62: 3D7C45603510C6916226B192C81B90EC213D30C11AA21C8520437CA5639D00EAB529A4C443C9A39C5E40DFEEA0F685B3D0E1277BEBDDBF80C3D5F9C8326765D9 + 63: BA081CA12FFBE3CA8F1E2703C96587634F8EB3BA140F93D997B6D0FAD1C1915ECF7D77CC0421E639B083451EDA605571D68DE81E7A4BFC183D7A53A07122168E + 64: CEFE2203F6428D267CD2E284C3B8C31E1946558A56A33291508093DCBF64FD5FA4D33FB723ED49CBA02D97743312138FA77AE960EDF5910E3ADBD02B1203FD97 + 65: DE0379336B1C7421AB4A7F5708BAA3D4E15CE75CEEB8C7349265E71942A963216559FD628C52F71356134AC328D0315ACB63A06382D4251A28127380CCEB08FA + 66: 95FD3399270415A80C2F295957C0BD8E33E35C679C31B2118DFABD542EF02F6E2E432559ED4066954AFBF90C982F60D73DA8BCC94DD48BEDBB00A8E458CCB6B8 + 67: DE49AD8262EACF733B567D8F7752711ECB5D0FF5CB18E5A99C6C35442E652643149A51C820E6D4481AFE63F5B6955105F8173DA57DEFA392E43F7285799A32B9 + 68: BED41AF0733EED85BB26E8A06949AFA1CBCA9BA87C085BDE29FD38F94709F4AC20360F7C7958457D2C49BC5A38FBA06D6A6AF77ACC883783B357032FBA9F93CD + 69: CE72D475D983EB5E528C4D71EEE48EF337E1723DEFDF142598E4CEB3B2978B1B4E36A69EAB6CEE8F3DB2EB353CBD27BF7D41F73FB184CC8785DDCE8EC22E9741 + 70: 24A8A7C759F59CD3DE2E3BA953EA975B60079D9B331AEC4D1F4586FFAD190EF53C2EC6BAB566660EB5D652D7D54265B8584C6BBF986537F54F9D8E4068C01F67 + 71: A7CBE72C99EEEACB387D4532BDB651EB46B8D30A9D5DB8095C9B3422D9D5C9480AA820CFAFE4047AA0546C03DBF07424FCF7B812274B3CDFDC76B9FBBBF08190 + 72: 16D536D1D673F74D9E298B16AE65C65E467131FDE5B4356FE16E3FC36624E19FA7B55727240C51C20491F3122A1AB073B98E095A24F4B3260EBE5211EA2DCB0F + 73: 692189C1FF6DA5862657623BC862F5041D63A2A1EC8986139CCBCAB114427B1A2500B152CC611C5D5599E9792F014A640FBF7C6D944EDA811CD92374326B2C52 + 74: 273E18F4B94E624988C47CC45820E4552DCC53BB40A9A24F744A14E56FB1DADD3EA4087A785AEDB5400A65971709DA1AAB9C18EF534087EA73A1FC8FDC865170 + 75: 8F048230B202743FF1DEBAFEF8CC93244687A58A8E5E3E6F7D85237ADBC724641431783E63FC8EF2FBEF9DE9CD50C9FB294341654706DBEFE6B05CA8588E1A3C + 76: 7AEF7701439F9DB556AD3B166B0B25A51795638A83E0EE25E5244BBE9D2E8CB6A8242D81E78E4906AC9CA0AD4FECD1006D89C5A8582D1BF51C278EE7A357232D + 77: 55CE718F7686A0692B3727BB5C24B16FCB87D8E8EC943A80236CF3E9B37A4A20194243E461B453CF03AD846A0B3287A2005D6603D5E080D700ED2FA25F0FCA87 + 78: 3378B07E0563CA7BCB91F29C8ECA876AD748760748AD07DE0208BAC227E0EED4A4834B8879F3DFE51FFA27B70AAD1F3E9FE1586B1D6B2B9757D545D9CC5DFBB2 + 79: 040E1EC767CDD85FEED2AC6767F0B3C17CE4579FD9525213A682A9B49ED03979144CCE2B94026AAF7D401355B90B25259954163E0C9739CB9E756177ABA053CE + 80: D1CAE0E4FB245C1AC27659C2EE86BADCE26228CF8EA24AA62B69995FF02F9A59B1ACC1C959EF91A7B6EC90EA9D57F49CD0E7621D09E4016676953A3F9B9D40E9 + 81: B41EAC0850797959C62DA2750F2BCAECCDFBAB843D56C034E4E0DC15C961FA611C50F22BBC135E5D99DC4E4B7634A8DF4B0262829593A8A86EF6C265DB9AE907 + 82: 66BE82FD1582736D0DE7861D9DF74715658CF3CD2BCED12868EC4D92F4B015B7BACBB331ACA8D58386AE6B0642C3740BF5F3CB26E76551541AD57E1C303D4527 + 83: C38BC2639AFEC1964C89CB92DE5ECB78E0B2994EF37F839D0A61EA688CCEB068B1A590D6CCC929EFF1145F5A5925A17BF2FC0AD352801CB92651F08352A992D5 + 84: B699ADFC29C54F178B3EFFBF8FE8BFBCD722F2997AC30754A8FC5CC6D51352AFFF7F31D7F71FD9D136E78D1C1E040B05E25CCB75C7AEEF714018F51663C7AD91 + 85: FDC4207E97D12B7A8D05F5073D47EF32BA32961568599ED34CA160F2EDC87726C53087711A63F6BB7E840F305477B931D1CBC1939A8B80205565D453675FCFD7 + 86: 07E1DDE64790A279B69873C6887FBFCA69B87C97BC25B969E2B16040CDD2051BCF43637F490EF1B051CD882B64E22DA55C253A5E796528526EC62A305FB05621 + 87: 3ABE353A4291A3A0ECF204994D49443C1FCC60C80BF6096026551048533E02C475B905046C7708F4852645168C88125221504E174A8B7E67AE424C0077163E0D + 88: 33793697140180A04DA72C0F74E1F845139937CD6F05AF74E3F3C5031D1D2DE571BD72916CBE67859FE501C0E56354C1360E3EBC36EBC11D11C1EE08D158247C + 89: 9E5A386AA9C4C5A2419B902D239E49ED84E542A6F949895C88129DFC2844FC77FB132592C7C1474E619C55FC2835F0810F227799984777CE99D586C158C8F9ED + 90: 6E0D9841C04BB47DEE30F6AB430E53FA1637421E460BBBD7BC8EA167B9A341DDC5E933B6983A025226B1FB3CC663EDC3477F8F0C8FA109A8B97B4B17AF3C2774 + 91: AA0218FD54533314F62390B8C02219D26801C249D394E33981E3B853C5735E331826FA02697DF54C9268B891592DBD876E25C8D985DE8752ADAA0CBE55AE7FFB + 92: 23905B9273CA17D80D9C877DD78150B5382744896B073DC636618C540876B9BA51EC60F5E45DD53BE210B6076554238A3B5EA95DCE3481F0FCF2825B852BDE3E + 93: 1815D1AA4018626EAFF051AFBB92E91F6D6D136F58E8DB160C9E85BEC027B6CC92F0F0760DFD722BE12A97F7D29EEC341BD309F230B55B81D146B409EAEEB7D0 + 94: A2358789A04795BB20D2EDBF95D5DA28A1FBAB329F99DFD0B103304F868CE5AA2DC1F52FE98CC84EB095B9C5ACBD6DC05FD03CFBB3F1D26675D0A8F652D38236 + 95: 2C4DEF028098A0680DF15DEBFE6A7FA42C7A7D75CF410340ADD5257037F0B2F98FB5A068361DF33010FD48A4B41E0E40A2730FF2148C45FA568FAA182589A543 + 96: 360F3B6819EAFD9B3D6BC469F4272F9458C0791759EC1136FAD500F3FCB4FA0598204669E865D7D5F8C289043A2A1CCB47F55CEEFAEAD98C7FDEF38FB22D3A29 + 97: 1CB2E98EE8795761EDB7579583EF86E7223A2109267E5234663BCAAF9FBF28EAE35FE362AE9AD075023C1D36672002E08CB36189A603C174D73BB9489E13355F + 98: 9B3F2D2B2E3D0401229F11E6DED451A1289C631122684BB32B8C0450043ED2267AAEA20E950F52B44EA5941C507F38D23CA76E212593B65BAB347841179BED1D + 99: 2E27C53324017626F7EE7EE26BB0C88450B3D882C2D8823647ECA7650CADDFF3E4201D7DFA2A07A51B9372FCB04C1A79A264DCD3D260DE135D08DBABD2C5869A +100: 0B3D7FFC5DC1CB18B867D995E3D02FB2FBA0DE27BCC85E49A3B01C5581EB3B14C19254C87D92D2EEF952C98E4E6F51C9662CDB982BC95B88C11CB2EECF032576 +101: 85C0B9C8AB8C670C01E179F495DE26F818EE772AAF6FCE4ECBDB4FFADEB1CFD8EA86E42020B47894301920B86082DE52A7E7CDC6DB4904F8F0D383D9CDA312E7 +102: 0C6637D399CFE2734AF7B63F81B7493158B7842E3C5B72E6CEA4388A5C6DB7222D46727B92FB82D88551A227703B8BB6A1AAF47247661E074CF6AE4277D586DB +103: DC54B4ABBB7942C502BF3275E37570947FF7162B6831AA430566E69AA80658C6E792B78EA081611256C64552A9E15A66000632116AC83769B7C58B809FD96021 +104: 532372848D0F525884E5ACED9A727E96A8D92B484DC2D4089206B001CF9EC52902E49E6FD9FDE634941BDF5AA2B45B0787D0B183B895470BF1E79B57DC976EE0 +105: 4B6CEB5AA2174E6486ECB185044629BE6C280807F102CE52D2CE2DCCCFE96E5586A6888DF7500614896C9FE70CF7BC83FE755E88170B3D39EF9B218BE809E495 +106: 6D506B4BD3F079EF4818FCFDA519E7E2AB6A03293525711142C3CDC5236A7CD82A880D9CEDCBC089F7A3D5D3E48BD75DCCA7ADC53B13A2FC9CAC80C037F2CE5D +107: B8ABE308840CC901C6C5FD908E2680886AAA0BDF7085C1A6ABC257186AFC52C522528BD7BF4E82553D9E64CBEE09B9318995E13715AB1F7809EF185E8473D70E +108: 9790A198DA7616F4D8ACDE68DE19635A555874EAE77AD4ECFEF7207DC305D475FD250F308F466B189425AB6A9722D744AEF14541FEB83698943E87E8A39DF838 +109: 816678F1D7484660F4701CE77F4C5E13E5DFADEE6622411BE86DBA4EB71A110DD1087AF7D3F37B8ECB1B9C44A3BD5EA73901C21AAB51E569E61EFF25B5E955F9 +110: 51881FF4B150EDC3542CA12CE6554A40415AFFAA1197FE7CA4B8B065A4FB1DC3B924A444CA31776CED52514C525261269895EBD8584C29747F8D527213534E49 +111: 6D8902F285029EE683CE1803B2D9C6BF6E4B7B59C0ADBFBCED3346782A35652DE3F304ABBDE9F22E4960DF6049431139EC6AA023EE2B013A426DB9A816D92699 +112: 06E5847A060BBC4FCE1375DCC15AEAFBF514EE1ADCDF42AFF932AA277DC09EF614651255E35C499D6BA1BB875EA3E80F80AABF8B7710AA5696B058BE91B99B01 +113: CB1859580DCA13556FAB791572E523C2E888115C18C043B0E33F2268DD0056F9A60EDBB65DD9C8B552CE2299E847ED4617BEF3A453ED2AC3B5366B4D9A651B61 +114: 39778F80D346E53D1B0E60FF7B36A92639D9E7F11548C9326A59D9311D57BF09F33BFD6AC5352F2F041BD07A6D26A181419F5FCD1D5FF8AD38E485DA7DBD5419 +115: E508C9A77F53E36F76F0E477DFF076DE810F9F1599A16A3EFF1840332B26D6C7CC40E03CA8CC212FDA776F4DF968FCF92CE492AEBAABD65F069D1AEBECD11B7B +116: 4659D0E1F9E5318D7B92FCF7700C467429B63F27188C0BA168F0D5696DC764FBFE2C5EFFCF6DF11EA77A17B0565CADC04F95FFB0485CE6900161B82608B1647B +117: B3DB7FF2F08F57F0CBF2195BB9600E9AE5D86A15921EB164A98D25D559BAF5FD740D68430653DE73F3277425DD77CC3FB0CB44ACC5FDE693D59D5FA6DED84597 +118: CA4559843946A7583F944D51E31FDF32BBDBBFC049724454C090A6DB9C356739F2B7E254CF9746521D965593FBBCFB26092069FBFB0D17A1593416D69681B687 +119: 27CB8A2143D1073AC17009C31B28DB95DC195E20AD7D245D8AD880789898F043F0565FE41485EDC239C7129E4B7FB693D9044B2C3D34C5648E4FD8447E85FD71 +120: 99811490C7FC83A10AAD197E95D3618ABF5018E9AF7EA0AA2CC0C771FC11FCEF9FD6070A0962A563D260E8CCFDB77B48745C8C27018F9140870F146F124FF14B +121: A1537FDAD7E18F732181CD9EC9BFD3993FAF5F994A8809A106B59D13BB70FD8D7D4E6A4BEDFA806A9D434AAB0368DE840FD64395B4A9A874DB39405707AE3AE3 +122: FB0D6D962055B47D3A72371BDAF77BE7BF965EA7D53018CAE086E3536804AC748E706E89772DB60896EB8FE2ED8F580866BAF3108CA0C97938B69830FFBC14E3 +123: 3C947F4136D9E780A7572CA4D5D7998DD82D3890CC3F1BCB59A7FE230E31DE322DBA7CF7C1DACB33A3EB1F7E75297C056570D2846EDF756D36C1AE92F8DF6954 +124: BC1BDEFFC6AB779A7ACFE53A3F9DD588CD3C77C740F944C69E331C38F162607E0D4A0CA874AC3D1D74965468843133AA9F961FBFCBF59B58818577132B863181 +125: 51143DA8F5D6E68EC97CE22A4961EF43B3AB658711280587D9ACEE701CA65CAE90D34B66DB52D779A8E2BB6204FFCBCA945C6B98B2C17C8375551FAAFE4C8A44 +126: 2550FCF54872616ED31C60FB3FD97B9AEC7A27B3CEC07D774FCE694ED9D60C43A968251C5F3C5B50E6214426B00C55D7DB1DB31CFC4BC07F6ACEA222052AB796 +127: 1D8B2525E519A3FF8BDAAF31E80EE695F5914B78E7DAB801729B5D84C3A7A2B36A33803F5E0723981CF8A9586EC1BEABC58154EFD919AFF08935FBD756327AAB +128: 4AABF1C3F24C20FFAA61D6106E32EF1BB7CDEB607354BD4B6251893941730054244E198EECD4943C77082CC9B406A2E12271BCA455DF15D3613336615C36B22E + diff --git a/notes/ocb_tv.txt b/notes/ocb_tv.txt new file mode 100644 index 0000000..aefd8fd --- /dev/null +++ b/notes/ocb_tv.txt @@ -0,0 +1,331 @@ +OCB Test Vectors. Uses the 00010203...NN-1 pattern for nonce/plaintext/key. The outputs +are of the form ciphertext,tag for a given NN. The key for step N>1 is the tag of the previous +step repeated sufficiently. The nonce is fixed throughout. + +OCB-aes (16 byte key) + 0: , 04ADA45E947BC5B6E00F4C8B8053902D + 1: 07, 987354C062CD6251CAA6D93280EFE9BE + 2: 1CB7, B9F1620EA8374E1C2D05110878D93069 + 3: B98C59, 3793FB737C2DFB29E73DD1AD8B8F71C7 + 4: 8978F240, 5E25316ED13D3300F2EC12D718A0BA8E + 5: CB4D261594, EDA252A1A5C7D0A4AB4620F771446DD3 + 6: 30D6B6688D59, 684037DE07832C6FC38CA42BDF2A7D53 + 7: D0583F9741BFA4, 3DF53DFF73431C0245982F4EEEAD432F + 8: EE3B9596CBEFF520, D283D1B9D990739EA05F4BAE2E96BE4E + 9: 6570FC25E6103AC125, 90D3F1FA6595B775749FAE7B00A8E5B1 + 10: F56750C98C370DFDC4A0, 19389A6875FAB432B72D64BCDD6BD26C + 11: 3344AE6D9528603CC1E4E1, 87AB6FBC7F919125A7DB0D17D19056B8 + 12: F3D9D816A727D3E67330C779, 07AC0F3841DFCFEC58A5AAC22270538C + 13: 976651E63ABC3B276799BC1FE4, EE603A8C66099AD6FF8667B3F34ABF29 + 14: A48E3ABC31336C6B717A96170A9B, A9D1B973D84D3125F5F9D7923BA0A8FF + 15: F60E9B2A911FAFB0080FAA3ECDEE42, 4902F8AEB7685F7B255ECC45B5B7D3D4 + 16: 0855DE488940144AF18C65A9966DDB66, A66B3E7A75D394273AC196FFD062F9DD + 17: 172DC1740F75AB2A27B2B80895961A69AB, D6986BB95F7E4137430CAC67F773623B + 18: A414234DCCC61B65A79B7C618A6B91ACA410, 6CE32E55E158BC3E51E94116A615F3A2 + 19: 16A1B16BC0F63D63179901F1CBC772D612C102, 54007EF9822E0E4A4F953838577C76FA + 20: 539788EBF85C15B3A638017B4054D71315BFF25F, 9B2511322E16CECD53E3241F3D51EB97 + 21: 7E74595A3DCFE1EA2C91B67738765463D50A22924A, AC9C9B526251C16F112E769F9FBE74E4 + 22: A2B61792102B2E44F1DC0E48B40472CE883730504FEB, 76452A49C2524404C8A4B098D6390F98 + 23: F58174BC06A022AB7D81991E9346F5E4B0AEC535D93473, 47F96374BC094BB2C1A5D1D291806912 + 24: A3A7713895D178A85D9092EA6138323DC2FF9090D7F01AC5, 3814208FA7009A2934F9A172D029667D + 25: 385525DAF9949DCDEB22F7518AF96438E40F7D94933706A9F2, 1249F3DF50084A6D1A76AA350FD85B0B + 26: 6838E207D98A5BF8D8E41454CF51663D8F8B76FD26092D45D1D9, 301723D0F49BF8CF37828340B894689C + 27: 736413C025A549CB2550E93139DFD5DC3CE241C296C9FE641FF520, BE07259963F251743A85DF51EB1B47FB + 28: 7F2CD26367A885BD9E2B515D4E871272AC1BEA1C650B530E5616B2D3, EEB37E8451597E5A53CB49072EDA9346 + 29: 68F23DCDEF223B60B46E3D724A93BEEF8B110D4394C990AC3D0E34E1B6, 9A60344982F852EFE02CBE9CBBAB60F1 + 30: 66C5DE3EB27139983D48BED81D0E5FCE6BA1AB402C357062FE989D31C69C, BAFA0A7997A529039F0CE8528E670415 + 31: D3B9009C1A930EE288C61B0B15C7E92CB73484C345594DC5A3F377147981DB, 1EDAACF7F1F3AC7EA613F94DA4DEF930 + 32: F7818DF15FE6FBC42A28FDE1D55A2C07EC8D82AA0E7A680DBD3CF26C13448F9B, 67FEB344108008A88067E92B210766D5 + +OCB-blowfish (8 byte key) + 0: , 07B7752047F9E0AE + 1: CE, 7D69017C42B06204 + 2: 1D6F, 4DFD4BD58439062F + 3: 30A011, DB49D988798F8842 + 4: B71C8951, AA3261584B0C20FD + 5: 06F89957DA, 88BFA80D36427F64 + 6: 45BC4CE5FABD, 4CAF71136ED166A7 + 7: A7405F124D0296, 5D8993CE64FFF0E7 + 8: ECABEFD9E6574E4D, B69349673CF86E41 + 9: F7D26A7E82A34ACC71, AFFDEE843ABEA68A + 10: E225C5F0FA1D649F81A3, 03AC1D5DF1323EF8 + 11: 58722FBFB86C2697061217, CE731D80E6355710 + 12: E577EB8FA70225C5A18D31DC, 2F08B140F0D3A255 + 13: 92154A94CD7D42EBADB6CFEE14, DC949170E84D3CA2 + 14: 5A3C08744FD85CA262D51AC6CD25, E83CE45547403BAD + 15: 8B2E4980ABA10A20573A402D89AD12, E3D978611DD831D0 + 16: 3EDC4A0FA95BD8F944BCE4F252B6470C, 87B54BBEA86A5B5C + +OCB-xtea (16 byte key) + 0: , 56722ECFE6ED1300 + 1: CA, DF53479333DB86AA + 2: 9529, D0B5A859106FCC9B + 3: DDBAB2, 3B31FFDA57CF51C8 + 4: 22EB7DD4, 2BB34D04FFF810CB + 5: 108693761A, 7AFF6F52574A019A + 6: 391FB7C61E76, 616C5E66297F2CCE + 7: 3E22E4A4A0BD13, E84C385ABE25C8D8 + 8: 94FA11D5243EE34F, 8F017DE96049D0F9 + 9: DADB6B5D27049240A7, CA69E14047C6BBA7 + 10: F79C8EA83C69DE914DAC, 1EF042DA68106C64 + 11: C5B6E04AB8B9491E6A99F8, 143515779A55C972 + 12: 33F493AB7AE62DADA38C5B24, 531BF7799A778620 + 13: 6DAA66BF02E66DF8C0B6C1CC24, 6CDF72786C5EC761 + 14: 4940E22F083A0F3EC01B3D468928, 185EE9CD2D7521AB + 15: 5D100BF55708147A9537C7DB6E42A6, 78984C682124E904 + 16: 744033532DDB372BA4AFADEA1959251E, 438EB9F6B939844C + +OCB-rc5 (8 byte key) + 0: , E7462C3C0C95A73E + 1: C5, 83CB00E780937259 + 2: 1533, 022FF70566E0BA87 + 3: 57543B, AC4EF15FC83BDF2D + 4: 01E4474B, BD817C06AC2141E0 + 5: 4CD7E850EE, 7BB6B3BDA5373422 + 6: 489C0CD1502A, 23DD4406F87EB164 + 7: 0CBAAE08E07EFF, 92569C958B722413 + 8: 073612F283F8A6E4, 1DD978D01CE8D1DF + 9: CDE676B1A3AC98B00E, C033F099E2620668 + 10: AD3BC88EEEDA40A83685, 36DA44E13C0C8A4D + 11: CA60E8B918F73E99986021, 45634CA0E43E4B13 + 12: 3B3CF82157ECEACAD8658EF5, E681F57616146CC7 + 13: EBC1A7068346EC1B7EB815A7DC, 2C806D2A909CCAF1 + 14: 97CDB3EF8276F1E7D6B6677DA2DB, 53F00B9A2E43DE08 + 15: 44169B3EDAD9506C51A6DA055EF9C2, 5BB6DD996130896B + 16: 35EC29065B1FC640015B0F779E7A358A, 867EBD0E86823F09 + +OCB-rc6 (16 byte key) + 0: , 27B9E3F544B8F567EEBF98ED5FD55C76 + 1: 92, 219FD2D74D7E3F21AA6C2A507C0A546B + 2: BECF, 96A656A16FB3C4579E6955D592AECAE1 + 3: 4DDE09, 7D1882879B5D6FD8C151502BD8AB220A + 4: 0D6B4FCC, E01FBD1ECA2A6A8DC6697A06AB12BDB0 + 5: E5E19C973B, E5A86AADF2F333D5DEDCE410688CC6A4 + 6: 90BA7D2A6965, 80523A2CAB2A7BB2E90B121DE80F46A9 + 7: 6FE258148EC8D0, B7254B11276A77C5F99FE5EC91D81F57 + 8: D887080095DF8817, F3FB938068A01EF89DE0F1226C544362 + 9: D9823313289D597614, A547764EF20BD4B4B303882B64FAF2C5 + 10: FF68942112CF01701E86, 94F3860D4438428EE296CEACB3EB67F5 + 11: FFD390D3E0B64F64D3192F, 99D2E424C67EBACCD4E2EB9A0CDB8CDD + 12: 3162235748BDDECC84FC8C94, BDD400A58AF59100A731DD5B4386444E + 13: D2A0EC8B1F20672289F7236C56, B245CF42644BDAC5F077143AF2A57BA7 + 14: 830929B2850E22F6C1BA2027248C, B6B522F7D6BA3CFFA92D093B383542FE + 15: 2A5FCCCCF43F845AA77750D3BC6B1E, 53A0A0882C7844636900509921661FCA + 16: 8480234796F9EAC313140CE014B0265C, 0656CA8D851B53FD5C1AAC303B264E43 + 17: F011A67C22F16A42CEA5E493CB766964AA, 830B8158B7A96224A53FB7F3A08CD128 + 18: F76274A730A608C2AB37497A049C3699882E, 4DC4DD4DF39D0E68D6169F9DC7F4A6D5 + 19: 7B38DD237DE552A72E4369A81C30AFEA5E5063, 01A62CBD30153702A5B29FB2A1683899 + 20: 58EB866F1FCB060ACC821D776AAC4AD9E87C326A, 25AFB8FC48605E1396EA8471F55C1294 + 21: A25F2C0FAD66B3580627498EC66C994B49C5445911, 0182A951D9A3DA53675612DE8EED1FB9 + 22: 8813977F092F07F251A1497C898967F3F98F5CB878CB, 80BC353E310880A83DD4DE4FE96AB6F0 + 23: 52DC8B76F5A6F78D51FB7DB51048E2663563335EC876A5, DC3689AA079C04C19D83646B272F9DEC + 24: 965437D3FDF91784B63C73C8CD001BD9372167963DF36B89, 9FF84E2845E3C1E3E6711D1646B18F21 + 25: ADD40F674BD56FFC8F9B4047FAAD2471F0A48F4544C894F806, 9D684F74F9734F1C497E33D96A27E00C + 26: 7B049B688839BC62785082397DEC7AA94B837D094AECA4B14571, EE711DF1C15B5C9E36B6E38B6F7152D2 + 27: DD4681F9C498A3CF69A9AC876E02BD9CDC4FB1F6798F772013B62D, C5A50676EFAA2A56CBDBE55CFED3050D + 28: 471B5E89A1337E75E88AFBAACA1C011790F1657425483229E55C34EE, 20F73F2AC452FFEA423BE2EBDF33CFA1 + 29: 71812C83DE34DB329C8DCD98890AFB1F7719E890DAE5CEB7AC9668CAD0, 6FAA03E10C6FB67D425C683C6D85FD76 + 30: 4BC2DB33786CFD29B5CA5B804454169906138E90E29E7BE9197971027AF7, 75053C433EF5572A70C58EEC96F56C53 + 31: 5E3A0AB41264AB65365458ED3B7E6A25827E50075A9E347F1622ED0723E229, C8F1ECD19AD5FC970CF0D31BF46B0F2B + 32: 2E48DEE4B379CD59F5367D17DC397C1BFD53B8C4CE46A8202518614076174EB6, EFCE758ECCB6BE875D16B7E03A498D31 + +OCB-safer+ (16 byte key) + 0: , 88618DEF98FE588E23107E9A5D89C26B + 1: 39, 2B01B202E751F957E331ECD1CEDE3456 + 2: 13CB, 17071E5AFD5D8CE953A73F49412BE8C4 + 3: DC4428, 4B0B1881C2540FF92E7DE63C479A7750 + 4: 120382B0, 0BB11D57B5BD9D846CF31033CD4CCB92 + 5: 97F332F95B, 335E0424D0A820F60DBB968B8B5AA057 + 6: 3C7AAE72037B, C8034C2C76C1CCD7C1B3F36DD8907E1D + 7: 8A99E4A1B89B6D, 06A8165DFADF1EA5ABD89E574422DF7F + 8: 676587065F0342B8, 93ADE63994DF2189079234DC204BF92B + 9: 8EC394CBC6877B245A, 1A89F0AB0B44BC708EBD9DE489E2EEB8 + 10: 5FB5366E5CAE4DB72411, 5CA5881A5805D53ACA4904A5EEC01550 + 11: 72A1994028F09ED6A4E45C, 0FFC0052996CE45DF4A28F7A6E9CFEA6 + 12: 1D5EF20F52A9B72386D1A601, A697DF1179628DE1120D5E8D9F39DA6E + 13: 79BD002AA59D74F125AD9E32DE, 2F02CB6F70BF57BBA0DF100DE503F633 + 14: 442C6F9016DF4C090056258756A9, 58C6FD3180B9B74459D70B5684BE3F4C + 15: 4FC5543D9A892B44ED04EE8B25E232, B8B858B3D3EB4B26E867E429F88A56B4 + 16: F06E7503167C2210AB332259BAFD6AB4, 73CE2589D1DF34CA3DC2B14CC9FA6276 + 17: BCCC260BD4823B64090FB33E6816F9C330, 81ABBDC83B2544907840FEB5AF4479EC + 18: 450C1105B76F960D1A5F33D7F9D37DAE20C3, C41DDC8980E88E3986D9C84857BBE1E7 + 19: C9F36EF3A990E0554EDB59E6788F8E9BF1DBC7, 90DD543E148D9A0B79A8B376C5509E09 + 20: 3666FEEA98A4FC434EDB7517E7FCEE2320C69BCB, 99F11B360DDB3A15C42110831CCBF21C + 21: 126F39C19D1E0B87F1180F6589A75712B66209E2CE, B4D268FB8EF5C048CA9A35337D57828A + 22: C1B6D14EE8B6D0A653BFCC295D5F94E6BCA09E181D8A, 4B4883B614D5CC412B53ED4203EA93B7 + 23: D1F2A10F1A9DAB738C61CD0EF66FE5F6D1DA95DC671128, 3F1EFDA55EFEF1A0B24708E132BC4D25 + 24: 9D457216C584F43DBA1DD55C54822A8B6A86D22DBFFA14D4, 53402970B128E98A5F0D62476A38F959 + 25: 012828614B5D67C9A1EE24A1EBCD322FE9C8BE0C3F20A53714, 2BFF288D90DBDC638084F80F3F7AADF3 + 26: B1904AECF599F6C74557475E409E75E646271DEDEC7A830260DB, BF119BDBDA27773E038B7067D2B0EECD + 27: ED831771C4346FC19435354AE29F7A9436D6E8D4D42CFF26207DBD, C3F029FC8AE690E84FBD0EF806B801F3 + 28: E051B958601223FECEADF932A277BCF18C25025AE4DA791155B85035, EB75E56BE7856F1B5ED3D125C092D38A + 29: AB3449537C5E22125BC32D483F74C3A3DBDBD5232839A85D300F65B4FD, 851B0FBABD080F783BDE4F47ADCD6D76 + 30: 4E68550837130652795A8C9D68530717D2B0AA5A17F3AEF92FFB502E46AC, 10E222706527A64E757EDE4B9EFC09DD + 31: C2D7033DA7A1857D79497EA6C64779EB969046CCEE6C74E6592FEE6E7C94C4, 2015674ECA80AC9B67AE854E18A7D56E + 32: 2F3F0374DDC24AE21F02D4DA74D46C71F0CD2269A68F32F7FAA0BAB64AA8E9BC, 737C8BA1677A8CE97D42FBB07530EE99 + +OCB-twofish (16 byte key) + 0: , 2CD8EF22E5457C7FE4016B0FB82FD204 + 1: 64, EB7BB60E4932C0E97A7A5906BD044ACF + 2: 3A59, E3D2024241666369BB542ED096F20C71 + 3: 67C038, 7E6F1EB3F2088F6416BB675DCAC0D484 + 4: BB36BF02, BDEEEF07EBB7A50A5201C8A2D72C0036 + 5: 6F06C0E293, C63557681D84ACCFFBFEE87D82EF1D3C + 6: 2015F94CC5AA, EF1DEAD4134D2A1A47A20F26FAA3554D + 7: A5F8CDD07964B0, 672B74D88C8AA7567C6AC4A896E0F6D1 + 8: 5EFC9D8C3B9E7F3F, DB9160C53AD429D4C22BC0E2E6C509C5 + 9: B62CB80F75594BC54F, 20020A798FF59F0472E750C796B5CC94 + 10: 970983B0F889760EEEF0, 360AE43CEBCC27755548D4984CEEA10C + 11: 75C3A8CCB30A94CD57D1F8, 79820F3B1625E216B5BC1D1A22B198F9 + 12: 033DA41CCBFE3C6897230FCE, CFE3EDD11627270CD63916508B058B7A + 13: 15358032F30043A66F49D3F76A, 98B8056A7991D5EF498E7C09DAC7B25D + 14: 71FBA7D6C2C8DC4A0E2773766F26, 22BA0ECEF19532554335D8F1A1C7DEFC + 15: BD761CD92C6F9FB651B38555CDFDC7, 8E3C7E1D8C4702B85C6FCD04184739E4 + 16: EB6D310E2B7F84C24872EC48BFAA6BD7, 12DE548D982A122716CEDF5B5D2176D9 + 17: 8DDF6CE25A67B409D3FB42A25C3AA7A842, 3E9FA2C6C65341A8E1101C15E1BBD936 + 18: 5563DFC29B750FBC647E427C5480B65846DB, 90881C6820901BD41F7B3C2DF529B8A9 + 19: 93343C1E9624321C2A0A155BA8B4E66FD92BE2, 71A641DDCD49825E10880D54BEF30E91 + 20: C256BCA0CF0ACCEEC1AA4B9372AF27D2C3C65AFC, 91D45C4DA49BBAD1809A11F4041C7D09 + 21: 3DE69FDB72C93518A3E317F7B26C425EE3DD42DA7E, 85E37B3E8EC3AF476DB7819D739D07D5 + 22: 676AC7885C7C8FBE9862242FCCC46C181440EE49AE59, BCDB42B53AC4FDDF9C3BF8849AB96EEC + 23: D71B98B88F46CC47D90BB931564CDF0157F0ABCB5E6954, 289CD5799D9E49F36D70F67726A59610 + 24: 669C16DB9DC175200C08476832155DAA52F1F8969DF3B79A, 835B210EBBE5C9D34C2E052E1843C1F8 + 25: 2F39346E14A34BBED0491929CD9F1FB3CEC412C25AB703372A, DC4B42E8BA676BA100B87BEE328C5229 + 26: 1FD0F8BD0AC95E91881635EB0CF0E4FB099CBB214CE556422E2D, 898CEB3CA8FCA565CE5B01EF932FD391 + 27: 7FBD32B3D88B7E002BA6055585B5D0E1CC648315A81CFECA363CC8, 804820B1E3813D244164F778B9C2A8C8 + 28: 877A5F336A1D33AB94751A33E285C21666F0D8F103AC1187FC205372, AF9F0AC165EAFCEE8C2A831608F166B4 + 29: ECCA297705B0395E71B9E4263343D486B29207DA188C2F1BA626EDBF46, A05DC873406B236E4DDBC038DC4D2627 + 30: FF3BD8D4E1108E98FBAE2E28BC12819CD7956BC491C0B3A291FBEE739599, 68DFE58473BA2818A23095D1D6EC065C + 31: F175230606040ADACEBAFE4D58BBD140B2D45E8BF7E5C904510B58E4B53D3F, DAF579E1A12481D39F4DCFB7C28794B1 + 32: 261388D491EF1CB92C261FD9B91CAD5B95440DE0A747144EB8697699F600801D, 749056EBEAF4F20CD8746AA8C8846C47 + +OCB-rc2 (8 byte key) + 0: , 1A073F25FF5690BE + 1: F4, 3D3221E92E40F634 + 2: 2C76, C22C20B7231A0DB9 + 3: C647CB, 3E6348D996399629 + 4: 2021891A, 8EF76B24E9D55FDA + 5: 1966CBCBBF, 310D24024D573E8D + 6: 42C15AC9AAF0, 217E83C0CDE4F077 + 7: AB70F3F73DF0B6, 16AB2679D96A591B + 8: B7C7DD845D7E76DD, F33065EA531545CA + 9: 468CC16A37CF63EA73, 88879733F70AE3D3 + 10: 4F769E25A7346E22A932, 26E1A92FEDEE0597 + 11: 304A8B53B1CD24C6C27C17, 48B46E9F091B0B2E + 12: 4E3DF867FEFF0B8E06D5FA70, 53BB48BFB8AB4750 + 13: 2BAB3F0A8C38A3BD3C49DBBA5A, 52303CADCBB6D312 + 14: 3D04A29924589AAEF93A29003EE7, 120EF9364B83748F + 15: 486127A80E4EC599C461451CF1D79B, 2245D51599CAD629 + 16: AF8FB3FD2DB343F1AFF564FCBEA58785, 805BF441E660B0B0 + +OCB-des (8 byte key) + 0: , 8A65BD7DE54082AD + 1: A8, 3A83897CC8EC7CF6 + 2: 9256, DC66C39C7DD87D93 + 3: C145A0, 45967F3764F62F48 + 4: CD314BAB, EF38B0213259C3D4 + 5: 7074014741, 6748F4BAF06DD7BD + 6: 9A874CAE01F1, E382DB7235624104 + 7: DFA0D86DC4CA84, 627ABB432E50455E + 8: 685C2B2CBDD8D144, D166082E085063BA + 9: 53515DAAC7F7B8CE1D, 6680B6C26E1B0994 + 10: 2B3967812BF4155A8D36, AFED7F38AFEFC543 + 11: F4E5AC3CC5913B8A7F35FB, 6181DD3C46A6C24F + 12: F3EC89AD4235287D53715A81, 12CC354833FE5BD8 + 13: 66D554AC2CA85C079F051B8459, 097F31088CFBA239 + 14: 8746061C26D72771A7586949A3E4, 6CEF3565D0E45C6B + 15: FB3BCC650B29F418930A467EA4FB73, 64D12723E100F08B + 16: DE1C27E9B3C391AF5DF403291F2C084A, 6BADE4638AE46BE2 + +OCB-3des (24 byte key) + 0: , 9CB7074F93CD37DD + 1: 4D, 51541A838A154E0B + 2: 5C77, 60E86F2F1F4C6F96 + 3: B3D2F0, 7D74A9E6A061457D + 4: B3556075, EAF7A89A07453460 + 5: 1B61CE7230, F90D18620E1AB877 + 6: 3987FEC8D0D7, B5EF04DEE2E528F9 + 7: EBD0A7EBEEFF3B, A72CA24DD77A5DDA + 8: 429FB38DDABF76D4, D0578484C37227C8 + 9: F8DF28BF5C4CD28B1B, 5E7C4DC8E694E3B4 + 10: 2BF436BBE063F7E830C2, 8D919637C973C71B + 11: ED21656C8878319F1B7D29, 8813280C1277DF26 + 12: F45F90980D38EDF5D0FEC926, F9619341E273A31F + 13: 52F2D3CACC294B141B35D73BBF, 7BBC3F1A0D38F61F + 14: 2E6DA0FB55962F79B8E890E8DD8D, 8060799DCAB802E4 + 15: D6F9A6B2420174C499F9FE91178784, D3AAF969ED2F7215 + 16: 4F1CF285B8748C4F8F4D201C06B343CA, 203A2692C077F1B5 + +OCB-cast5 (8 byte key) + 0: , 77E8002236021687 + 1: 52, D57DF1037B6A799D + 2: 31C9, 7E781759B057D695 + 3: 5C8324, 56965D6CB2C97C0C + 4: 17D99099, 7C52B5D09475F5D3 + 5: 400082C475, 3CA5CDB9B4A0FAE9 + 6: 4DF0E4000C24, DCFEE2C3384F9731 + 7: 10004C3CE32255, 0A6832F985F61658 + 8: FFA6EA76B346893C, 6202693B153254D6 + 9: E96378C94D246AB51C, 5B259FEB715B9159 + 10: A9BED2D59A92D3D9418A, 1E7E066C098A023D + 11: 4EF144B7D4622BAD4DC840, 5DAB2C1D0DF56B08 + 12: 6DBCDF56E57CE47DD3D0CF44, 2A24F2A224368F55 + 13: 43241A0AD933635D7C8EAD47DC, 86B4B5AC22177F19 + 14: 920D6BDBE073F3C75052420C883D, 10943DBB23BD894D + 15: B2C75DF024269833B039CAB19EC865, 84B7DBB425E45855 + 16: 6A9424B6A873BB7155C01DC87E23EC52, 82C5047655952B01 + +OCB-noekeon (16 byte key) + 0: , 72751E743D0B7A07EFB23444F1492DDC + 1: 61, 41BDE9478A47B2B612A23752B5A42915 + 2: F4EB, 90EF542D89F867CDFB1A0807F8AA3CC6 + 3: F5A59B, 1BED873B613096546D4C201347CC3858 + 4: F454610B, FB4035F28AA75221F599668ABBE21782 + 5: 382FC932F1, B40270E2084E8DCEB14C6603D080D7C2 + 6: 18F921441119, 47F1F889B307298150750E81E94AB360 + 7: EF01C70C9D1810, AE0439DBB3825F27CF846B43E4C3AA80 + 8: 89863EDCAD471C3A, F4E8AF73BFC4CB79AECBBB3774DAF8C2 + 9: A6F494092E066A70F6, F73D3B04752B7D913420C17E656C7F86 + 10: 342459682E0A8D53AF4F, 61E7CF14E9878E0726C64B1E8CA08BFF + 11: 65E520D5A99825DE2441D1, 7A2AA740D786EB7015C61B31959E55D9 + 12: 2F96D0BB72E37DA202410302, 1A313242527FB522289094B9AFDB5F7B + 13: 3E8F8A1FCEE3F866EC29128BA0, B8065DA2DABF04129E5AE28ECC11A15B + 14: C2C15976D3C2499ACB9454878131, 372CAD486E104098EB1AA78A2922A1BE + 15: 1F12CADABAEE80E448B7EDCB42F8FE, 86A38DE5363787F55B16462C684E08DC + 16: 3B9ABB3304E75BF5B63E7F5B5A3F3980, 1FBD6B93E457B9779E2D12D78301EFA9 + 17: DC0CD805E43675A4317452E378AD48AC4C, 40AE4AFA4B3E580EFDB4AD0AF5BC4E4A + 18: E9DD52EA7264C6C7BBA39B761B6E87B65687, 4061DD65D5E7FFFE8D3D4261494D4F8C + 19: 80A9735CA1175072823828123413CCE772D521, D3378A12E79C49A37378DF527A460AB2 + 20: 09AD495AFFBF7CB8841262E7E5E8952878D4391A, C25D7A98C6F260B5FBCA3B8B5F7F33C1 + 21: 3925615707CC40C351D4A49794778545BC1F683175, 97622437A7208383A4A8D276D5551876 + 22: 5BB0D41ECD7BD2CF0B12A933255D95A3FE35E4C896BB, 4B8AD84EEA3156765A46AC19C68B6F88 + 23: 1EE71FE23CBFD5683AB1B391FC12B4E5952E4E6AA3D189, B0FD75996F28E071EB6C86BD7102BAA5 + 24: 0AA3D8C98AADEEE1867B13B017DD263BD16E960DA64FD071, 5204780963A62C2F4F7B3555BFF73836 + 25: 3A88B6F2AE321B226DA90B98E04A6A1589411BEDBE994632D5, 5638AF04EACF1EB986AC0702B4373A22 + 26: C2731661AC634A4DC0345F040DA7AEE507A3B9D019B5958543BA, 4C67D3FE37ABEE928B3BB812E7346823 + 27: D3E7651AA6DA035D05D599EFB806E8FD45177224593B5974758419, 5814E84258E1B9BD56A188AAE6F25138 + 28: 17818E7102B8C123230C5D64F18BE94C3159B85C8F7B64A7D4712CDA, FAA905B587A93DCF600BA8589A985432 + 29: BCA4335C6C29D978032C216114D39C01C6F161BF69D5A1CE55FBA8C575, BE24424A162E43A19755E2EFD274DBED + 30: 24C33CEE022F8A633DE9DFD009F535B52BCF64F390D2375E5BED65B70D08, 138F21D54B6B7E34628397DCDE0D33BF + 31: 838FE950C8165ADBBD6B61E9732F9A727CA7AE74376981382F0C531C331915, 0742E769CCBA2D1CAC7CAD4E0F012810 + 32: 57CD778DAD477271794FBF763662D97F8A10B17D70A69FDCB974FFE67E558519, 942C7D1C200C3845748F8131DF71AE26 + +OCB-skipjack (10 byte key) + 0: , 90EAAB5131AEB43B + 1: 2F, 6274B82063314006 + 2: DAF6, 6A6BCCE84FD4EF02 + 3: 5C2A88, C83D54C562A62852 + 4: B6E8FB5E, C44459EF41C8F296 + 5: 6C0888C119, 269DD7657BD0225F + 6: 1FD9AD7ECCC3, 3CA090F46B107839 + 7: 1EDBFF8AE458A3, 440380BF9745132B + 8: 04DBECC1F31F9F96, 2653620A4877B0E6 + 9: 908AE5648AF988A896, 00180FF33C1DD249 + 10: 53E63E0C297C1FC7859B, 36616209504C4230 + 11: 407BE16144187B4BEBD3A3, 4754B7DD4DB2927B + 12: 9961D87CFEDDF9CC22F2C806, 5947FC41E6B9CEC9 + 13: 9F5254962E4D210ED8AC301252, 97A392BEAF9B3B04 + 14: 379FDA76ECCFDAAC10F67FBF624C, 1D895ABD932BD5EC + 15: 1D5A7AD556FF3078284BB21A536DAA, 01FAE2F4936ED9D2 + 16: 4B8B71396924880CB33EA6EC6593F969, A0F4B1BE3B9B4CCE + diff --git a/notes/omac_tv.txt b/notes/omac_tv.txt new file mode 100644 index 0000000..e74f76f --- /dev/null +++ b/notes/omac_tv.txt @@ -0,0 +1,331 @@ +OMAC Tests. In these tests messages of N bytes long (00,01,02,...,NN-1) are OMAC'ed. The initial key is +of the same format (length specified per cipher). The OMAC key in step N+1 is the OMAC output of +step N (repeated as required to fill the array). + +OMAC-aes (16 byte key) + 0: 97DD6E5A882CBD564C39AE7D1C5A31AA + 1: F69346EEB9A76553172FC20E9DB18C63 + 2: 996B17202E2EDEBD63F414DD5E84F3AF + 3: D00D7DA967A2873589A7496503B3DBAB + 4: B43C24C0A82DAA12D328395C2ABD7CAE + 5: 9B902B6663B5FEDC6F9DCE74B35B91F2 + 6: 06A9678C65D7CE225E082ECA31788335 + 7: 7D67866CDB313DF65DED113DB02D6362 + 8: 259E28CF3E578AC47A21A77BA9EA8261 + 9: 32F23C8F93EA301C6D3FE0840CA8DB4B + 10: C2B06388AD6F8C43D19FE4F6A8ED21AE + 11: FA8622485DB2F62F84FF46E532A1A141 + 12: F312D9B2E6272578F406B66C79F30A0E + 13: 7A5DE06B2BFB75ADA665E96F680AC098 + 14: C3B00380F0BD8E2F5C9DD9945E0F36EE + 15: DDD87974A5FB2E7A4514241E94526B5B + 16: AD24FC47A0FEA84C54696DE997A94F4B + 17: 7538713D8AA2AE3726307EFF087BBF5E + 18: 7619A52B4C34A98440812F5F28F8DC4F + 19: 7E797B8846554888622CC5E400B2FA44 + 20: 61E8DD3E09145F5657DB4B8F7BD2D7D8 + 21: FDAE2A3FE60DDF1871C2613A293AB6F1 + 22: A186D6EFD10DFFD2C088480B0A784185 + 23: 3119D337865618CDA55C06FB992427CF + 24: 413E3EAD7E3F169A37C49F9CA92E235E + 25: 37A55AF22373B9A1E2F8368B2FB992CA + 26: 4941F604C40EEEE1A16CFE073C12D1FE + 27: 3E8F4A0876BF12A2DCA87157F15DC884 + 28: 5DFAE292D8EEB13D8FE5725E5D169742 + 29: 59160455E0C0B35D950BA67C77F9FB05 + 30: 5AC0D736A06A7DD146B137ADEE78EE06 + 31: 0CA1178F28B953045EE76E2E760036CA + 32: 025616215F870D1EF838AD1D2AE0C649 + +OMAC-blowfish (8 byte key) + 0: 2CFB5DE451FFE8CC + 1: A5AC339DB44D020C + 2: A3CE0CF62249444D + 3: 3076B7129CE3F6A1 + 4: 9E091A637DDF70E3 + 5: 275199AB20A5F09C + 6: CDEDA8D16A401E62 + 7: FC980516CF5C9E30 + 8: 659D0B31D21B622B + 9: 8306847B5E72E018 + 10: 7AD029BBF1D2919F + 11: 133181425C6808C9 + 12: FC5AC60E367F413A + 13: E0DF8BCCF0AD01D9 + 14: AC5015398FA64A85 + 15: 1F068F22AFFECEE1 + 16: 8E6831D5370678EF + +OMAC-xtea (16 byte key) + 0: 4A0B6160602E6C69 + 1: 1B797D5E14237F21 + 2: 938300C83B99D0AC + 3: F989B99B3DE563C6 + 4: F65DEA2A6AD45D1E + 5: 1DB329F0239E162E + 6: C0C148C4EE8B4E1F + 7: D82B387D5DFFE1FB + 8: 1D027A4493898DF2 + 9: 196369F6B0AF971A + 10: 2A37A2655191D10A + 11: BD514BE32718EB4A + 12: B4DBC978F8EE74ED + 13: 8ACCAD35C3D436AE + 14: 73ABDC1956630C9B + 15: 73410D3D169373CE + 16: 23D797B3C7919374 + +OMAC-rc5 (8 byte key) + 0: E374E40562C3CB23 + 1: B46D83F69233E236 + 2: 7CB72B1D335F04B0 + 3: 94457CBC97B31328 + 4: 543D0EDFCDCD7C76 + 5: 5164EFA8412EAA5D + 6: 13CA0717EF95F9A7 + 7: 2AA49A7AA7719700 + 8: C9E7C56125C3D90F + 9: 2BE3E15FE58648AA + 10: 77D0B90372D6D0FD + 11: 17408F62ECD62F57 + 12: 7864EFFA59DC059B + 13: 3212E76E25E5DEA8 + 14: E2424C083CDE5A6A + 15: DE86FFDBDA65D138 + 16: 85482C24D61B8950 + +OMAC-rc6 (16 byte key) + 0: E103BD8BA47B7C1C010E1561712E6722 + 1: E51AEECFED3AF40443B3A1C011407736 + 2: FA6506C5ABE03381B045D28D1D828966 + 3: FAC4237FFE7772E2299D3D983BB130DD + 4: 3A7E24D41121A5D4F96FCECF0C2A4A10 + 5: AA44291E5500C1C8E1A14CB56E4F979A + 6: 4B8FDA6DA6B3266E39111F403C31754E + 7: 4DF5F1A1C8EBC7F56D0D12EEB63FF585 + 8: 46A6DDE419355EDE14D31045FCA1BA35 + 9: 71756D4D3DF59578B7F93FD4B5C08187 + 10: ADA292A19F8636A03A8BC58C26D65B0D + 11: 703190DAF17F8D08A67A11FDF0C2A622 + 12: D2B94CAD1AFC5CD012575964D1425BE6 + 13: 45FD0069FCA6F72E23E4DB41AA543091 + 14: 36F652600F5C9F226721400A7199E2BA + 15: E8CC6389ECF8EF1DBB90A0FD051B7570 + 16: 8125446B975DBDA742A903340D6B96C7 + 17: 00B55E4399EB930E592F507F896BF3DC + 18: 33E58F42A47C9543A851D6CA9324FEE0 + 19: 9F28FDEA3EC7F515128F5D0C0EB684C5 + 20: AC1DAF6C01AA28BCC0A819189FA949D7 + 21: D0532B5F54A179444D052A4D2AD6E4F9 + 22: 58B80A66549404C7B9F64D5AE3F798AB + 23: D0D6D586477F92311DDF667E0749D338 + 24: 0DFC0FAA67FF114398CE94D0688AE146 + 25: E163B8C00CF5CC9FA23ACACD62B53D64 + 26: ACE9270456AF9BD388BA72E98825CFE8 + 27: 4302EED9BAA19C7A296585E23A066A44 + 28: B3EEABEFAB25C7478419265564715387 + 29: 9F0630ADE9C74AB2981D63F3B69E85BF + 30: 1215A9446A275CCE2714F94F3C213BB7 + 31: AF43D7F748DE0E3458DB970BAC37E98D + 32: BF871AC9E892CE0DCD7C8C7ADDD854C6 + +OMAC-safer+ (16 byte key) + 0: A2C8C7FEA5529D01C3FF4E9359EF74F4 + 1: EAB87021118FF24FE79B69ABCCB14A8F + 2: 789566F467BAA68F4CC3C4B61901D6D4 + 3: 369F41EEAF7D628F9E0D77BE43BFC1D2 + 4: DC46A20E1F36F45006ED5B43BEC20DA6 + 5: 8F150CE34F57BBA2E6CE3431B78E4ACD + 6: 61CD154478BE20F33B26CD8FC58091A5 + 7: 4E6DAA575CF28F1F48B256262B7D558C + 8: D21FA4F1859571DB91E92767C5487AA2 + 9: E3D009DC7E71FBBB030B8FF0B544A2C9 + 10: 094C236EA48ABF7DBAE5A88AA3DE07D7 + 11: 00C401996F8224359566660AC1CEDAA1 + 12: D580EC60F712558D875F01643D96653F + 13: 8482298027C7B4D5969787A1DB1B1F2F + 14: AB726AE3DA95CB242E63EF876A4BC446 + 15: D668ED4919003F5E45590663FAED41DA + 16: E4CFFD7E0E7B176867C386001849FD6F + 17: 37B3C6DEFC5573879006D15F982A397C + 18: 0AB8847EE6A41A0E960080EF0D1BF1C5 + 19: 2C94FCA2A685F276A65ED286AE12FD9F + 20: 23383032032D7B5165A31ECA156DBD23 + 21: E1EECFB3D671DF694FFB05AE4305AD4C + 22: A0F6CA99B96CD1EDD04C52828C8A4D74 + 23: 12D6B7053417AF3E407EFD6EE1CC38FE + 24: A566D1C39AE7A1A0A77D5A1F56C5FAAB + 25: 81C9FAECEAEA326140AFCD569668F669 + 26: 6A00BF1D0DC893868378E4347CB4A1B9 + 27: 98842956DBE7AFB1BF49C46497BD54C7 + 28: 88EFCD5A1644B75BB0B3F5DD338849CE + 29: 77EC62C278C61163B1BEC595A11F047A + 30: 147424E817DC69413CC657E0CB292F7F + 31: A2946CBB910743EF62D8A3C7391B9B9B + 32: 00EEDA55520B8A5B88B76487E80EB6E1 + +OMAC-twofish (16 byte key) + 0: 0158EB365FCCFDD94EBA6BE42B6659C4 + 1: 17DA580917D147D10CB73DB6800B0E59 + 2: 3F185CC15EF3328D3E075665308C07C8 + 3: 5712A97ACC9D08FE9D2087D0CA16B0AD + 4: 90425A8CC1C026DDD896FC2131AF654B + 5: 30A43D4FEAE71F5396308C16DA081B4A + 6: 6839FEF605704D49F1A379A9E9595E6F + 7: 56A8F06DFEE543971B351B07430E2026 + 8: 36DD0E4B55C5314F9F2753D7EB6F0849 + 9: 8E319249A3CD456460F410F518F8CEDB + 10: 463978BE2A063C22E71DC71520723517 + 11: 1B735E45FD3DF636E0A6104D4A2E9CB8 + 12: 628A82213148AD9791153D5AAFBDDFDC + 13: 21AFDF08A36ADB6659B656C8EA0800E5 + 14: E5C3E58803DDBE174E0D4C2B8171AEF0 + 15: FC6981F2B4359BA05988D61822C0FA88 + 16: 7B03498FAFB04A6542248852225F9DAE + 17: 9B173E91E59A940186E57BB867B8307B + 18: 470BF2EE614C8423AA3FDF323F1C103E + 19: 6E664AFDFD8306547BBEDA036D267B79 + 20: F61AEC1144C3DD646169E16073700AC6 + 21: AE503B139707AFA494F7F2DE933EE81A + 22: A0A8BDD4ED0DCAE4A8E1DCEE56368FF0 + 23: 460B8207930DA434AE6AFECC305D9A26 + 24: 7F03F8C7BA5365CC65F7864A42693BC8 + 25: 31448849D6190484192F29A221700011 + 26: BDA941019C75551D858F70FB1362EB23 + 27: 2880CB3E62447AE8EACA76C17971BB18 + 28: FC8D710FA3990B56357E61C2A302EB84 + 29: 793CD15348D7DFF301C47BC6E6235E22 + 30: 6FB0CE69A15A3B6A933324A480077D35 + 31: C24FCA5DD4AE0DF2BFF17364D17D6743 + 32: DC6738080478AF9AF7CA833295031E06 + +OMAC-rc2 (8 byte key) + 0: F001FE9BBC3A97B0 + 1: 8F8DC9C952897FBD + 2: EC82EAD195AAC38C + 3: 53DD52269B19E9A4 + 4: 9B86F64BF72A0647 + 5: 664A88A29F2898C6 + 6: AFEC3F71C1415666 + 7: 9BA1F2C1A2E765F9 + 8: 402A12120908B436 + 9: 03ECCD4C6AF44144 + 10: E8CA3529B5D9D6FC + 11: 951EE10779CC585D + 12: B9083CA88E7E819B + 13: AFFB9E884DACC5B7 + 14: E942E8BC241343D6 + 15: 9B190489091344FB + 16: 9330A9E05554A15A + +OMAC-des (8 byte key) + 0: C9085E99D74DF01D + 1: FAC84F0EFBEF8630 + 2: C37C5FECE671CF16 + 3: 45B2CBEE8701A5B1 + 4: 53665E1F024EB001 + 5: 357123CEDFC9FF61 + 6: BD2CFD33FB1F832B + 7: 1AAA9D8C9120BDBF + 8: EB9F589AE9D4E78F + 9: C8F9D2ACE691922D + 10: 81ED6F3611DDC0FD + 11: 2965ABEAC46839EE + 12: 2208B1E095F7AE2E + 13: C0414FE41800113E + 14: 653A24119CF43D97 + 15: 7FB7CE0862958B37 + 16: 55097816B10C549B + +OMAC-3des (24 byte key) + 0: 7F07A9EA8ECEDF9E + 1: 4E2A652EB5FBF5F8 + 2: 4F84E3779ACCB9F5 + 3: 7134AB3463115DC6 + 4: 82327BE8EA2D7E0B + 5: 24950B9C14D87CD9 + 6: B25A097BB7E0E18A + 7: ED51BAE55ED925E7 + 8: 56B79E7644556975 + 9: A65BD98E4D4E31E2 + 10: 11145BB51514482D + 11: 397486787E676BA6 + 12: BD1F6DEBAF6D9AEF + 13: 5CC3921F7DB815CF + 14: B0C0E60DA5F727F3 + 15: F8637AEEFF10F470 + 16: 0EA19531D42706EA + +OMAC-cast5 (8 byte key) + 0: 7413DCDB9F0C3100 + 1: 423799EDF1472B79 + 2: 03856F0CB4F11606 + 3: F152AE6360813DE0 + 4: 853998BD980AD146 + 5: AE6C3D667DB8B414 + 6: B5A4986A34BDE20F + 7: E5ABE5B979798942 + 8: BEE8DFED4555F405 + 9: 6B5339E952AF61BE + 10: 5E867CF34D9C1149 + 11: F9C55CB3BC655E08 + 12: EA09A2929AC7D915 + 13: CE8EB0E4370E1933 + 14: 749A424B2AA91B98 + 15: 8DDA93C2B814D5D1 + 16: E8B0B219D4CB699B + +OMAC-noekeon (16 byte key) + 0: EC61647B281C47C1B43F9815064BF953 + 1: B100B1B6CD96DCED8F47A77E70670A92 + 2: A96CDE3C48831A6B0A5ADFECA6399BDB + 3: 14E75E7CAD840208834918B29A5D4430 + 4: 9577083713AE6E44EEC987C77C93C072 + 5: 2A738C02841E461238C02F5CFC8E66A6 + 6: A901327E451BE0D2D9DEC83DEEA9A022 + 7: 5ED7EE1BE04A64A689D15F6970A821A6 + 8: BA053E24FCFD02C731A8CFCA19EE66A0 + 9: 57139CA8C91072555B29F85A19E2C84D + 10: 4585EAC7EFB84869FD96EE7A5FDD350B + 11: 62AF6C415CA73E54E82EA306254C1BDE + 12: 75304F9724BD364F84371EE154F5210E + 13: 7FE5DBCEE826760434745D417453182B + 14: EC98DA2A580E9131218D1CDE835423D4 + 15: 631BD9EAFD1AE445F2C1C35E2B4416ED + 16: CA2D902A1D83388FE35BAB7C29F359BA + 17: 0DBF0AF7FCBEEE21FB6159C0A2FFCD4C + 18: BD7CD2C49241032DA33B1975EE2EE982 + 19: B30B090EE8626D77D310EDB957552D46 + 20: 64F608AC5707C381AC6878AA38345144 + 21: 28513CA7795B23A02B37DC3732413D23 + 22: 9F440700094517847E9E013C8915C433 + 23: 8CA483F313D20BFE7E0C089DAA4145BD + 24: FA44872743E20E5E0A069B3C4578DB50 + 25: F6DE8FFBECD52CC1F213CD9E406DF3BC + 26: B9702B7E846735A3DCC0724255F88FEC + 27: A1DDAFED2B1732C7BA89C2F194AF039E + 28: 2549C5F0E30F8F4002431D2C098805B8 + 29: 52E3836181BF5C9B09A507D5330CD14F + 30: 01C55DCBCCFD9D7A4D27BDE2A89AA8EF + 31: 3CF721A0CF006702CDA91F2FF3E4D5E3 + 32: 6D264B9065BE98C170E68E9D2A4DE86E + +OMAC-skipjack (10 byte key) + 0: 84EDFA769040603C + 1: 7DA58A4CBD642627 + 2: 118F60115CFC8229 + 3: A7F7346D34DB2F0E + 4: 35615CCD526CD57F + 5: DE471601A3660844 + 6: 15FCCE6D6D883D1F + 7: C6F694861233151B + 8: 3B762B397F16E807 + 9: 976C6AB59FB3AB12 + 10: 6810791F2C595961 + 11: 7FA3478286917F17 + 12: 73DEE44A51C6B610 + 13: 89EE8B253B1ACE81 + 14: CDF2586A56C8A0B5 + 15: ED91F98DA98F42C4 + 16: D8D0FA5CE96B08BF + diff --git a/notes/pmac_tv.txt b/notes/pmac_tv.txt new file mode 100644 index 0000000..6a920cb --- /dev/null +++ b/notes/pmac_tv.txt @@ -0,0 +1,331 @@ +PMAC Tests. In these tests messages of N bytes long (00,01,02,...,NN-1) are OMAC'ed. The initial key is +of the same format (length specified per cipher). The OMAC key in step N+1 is the OMAC output of +step N (repeated as required to fill the array). + +PMAC-aes (16 byte key) + 0: 4399572CD6EA5341B8D35876A7098AF7 + 1: 580F7AA4AA45857C79BA2FB892228893 + 2: 24D2D1DBABDB25F9F2D391BB61F4204A + 3: 083BF95E310B42A89751BC8E65ABA8B5 + 4: 69BEB9268CD7FD3D7AB820BD7E226955 + 5: FD71B0E647ADB4BB3F587E82B8B3401A + 6: 07EA46271081840737CEB1AC9E5E22E3 + 7: FFA12AD9A9FDB5EE126084F82B381B10 + 8: 8A11AF301AAFEAC8A75984ED16BB3292 + 9: 368BDC3F4220E89B54C5F9D09FFB8F34 + 10: 8B6DBFF776FD526147D1C4655626374F + 11: C538C09FC10DF38217CD8E799D8D1DC9 + 12: FC1264A2051DEF73339432EA39443CFD + 13: 8AF37ED2FB2E8E30E9C4B75C1F1363E1 + 14: 4295541FC62F6774068B8194CC9D9A46 + 15: CFAF4D8EA09BB342F07131344DB0AA52 + 16: B6CBD6E95959B2A8E22DE07E38B64D8D + 17: 3124E42DE3273B0F4806FB72A50F3E54 + 18: 252D49403509B618AB3A6A1D99F9E9FA + 19: 9CDA75594CB696EB19C022DDA7324C10 + 20: 33BB8AE43B7BC179E85F157FA19607D0 + 21: 12FE91BCF2F2875379DC671C6F1B403E + 22: 416A3E519D1E406C92F8BB0DDBBBB6BF + 23: 6F98DCCD5A8D60DEAF612ACCEDD7E465 + 24: FFCE7604609B2C3C050921854C638B7E + 25: DD2BB10AA07A5EC8D326BB7BF8D407F4 + 26: 468BFE669FCDF354E4F9768FE1EAF8F6 + 27: 01724D2F2C61EB4F380852218212E892 + 28: 2D90EC658F57138505598C659C539A3E + 29: 6301EAA0E1500FFEB86752744EFFF23D + 30: 3CCB177486377616056D835F6F857F7C + 31: BFB3C7755C1F4543B516EB8610CB219F + 32: D5C505847D7CFFD8CED848F6CB613105 + +PMAC-blowfish (8 byte key) + 0: 3B7E4EFE92FA46AF + 1: 746840017C38C892 + 2: 3B6A92C731465B64 + 3: D89D3B05143B6704 + 4: 43F70D54B808B7CE + 5: 84E4063AB32F046C + 6: A7E78CD5CCD23805 + 7: A78FB083475FEF10 + 8: D4F6C26B5386BA25 + 9: 184768A079853C90 + 10: 0702E6C8140C5D3B + 11: 786D94565AA0DF4B + 12: F6D36D3A2F4FB2C1 + 13: 7BB3A0592E02B391 + 14: 5B575C77A470946B + 15: 686DAD633B5A8CC3 + 16: BDFE0C7F0254BAD5 + +PMAC-xtea (16 byte key) + 0: A7EF6BB667216DDA + 1: B039E53812C4ABDC + 2: 87D2F8EA5FB6864D + 3: F85E3F4C1D9F5EFC + 4: 4EB749D982FB5FE2 + 5: 0BFA0F172027441A + 6: FF82D01F36A6EC91 + 7: 3BC2AA2028EBBD7A + 8: 15AA03A97A971E2A + 9: C974691F5D66B835 + 10: 4FC7AA8F399A79ED + 11: 2633DA9E94673BAE + 12: 82A9FD48C5B60902 + 13: 31BF6DA9EE0CE7E4 + 14: 26B2538601B7620E + 15: D103F3C0B4579BE5 + 16: 031346BA20CD87BC + +PMAC-rc5 (8 byte key) + 0: C6B48F8DEC631F7C + 1: F7AA62C39972C358 + 2: 0E26EC105D99F417 + 3: 7D3C942798F20B8C + 4: 415CDA53E1DE3888 + 5: A314BA5BCA9A67AC + 6: 02A5D00A3E371326 + 7: E210F0A597A639E5 + 8: D4A15EED872B78A2 + 9: AC5F99886123F7DC + 10: 69AEB2478B58FFDF + 11: 8AB167DFC9EF7854 + 12: 945786A136B98E07 + 13: F3822AB46627CAB5 + 14: 23833793C3A83DA9 + 15: 70E6AB9E6734E5A6 + 16: 0705C312A4BB6EDE + +PMAC-rc6 (16 byte key) + 0: C7715A17012401DE248DC944DEEBD551 + 1: 5B804C6CCDF97BB28811C9ED24FE6157 + 2: 7528378C052F4346253CB0DFA3D251C7 + 3: 6DA86EE0B28606861B1A954D7429A93C + 4: B4DFF84C25937FB50EE79D4037323160 + 5: A60FD9BE5E1FF67EC9734776C8781096 + 6: 81D3F8EDC0A197DD3739EAE648F38580 + 7: 8BAF47F02120E898916D678DBD0C1641 + 8: 7A9EEC96F10B7CF557B61EF35BB55B08 + 9: B88C11221014F8AE048E56C427DF4A46 + 10: 4BBA8EED89F357861A265006816D9B04 + 11: 8497C1D55010A65ED8C3688B75A7CABF + 12: 95E1720C06A373CAD1A22F432F26BCCA + 13: A175FB732692831E96AFB587BC49E18C + 14: 54EBC04FCFD90302907BF77C4D8AC77C + 15: EA9F13EE5548CDF771C354527CDDA09B + 16: 4EDBCFD0E2E6B321530EB31B3E8C2FE4 + 17: F412304C1A5B9005CC3B7900A597DFB5 + 18: 3B9247C12BB25DF048BF5541E91E1A78 + 19: 39626488635D0A6224CD23C13B25AE8E + 20: 40305F5C2FCEF34E764E33EF635A3DC5 + 21: F84499804086033E85633A1EF9908617 + 22: C4D263CDC7E0969B8AC6FA9AD9D65CB8 + 23: 6137DC840E61EA6A288D017EFB9646FC + 24: 8619960428EB29B1D5390F40173C152F + 25: F0464509D0FBDBECEC9DFC57A820016D + 26: 630EED23E87059051E564194831BAEF6 + 27: 4B792B412458DC9411F281D5DD3A8DF6 + 28: F2349FA4418BC89853706B35A9F887BA + 29: FEAC41D48AEAB0955745DC2BE1E024D5 + 30: A67A135B4E6043CB7C9CAFBFA25D1828 + 31: EC12C9574BDE5B0001EE3895B53716E2 + 32: 44903C5737EE6B08FD7D7A3937CC840D + +PMAC-safer+ (16 byte key) + 0: E8603C78F9324E9D294DA13C1C6E6E9B + 1: 3F1178DFC2A10567D4BCC817D35D1E16 + 2: 27FE01F90E09237B4B888746199908EE + 3: 4F5172E3D8A58CD775CD480D85E70835 + 4: 74BED75EFAAB3E8AA0027D6730318521 + 5: 54B003AB0BE29B7C69F7C7494E4E9623 + 6: 8A2DAD967747AEA24670141B52494E2F + 7: 69EB054A24EE814E1FB7E78395339781 + 8: E59C2D16B76B700DC62093F0A7F716CC + 9: AB227D6303007FD2001D0B6A9E2BFEB7 + 10: AE107117D9457A1166C6DFD27A819B44 + 11: F84DE551B480CED350458851BAE20541 + 12: B0EB5103E7559B967D06A081665421E0 + 13: CDB14F3AD1170CE8C6091947BE89DE7B + 14: 24FA2F476407094152D528FCF124E438 + 15: 440144B31EC09BD8791BFE02E24EA170 + 16: 697D268A46E8B33CEC0BAB8CAF43F52D + 17: 587CBDE7608449BD162184020FBFCC8D + 18: 3EA999C2169CC65735737F50FCD7956B + 19: C6D692698CD8BEEBF2387C6A35A261B0 + 20: 46DAB3AD3C4E2EF712FAC38F846C63E1 + 21: 7261E68B530D10DDC9AD4C9AB5D95693 + 22: 4D0BA5773E988C2B7B2302BBA0A9D368 + 23: 8617154626362736698613151D1FD03A + 24: 23CF25F68B281E21777DC409FE3B774A + 25: CA626956C97DC4207D968A8CC85940B8 + 26: 24C39BE160BDBB753513F949C238014E + 27: 83CD65C010FB69A77EEDEA022A650530 + 28: 1A72DC8438B927464125C0DFEACDE75D + 29: 546054936A2CB5BFBB5E25FFD07C9B51 + 30: 0EB81A268F1BB91997CB9809D7F9F2AD + 31: 7D08B4DE960CADC483D55745BB4B2C17 + 32: FD45061D378A31D0186598B088F6261B + +PMAC-twofish (16 byte key) + 0: D2D40F078CEDC1A330279CB71B0FF12B + 1: D1C1E80FD5F38212C3527DA3797DA71D + 2: 071118A5A87F637D627E27CB581AD58C + 3: C8CFA166A9B300F720590382CE503B94 + 4: 3965342C5A6AC5F7B0A40DC3B89ED4EB + 5: 6830AB8969796682C3705E368B2BDF74 + 6: FF4DCC4D16B71AFEEA405D0097AD6B89 + 7: ADB77760B079C010889F79AA02190D70 + 8: 5F2FCD6AA2A22CEECAA4671EE0403B88 + 9: 70DD6D396330904A0A03E19046F4C0BF + 10: 8A2C9D88FA0303123275C704445A7F47 + 11: BA0B2F6D029DCD72566821AB884A8427 + 12: C8DF45FF13D7A2E4CFE1546279172300 + 13: 512659AD40DC2B9D31D299A1B00B3DAD + 14: A8A0E99D2E231180949FC4DFB4B79ED4 + 15: CA161AFB2BC7D891AAE268D167897EF2 + 16: D6C19BBDFFC5822663B604B1F836D8BD + 17: 4BF115F409A41A26E89C8D758BBF5F68 + 18: 02E3196D888D5A8DE818DBCBAD6E6DC7 + 19: 995C9DD698EC711A73BD41CAAE8EB633 + 20: A031857FADC8C8AFEABF14EF663A712D + 21: 124695C9A8132618B10E9800A4EFACC5 + 22: 997E5E41798648B8CE0C398EF9135A2C + 23: 42C92154B71FB4E133F8F5B2A2007AB2 + 24: 945DC568188D036AC91051A11AC92BBF + 25: D5A860CC4C3087E9F4988B25D1F7FAAE + 26: 6CD6ABF8EDF3102659AFFBE476E2CBE8 + 27: 45ECD0C37091414E28153AA5AFA3E0B2 + 28: CBA6FE296DDE36FE689C65667F67A038 + 29: C4022281633F2FC438625540B2EE4EB8 + 30: 864E27045F9CC79B5377FDF80A6199CF + 31: 0D06F2FAEC5AA404A4087AAEBC4DBB36 + 32: 0F396FE9E3D9D74D17EB7A0BF603AB51 + +PMAC-rc2 (8 byte key) + 0: E5AF80FAC4580444 + 1: 6A15D6211EB4FF99 + 2: DDB95E9486C4B034 + 3: 9764761DC2AAD5C0 + 4: 1B1CD2E799D44B4F + 5: 4F80FE32256CF2EC + 6: 7B70CF31C81CD384 + 7: 9BC10DD9332CF3BB + 8: 628189801879FDD8 + 9: 5FC17C555E2AE28B + 10: E20E68327ABEAC32 + 11: 5D375CA59E7E2A7C + 12: A9F4CFC684113161 + 13: 3A0E069940DDD13C + 14: EAC25B6351941674 + 15: CB8B5CF885D838CF + 16: DCBCDDFC06D3DB9A + +PMAC-des (8 byte key) + 0: 086A2A7CFC08E28E + 1: F66A1FB75AF18EC9 + 2: B58561DE2BEB96DF + 3: 9C50856F571B3167 + 4: 6CC645BF3FB00754 + 5: 0E4BEE62B2972C5A + 6: D2215E451649F11F + 7: E83DDC61D12F3995 + 8: 155B20BDA899D2CF + 9: 2567071973052B1D + 10: DB9C20237A2D8575 + 11: DAF4041E5674A48C + 12: 552DB7A627E8ECC4 + 13: 1E8B7F823488DEC0 + 14: 84AA15713793B25D + 15: FCE22E6CAD528B49 + 16: 993884FB9B3FB620 + +PMAC-3des (24 byte key) + 0: E42CCBC9C9457DF6 + 1: FE766F7930557708 + 2: B9011E8AF7CD1E16 + 3: 5AE38B037BEA850B + 4: A6B2C586E1875116 + 5: BF8BA4F1D53A4473 + 6: 3EB4A079E4E39AD5 + 7: 80293018AC36EDBF + 8: CC3F5F62C2CEE93C + 9: EE6AA24CE39BE821 + 10: 487A6EAF915966EA + 11: D94AD6393DF44F00 + 12: F4BFCCC818B4E20D + 13: 2BE9BC57412591AA + 14: 7F7CC8D87F2CDAB7 + 15: B13BFD07E7A202CB + 16: 58A6931335B4B2C2 + +PMAC-cast5 (8 byte key) + 0: 0654F2F4BC1F7470 + 1: 3F725B162A1C8E6B + 2: BCFBDC680A20F379 + 3: 027922705BCACDEE + 4: 44E2F4BE59774BA4 + 5: 3ABD1AFC8EE291F7 + 6: D96347E717921E96 + 7: 96257299FCE55BC6 + 8: C2C1DA176EE98170 + 9: FD415C122E604589 + 10: DCBCA228D45AEDA4 + 11: 7801FBCFAAB9DF75 + 12: D38CB38574474B7F + 13: F5C5A23FF3E80F37 + 14: 83FA4DAD55D092F5 + 15: BDC0A27EE0CB1657 + 16: 87D907CACA80A138 + +PMAC-noekeon (16 byte key) + 0: A1E4C84B5958726557DF0855B37AA551 + 1: 5DE20299CA919D3365B493D3D4895F92 + 2: AF7E70C336571A857F62A18649EDB197 + 3: C5F55CFE1AA119C352B64252AD246CBD + 4: FEF68A0CE08E8BA315B73B62F861824F + 5: 8321C2958DE4903DC12C42A8845ECC20 + 6: 370466D1324AECF1F5B42E0E01381613 + 7: 5CB900190F5CACBACFE5EAB0CC289D87 + 8: A13C043E6CAAA1E34601A93C497446A4 + 9: 865E11622A4CC8A9E1408E00F56C4543 + 10: 9DC42C26868374649BD17D69D025CA1B + 11: 37D33C11B433C91DA09925CA9E86757A + 12: 1373D769C270E7137C953AC0F8F37941 + 13: 7E81DEC583348B1E2F6267ECF82CB994 + 14: 505B6329338556518FF364CAA730F5E8 + 15: 0C085AEEB315968B0BDE904E8BBC6FD0 + 16: 5FED63259364BE7E5133FF0507DD2D4C + 17: F7EE5C80A99AAEADB49E7CC69BFFF679 + 18: 4388FA5E763A641130940EB705BEFD08 + 19: 1BC31CA79EBE1674CEBE01BC9988267B + 20: BE88961637EFFE2D6905D104FEDD51A4 + 21: 9C341004FB22AFCC496094E3207CA761 + 22: B9DAA3620E38FFC7C5D5E7D2D8FE3DE4 + 23: A38D2E571F037061B4400F1131FDBDEA + 24: 61DB71AE77A6EB47F2E9E14E8CBF2F4B + 25: 9903A072274CC048EF2C51493266D9ED + 26: 1EBEA421DD08859C17DDF39B20A82102 + 27: F425858618E1A86F4912E4714EFB9E75 + 28: 3B3D4EA07F7FE6DDFDD02D624ACDFC9F + 29: CEEE256591D701514EB17DF73B08A970 + 30: 5CC56D5D46120C530A23B6C511C685FC + 31: 68E484CE18BE28EADD0BBF23291B8237 + 32: ABD58A9CDF8AA68168A1A402074CF520 + +PMAC-skipjack (10 byte key) + 0: 9CD94B75BC43B647 + 1: B069ACB82B12BC7B + 2: 6DD40E71EB03E311 + 3: 74CBED61D77DBA7D + 4: DD1B7E0D181537FE + 5: ACB5B96FA0AD1786 + 6: B34E01EB2567D381 + 7: 9623DAADE57B9549 + 8: 8BA384BABB798344 + 9: B147AA9D5C5C67CF + 10: 0033C520F4C67523 + 11: 42DAC184BEABC3E5 + 12: 428029311004AEBB + 13: AC2BB1C0F0ED649B + 14: F7CAA9A3BF749C1A + 15: 2C5BD475AAC44C77 + 16: FEB892DA66D31A84 + diff --git a/notes/tech0001.txt b/notes/tech0001.txt new file mode 100644 index 0000000..daf7e57 --- /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/notes/tech0002.txt b/notes/tech0002.txt new file mode 100644 index 0000000..b9990e0 --- /dev/null +++ b/notes/tech0002.txt @@ -0,0 +1,52 @@ +Tech Note 0002 +How to avoid non-intrusive timing attacks with online computations +Tom St Denis + +Introduction +------------ + +A timing attack is when an attacker can observe a side channel of the device (in this case time). In this tech note +we consider only non-intrusive timing attacks with respect to online computations. That is an attacker can +determine when a computation (such as a public key encryption) begins and ends but cannot observe the device +directly. This is specifically important for applications which transmit data via a public network. + +Consider a Diffie-Hellman encryption which requires the sender to make up a public key "y = g^x mod p". Libtomcrypt +uses the MPI bignum library to perform the operation. The time it takes to compute y is controlled by the number +of 1 bits in the exponent 'x'. To a large extent there will be the same number of squaring operations. "1" bits in +the exponent require the sender to perform a multiplication. This means to a certain extent an attacker can +determine not only the magnitude of 'x' but the number of one bits. With this information the attacker cannot directly +learn the key used. However, good cryptography mandates the close scrutiny of any practical side channel. + +Similar logic applies to the other various routines. Fortunately for this case there is a simple solution. First, +determine the maximum time the particular operation can require. For instance, on an Athlon 1.53Ghz XP processor a +DH-768 encryption requires roughly 50 milliseconds. Take that time and round it up. Now place a delay after the call. + +For example, + +void demo(void) { + clock_t t1; + + // get initial clock + t1 = clock(); + + // some PK function + + // now delay + while (clock() < (t1 + 100)); + + // transmit data... + +} + +This code has the effect of taking at least 100 ms always. In effect someone analyzing the traffic will see that the +operations always take a fixed amount of time. Since no two platforms are the same this type of fix has not been +incorporated into libtomcrypt (nor is it desired for many platforms). This requires on the developers part to profile +the code to determine the delays required. + +Note that this "quick" fix has no effect against an intrusive attacker. For example, power consumption will drop +significantly in the loop after the operation. However, this type of fix is more important to secure the user of the +application/device. For example, a user placing an order online won't try to cheat themselves by cracking open their +device and performing side-channel cryptanalysis. An attacker over a network might try to use the timing information +against the user. + + diff --git a/notes/tech0003.txt b/notes/tech0003.txt new file mode 100644 index 0000000..1a21867 --- /dev/null +++ b/notes/tech0003.txt @@ -0,0 +1,52 @@ +Tech Note 0003 +Minimizing Memory Usage +Tom St Denis + +Introduction +------------ + +For the most part the library can get by with around 20KB of stack and about 32KB of heap even if you use the +public key functions. If all you plan on using are the hashes and ciphers than only about 1KB of stack is required +and no heap. + +To save space all of the symmetric key scheduled keys are stored in a union called "symmetric_key". This means the +size of a symmetric_key is the size of the largest scheduled key. By removing the ciphers you don't use from +the build you can minimize the size of this structure. For instance, by removing both Twofish and Blowfish the +size reduces to 768 bytes from the 4,256 bytes it would have been (on a 32-bit platform). Or if you remove +Blowfish and use Twofish with TWOFISH_SMALL defined its still 768 bytes. Even at its largest the structure is only +4KB which is normally not a problem for any platform. + + +Cipher Name | Size of scheduled key (bytes) | +------------+-------------------------------| +Twofish | 4,256 | +Blowfish | 4,168 | +3DES | 768 | +SAFER+ | 532 | +Serpent | 528 | +Rijndael | 516 | +XTEA | 256 | +RC2 | 256 | +DES | 256 | +SAFER [#] | 217 | +RC5 | 204 | +Twofish [*] | 193 | +RC6 | 176 | +CAST5 | 132 | +Noekeon | 32 | +Skipjack | 10 | +------------+-------------------------------/ +Memory used per cipher on a 32-bit platform. + +[*] For Twofish with TWOFISH_SMALL defined +[#] For all 64-bit SAFER ciphers. + +Noekeon is a fairly fast cipher and uses very little memory. Ideally in low-ram platforms all other ciphers should be +left undefined and Noekeon should remain. While Noekeon is generally considered a secure block cipher (it is insecure +as a hash) CAST5 is perhaps a "runner-up" choice. CAST5 has been around longer (it is also known as CAST-128) and is +fairly fast as well. + +You can easily accomplish this via the "config.pl" script. Simply answer "n" to all of the ciphers except the one you want +and then rebuild the library. [or you can hand edit mycrypt_custom.h] + + diff --git a/ocb_decrypt.c b/ocb_decrypt.c new file mode 100644 index 0000000..1e409f2 --- /dev/null +++ b/ocb_decrypt.c @@ -0,0 +1,58 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* OCB Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef OCB_MODE + +int ocb_decrypt(ocb_state *ocb, const unsigned char *ct, unsigned char *pt) +{ + unsigned char Z[MAXBLOCKSIZE], tmp[MAXBLOCKSIZE]; + int err, x; + + _ARGCHK(ocb != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) { + return err; + } + if (ocb->block_len != cipher_descriptor[ocb->cipher].block_length) { + return CRYPT_INVALID_ARG; + } + + /* Get Z[i] value */ + ocb_shift_xor(ocb, Z); + + /* xor ct in, encrypt, xor Z out */ + for (x = 0; x < ocb->block_len; x++) { + tmp[x] = ct[x] ^ Z[x]; + } + cipher_descriptor[ocb->cipher].ecb_decrypt(tmp, pt, &ocb->key); + for (x = 0; x < ocb->block_len; x++) { + pt[x] ^= Z[x]; + } + + /* compute checksum */ + for (x = 0; x < ocb->block_len; x++) { + ocb->checksum[x] ^= pt[x]; + } + + +#ifdef CLEAN_STACK + zeromem(Z, sizeof(Z)); + zeromem(tmp, sizeof(tmp)); +#endif + return CRYPT_OK; +} + +#endif + diff --git a/ocb_decrypt_verify_memory.c b/ocb_decrypt_verify_memory.c new file mode 100644 index 0000000..f0e29fa --- /dev/null +++ b/ocb_decrypt_verify_memory.c @@ -0,0 +1,52 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* OCB Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef OCB_MODE + +int ocb_decrypt_verify_memory(int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, + const unsigned char *ct, unsigned long ctlen, + unsigned char *pt, + const unsigned char *tag, unsigned long taglen, + int *res) +{ + int err; + ocb_state ocb; + + + _ARGCHK(key != NULL); + _ARGCHK(nonce != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(tag != NULL); + _ARGCHK(res != NULL); + + if ((err = ocb_init(&ocb, cipher, key, keylen, nonce)) != CRYPT_OK) { + return err; + } + + while (ctlen > (unsigned long)ocb.block_len) { + if ((err = ocb_decrypt(&ocb, ct, pt)) != CRYPT_OK) { + return err; + } + ctlen -= ocb.block_len; + pt += ocb.block_len; + ct += ocb.block_len; + } + + return ocb_done_decrypt(&ocb, ct, ctlen, pt, tag, taglen, res); +} + +#endif diff --git a/ocb_done_decrypt.c b/ocb_done_decrypt.c new file mode 100644 index 0000000..97ba393 --- /dev/null +++ b/ocb_done_decrypt.c @@ -0,0 +1,51 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* OCB Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef OCB_MODE + +int ocb_done_decrypt(ocb_state *ocb, + const unsigned char *ct, unsigned long ctlen, + unsigned char *pt, + const unsigned char *tag, unsigned long taglen, int *res) +{ + int err; + unsigned char tagbuf[MAXBLOCKSIZE]; + unsigned long tagbuflen; + + _ARGCHK(ocb != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(tag != NULL); + _ARGCHK(res != NULL); + + *res = 0; + + tagbuflen = sizeof(tagbuf); + if ((err = __ocb_done(ocb, ct, ctlen, pt, tagbuf, &tagbuflen, 1)) != CRYPT_OK) { + return err; + } + + if (taglen <= tagbuflen && memcmp(tagbuf, tag, taglen) == 0) { + *res = 1; + } + +#ifdef CLEAN_STACK + zeromem(tagbuf, sizeof(tagbuf)); +#endif + + return CRYPT_OK; +} + +#endif + diff --git a/ocb_done_encrypt.c b/ocb_done_encrypt.c new file mode 100644 index 0000000..209892e --- /dev/null +++ b/ocb_done_encrypt.c @@ -0,0 +1,29 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* OCB Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef OCB_MODE + +int ocb_done_encrypt(ocb_state *ocb, const unsigned char *pt, unsigned long ptlen, + unsigned char *ct, unsigned char *tag, unsigned long *taglen) +{ + _ARGCHK(ocb != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(tag != NULL); + _ARGCHK(taglen != NULL); + return __ocb_done(ocb, pt, ptlen, ct, tag, taglen, 0); +} + +#endif + diff --git a/ocb_encrypt.c b/ocb_encrypt.c new file mode 100644 index 0000000..d951933 --- /dev/null +++ b/ocb_encrypt.c @@ -0,0 +1,56 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* OCB Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef OCB_MODE + +int ocb_encrypt(ocb_state *ocb, const unsigned char *pt, unsigned char *ct) +{ + unsigned char Z[MAXBLOCKSIZE], tmp[MAXBLOCKSIZE]; + int err, x; + + _ARGCHK(ocb != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) { + return err; + } + if (ocb->block_len != cipher_descriptor[ocb->cipher].block_length) { + return CRYPT_INVALID_ARG; + } + + /* compute checksum */ + for (x = 0; x < ocb->block_len; x++) { + ocb->checksum[x] ^= pt[x]; + } + + /* Get Z[i] value */ + ocb_shift_xor(ocb, Z); + + /* xor pt in, encrypt, xor Z out */ + for (x = 0; x < ocb->block_len; x++) { + tmp[x] = pt[x] ^ Z[x]; + } + cipher_descriptor[ocb->cipher].ecb_encrypt(tmp, ct, &ocb->key); + for (x = 0; x < ocb->block_len; x++) { + ct[x] ^= Z[x]; + } + +#ifdef CLEAN_STACK + zeromem(Z, sizeof(Z)); + zeromem(tmp, sizeof(tmp)); +#endif + return CRYPT_OK; +} + +#endif diff --git a/ocb_encrypt_authenticate_memory.c b/ocb_encrypt_authenticate_memory.c new file mode 100644 index 0000000..839da02 --- /dev/null +++ b/ocb_encrypt_authenticate_memory.c @@ -0,0 +1,50 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* OCB Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef OCB_MODE + +int ocb_encrypt_authenticate_memory(int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *nonce, + const unsigned char *pt, unsigned long ptlen, + unsigned char *ct, + unsigned char *tag, unsigned long *taglen) +{ + int err; + ocb_state ocb; + + _ARGCHK(key != NULL); + _ARGCHK(nonce != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(tag != NULL); + _ARGCHK(taglen != NULL); + + if ((err = ocb_init(&ocb, cipher, key, keylen, nonce)) != CRYPT_OK) { + return err; + } + + while (ptlen > (unsigned long)ocb.block_len) { + if ((err = ocb_encrypt(&ocb, pt, ct)) != CRYPT_OK) { + return err; + } + ptlen -= ocb.block_len; + pt += ocb.block_len; + ct += ocb.block_len; + } + + return ocb_done_encrypt(&ocb, pt, ptlen, ct, tag, taglen); +} + +#endif diff --git a/ocb_init.c b/ocb_init.c new file mode 100644 index 0000000..bfb5a87 --- /dev/null +++ b/ocb_init.c @@ -0,0 +1,117 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* OCB Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef OCB_MODE + +static const struct { + int len; + unsigned char poly_div[MAXBLOCKSIZE], + poly_mul[MAXBLOCKSIZE]; +} polys[] = { +{ + 8, + { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B } +}, { + 16, + { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 } +} +}; + +int ocb_init(ocb_state *ocb, int cipher, + const unsigned char *key, unsigned long keylen, const unsigned char *nonce) +{ + int poly, x, y, m, err; + + _ARGCHK(ocb != NULL); + _ARGCHK(key != NULL); + _ARGCHK(nonce != NULL); + + /* valid cipher? */ + if ((err = cipher_is_valid(cipher)) != CRYPT_OK) { + return err; + } + + /* determine which polys to use */ + ocb->block_len = cipher_descriptor[cipher].block_length; + for (poly = 0; poly < (int)(sizeof(polys)/sizeof(polys[0])); poly++) { + if (polys[poly].len == ocb->block_len) { + break; + } + } + if (polys[poly].len != ocb->block_len) { + return CRYPT_INVALID_ARG; + } + + /* schedule the key */ + if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, &ocb->key)) != CRYPT_OK) { + return err; + } + + /* find L = E[0] */ + zeromem(ocb->L, ocb->block_len); + cipher_descriptor[cipher].ecb_encrypt(ocb->L, ocb->L, &ocb->key); + + /* find R = E[N xor L] */ + for (x = 0; x < ocb->block_len; x++) { + ocb->R[x] = ocb->L[x] ^ nonce[x]; + } + cipher_descriptor[cipher].ecb_encrypt(ocb->R, ocb->R, &ocb->key); + + /* find Ls[i] = L << i for i == 0..31 */ + memcpy(ocb->Ls[0], ocb->L, ocb->block_len); + for (x = 1; x < 32; x++) { + m = ocb->Ls[x-1][0] >> 7; + for (y = 0; y < ocb->block_len-1; y++) { + ocb->Ls[x][y] = ((ocb->Ls[x-1][y] << 1) | (ocb->Ls[x-1][y+1] >> 7)) & 255; + } + ocb->Ls[x][ocb->block_len-1] = (ocb->Ls[x-1][ocb->block_len-1] << 1) & 255; + + if (m == 1) { + for (y = 0; y < ocb->block_len; y++) { + ocb->Ls[x][y] ^= polys[poly].poly_mul[y]; + } + } + } + + /* find Lr = L / x */ + m = ocb->L[ocb->block_len-1] & 1; + + /* shift right */ + for (x = ocb->block_len - 1; x > 0; x--) { + ocb->Lr[x] = ((ocb->L[x] >> 1) | (ocb->L[x-1] << 7)) & 255; + } + ocb->Lr[0] = ocb->L[0] >> 1; + + if (m == 1) { + for (x = 0; x < ocb->block_len; x++) { + ocb->Lr[x] ^= polys[poly].poly_div[x]; + } + } + + /* set Li, checksum */ + zeromem(ocb->Li, ocb->block_len); + zeromem(ocb->checksum, ocb->block_len); + + /* set other params */ + ocb->block_index = 1; + ocb->cipher = cipher; + + return CRYPT_OK; +} + +#endif diff --git a/ocb_ntz.c b/ocb_ntz.c new file mode 100644 index 0000000..fbf6bb6 --- /dev/null +++ b/ocb_ntz.c @@ -0,0 +1,29 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* OCB Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef OCB_MODE + +int ocb_ntz(unsigned long x) +{ + int c; + x &= 0xFFFFFFFFUL; + c = 0; + while ((x & 1) == 0) { + ++c; + x >>= 1; + } + return c; +} + +#endif diff --git a/ocb_shift_xor.c b/ocb_shift_xor.c new file mode 100644 index 0000000..ce93138 --- /dev/null +++ b/ocb_shift_xor.c @@ -0,0 +1,27 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* OCB Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef OCB_MODE + +void ocb_shift_xor(ocb_state *ocb, unsigned char *Z) +{ + int x, y; + y = ocb_ntz(ocb->block_index++); + for (x = 0; x < ocb->block_len; x++) { + ocb->Li[x] ^= ocb->Ls[y][x]; + Z[x] = ocb->Li[x] ^ ocb->R[x]; + } +} + +#endif diff --git a/ocb_test.c b/ocb_test.c new file mode 100644 index 0000000..0b5dafd --- /dev/null +++ b/ocb_test.c @@ -0,0 +1,226 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* OCB Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef OCB_MODE + +int ocb_test(void) +{ +#ifndef LTC_TEST + return CRYPT_NOP; +#else + static const struct { + int ptlen; + unsigned char key[16], nonce[16], pt[34], ct[34], tag[16]; + } tests[] = { + + /* OCB-AES-128-0B */ +{ + 0, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* nonce */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + /* pt */ + { 0 }, + /* ct */ + { 0 }, + /* tag */ + { 0x15, 0xd3, 0x7d, 0xd7, 0xc8, 0x90, 0xd5, 0xd6, + 0xac, 0xab, 0x92, 0x7b, 0xc0, 0xdc, 0x60, 0xee }, +}, + + + /* OCB-AES-128-3B */ +{ + 3, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* nonce */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + /* pt */ + { 0x00, 0x01, 0x02 }, + /* ct */ + { 0xfc, 0xd3, 0x7d }, + /* tag */ + { 0x02, 0x25, 0x47, 0x39, 0xa5, 0xe3, 0x56, 0x5a, + 0xe2, 0xdc, 0xd6, 0x2c, 0x65, 0x97, 0x46, 0xba }, +}, + + /* OCB-AES-128-16B */ +{ + 16, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* nonce */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + /* pt */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* ct */ + { 0x37, 0xdf, 0x8c, 0xe1, 0x5b, 0x48, 0x9b, 0xf3, + 0x1d, 0x0f, 0xc4, 0x4d, 0xa1, 0xfa, 0xf6, 0xd6 }, + /* tag */ + { 0xdf, 0xb7, 0x63, 0xeb, 0xdb, 0x5f, 0x0e, 0x71, + 0x9c, 0x7b, 0x41, 0x61, 0x80, 0x80, 0x04, 0xdf }, +}, + + /* OCB-AES-128-20B */ +{ + 20, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* nonce */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + /* pt */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13 }, + /* ct */ + { 0x01, 0xa0, 0x75, 0xf0, 0xd8, 0x15, 0xb1, 0xa4, + 0xe9, 0xc8, 0x81, 0xa1, 0xbc, 0xff, 0xc3, 0xeb, + 0x70, 0x03, 0xeb, 0x55}, + /* tag */ + { 0x75, 0x30, 0x84, 0x14, 0x4e, 0xb6, 0x3b, 0x77, + 0x0b, 0x06, 0x3c, 0x2e, 0x23, 0xcd, 0xa0, 0xbb }, +}, + + /* OCB-AES-128-32B */ +{ + 32, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* nonce */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + /* pt */ + { 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 }, + /* ct */ + { 0x01, 0xa0, 0x75, 0xf0, 0xd8, 0x15, 0xb1, 0xa4, + 0xe9, 0xc8, 0x81, 0xa1, 0xbc, 0xff, 0xc3, 0xeb, + 0x4a, 0xfc, 0xbb, 0x7f, 0xed, 0xc0, 0x8c, 0xa8, + 0x65, 0x4c, 0x6d, 0x30, 0x4d, 0x16, 0x12, 0xfa }, + + /* tag */ + { 0xc1, 0x4c, 0xbf, 0x2c, 0x1a, 0x1f, 0x1c, 0x3c, + 0x13, 0x7e, 0xad, 0xea, 0x1f, 0x2f, 0x2f, 0xcf }, +}, + + /* OCB-AES-128-34B */ +{ + 34, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* nonce */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + /* pt */ + { 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, + 0x20, 0x21 }, + /* ct */ + { 0x01, 0xa0, 0x75, 0xf0, 0xd8, 0x15, 0xb1, 0xa4, + 0xe9, 0xc8, 0x81, 0xa1, 0xbc, 0xff, 0xc3, 0xeb, + 0xd4, 0x90, 0x3d, 0xd0, 0x02, 0x5b, 0xa4, 0xaa, + 0x83, 0x7c, 0x74, 0xf1, 0x21, 0xb0, 0x26, 0x0f, + 0xa9, 0x5d }, + + /* tag */ + { 0xcf, 0x83, 0x41, 0xbb, 0x10, 0x82, 0x0c, 0xcf, + 0x14, 0xbd, 0xec, 0x56, 0xb8, 0xd7, 0xd6, 0xab }, +}, + +}; + + int err, x, idx, res; + unsigned long len; + unsigned char outct[MAXBLOCKSIZE], outtag[MAXBLOCKSIZE]; + + /* AES can be under rijndael or aes... try to find it */ + if ((idx = find_cipher("aes")) == -1) { + if ((idx = find_cipher("rijndael")) == -1) { + return CRYPT_NOP; + } + } + + for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { + len = sizeof(outtag); + if ((err = ocb_encrypt_authenticate_memory(idx, tests[x].key, 16, + tests[x].nonce, tests[x].pt, tests[x].ptlen, outct, outtag, &len)) != CRYPT_OK) { + return err; + } + + if (memcmp(outtag, tests[x].tag, len) || memcmp(outct, tests[x].ct, tests[x].ptlen)) { +#if 0 + unsigned long y; + printf("\n\nFailure: \nCT:\n"); + for (y = 0; y < (unsigned long)tests[x].ptlen; ) { + printf("0x%02x", outct[y]); + if (y < (unsigned long)(tests[x].ptlen-1)) printf(", "); + if (!(++y % 8)) printf("\n"); + } + printf("\nTAG:\n"); + for (y = 0; y < len; ) { + printf("0x%02x", outtag[y]); + if (y < len-1) printf(", "); + if (!(++y % 8)) printf("\n"); + } +#endif + return CRYPT_FAIL_TESTVECTOR; + } + + if ((err = ocb_decrypt_verify_memory(idx, tests[x].key, 16, tests[x].nonce, outct, tests[x].ptlen, + outct, tests[x].tag, len, &res)) != CRYPT_OK) { + return err; + } + if ((res != 1) || memcmp(tests[x].pt, outct, tests[x].ptlen)) { +#if 0 + unsigned long y; + printf("\n\nFailure-decrypt: \nPT:\n"); + for (y = 0; y < (unsigned long)tests[x].ptlen; ) { + printf("0x%02x", outct[y]); + if (y < (unsigned long)(tests[x].ptlen-1)) printf(", "); + if (!(++y % 8)) printf("\n"); + } + printf("\nres = %d\n\n", res); +#endif + } + } + return CRYPT_OK; +#endif /* LTC_TEST */ +} + +#endif /* OCB_MODE */ + + +/* some comments + + -- it's hard to seek + -- hard to stream [you can't emit ciphertext until full block] + -- The setup is somewhat complicated... +*/ diff --git a/ofb_decrypt.c b/ofb_decrypt.c new file mode 100644 index 0000000..9531969 --- /dev/null +++ b/ofb_decrypt.c @@ -0,0 +1,26 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef OFB + +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/ofb_encrypt.c b/ofb_encrypt.c new file mode 100644 index 0000000..d5d06f3 --- /dev/null +++ b/ofb_encrypt.c @@ -0,0 +1,41 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef OFB + +int ofb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_OFB *ofb) +{ + int err; + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(ofb != NULL); + if ((err = cipher_is_valid(ofb->cipher)) != CRYPT_OK) { + return err; + } + + /* is blocklen/padlen valid? */ + if (ofb->blocklen < 0 || ofb->blocklen > (int)sizeof(ofb->IV) || + ofb->padlen < 0 || ofb->padlen > (int)sizeof(ofb->IV)) { + return CRYPT_INVALID_ARG; + } + + while (len-- > 0) { + 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; +} + +#endif diff --git a/ofb_start.c b/ofb_start.c new file mode 100644 index 0000000..45fcc70 --- /dev/null +++ b/ofb_start.c @@ -0,0 +1,40 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#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, err; + + _ARGCHK(IV != NULL); + _ARGCHK(key != NULL); + _ARGCHK(ofb != NULL); + + if ((err = cipher_is_valid(cipher)) != CRYPT_OK) { + return err; + } + + /* 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); +} + +#endif diff --git a/omac_done.c b/omac_done.c new file mode 100644 index 0000000..f065a1d --- /dev/null +++ b/omac_done.c @@ -0,0 +1,66 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* OMAC1 Support by Tom St Denis (for 64 and 128 bit block ciphers only) */ +#include "mycrypt.h" + +#ifdef OMAC + +int omac_done(omac_state *state, unsigned char *out, unsigned long *outlen) +{ + int err, mode, x; + + _ARGCHK(state != NULL); + _ARGCHK(out != NULL); + if ((err = cipher_is_valid(state->cipher_idx)) != CRYPT_OK) { + return err; + } + + if ((state->buflen > (int)sizeof(state->block)) || (state->buflen < 0) || + (state->blklen > (int)sizeof(state->block)) || (state->buflen > state->blklen)) { + return CRYPT_INVALID_ARG; + } + + /* figure out mode */ + if (state->buflen != state->blklen) { + /* add the 0x80 byte */ + state->block[state->buflen++] = 0x80; + + /* pad with 0x00 */ + while (state->buflen < state->blklen) { + state->block[state->buflen++] = 0x00; + } + mode = 1; + } else { + mode = 0; + } + + /* now xor prev + Lu[mode] */ + for (x = 0; x < state->blklen; x++) { + state->block[x] ^= state->prev[x] ^ state->Lu[mode][x]; + } + + /* encrypt it */ + cipher_descriptor[state->cipher_idx].ecb_encrypt(state->block, state->block, &state->key); + + /* output it */ + for (x = 0; x < state->blklen && (unsigned long)x < *outlen; x++) { + out[x] = state->block[x]; + } + *outlen = x; + +#ifdef CLEAN_STACK + zeromem(state, sizeof(*state)); +#endif + return CRYPT_OK; +} + +#endif + diff --git a/omac_file.c b/omac_file.c new file mode 100644 index 0000000..09d2d4b --- /dev/null +++ b/omac_file.c @@ -0,0 +1,65 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* OMAC1 Support by Tom St Denis (for 64 and 128 bit block ciphers only) */ +#include "mycrypt.h" + +#ifdef OMAC + +int omac_file(int cipher, + const unsigned char *key, unsigned long keylen, + const char *filename, + unsigned char *out, unsigned long *outlen) +{ +#ifdef NO_FILE + return CRYPT_NOP; +#else + int err, x; + omac_state omac; + FILE *in; + unsigned char buf[512]; + + _ARGCHK(key != NULL); + _ARGCHK(filename != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + in = fopen(filename, "rb"); + if (in == NULL) { + return CRYPT_FILE_NOTFOUND; + } + + if ((err = omac_init(&omac, cipher, key, keylen)) != CRYPT_OK) { + fclose(in); + return err; + } + + do { + x = fread(buf, 1, sizeof(buf), in); + if ((err = omac_process(&omac, buf, x)) != CRYPT_OK) { + fclose(in); + return err; + } + } while (x == sizeof(buf)); + fclose(in); + + if ((err = omac_done(&omac, out, outlen)) != CRYPT_OK) { + return err; + } + +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + + return CRYPT_OK; +#endif +} + +#endif diff --git a/omac_init.c b/omac_init.c new file mode 100644 index 0000000..3945630 --- /dev/null +++ b/omac_init.c @@ -0,0 +1,76 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* OMAC1 Support by Tom St Denis (for 64 and 128 bit block ciphers only) */ +#include "mycrypt.h" + +#ifdef OMAC + +int omac_init(omac_state *omac, int cipher, const unsigned char *key, unsigned long keylen) +{ + int err, x, y, mask, msb, len; + + _ARGCHK(omac != NULL); + _ARGCHK(key != NULL); + + /* schedule the key */ + if ((err = cipher_is_valid(cipher)) != CRYPT_OK) { + return err; + } + + /* now setup the system */ + switch (cipher_descriptor[cipher].block_length) { + case 8: mask = 0x1B; + len = 8; + break; + case 16: mask = 0x87; + len = 16; + break; + default: return CRYPT_INVALID_ARG; + } + + if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, &omac->key)) != CRYPT_OK) { + return err; + } + + /* ok now we need Lu and Lu^2 [calc one from the other] */ + + /* first calc L which is Ek(0) */ + zeromem(omac->Lu[0], cipher_descriptor[cipher].block_length); + cipher_descriptor[cipher].ecb_encrypt(omac->Lu[0], omac->Lu[0], &omac->key); + + /* now do the mults, whoopy! */ + for (x = 0; x < 2; x++) { + /* if msb(L * u^(x+1)) = 0 then just shift, otherwise shift and xor constant mask */ + msb = omac->Lu[x][0] >> 7; + + /* shift left */ + for (y = 0; y < (len - 1); y++) { + omac->Lu[x][y] = ((omac->Lu[x][y] << 1) | (omac->Lu[x][y+1] >> 7)) & 255; + } + omac->Lu[x][len - 1] = ((omac->Lu[x][len - 1] << 1) ^ (msb ? mask : 0)) & 255; + + /* copy up as require */ + if (x == 0) { + memcpy(omac->Lu[1], omac->Lu[0], sizeof(omac->Lu[0])); + } + } + + /* setup state */ + omac->cipher_idx = cipher; + omac->buflen = 0; + omac->blklen = len; + zeromem(omac->prev, sizeof(omac->prev)); + zeromem(omac->block, sizeof(omac->block)); + + return CRYPT_OK; +} + +#endif diff --git a/omac_memory.c b/omac_memory.c new file mode 100644 index 0000000..1cca891 --- /dev/null +++ b/omac_memory.c @@ -0,0 +1,42 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* OMAC1 Support by Tom St Denis (for 64 and 128 bit block ciphers only) */ +#include "mycrypt.h" + +#ifdef OMAC + +int omac_memory(int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *msg, unsigned long msglen, + unsigned char *out, unsigned long *outlen) +{ + int err; + omac_state omac; + + _ARGCHK(key != NULL); + _ARGCHK(msg != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + if ((err = omac_init(&omac, cipher, key, keylen)) != CRYPT_OK) { + return err; + } + if ((err = omac_process(&omac, msg, msglen)) != CRYPT_OK) { + return err; + } + if ((err = omac_done(&omac, out, outlen)) != CRYPT_OK) { + return err; + } + + return CRYPT_OK; +} + +#endif diff --git a/omac_process.c b/omac_process.c new file mode 100644 index 0000000..8da1527 --- /dev/null +++ b/omac_process.c @@ -0,0 +1,53 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* OMAC1 Support by Tom St Denis (for 64 and 128 bit block ciphers only) */ +#include "mycrypt.h" + +#ifdef OMAC + +int omac_process(omac_state *state, const unsigned char *buf, unsigned long len) +{ + int err, n, x; + + _ARGCHK(state != NULL); + _ARGCHK(buf != NULL); + if ((err = cipher_is_valid(state->cipher_idx)) != CRYPT_OK) { + return err; + } + + if ((state->buflen > (int)sizeof(state->block)) || (state->buflen < 0) || + (state->blklen > (int)sizeof(state->block)) || (state->buflen > state->blklen)) { + return CRYPT_INVALID_ARG; + } + + while (len != 0) { + /* ok if the block is full we xor in prev, encrypt and replace prev */ + if (state->buflen == state->blklen) { + for (x = 0; x < state->blklen; x++) { + state->block[x] ^= state->prev[x]; + } + cipher_descriptor[state->cipher_idx].ecb_encrypt(state->block, state->prev, &state->key); + state->buflen = 0; + } + + /* add bytes */ + n = MIN(len, (unsigned long)(state->blklen - state->buflen)); + memcpy(state->block + state->buflen, buf, n); + state->buflen += n; + len -= n; + buf += n; + } + + return CRYPT_OK; +} + +#endif + diff --git a/omac_test.c b/omac_test.c new file mode 100644 index 0000000..2d50d9a --- /dev/null +++ b/omac_test.c @@ -0,0 +1,95 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* OMAC1 Support by Tom St Denis (for 64 and 128 bit block ciphers only) */ +#include "mycrypt.h" + +#ifdef OMAC + +int omac_test(void) +{ +#if !defined(LTC_TEST) + return CRYPT_NOP; +#else + static const struct { + int keylen, msglen; + unsigned char key[16], msg[64], tag[16]; + } tests[] = { + { 16, 0, + { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, + { 0x00 }, + { 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, + 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 } + }, + { 16, 16, + { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, + { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a }, + { 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c } + }, + { 16, 40, + { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, + { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 }, + { 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, + 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 } + }, + { 16, 64, + { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, + { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, + { 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, + 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe } + } + + }; + unsigned char out[16]; + int x, y, err, idx; + unsigned long len; + + + /* AES can be under rijndael or aes... try to find it */ + if ((idx = find_cipher("aes")) == -1) { + if ((idx = find_cipher("rijndael")) == -1) { + return CRYPT_NOP; + } + } + + for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { + len = sizeof(out); + if ((err = omac_memory(idx, tests[x].key, tests[x].keylen, tests[x].msg, tests[x].msglen, out, &len)) != CRYPT_OK) { + return err; + } + + if (memcmp(out, tests[x].tag, 16) != 0) { + printf("\n\nTag: "); + for (y = 0; y < 16; y++) printf("%02x", out[y]); printf("\n\n"); + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; +#endif +} + +#endif diff --git a/packet_store_header.c b/packet_store_header.c new file mode 100644 index 0000000..d750718 --- /dev/null +++ b/packet_store_header.c @@ -0,0 +1,29 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef PACKET + +void packet_store_header(unsigned char *dst, int section, int subsection) +{ + _ARGCHK(dst != NULL); + + /* store version number */ + dst[0] = (unsigned char)(CRYPT&255); + dst[1] = (unsigned char)((CRYPT>>8)&255); + + /* store section and subsection */ + dst[2] = (unsigned char)(section & 255); + dst[3] = (unsigned char)(subsection & 255); + +} + +#endif diff --git a/packet_valid_header.c b/packet_valid_header.c new file mode 100644 index 0000000..7fda507 --- /dev/null +++ b/packet_valid_header.c @@ -0,0 +1,37 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef PACKET + +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] << 8U); + if (CRYPT < ver) { + return CRYPT_INVALID_PACKET; + } + + /* check section and subsection */ + if (section != (int)src[2] || subsection != (int)src[3]) { + return CRYPT_INVALID_PACKET; + } + + return CRYPT_OK; +} + +#endif + + diff --git a/pkcs_1_i2osp.c b/pkcs_1_i2osp.c new file mode 100644 index 0000000..1a7fadd --- /dev/null +++ b/pkcs_1_i2osp.c @@ -0,0 +1,40 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +/* Integer to Octet I2OSP -- Tom St Denis */ + +#ifdef PKCS_1 + +/* always stores the same # of bytes, pads with leading zero bytes + as required + */ +int pkcs_1_i2osp(mp_int *n, unsigned long modulus_len, unsigned char *out) +{ + int err; + unsigned long size; + + size = mp_unsigned_bin_size(n); + + if (size > modulus_len) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* store it */ + zeromem(out, modulus_len); + if ((err = mp_to_unsigned_bin(n, out+(modulus_len-size))) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + return CRYPT_OK; +} + +#endif /* PKCS_1 */ + diff --git a/pkcs_1_mgf1.c b/pkcs_1_mgf1.c new file mode 100644 index 0000000..b21d928 --- /dev/null +++ b/pkcs_1_mgf1.c @@ -0,0 +1,66 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +/* The Mask Generation Function (MGF1) for PKCS #1 -- Tom St Denis */ + +#ifdef PKCS_1 + +int pkcs_1_mgf1(const unsigned char *seed, unsigned long seedlen, + int hash_idx, + unsigned char *mask, unsigned long masklen) +{ + unsigned long hLen, counter, x; + int err; + hash_state md; + unsigned char buf[MAXBLOCKSIZE]; + + _ARGCHK(seed != NULL); + _ARGCHK(mask != NULL); + + /* ensure valid hash */ + if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { + return err; + } + + /* get hash output size */ + hLen = hash_descriptor[hash_idx].hashsize; + + /* start counter */ + counter = 0; + + while (masklen > 0) { + /* handle counter */ + STORE32H(counter, buf); + ++counter; + + /* get hash of seed || counter */ + hash_descriptor[hash_idx].init(&md); + if ((err = hash_descriptor[hash_idx].process(&md, seed, seedlen)) != CRYPT_OK) { + return err; + } + if ((err = hash_descriptor[hash_idx].process(&md, buf, 4)) != CRYPT_OK) { + return err; + } + if ((err = hash_descriptor[hash_idx].done(&md, buf)) != CRYPT_OK) { + return err; + } + + /* store it */ + for (x = 0; x < hLen && masklen > 0; x++, masklen--) { + *mask++ = buf[x]; + } + } + + return CRYPT_OK; +} + +#endif /* PKCS_1 */ diff --git a/pkcs_1_oaep_decode.c b/pkcs_1_oaep_decode.c new file mode 100644 index 0000000..d9430dc --- /dev/null +++ b/pkcs_1_oaep_decode.c @@ -0,0 +1,135 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +/* OAEP Padding for PKCS #1 -- Tom St Denis */ + +#ifdef PKCS_1 + +int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, + const unsigned char *lparam, unsigned long lparamlen, + unsigned long modulus_bitlen, int hash_idx, + unsigned char *out, unsigned long *outlen) +{ + unsigned char DB[1024], seed[MAXBLOCKSIZE], mask[sizeof(DB)]; + unsigned long hLen, x, y, modulus_len; + int err; + + _ARGCHK(msg != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* test valid hash */ + if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { + return err; + } + hLen = hash_descriptor[hash_idx].hashsize; + modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0); + + /* test message size */ + if (modulus_len >= sizeof(DB) || msglen != modulus_len) { + return CRYPT_PK_INVALID_SIZE; + } + + /* ok so it's now in the form + + 0x00 || maskedseed || maskedDB + + 1 || hLen || modulus_len - hLen - 1 + + */ + + /* must have leading 0x00 byte */ + if (msg[0] != 0x00) { + return CRYPT_INVALID_PACKET; + } + + /* now read the masked seed */ + for (x = 1, y = 0; y < hLen; y++) { + seed[y] = msg[x++]; + } + + /* now read the masked DB */ + for (y = 0; y < modulus_len - hLen - 1; y++) { + DB[y] = msg[x++]; + } + + /* compute MGF1 of maskedDB (hLen) */ + if ((err = pkcs_1_mgf1(DB, modulus_len - hLen - 1, hash_idx, mask, hLen)) != CRYPT_OK) { + return err; + } + + /* XOR against seed */ + for (y = 0; y < hLen; y++) { + seed[y] ^= mask[y]; + } + + /* compute MGF1 of seed (k - hlen - 1) */ + if ((err = pkcs_1_mgf1(seed, hLen, hash_idx, mask, modulus_len - hLen - 1)) != CRYPT_OK) { + return err; + } + + /* xor against DB */ + for (y = 0; y < (modulus_len - hLen - 1); y++) { + DB[y] ^= mask[y]; + } + + /* now DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes */ + + /* compute lhash and store it in seed [reuse temps!] */ + x = sizeof(seed); + if (lparam != NULL) { + if ((err = hash_memory(hash_idx, lparam, lparamlen, seed, &x)) != CRYPT_OK) { + return err; + } + } else { + /* can't pass hash_memory a NULL so use DB with zero length */ + if ((err = hash_memory(hash_idx, DB, 0, seed, &x)) != CRYPT_OK) { + return err; + } + } + + /* compare the lhash'es */ + if (memcmp(seed, DB, hLen) != 0) { + return CRYPT_INVALID_PACKET; + } + + /* now zeroes before a 0x01 */ + for (x = hLen; x < (modulus_len - hLen - 1) && DB[x] == 0x00; x++) { + /* step... */ + } + + /* error out if wasn't 0x01 */ + if (x == (modulus_len - hLen - 1) || DB[x] != 0x01) { + return CRYPT_INVALID_PACKET; + } + + /* rest is the message (and skip 0x01) */ + if (msglen - ++x > *outlen) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* copy message */ + *outlen = (modulus_len - hLen - 1) - x; + for (y = 0; x != (modulus_len - hLen - 1); ) { + out[y++] = DB[x++]; + } + +#ifdef CLEAN_STACK + zeromem(DB, sizeof(DB)); + zeromem(seed, sizeof(seed)); + zeromem(mask, sizeof(mask)); +#endif + + return CRYPT_OK; +} + +#endif /* PKCS_1 */ diff --git a/pkcs_1_oaep_encode.c b/pkcs_1_oaep_encode.c new file mode 100644 index 0000000..2c8f5c0 --- /dev/null +++ b/pkcs_1_oaep_encode.c @@ -0,0 +1,128 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +/* OAEP Padding for PKCS #1 -- Tom St Denis */ + +#ifdef PKCS_1 + +int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, + const unsigned char *lparam, unsigned long lparamlen, + unsigned long modulus_bitlen, int hash_idx, + int prng_idx, prng_state *prng, + unsigned char *out, unsigned long *outlen) +{ + unsigned char DB[1024], seed[MAXBLOCKSIZE], mask[sizeof(DB)]; + unsigned long hLen, x, y, modulus_len; + int err; + + _ARGCHK(msg != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* test valid hash */ + if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { + return err; + } + + /* valid prng */ + if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) { + return err; + } + + hLen = hash_descriptor[hash_idx].hashsize; + modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0); + + /* test message size */ + if (modulus_len >= sizeof(DB) || msglen > (modulus_len - 2*hLen - 2)) { + return CRYPT_PK_INVALID_SIZE; + } + + /* get lhash */ +// DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes + x = sizeof(DB); + if (lparam != NULL) { + if ((err = hash_memory(hash_idx, lparam, lparamlen, DB, &x)) != CRYPT_OK) { + return err; + } + } else { + /* can't pass hash_memory a NULL so use DB with zero length */ + if ((err = hash_memory(hash_idx, DB, 0, DB, &x)) != CRYPT_OK) { + return err; + } + } + + /* append PS then 0x01 (to lhash) */ + x = hLen; + y = modulus_len - msglen - 2*hLen - 2; + while (y--) { + DB[x++] = 0x00; + } + DB[x++] = 0x01; + + /* message */ + y = msglen; + while (y--) { + DB[x++] = *msg++; + } + + /* now choose a random seed */ + if (prng_descriptor[prng_idx].read(seed, hLen, prng) != hLen) { + return CRYPT_ERROR_READPRNG; + } + + /* compute MGF1 of seed (k - hlen - 1) */ + if ((err = pkcs_1_mgf1(seed, hLen, hash_idx, mask, modulus_len - hLen - 1)) != CRYPT_OK) { + return err; + } + + /* xor against DB */ + for (y = 0; y < (modulus_len - hLen - 1); y++) { + DB[y] ^= mask[y]; + } + + /* compute MGF1 of maskedDB (hLen) */ + if ((err = pkcs_1_mgf1(DB, modulus_len - hLen - 1, hash_idx, mask, hLen)) != CRYPT_OK) { + return err; + } + + /* XOR against seed */ + for (y = 0; y < hLen; y++) { + seed[y] ^= mask[y]; + } + + /* create string of length modulus_len */ + if (*outlen < modulus_len) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* start output which is 0x00 || maskedSeed || maskedDB */ + x = 0; + out[x++] = 0x00; + for (y = 0; y < hLen; y++) { + out[x++] = seed[y]; + } + for (y = 0; y < modulus_len - hLen - 1; y++) { + out[x++] = DB[y]; + } + *outlen = x; + +#ifdef CLEAN_STACK + zeromem(DB, sizeof(DB)); + zeromem(seed, sizeof(seed)); + zeromem(mask, sizeof(mask)); +#endif + + return CRYPT_OK; +} + +#endif /* PKCS_1 */ + diff --git a/pkcs_1_os2ip.c b/pkcs_1_os2ip.c new file mode 100644 index 0000000..cff881e --- /dev/null +++ b/pkcs_1_os2ip.c @@ -0,0 +1,27 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +/* Octet to Integer OS2IP -- Tom St Denis */ +#ifdef PKCS_1 + +int pkcs_1_os2ip(mp_int *n, unsigned char *in, unsigned long inlen) +{ + int err; + /* read it */ + if ((err = mp_read_unsigned_bin(n, in, inlen)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + return CRYPT_OK; +} + +#endif /* PKCS_1 */ + diff --git a/pkcs_1_pss_decode.c b/pkcs_1_pss_decode.c new file mode 100644 index 0000000..313677c --- /dev/null +++ b/pkcs_1_pss_decode.c @@ -0,0 +1,121 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +/* PKCS #1 PSS Signature Padding -- Tom St Denis */ + +#ifdef PKCS_1 + +int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, + const unsigned char *sig, unsigned long siglen, + unsigned long saltlen, int hash_idx, + unsigned long modulus_bitlen, int *res) +{ + unsigned char DB[1024], mask[sizeof(DB)], salt[sizeof(DB)], hash[sizeof(DB)]; + unsigned long x, y, hLen, modulus_len; + int err; + hash_state md; + + _ARGCHK(msghash != NULL); + _ARGCHK(res != NULL); + + /* default to invalid */ + *res = 0; + + /* ensure hash is valid */ + if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { + return err; + } + + hLen = hash_descriptor[hash_idx].hashsize; + modulus_len = (modulus_bitlen>>3) + (modulus_bitlen & 7 ? 1 : 0); + + /* check sizes */ + if ((saltlen > sizeof(salt)) || (modulus_len > sizeof(DB)) || + (modulus_len < hLen + saltlen + 2) || (siglen != modulus_len)) { + return CRYPT_INVALID_ARG; + } + + /* ensure the 0xBC byte */ + if (sig[siglen-1] != 0xBC) { + return CRYPT_OK; + } + + /* copy out the DB */ + for (x = 0; x < modulus_len - hLen - 1; x++) { + DB[x] = sig[x]; + } + + /* copy out the hash */ + for (y = 0; y < hLen; y++) { + hash[y] = sig[x++]; + } + + /* check the MSB */ + if ((sig[0] & ~(0xFF >> ((modulus_len<<3) - modulus_bitlen))) != 0) { + return CRYPT_OK; + } + + /* generate mask of length modulus_len - hLen - 1 from hash */ + if ((err = pkcs_1_mgf1(hash, hLen, hash_idx, mask, modulus_len - hLen - 1)) != CRYPT_OK) { + return err; + } + + /* xor against DB */ + for (y = 0; y < (modulus_len - hLen - 1); y++) { + DB[y] ^= mask[y]; + } + + /* DB = PS || 0x01 || salt, PS == modulus_len - saltlen - hLen - 2 zero bytes */ + + /* check for zeroes and 0x01 */ + for (x = 0; x < modulus_len - saltlen - hLen - 2; x++) { + if (DB[x] != 0x00) { + return CRYPT_OK; + } + } + + if (DB[x++] != 0x01) { + return CRYPT_OK; + } + + /* M = (eight) 0x00 || msghash || salt, mask = H(M) */ + hash_descriptor[hash_idx].init(&md); + zeromem(mask, 8); + if ((err = hash_descriptor[hash_idx].process(&md, mask, 8)) != CRYPT_OK) { + return err; + } + if ((err = hash_descriptor[hash_idx].process(&md, msghash, msghashlen)) != CRYPT_OK) { + return err; + } + if ((err = hash_descriptor[hash_idx].process(&md, DB+x, saltlen)) != CRYPT_OK) { + return err; + } + if ((err = hash_descriptor[hash_idx].done(&md, mask)) != CRYPT_OK) { + return err; + } + + /* mask == hash means valid signature */ + if (memcmp(mask, hash, hLen) == 0) { + *res = 1; + } + +#ifdef CLEAN_STACK + zeromem(DB, sizeof(DB)); + zeromem(mask, sizeof(mask)); + zeromem(salt, sizeof(salt)); + zeromem(hash, sizeof(hash)); +#endif + + return CRYPT_OK; +} + +#endif /* PKCS_1 */ diff --git a/pkcs_1_pss_encode.c b/pkcs_1_pss_encode.c new file mode 100644 index 0000000..01d219a --- /dev/null +++ b/pkcs_1_pss_encode.c @@ -0,0 +1,122 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +/* PKCS #1 PSS Signature Padding -- Tom St Denis */ + +#ifdef PKCS_1 + +int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, + unsigned long saltlen, int hash_idx, + int prng_idx, prng_state *prng, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen) +{ + unsigned char DB[1024], mask[sizeof(DB)], salt[sizeof(DB)], hash[sizeof(DB)]; + unsigned long x, y, hLen, modulus_len; + int err; + hash_state md; + + _ARGCHK(msghash != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* ensure hash and PRNG are valid */ + if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { + return err; + } + if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) { + return err; + } + + hLen = hash_descriptor[hash_idx].hashsize; + modulus_len = (modulus_bitlen>>3) + (modulus_bitlen & 7 ? 1 : 0); + + /* check sizes */ + if ((saltlen > sizeof(salt)) || (modulus_len > sizeof(DB)) || (modulus_len < hLen + saltlen + 2)) { + return CRYPT_INVALID_ARG; + } + + /* generate random salt */ + if (saltlen > 0) { + if (prng_descriptor[prng_idx].read(salt, saltlen, prng) != saltlen) { + return CRYPT_ERROR_READPRNG; + } + } + + /* M = (eight) 0x00 || msghash || salt, hash = H(M) */ + hash_descriptor[hash_idx].init(&md); + zeromem(DB, 8); + if ((err = hash_descriptor[hash_idx].process(&md, DB, 8)) != CRYPT_OK) { + return err; + } + if ((err = hash_descriptor[hash_idx].process(&md, msghash, msghashlen)) != CRYPT_OK) { + return err; + } + if ((err = hash_descriptor[hash_idx].process(&md, salt, saltlen)) != CRYPT_OK) { + return err; + } + if ((err = hash_descriptor[hash_idx].done(&md, hash)) != CRYPT_OK) { + return err; + } + + /* generate DB = PS || 0x01 || salt, PS == modulus_len - saltlen - hLen - 2 zero bytes */ + for (x = 0; x < (modulus_len - saltlen - hLen - 2); x++) { + DB[x] = 0x00; + } + DB[x++] = 0x01; + for (y = 0; y < saltlen; y++) { + DB[x++] = salt[y]; + } + + /* generate mask of length modulus_len - hLen - 1 from hash */ + if ((err = pkcs_1_mgf1(hash, hLen, hash_idx, mask, modulus_len - hLen - 1)) != CRYPT_OK) { + return err; + } + + /* xor against DB */ + for (y = 0; y < (modulus_len - hLen - 1); y++) { + DB[y] ^= mask[y]; + } + + /* output is DB || hash || 0xBC */ + if (*outlen < modulus_len) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* DB */ + for (y = x = 0; x < modulus_len - hLen - 1; x++) { + out[y++] = DB[x]; + } + /* hash */ + for (x = 0; x < hLen; x++) { + out[y++] = hash[x]; + } + /* 0xBC */ + out[y] = 0xBC; + + /* now clear the 8*modulus_len - modulus_bitlen most significant bits */ + out[0] &= 0xFF >> ((modulus_len<<3) - modulus_bitlen); + + /* store output size */ + *outlen = modulus_len; + +#ifdef CLEAN_STACK + zeromem(DB, sizeof(DB)); + zeromem(mask, sizeof(mask)); + zeromem(salt, sizeof(salt)); + zeromem(hash, sizeof(hash)); +#endif + + return CRYPT_OK; +} + +#endif /* PKCS_1 */ diff --git a/pkcs_5_1.c b/pkcs_5_1.c new file mode 100644 index 0000000..d7ae0e1 --- /dev/null +++ b/pkcs_5_1.c @@ -0,0 +1,63 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include + +/* PKCS #5, Algorithm #1 */ +#ifdef PKCS_5 + +int pkcs_5_alg1(const unsigned char *password, unsigned long password_len, + const unsigned char *salt, + int iteration_count, int hash_idx, + unsigned char *out, unsigned long *outlen) +{ + int err; + unsigned long x; + hash_state md; + unsigned char buf[MAXBLOCKSIZE]; + + _ARGCHK(password != NULL); + _ARGCHK(salt != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* test hash IDX */ + if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { + return err; + } + + /* hash initial password + salt */ + hash_descriptor[hash_idx].init(&md); + hash_descriptor[hash_idx].process(&md, password, password_len); + hash_descriptor[hash_idx].process(&md, salt, 8); + hash_descriptor[hash_idx].done(&md, buf); + + while (--iteration_count) { + // code goes here. + x = sizeof(buf); + if ((err = hash_memory(hash_idx, buf, hash_descriptor[hash_idx].hashsize, buf, &x)) != CRYPT_OK) { + return err; + } + } + + /* copy upto outlen bytes */ + for (x = 0; x < hash_descriptor[hash_idx].hashsize && x < *outlen; x++) { + out[x] = buf[x]; + } + *outlen = x; + +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + + return CRYPT_OK; +} + +#endif diff --git a/pkcs_5_2.c b/pkcs_5_2.c new file mode 100644 index 0000000..46bf75b --- /dev/null +++ b/pkcs_5_2.c @@ -0,0 +1,88 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include + +/* PKCS #5, Algorithm #2 */ +#ifdef PKCS_5 + +int pkcs_5_alg2(const unsigned char *password, unsigned long password_len, + const unsigned char *salt, unsigned long salt_len, + int iteration_count, int hash_idx, + unsigned char *out, unsigned long *outlen) +{ + int err, itts; + unsigned long stored, left, x, y, blkno; + unsigned char buf[2][MAXBLOCKSIZE]; + hmac_state hmac; + + _ARGCHK(password != NULL); + _ARGCHK(salt != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + /* test hash IDX */ + if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { + return err; + } + + left = *outlen; + blkno = 1; + stored = 0; + while (left != 0) { + /* process block number blkno */ + zeromem(buf, sizeof(buf)); + + /* store current block number and increment for next pass */ + STORE32H(blkno, buf[1]); + ++blkno; + + /* get PRF(P, S||int(blkno)) */ + if ((err = hmac_init(&hmac, hash_idx, password, password_len)) != CRYPT_OK) { + return err; + } + if ((err = hmac_process(&hmac, salt, salt_len)) != CRYPT_OK) { + return err; + } + if ((err = hmac_process(&hmac, buf[1], 4)) != CRYPT_OK) { + return err; + } + x = sizeof(buf[0]); + if ((err = hmac_done(&hmac, buf[0], &x)) != CRYPT_OK) { + return err; + } + + /* now compute repeated and XOR it in buf[1] */ + memcpy(buf[1], buf[0], x); + for (itts = 2; itts < iteration_count; ++itts) { + if ((err = hmac_memory(hash_idx, password, password_len, buf[0], x, buf[0], &x)) != CRYPT_OK) { + return err; + } + for (y = 0; y < x; y++) { + buf[1][y] ^= buf[0][y]; + } + } + + /* now emit upto x bytes of buf[1] to output */ + for (y = 0; y < x && left != 0; ++y) { + out[stored++] = buf[1][y]; + --left; + } + } + *outlen = stored; + +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + return CRYPT_OK; +} + +#endif + diff --git a/pmac_done.c b/pmac_done.c new file mode 100644 index 0000000..8051da7 --- /dev/null +++ b/pmac_done.c @@ -0,0 +1,64 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* PMAC implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef PMAC + +int pmac_done(pmac_state *state, unsigned char *out, unsigned long *outlen) +{ + int err, x; + + _ARGCHK(state != NULL); + _ARGCHK(out != NULL); + if ((err = cipher_is_valid(state->cipher_idx)) != CRYPT_OK) { + return err; + } + + if ((state->buflen > (int)sizeof(state->block)) || (state->buflen < 0) || + (state->block_len > (int)sizeof(state->block)) || (state->buflen > state->block_len)) { + return CRYPT_INVALID_ARG; + } + + + /* handle padding. If multiple xor in L/x */ + + if (state->buflen == state->block_len) { + /* xor Lr against the checksum */ + for (x = 0; x < state->block_len; x++) { + state->checksum[x] ^= state->block[x] ^ state->Lr[x]; + } + } else { + /* otherwise xor message bytes then the 0x80 byte */ + for (x = 0; x < state->buflen; x++) { + state->checksum[x] ^= state->block[x]; + } + state->checksum[x] ^= 0x80; + } + + /* encrypt it */ + cipher_descriptor[state->cipher_idx].ecb_encrypt(state->checksum, state->checksum, &state->key); + + /* store it */ + for (x = 0; x < state->block_len && x <= (int)*outlen; x++) { + out[x] = state->checksum[x]; + } + *outlen = x; + +#ifdef CLEAN_STACK + zeromem(state, sizeof(*state)); +#endif + return CRYPT_OK; +} + +#endif + diff --git a/pmac_file.c b/pmac_file.c new file mode 100644 index 0000000..c664a09 --- /dev/null +++ b/pmac_file.c @@ -0,0 +1,67 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* PMAC implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef PMAC + +int pmac_file(int cipher, + const unsigned char *key, unsigned long keylen, + const char *filename, + unsigned char *out, unsigned long *outlen) +{ +#ifdef NO_FILE + return CRYPT_NOP; +#else + int err, x; + pmac_state pmac; + FILE *in; + unsigned char buf[512]; + + + _ARGCHK(key != NULL); + _ARGCHK(filename != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + in = fopen(filename, "rb"); + if (in == NULL) { + return CRYPT_FILE_NOTFOUND; + } + + if ((err = pmac_init(&pmac, cipher, key, keylen)) != CRYPT_OK) { + fclose(in); + return err; + } + + do { + x = fread(buf, 1, sizeof(buf), in); + if ((err = pmac_process(&pmac, buf, x)) != CRYPT_OK) { + fclose(in); + return err; + } + } while (x == sizeof(buf)); + fclose(in); + + if ((err = pmac_done(&pmac, out, outlen)) != CRYPT_OK) { + return err; + } + +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + + return CRYPT_OK; +#endif +} + +#endif diff --git a/pmac_init.c b/pmac_init.c new file mode 100644 index 0000000..b4ef111 --- /dev/null +++ b/pmac_init.c @@ -0,0 +1,114 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* PMAC implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef PMAC + +static const struct { + int len; + unsigned char poly_div[MAXBLOCKSIZE], + poly_mul[MAXBLOCKSIZE]; +} polys[] = { +{ + 8, + { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B } +}, { + 16, + { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 } +} +}; + +int pmac_init(pmac_state *pmac, int cipher, const unsigned char *key, unsigned long keylen) +{ + int poly, x, y, m, err; + unsigned char L[MAXBLOCKSIZE]; + + _ARGCHK(pmac != NULL); + _ARGCHK(key != NULL); + + /* valid cipher? */ + if ((err = cipher_is_valid(cipher)) != CRYPT_OK) { + return err; + } + + /* determine which polys to use */ + pmac->block_len = cipher_descriptor[cipher].block_length; + for (poly = 0; poly < (int)(sizeof(polys)/sizeof(polys[0])); poly++) { + if (polys[poly].len == pmac->block_len) { + break; + } + } + if (polys[poly].len != pmac->block_len) { + return CRYPT_INVALID_ARG; + } + + /* schedule the key */ + if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, &pmac->key)) != CRYPT_OK) { + return err; + } + + /* find L = E[0] */ + zeromem(L, pmac->block_len); + cipher_descriptor[cipher].ecb_encrypt(L, L, &pmac->key); + + /* find Ls[i] = L << i for i == 0..31 */ + memcpy(pmac->Ls[0], L, pmac->block_len); + for (x = 1; x < 32; x++) { + m = pmac->Ls[x-1][0] >> 7; + for (y = 0; y < pmac->block_len-1; y++) { + pmac->Ls[x][y] = ((pmac->Ls[x-1][y] << 1) | (pmac->Ls[x-1][y+1] >> 7)) & 255; + } + pmac->Ls[x][pmac->block_len-1] = (pmac->Ls[x-1][pmac->block_len-1] << 1) & 255; + + if (m == 1) { + for (y = 0; y < pmac->block_len; y++) { + pmac->Ls[x][y] ^= polys[poly].poly_mul[y]; + } + } + } + + /* find Lr = L / x */ + m = L[pmac->block_len-1] & 1; + + /* shift right */ + for (x = pmac->block_len - 1; x > 0; x--) { + pmac->Lr[x] = ((L[x] >> 1) | (L[x-1] << 7)) & 255; + } + pmac->Lr[0] = L[0] >> 1; + + if (m == 1) { + for (x = 0; x < pmac->block_len; x++) { + pmac->Lr[x] ^= polys[poly].poly_div[x]; + } + } + + /* zero buffer, counters, etc... */ + pmac->block_index = 1; + pmac->cipher_idx = cipher; + pmac->buflen = 0; + zeromem(pmac->block, sizeof(pmac->block)); + zeromem(pmac->Li, sizeof(pmac->Li)); + zeromem(pmac->checksum, sizeof(pmac->checksum)); + +#ifdef CLEAN_STACK + zeromem(L, sizeof(L)); +#endif + + return CRYPT_OK; +} + +#endif diff --git a/pmac_memory.c b/pmac_memory.c new file mode 100644 index 0000000..c279d71 --- /dev/null +++ b/pmac_memory.c @@ -0,0 +1,44 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* PMAC implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef PMAC + +int pmac_memory(int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *msg, unsigned long msglen, + unsigned char *out, unsigned long *outlen) +{ + int err; + pmac_state pmac; + + _ARGCHK(key != NULL); + _ARGCHK(msg != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + + + if ((err = pmac_init(&pmac, cipher, key, keylen)) != CRYPT_OK) { + return err; + } + if ((err = pmac_process(&pmac, msg, msglen)) != CRYPT_OK) { + return err; + } + if ((err = pmac_done(&pmac, out, outlen)) != CRYPT_OK) { + return err; + } + + return CRYPT_OK; +} + +#endif diff --git a/pmac_ntz.c b/pmac_ntz.c new file mode 100644 index 0000000..98ec430 --- /dev/null +++ b/pmac_ntz.c @@ -0,0 +1,29 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* PMAC implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef PMAC + +int pmac_ntz(unsigned long x) +{ + int c; + x &= 0xFFFFFFFFUL; + c = 0; + while ((x & 1) == 0) { + ++c; + x >>= 1; + } + return c; +} + +#endif diff --git a/pmac_process.c b/pmac_process.c new file mode 100644 index 0000000..ff2c3fe --- /dev/null +++ b/pmac_process.c @@ -0,0 +1,62 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* PMAC implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef PMAC + +int pmac_process(pmac_state *state, const unsigned char *buf, unsigned long len) +{ + int err, n, x; + unsigned char Z[MAXBLOCKSIZE]; + + _ARGCHK(state != NULL); + _ARGCHK(buf != NULL); + if ((err = cipher_is_valid(state->cipher_idx)) != CRYPT_OK) { + return err; + } + + if ((state->buflen > (int)sizeof(state->block)) || (state->buflen < 0) || + (state->block_len > (int)sizeof(state->block)) || (state->buflen > state->block_len)) { + return CRYPT_INVALID_ARG; + } + + while (len != 0) { + /* ok if the block is full we xor in prev, encrypt and replace prev */ + if (state->buflen == state->block_len) { + pmac_shift_xor(state); + for (x = 0; x < state->block_len; x++) { + Z[x] = state->Li[x] ^ state->block[x]; + } + cipher_descriptor[state->cipher_idx].ecb_encrypt(Z, Z, &state->key); + for (x = 0; x < state->block_len; x++) { + state->checksum[x] ^= Z[x]; + } + state->buflen = 0; + } + + /* add bytes */ + n = MIN(len, (unsigned long)(state->block_len - state->buflen)); + memcpy(state->block + state->buflen, buf, n); + state->buflen += n; + len -= n; + buf += n; + } + +#ifdef CLEAN_STACK + zeromem(Z, sizeof(Z)); +#endif + + return CRYPT_OK; +} + +#endif diff --git a/pmac_shift_xor.c b/pmac_shift_xor.c new file mode 100644 index 0000000..46159fb --- /dev/null +++ b/pmac_shift_xor.c @@ -0,0 +1,26 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* PMAC implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef PMAC + +void pmac_shift_xor(pmac_state *pmac) +{ + int x, y; + y = pmac_ntz(pmac->block_index++); + for (x = 0; x < pmac->block_len; x++) { + pmac->Li[x] ^= pmac->Ls[y][x]; + } +} + +#endif diff --git a/pmac_test.c b/pmac_test.c new file mode 100644 index 0000000..e813eb5 --- /dev/null +++ b/pmac_test.c @@ -0,0 +1,153 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* PMAC implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef PMAC + +int pmac_test(void) +{ +#if !defined(LTC_TEST) + return CRYPT_NOP; +#else + static const struct { + int msglen; + unsigned char key[16], msg[34], tag[16]; + } tests[] = { + + /* PMAC-AES-128-0B */ +{ + 0, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* msg */ + { 0x00 }, + /* tag */ + { 0x43, 0x99, 0x57, 0x2c, 0xd6, 0xea, 0x53, 0x41, + 0xb8, 0xd3, 0x58, 0x76, 0xa7, 0x09, 0x8a, 0xf7 } +}, + + /* PMAC-AES-128-3B */ +{ + 3, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* msg */ + { 0x00, 0x01, 0x02 }, + /* tag */ + { 0x25, 0x6b, 0xa5, 0x19, 0x3c, 0x1b, 0x99, 0x1b, + 0x4d, 0xf0, 0xc5, 0x1f, 0x38, 0x8a, 0x9e, 0x27 } +}, + + /* PMAC-AES-128-16B */ +{ + 16, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* msg */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* tag */ + { 0xeb, 0xbd, 0x82, 0x2f, 0xa4, 0x58, 0xda, 0xf6, + 0xdf, 0xda, 0xd7, 0xc2, 0x7d, 0xa7, 0x63, 0x38 } +}, + + /* PMAC-AES-128-20B */ +{ + 20, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* msg */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13 }, + /* tag */ + { 0x04, 0x12, 0xca, 0x15, 0x0b, 0xbf, 0x79, 0x05, + 0x8d, 0x8c, 0x75, 0xa5, 0x8c, 0x99, 0x3f, 0x55 } +}, + + /* PMAC-AES-128-32B */ +{ + 32, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* msg */ + { 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 }, + /* tag */ + { 0xe9, 0x7a, 0xc0, 0x4e, 0x9e, 0x5e, 0x33, 0x99, + 0xce, 0x53, 0x55, 0xcd, 0x74, 0x07, 0xbc, 0x75 } +}, + + /* PMAC-AES-128-34B */ +{ + 34, + /* key */ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + /* msg */ + { 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, + 0x20, 0x21 }, + /* tag */ + { 0x5c, 0xba, 0x7d, 0x5e, 0xb2, 0x4f, 0x7c, 0x86, + 0xcc, 0xc5, 0x46, 0x04, 0xe5, 0x3d, 0x55, 0x12 } +} + +}; + int err, x, idx; + unsigned long len; + unsigned char outtag[MAXBLOCKSIZE]; + + /* AES can be under rijndael or aes... try to find it */ + if ((idx = find_cipher("aes")) == -1) { + if ((idx = find_cipher("rijndael")) == -1) { + return CRYPT_NOP; + } + } + + for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { + len = sizeof(outtag); + if ((err = pmac_memory(idx, tests[x].key, 16, tests[x].msg, tests[x].msglen, outtag, &len)) != CRYPT_OK) { + return err; + } + + if (memcmp(outtag, tests[x].tag, len)) { +#if 0 + unsigned long y; + printf("\nTAG:\n"); + for (y = 0; y < len; ) { + printf("0x%02x", outtag[y]); + if (y < len-1) printf(", "); + if (!(++y % 8)) printf("\n"); + } +#endif + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; +#endif /* LTC_TEST */ +} + +#endif /* PMAC_MODE */ + + + diff --git a/rand_prime.c b/rand_prime.c new file mode 100644 index 0000000..2834c6a --- /dev/null +++ b/rand_prime.c @@ -0,0 +1,65 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +#ifdef MPI + +struct rng_data { + prng_state *prng; + int wprng; +}; + +static int rand_prime_helper(unsigned char *dst, int len, void *dat) +{ + return (int)prng_descriptor[((struct rng_data *)dat)->wprng].read(dst, len, ((struct rng_data *)dat)->prng); +} + +int rand_prime(mp_int *N, long len, prng_state *prng, int wprng) +{ + struct rng_data rng; + int type, err; + + _ARGCHK(N != NULL); + + /* allow sizes between 2 and 256 bytes for a prime size */ + if (len < 16 || len > 4096) { + return CRYPT_INVALID_PRIME_SIZE; + } + + /* valid PRNG? Better be! */ + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + /* setup our callback data, then world domination! */ + rng.prng = prng; + rng.wprng = wprng; + + /* get type */ + if (len < 0) { + type = LTM_PRIME_BBS; + len = -len; + } else { + type = 0; + } + + /* New prime generation makes the code even more cryptoish-insane. Do you know what this means!!! + -- Gir: Yeah, oh wait, er, no. + */ + if ((err = mp_prime_random_ex(N, mp_prime_rabin_miller_trials(len), len, type, rand_prime_helper, &rng)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + + return CRYPT_OK; +} + +#endif + diff --git a/rc2.c b/rc2.c new file mode 100644 index 0000000..a8f1d2d --- /dev/null +++ b/rc2.c @@ -0,0 +1,319 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/**********************************************************************\ +* 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 != 0 && rounds != 16) { + return CRYPT_INVALID_ROUNDS; + } + + for (i = 0; i < keylen; i++) { + tmp[i] = key[i] & 255; + } + + /* Phase 1: Expand input key to 128 bytes */ + if (keylen < 128) { + for (i = keylen; i < 128; i++) { + tmp[i] = permute[(int)((tmp[i - 1] + tmp[i - keylen]) & 255)]; + } + } + + /* Phase 2 - reduce effective key size to "bits" */ + bits = keylen*8; + T8 = (unsigned)(bits+7)>>3; + TM = (255 >> (unsigned)(7 & -bits)); + tmp[128 - T8] = permute[(int)(tmp[128 - T8] & TM)]; + for (i = 127 - T8; i >= 0; i--) { + tmp[i] = permute[(int)(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-- > 0); + +#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; + unsigned x76, x54, x32, x10, i; + + _ARGCHK(plain != NULL); + _ARGCHK(cipher != NULL); + _ARGCHK(skey != NULL); + + xkey = skey->rc2.xkey; + + 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; + int i; + + _ARGCHK(plain != NULL); + _ARGCHK(cipher != NULL); + _ARGCHK(skey != NULL); + + xkey = skey->rc2.xkey; + + 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) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + 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, y, err; + symmetric_key skey; + unsigned char tmp[2][8]; + + for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) { + zeromem(tmp, sizeof(tmp)); + if ((err = rc2_setup(tests[x].key, tests[x].keylen, 0, &skey)) != CRYPT_OK) { + return err; + } + + rc2_ecb_encrypt(tests[x].pt, tmp[0], &skey); + rc2_ecb_decrypt(tmp[0], tmp[1], &skey); + + if (memcmp(tmp[0], tests[x].ct, 8) != 0 || memcmp(tmp[1], tests[x].pt, 8) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + + /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ + for (y = 0; y < 8; y++) tmp[0][y] = 0; + for (y = 0; y < 1000; y++) rc2_ecb_encrypt(tmp[0], tmp[0], &skey); + for (y = 0; y < 1000; y++) rc2_ecb_decrypt(tmp[0], tmp[0], &skey); + for (y = 0; y < 8; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; + } + return CRYPT_OK; + #endif +} + +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..9d2f6b7 --- /dev/null +++ b/rc4.c @@ -0,0 +1,107 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#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..ab79535 --- /dev/null +++ b/rc5.c @@ -0,0 +1,269 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* RC5 code by Tom St Denis */ + +#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 +}; + +static const ulong32 stab[50] = { +0xb7e15163UL, 0x5618cb1cUL, 0xf45044d5UL, 0x9287be8eUL, 0x30bf3847UL, 0xcef6b200UL, 0x6d2e2bb9UL, 0x0b65a572UL, +0xa99d1f2bUL, 0x47d498e4UL, 0xe60c129dUL, 0x84438c56UL, 0x227b060fUL, 0xc0b27fc8UL, 0x5ee9f981UL, 0xfd21733aUL, +0x9b58ecf3UL, 0x399066acUL, 0xd7c7e065UL, 0x75ff5a1eUL, 0x1436d3d7UL, 0xb26e4d90UL, 0x50a5c749UL, 0xeedd4102UL, +0x8d14babbUL, 0x2b4c3474UL, 0xc983ae2dUL, 0x67bb27e6UL, 0x05f2a19fUL, 0xa42a1b58UL, 0x42619511UL, 0xe0990ecaUL, +0x7ed08883UL, 0x1d08023cUL, 0xbb3f7bf5UL, 0x5976f5aeUL, 0xf7ae6f67UL, 0x95e5e920UL, 0x341d62d9UL, 0xd254dc92UL, +0x708c564bUL, 0x0ec3d004UL, 0xacfb49bdUL, 0x4b32c376UL, 0xe96a3d2fUL, 0x87a1b6e8UL, 0x25d930a1UL, 0xc410aa5aUL, +0x62482413UL, 0x007f9dccUL +}; + +#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 +{ + ulong32 L[64], *S, 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; + } + + skey->rc5.rounds = num_rounds; + S = skey->rc5.K; + + /* copy the key into the L array */ + for (A = i = j = 0; i < (ulong32)keylen; ) { + A = (A << 8) | ((ulong32)(key[i++] & 255)); + if ((i & 3) == 0) { + L[j++] = BSWAP(A); + A = 0; + } + } + + if ((keylen & 3) != 0) { + A <<= (ulong32)((8 * (4 - (keylen&3)))); + L[j++] = BSWAP(A); + } + + /* setup the S array */ + t = (ulong32)(2 * (num_rounds + 1)); + memcpy(S, stab, t * sizeof(*S)); + + /* 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)); + if (++i == t) { i = 0; } + if (++j == l) { j = 0; } + } + 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(ulong32) * 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 +{ + ulong32 A, B, *K; + 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]; + K = key->rc5.K + 2; + + if ((key->rc5.rounds & 1) == 0) { + for (r = 0; r < key->rc5.rounds; r += 2) { + A = ROL(A ^ B, B) + K[0]; + B = ROL(B ^ A, A) + K[1]; + A = ROL(A ^ B, B) + K[2]; + B = ROL(B ^ A, A) + K[3]; + K += 4; + } + } else { + for (r = 0; r < key->rc5.rounds; r++) { + A = ROL(A ^ B, B) + K[0]; + B = ROL(B ^ A, A) + K[1]; + K += 2; + } + } + 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(ulong32) * 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 +{ + ulong32 A, B, *K; + int r; + _ARGCHK(key != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + + LOAD32L(A, &ct[0]); + LOAD32L(B, &ct[4]); + K = key->rc5.K + (key->rc5.rounds << 1); + + if ((key->rc5.rounds & 1) == 0) { + K -= 2; + for (r = key->rc5.rounds - 1; r >= 0; r -= 2) { + B = ROR(B - K[3], A) ^ A; + A = ROR(A - K[2], B) ^ B; + B = ROR(B - K[1], A) ^ A; + A = ROR(A - K[0], B) ^ B; + K -= 4; + } + } else { + for (r = key->rc5.rounds - 1; r >= 0; r--) { + B = ROR(B - K[1], A) ^ A; + A = ROR(A - K[0], B) ^ B; + K -= 2; + } + } + 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(ulong32) * 2 + sizeof(int)); +} +#endif + +int rc5_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + 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 tmp[2][8]; + int x, y, err; + symmetric_key key; + + for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) { + /* setup key */ + if ((err = rc5_setup(tests[x].key, 16, 12, &key)) != CRYPT_OK) { + return err; + } + + /* encrypt and decrypt */ + rc5_ecb_encrypt(tests[x].pt, tmp[0], &key); + rc5_ecb_decrypt(tmp[0], tmp[1], &key); + + /* compare */ + if (memcmp(tmp[0], tests[x].ct, 8) != 0 || memcmp(tmp[1], tests[x].pt, 8) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + + /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ + for (y = 0; y < 8; y++) tmp[0][y] = 0; + for (y = 0; y < 1000; y++) rc5_ecb_encrypt(tmp[0], tmp[0], &key); + for (y = 0; y < 1000; y++) rc5_ecb_decrypt(tmp[0], tmp[0], &key); + for (y = 0; y < 8; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; + } + return CRYPT_OK; + #endif +} + +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..8cc165c --- /dev/null +++ b/rc6.c @@ -0,0 +1,298 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* RC6 code by Tom St Denis */ +#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 +}; + +static const ulong32 stab[44] = { +0xb7e15163UL, 0x5618cb1cUL, 0xf45044d5UL, 0x9287be8eUL, 0x30bf3847UL, 0xcef6b200UL, 0x6d2e2bb9UL, 0x0b65a572UL, +0xa99d1f2bUL, 0x47d498e4UL, 0xe60c129dUL, 0x84438c56UL, 0x227b060fUL, 0xc0b27fc8UL, 0x5ee9f981UL, 0xfd21733aUL, +0x9b58ecf3UL, 0x399066acUL, 0xd7c7e065UL, 0x75ff5a1eUL, 0x1436d3d7UL, 0xb26e4d90UL, 0x50a5c749UL, 0xeedd4102UL, +0x8d14babbUL, 0x2b4c3474UL, 0xc983ae2dUL, 0x67bb27e6UL, 0x05f2a19fUL, 0xa42a1b58UL, 0x42619511UL, 0xe0990ecaUL, +0x7ed08883UL, 0x1d08023cUL, 0xbb3f7bf5UL, 0x5976f5aeUL, 0xf7ae6f67UL, 0x95e5e920UL, 0x341d62d9UL, 0xd254dc92UL, +0x708c564bUL, 0x0ec3d004UL, 0xacfb49bdUL, 0x4b32c376UL }; + +#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 +{ + ulong32 L[64], S[50], A, B, i, j, v, s, 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 < (ulong32)keylen; ) { + A = (A << 8) | ((ulong32)(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 */ + memcpy(S, stab, 44 * sizeof(stab[0])); + + /* mix buffer */ + s = 3 * MAX(44, 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)); + if (++i == 44) { i = 0; } + if (++j == l) { j = 0; } + } + + /* copy to key */ + for (i = 0; i < 44; 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(ulong32) * 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 +{ + ulong32 a,b,c,d,t,u, *K; + 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]; + +#define RND(a,b,c,d) \ + t = (b * (b + b + 1)); t = ROL(t, 5); \ + u = (d * (d + d + 1)); u = ROL(u, 5); \ + a = ROL(a^t,u) + K[0]; \ + c = ROL(c^u,t) + K[1]; K += 2; + + K = key->rc6.K + 2; + for (r = 0; r < 20; r += 4) { + RND(a,b,c,d); + RND(b,c,d,a); + RND(c,d,a,b); + RND(d,a,b,c); + } + +#undef RND + + 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(ulong32) * 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 +{ + ulong32 a,b,c,d,t,u, *K; + 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]; + +#define RND(a,b,c,d) \ + t = (b * (b + b + 1)); t = ROL(t, 5); \ + u = (d * (d + d + 1)); u = ROL(u, 5); \ + c = ROR(c - K[1], t) ^ u; \ + a = ROR(a - K[0], u) ^ t; K -= 2; + + K = key->rc6.K + 40; + + for (r = 0; r < 20; r += 4) { + RND(d,a,b,c); + RND(c,d,a,b); + RND(b,c,d,a); + RND(a,b,c,d); + } + +#undef RND + + 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(ulong32) * 6 + sizeof(int)); +} +#endif + +int rc6_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + 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 tmp[2][16]; + int x, y, err; + symmetric_key key; + + for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) { + /* setup key */ + if ((err = rc6_setup(tests[x].key, tests[x].keylen, 0, &key)) != CRYPT_OK) { + return err; + } + + /* encrypt and decrypt */ + rc6_ecb_encrypt(tests[x].pt, tmp[0], &key); + rc6_ecb_decrypt(tmp[0], tmp[1], &key); + + /* compare */ + if (memcmp(tmp[0], tests[x].ct, 16) || memcmp(tmp[1], tests[x].pt, 16)) { +#if 0 + printf("\n\nFailed test %d\n", x); + if (memcmp(tmp[0], tests[x].ct, 16)) { + printf("Ciphertext: "); + for (y = 0; y < 16; y++) printf("%02x ", tmp[0][y]); + printf("\nExpected : "); + for (y = 0; y < 16; y++) printf("%02x ", tests[x].ct[y]); + printf("\n"); + } + if (memcmp(tmp[1], tests[x].pt, 16)) { + printf("Plaintext: "); + for (y = 0; y < 16; y++) printf("%02x ", tmp[0][y]); + printf("\nExpected : "); + for (y = 0; y < 16; y++) printf("%02x ", tests[x].pt[y]); + printf("\n"); + } +#endif + return CRYPT_FAIL_TESTVECTOR; + } + + /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ + for (y = 0; y < 16; y++) tmp[0][y] = 0; + for (y = 0; y < 1000; y++) rc6_ecb_encrypt(tmp[0], tmp[0], &key); + for (y = 0; y < 1000; y++) rc6_ecb_decrypt(tmp[0], tmp[0], &key); + for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; + } + return CRYPT_OK; + #endif +} + +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/rmd128.c b/rmd128.c new file mode 100644 index 0000000..4aaf8d5 --- /dev/null +++ b/rmd128.c @@ -0,0 +1,368 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* Implementation of RIPEMD-128 based on the source by Antoon Bosselaers, ESAT-COSIC + * + * This source has been radically overhauled to be portable and work within + * the LibTomCrypt API by Tom St Denis + */ +#include "mycrypt.h" + +#ifdef RIPEMD128 + +const struct _hash_descriptor rmd128_desc = +{ + "rmd128", + 8, + 16, + 64, + &rmd128_init, + &rmd128_process, + &rmd128_done, + &rmd128_test +}; + +/* the four basic functions F(), G() and H() */ +#define F(x, y, z) ((x) ^ (y) ^ (z)) +#define G(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define H(x, y, z) (((x) | ~(y)) ^ (z)) +#define I(x, y, z) (((x) & (z)) | ((y) & ~(z))) + +/* the eight basic operations FF() through III() */ +#define FF(a, b, c, d, x, s) \ + (a) += F((b), (c), (d)) + (x);\ + (a) = ROL((a), (s)); + +#define GG(a, b, c, d, x, s) \ + (a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\ + (a) = ROL((a), (s)); + +#define HH(a, b, c, d, x, s) \ + (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\ + (a) = ROL((a), (s)); + +#define II(a, b, c, d, x, s) \ + (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\ + (a) = ROL((a), (s)); + +#define FFF(a, b, c, d, x, s) \ + (a) += F((b), (c), (d)) + (x);\ + (a) = ROL((a), (s)); + +#define GGG(a, b, c, d, x, s) \ + (a) += G((b), (c), (d)) + (x) + 0x6d703ef3UL;\ + (a) = ROL((a), (s)); + +#define HHH(a, b, c, d, x, s) \ + (a) += H((b), (c), (d)) + (x) + 0x5c4dd124UL;\ + (a) = ROL((a), (s)); + +#define III(a, b, c, d, x, s) \ + (a) += I((b), (c), (d)) + (x) + 0x50a28be6UL;\ + (a) = ROL((a), (s)); + +#ifdef CLEAN_STACK +static void _rmd128_compress(hash_state *md, unsigned char *buf) +#else +static void rmd128_compress(hash_state *md, unsigned char *buf) +#endif +{ + ulong32 aa,bb,cc,dd,aaa,bbb,ccc,ddd,X[16]; + int i; + + /* load words X */ + for (i = 0; i < 16; i++){ + LOAD32L(X[i], buf + (4 * i)); + } + + /* load state */ + aa = aaa = md->rmd128.state[0]; + bb = bbb = md->rmd128.state[1]; + cc = ccc = md->rmd128.state[2]; + dd = ddd = md->rmd128.state[3]; + + /* round 1 */ + FF(aa, bb, cc, dd, X[ 0], 11); + FF(dd, aa, bb, cc, X[ 1], 14); + FF(cc, dd, aa, bb, X[ 2], 15); + FF(bb, cc, dd, aa, X[ 3], 12); + FF(aa, bb, cc, dd, X[ 4], 5); + FF(dd, aa, bb, cc, X[ 5], 8); + FF(cc, dd, aa, bb, X[ 6], 7); + FF(bb, cc, dd, aa, X[ 7], 9); + FF(aa, bb, cc, dd, X[ 8], 11); + FF(dd, aa, bb, cc, X[ 9], 13); + FF(cc, dd, aa, bb, X[10], 14); + FF(bb, cc, dd, aa, X[11], 15); + FF(aa, bb, cc, dd, X[12], 6); + FF(dd, aa, bb, cc, X[13], 7); + FF(cc, dd, aa, bb, X[14], 9); + FF(bb, cc, dd, aa, X[15], 8); + + /* round 2 */ + GG(aa, bb, cc, dd, X[ 7], 7); + GG(dd, aa, bb, cc, X[ 4], 6); + GG(cc, dd, aa, bb, X[13], 8); + GG(bb, cc, dd, aa, X[ 1], 13); + GG(aa, bb, cc, dd, X[10], 11); + GG(dd, aa, bb, cc, X[ 6], 9); + GG(cc, dd, aa, bb, X[15], 7); + GG(bb, cc, dd, aa, X[ 3], 15); + GG(aa, bb, cc, dd, X[12], 7); + GG(dd, aa, bb, cc, X[ 0], 12); + GG(cc, dd, aa, bb, X[ 9], 15); + GG(bb, cc, dd, aa, X[ 5], 9); + GG(aa, bb, cc, dd, X[ 2], 11); + GG(dd, aa, bb, cc, X[14], 7); + GG(cc, dd, aa, bb, X[11], 13); + GG(bb, cc, dd, aa, X[ 8], 12); + + /* round 3 */ + HH(aa, bb, cc, dd, X[ 3], 11); + HH(dd, aa, bb, cc, X[10], 13); + HH(cc, dd, aa, bb, X[14], 6); + HH(bb, cc, dd, aa, X[ 4], 7); + HH(aa, bb, cc, dd, X[ 9], 14); + HH(dd, aa, bb, cc, X[15], 9); + HH(cc, dd, aa, bb, X[ 8], 13); + HH(bb, cc, dd, aa, X[ 1], 15); + HH(aa, bb, cc, dd, X[ 2], 14); + HH(dd, aa, bb, cc, X[ 7], 8); + HH(cc, dd, aa, bb, X[ 0], 13); + HH(bb, cc, dd, aa, X[ 6], 6); + HH(aa, bb, cc, dd, X[13], 5); + HH(dd, aa, bb, cc, X[11], 12); + HH(cc, dd, aa, bb, X[ 5], 7); + HH(bb, cc, dd, aa, X[12], 5); + + /* round 4 */ + II(aa, bb, cc, dd, X[ 1], 11); + II(dd, aa, bb, cc, X[ 9], 12); + II(cc, dd, aa, bb, X[11], 14); + II(bb, cc, dd, aa, X[10], 15); + II(aa, bb, cc, dd, X[ 0], 14); + II(dd, aa, bb, cc, X[ 8], 15); + II(cc, dd, aa, bb, X[12], 9); + II(bb, cc, dd, aa, X[ 4], 8); + II(aa, bb, cc, dd, X[13], 9); + II(dd, aa, bb, cc, X[ 3], 14); + II(cc, dd, aa, bb, X[ 7], 5); + II(bb, cc, dd, aa, X[15], 6); + II(aa, bb, cc, dd, X[14], 8); + II(dd, aa, bb, cc, X[ 5], 6); + II(cc, dd, aa, bb, X[ 6], 5); + II(bb, cc, dd, aa, X[ 2], 12); + + /* parallel round 1 */ + III(aaa, bbb, ccc, ddd, X[ 5], 8); + III(ddd, aaa, bbb, ccc, X[14], 9); + III(ccc, ddd, aaa, bbb, X[ 7], 9); + III(bbb, ccc, ddd, aaa, X[ 0], 11); + III(aaa, bbb, ccc, ddd, X[ 9], 13); + III(ddd, aaa, bbb, ccc, X[ 2], 15); + III(ccc, ddd, aaa, bbb, X[11], 15); + III(bbb, ccc, ddd, aaa, X[ 4], 5); + III(aaa, bbb, ccc, ddd, X[13], 7); + III(ddd, aaa, bbb, ccc, X[ 6], 7); + III(ccc, ddd, aaa, bbb, X[15], 8); + III(bbb, ccc, ddd, aaa, X[ 8], 11); + III(aaa, bbb, ccc, ddd, X[ 1], 14); + III(ddd, aaa, bbb, ccc, X[10], 14); + III(ccc, ddd, aaa, bbb, X[ 3], 12); + III(bbb, ccc, ddd, aaa, X[12], 6); + + /* parallel round 2 */ + HHH(aaa, bbb, ccc, ddd, X[ 6], 9); + HHH(ddd, aaa, bbb, ccc, X[11], 13); + HHH(ccc, ddd, aaa, bbb, X[ 3], 15); + HHH(bbb, ccc, ddd, aaa, X[ 7], 7); + HHH(aaa, bbb, ccc, ddd, X[ 0], 12); + HHH(ddd, aaa, bbb, ccc, X[13], 8); + HHH(ccc, ddd, aaa, bbb, X[ 5], 9); + HHH(bbb, ccc, ddd, aaa, X[10], 11); + HHH(aaa, bbb, ccc, ddd, X[14], 7); + HHH(ddd, aaa, bbb, ccc, X[15], 7); + HHH(ccc, ddd, aaa, bbb, X[ 8], 12); + HHH(bbb, ccc, ddd, aaa, X[12], 7); + HHH(aaa, bbb, ccc, ddd, X[ 4], 6); + HHH(ddd, aaa, bbb, ccc, X[ 9], 15); + HHH(ccc, ddd, aaa, bbb, X[ 1], 13); + HHH(bbb, ccc, ddd, aaa, X[ 2], 11); + + /* parallel round 3 */ + GGG(aaa, bbb, ccc, ddd, X[15], 9); + GGG(ddd, aaa, bbb, ccc, X[ 5], 7); + GGG(ccc, ddd, aaa, bbb, X[ 1], 15); + GGG(bbb, ccc, ddd, aaa, X[ 3], 11); + GGG(aaa, bbb, ccc, ddd, X[ 7], 8); + GGG(ddd, aaa, bbb, ccc, X[14], 6); + GGG(ccc, ddd, aaa, bbb, X[ 6], 6); + GGG(bbb, ccc, ddd, aaa, X[ 9], 14); + GGG(aaa, bbb, ccc, ddd, X[11], 12); + GGG(ddd, aaa, bbb, ccc, X[ 8], 13); + GGG(ccc, ddd, aaa, bbb, X[12], 5); + GGG(bbb, ccc, ddd, aaa, X[ 2], 14); + GGG(aaa, bbb, ccc, ddd, X[10], 13); + GGG(ddd, aaa, bbb, ccc, X[ 0], 13); + GGG(ccc, ddd, aaa, bbb, X[ 4], 7); + GGG(bbb, ccc, ddd, aaa, X[13], 5); + + /* parallel round 4 */ + FFF(aaa, bbb, ccc, ddd, X[ 8], 15); + FFF(ddd, aaa, bbb, ccc, X[ 6], 5); + FFF(ccc, ddd, aaa, bbb, X[ 4], 8); + FFF(bbb, ccc, ddd, aaa, X[ 1], 11); + FFF(aaa, bbb, ccc, ddd, X[ 3], 14); + FFF(ddd, aaa, bbb, ccc, X[11], 14); + FFF(ccc, ddd, aaa, bbb, X[15], 6); + FFF(bbb, ccc, ddd, aaa, X[ 0], 14); + FFF(aaa, bbb, ccc, ddd, X[ 5], 6); + FFF(ddd, aaa, bbb, ccc, X[12], 9); + FFF(ccc, ddd, aaa, bbb, X[ 2], 12); + FFF(bbb, ccc, ddd, aaa, X[13], 9); + FFF(aaa, bbb, ccc, ddd, X[ 9], 12); + FFF(ddd, aaa, bbb, ccc, X[ 7], 5); + FFF(ccc, ddd, aaa, bbb, X[10], 15); + FFF(bbb, ccc, ddd, aaa, X[14], 8); + + /* combine results */ + ddd += cc + md->rmd128.state[1]; /* final result for MDbuf[0] */ + md->rmd128.state[1] = md->rmd128.state[2] + dd + aaa; + md->rmd128.state[2] = md->rmd128.state[3] + aa + bbb; + md->rmd128.state[3] = md->rmd128.state[0] + bb + ccc; + md->rmd128.state[0] = ddd; +} + +#ifdef CLEAN_STACK +static void rmd128_compress(hash_state *md, unsigned char *buf) +{ + _rmd128_compress(md, buf); + burn_stack(sizeof(ulong32) * 24 + sizeof(int)); +} +#endif + +void rmd128_init(hash_state * md) +{ + _ARGCHK(md != NULL); + md->rmd128.state[0] = 0x67452301UL; + md->rmd128.state[1] = 0xefcdab89UL; + md->rmd128.state[2] = 0x98badcfeUL; + md->rmd128.state[3] = 0x10325476UL; + md->rmd128.curlen = 0; + md->rmd128.length = 0; +} + +HASH_PROCESS(rmd128_process, rmd128_compress, rmd128, 64) + +int rmd128_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->rmd128.curlen >= sizeof(md->rmd128.buf)) { + return CRYPT_INVALID_ARG; + } + + + /* increase the length of the message */ + md->rmd128.length += md->rmd128.curlen * 8; + + /* append the '1' bit */ + md->rmd128.buf[md->rmd128.curlen++] = (unsigned char)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->rmd128.curlen > 56) { + while (md->rmd128.curlen < 64) { + md->rmd128.buf[md->rmd128.curlen++] = (unsigned char)0; + } + rmd128_compress(md, md->rmd128.buf); + md->rmd128.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->rmd128.curlen < 56) { + md->rmd128.buf[md->rmd128.curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64L(md->rmd128.length, md->rmd128.buf+56); + rmd128_compress(md, md->rmd128.buf); + + /* copy output */ + for (i = 0; i < 4; i++) { + STORE32L(md->rmd128.state[i], hash+(4*i)); + } +#ifdef CLEAN_STACK + zeromem(md, sizeof(hash_state)); +#endif + return CRYPT_OK; +} + +int rmd128_test(void) +{ +#ifndef LTC_TEST + return CRYPT_NOP; +#else + static const struct { + char *msg; + unsigned char md[16]; + } tests[] = { + { "", + { 0xcd, 0xf2, 0x62, 0x13, 0xa1, 0x50, 0xdc, 0x3e, + 0xcb, 0x61, 0x0f, 0x18, 0xf6, 0xb3, 0x8b, 0x46 } + }, + { "a", + { 0x86, 0xbe, 0x7a, 0xfa, 0x33, 0x9d, 0x0f, 0xc7, + 0xcf, 0xc7, 0x85, 0xe7, 0x2f, 0x57, 0x8d, 0x33 } + }, + { "abc", + { 0xc1, 0x4a, 0x12, 0x19, 0x9c, 0x66, 0xe4, 0xba, + 0x84, 0x63, 0x6b, 0x0f, 0x69, 0x14, 0x4c, 0x77 } + }, + { "message digest", + { 0x9e, 0x32, 0x7b, 0x3d, 0x6e, 0x52, 0x30, 0x62, + 0xaf, 0xc1, 0x13, 0x2d, 0x7d, 0xf9, 0xd1, 0xb8 } + }, + { "abcdefghijklmnopqrstuvwxyz", + { 0xfd, 0x2a, 0xa6, 0x07, 0xf7, 0x1d, 0xc8, 0xf5, + 0x10, 0x71, 0x49, 0x22, 0xb3, 0x71, 0x83, 0x4e } + }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + { 0xd1, 0xe9, 0x59, 0xeb, 0x17, 0x9c, 0x91, 0x1f, + 0xae, 0xa4, 0x62, 0x4c, 0x60, 0xc5, 0xc7, 0x02 } + } + }; + int x; + unsigned char buf[16]; + hash_state md; + + for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { + rmd128_init(&md); + rmd128_process(&md, (unsigned char *)tests[x].msg, strlen(tests[x].msg)); + rmd128_done(&md, buf); + if (memcmp(buf, tests[x].md, 16) != 0) { + #if 0 + printf("Failed test %d\n", x); + #endif + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; +#endif +} + +#endif + diff --git a/rmd160.c b/rmd160.c new file mode 100644 index 0000000..93a2cab --- /dev/null +++ b/rmd160.c @@ -0,0 +1,427 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* Implementation of RIPEMD-160 based on the source by Antoon Bosselaers, ESAT-COSIC + * + * This source has been radically overhauled to be portable and work within + * the LibTomCrypt API by Tom St Denis + */ +#include "mycrypt.h" + +#ifdef RIPEMD160 + +const struct _hash_descriptor rmd160_desc = +{ + "rmd160", + 9, + 20, + 64, + &rmd160_init, + &rmd160_process, + &rmd160_done, + &rmd160_test +}; + +/* the five basic functions F(), G() and H() */ +#define F(x, y, z) ((x) ^ (y) ^ (z)) +#define G(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define H(x, y, z) (((x) | ~(y)) ^ (z)) +#define I(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define J(x, y, z) ((x) ^ ((y) | ~(z))) + +/* the ten basic operations FF() through III() */ +#define FF(a, b, c, d, e, x, s) \ + (a) += F((b), (c), (d)) + (x);\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10); + +#define GG(a, b, c, d, e, x, s) \ + (a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10); + +#define HH(a, b, c, d, e, x, s) \ + (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10); + +#define II(a, b, c, d, e, x, s) \ + (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10); + +#define JJ(a, b, c, d, e, x, s) \ + (a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10); + +#define FFF(a, b, c, d, e, x, s) \ + (a) += F((b), (c), (d)) + (x);\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10); + +#define GGG(a, b, c, d, e, x, s) \ + (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10); + +#define HHH(a, b, c, d, e, x, s) \ + (a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10); + +#define III(a, b, c, d, e, x, s) \ + (a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10); + +#define JJJ(a, b, c, d, e, x, s) \ + (a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\ + (a) = ROL((a), (s)) + (e);\ + (c) = ROL((c), 10); + + +#ifdef CLEAN_STACK +static void _rmd160_compress(hash_state *md, unsigned char *buf) +#else +static void rmd160_compress(hash_state *md, unsigned char *buf) +#endif +{ + ulong32 aa,bb,cc,dd,ee,aaa,bbb,ccc,ddd,eee,X[16]; + int i; + + /* load words X */ + for (i = 0; i < 16; i++){ + LOAD32L(X[i], buf + (4 * i)); + } + + /* load state */ + aa = aaa = md->rmd160.state[0]; + bb = bbb = md->rmd160.state[1]; + cc = ccc = md->rmd160.state[2]; + dd = ddd = md->rmd160.state[3]; + ee = eee = md->rmd160.state[4]; + + /* round 1 */ + FF(aa, bb, cc, dd, ee, X[ 0], 11); + FF(ee, aa, bb, cc, dd, X[ 1], 14); + FF(dd, ee, aa, bb, cc, X[ 2], 15); + FF(cc, dd, ee, aa, bb, X[ 3], 12); + FF(bb, cc, dd, ee, aa, X[ 4], 5); + FF(aa, bb, cc, dd, ee, X[ 5], 8); + FF(ee, aa, bb, cc, dd, X[ 6], 7); + FF(dd, ee, aa, bb, cc, X[ 7], 9); + FF(cc, dd, ee, aa, bb, X[ 8], 11); + FF(bb, cc, dd, ee, aa, X[ 9], 13); + FF(aa, bb, cc, dd, ee, X[10], 14); + FF(ee, aa, bb, cc, dd, X[11], 15); + FF(dd, ee, aa, bb, cc, X[12], 6); + FF(cc, dd, ee, aa, bb, X[13], 7); + FF(bb, cc, dd, ee, aa, X[14], 9); + FF(aa, bb, cc, dd, ee, X[15], 8); + + /* round 2 */ + GG(ee, aa, bb, cc, dd, X[ 7], 7); + GG(dd, ee, aa, bb, cc, X[ 4], 6); + GG(cc, dd, ee, aa, bb, X[13], 8); + GG(bb, cc, dd, ee, aa, X[ 1], 13); + GG(aa, bb, cc, dd, ee, X[10], 11); + GG(ee, aa, bb, cc, dd, X[ 6], 9); + GG(dd, ee, aa, bb, cc, X[15], 7); + GG(cc, dd, ee, aa, bb, X[ 3], 15); + GG(bb, cc, dd, ee, aa, X[12], 7); + GG(aa, bb, cc, dd, ee, X[ 0], 12); + GG(ee, aa, bb, cc, dd, X[ 9], 15); + GG(dd, ee, aa, bb, cc, X[ 5], 9); + GG(cc, dd, ee, aa, bb, X[ 2], 11); + GG(bb, cc, dd, ee, aa, X[14], 7); + GG(aa, bb, cc, dd, ee, X[11], 13); + GG(ee, aa, bb, cc, dd, X[ 8], 12); + + /* round 3 */ + HH(dd, ee, aa, bb, cc, X[ 3], 11); + HH(cc, dd, ee, aa, bb, X[10], 13); + HH(bb, cc, dd, ee, aa, X[14], 6); + HH(aa, bb, cc, dd, ee, X[ 4], 7); + HH(ee, aa, bb, cc, dd, X[ 9], 14); + HH(dd, ee, aa, bb, cc, X[15], 9); + HH(cc, dd, ee, aa, bb, X[ 8], 13); + HH(bb, cc, dd, ee, aa, X[ 1], 15); + HH(aa, bb, cc, dd, ee, X[ 2], 14); + HH(ee, aa, bb, cc, dd, X[ 7], 8); + HH(dd, ee, aa, bb, cc, X[ 0], 13); + HH(cc, dd, ee, aa, bb, X[ 6], 6); + HH(bb, cc, dd, ee, aa, X[13], 5); + HH(aa, bb, cc, dd, ee, X[11], 12); + HH(ee, aa, bb, cc, dd, X[ 5], 7); + HH(dd, ee, aa, bb, cc, X[12], 5); + + /* round 4 */ + II(cc, dd, ee, aa, bb, X[ 1], 11); + II(bb, cc, dd, ee, aa, X[ 9], 12); + II(aa, bb, cc, dd, ee, X[11], 14); + II(ee, aa, bb, cc, dd, X[10], 15); + II(dd, ee, aa, bb, cc, X[ 0], 14); + II(cc, dd, ee, aa, bb, X[ 8], 15); + II(bb, cc, dd, ee, aa, X[12], 9); + II(aa, bb, cc, dd, ee, X[ 4], 8); + II(ee, aa, bb, cc, dd, X[13], 9); + II(dd, ee, aa, bb, cc, X[ 3], 14); + II(cc, dd, ee, aa, bb, X[ 7], 5); + II(bb, cc, dd, ee, aa, X[15], 6); + II(aa, bb, cc, dd, ee, X[14], 8); + II(ee, aa, bb, cc, dd, X[ 5], 6); + II(dd, ee, aa, bb, cc, X[ 6], 5); + II(cc, dd, ee, aa, bb, X[ 2], 12); + + /* round 5 */ + JJ(bb, cc, dd, ee, aa, X[ 4], 9); + JJ(aa, bb, cc, dd, ee, X[ 0], 15); + JJ(ee, aa, bb, cc, dd, X[ 5], 5); + JJ(dd, ee, aa, bb, cc, X[ 9], 11); + JJ(cc, dd, ee, aa, bb, X[ 7], 6); + JJ(bb, cc, dd, ee, aa, X[12], 8); + JJ(aa, bb, cc, dd, ee, X[ 2], 13); + JJ(ee, aa, bb, cc, dd, X[10], 12); + JJ(dd, ee, aa, bb, cc, X[14], 5); + JJ(cc, dd, ee, aa, bb, X[ 1], 12); + JJ(bb, cc, dd, ee, aa, X[ 3], 13); + JJ(aa, bb, cc, dd, ee, X[ 8], 14); + JJ(ee, aa, bb, cc, dd, X[11], 11); + JJ(dd, ee, aa, bb, cc, X[ 6], 8); + JJ(cc, dd, ee, aa, bb, X[15], 5); + JJ(bb, cc, dd, ee, aa, X[13], 6); + + /* parallel round 1 */ + JJJ(aaa, bbb, ccc, ddd, eee, X[ 5], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[14], 9); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 7], 9); + JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13); + JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15); + JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 4], 5); + JJJ(ccc, ddd, eee, aaa, bbb, X[13], 7); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 6], 7); + JJJ(aaa, bbb, ccc, ddd, eee, X[15], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14); + JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12); + JJJ(aaa, bbb, ccc, ddd, eee, X[12], 6); + + /* parallel round 2 */ + III(eee, aaa, bbb, ccc, ddd, X[ 6], 9); + III(ddd, eee, aaa, bbb, ccc, X[11], 13); + III(ccc, ddd, eee, aaa, bbb, X[ 3], 15); + III(bbb, ccc, ddd, eee, aaa, X[ 7], 7); + III(aaa, bbb, ccc, ddd, eee, X[ 0], 12); + III(eee, aaa, bbb, ccc, ddd, X[13], 8); + III(ddd, eee, aaa, bbb, ccc, X[ 5], 9); + III(ccc, ddd, eee, aaa, bbb, X[10], 11); + III(bbb, ccc, ddd, eee, aaa, X[14], 7); + III(aaa, bbb, ccc, ddd, eee, X[15], 7); + III(eee, aaa, bbb, ccc, ddd, X[ 8], 12); + III(ddd, eee, aaa, bbb, ccc, X[12], 7); + III(ccc, ddd, eee, aaa, bbb, X[ 4], 6); + III(bbb, ccc, ddd, eee, aaa, X[ 9], 15); + III(aaa, bbb, ccc, ddd, eee, X[ 1], 13); + III(eee, aaa, bbb, ccc, ddd, X[ 2], 11); + + /* parallel round 3 */ + HHH(ddd, eee, aaa, bbb, ccc, X[15], 9); + HHH(ccc, ddd, eee, aaa, bbb, X[ 5], 7); + HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15); + HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11); + HHH(eee, aaa, bbb, ccc, ddd, X[ 7], 8); + HHH(ddd, eee, aaa, bbb, ccc, X[14], 6); + HHH(ccc, ddd, eee, aaa, bbb, X[ 6], 6); + HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14); + HHH(aaa, bbb, ccc, ddd, eee, X[11], 12); + HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13); + HHH(ddd, eee, aaa, bbb, ccc, X[12], 5); + HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14); + HHH(bbb, ccc, ddd, eee, aaa, X[10], 13); + HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13); + HHH(eee, aaa, bbb, ccc, ddd, X[ 4], 7); + HHH(ddd, eee, aaa, bbb, ccc, X[13], 5); + + /* parallel round 4 */ + GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15); + GGG(bbb, ccc, ddd, eee, aaa, X[ 6], 5); + GGG(aaa, bbb, ccc, ddd, eee, X[ 4], 8); + GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11); + GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14); + GGG(ccc, ddd, eee, aaa, bbb, X[11], 14); + GGG(bbb, ccc, ddd, eee, aaa, X[15], 6); + GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14); + GGG(eee, aaa, bbb, ccc, ddd, X[ 5], 6); + GGG(ddd, eee, aaa, bbb, ccc, X[12], 9); + GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12); + GGG(bbb, ccc, ddd, eee, aaa, X[13], 9); + GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12); + GGG(eee, aaa, bbb, ccc, ddd, X[ 7], 5); + GGG(ddd, eee, aaa, bbb, ccc, X[10], 15); + GGG(ccc, ddd, eee, aaa, bbb, X[14], 8); + + /* parallel round 5 */ + FFF(bbb, ccc, ddd, eee, aaa, X[12] , 8); + FFF(aaa, bbb, ccc, ddd, eee, X[15] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12); + FFF(ddd, eee, aaa, bbb, ccc, X[ 4] , 9); + FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12); + FFF(bbb, ccc, ddd, eee, aaa, X[ 5] , 5); + FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14); + FFF(eee, aaa, bbb, ccc, ddd, X[ 7] , 6); + FFF(ddd, eee, aaa, bbb, ccc, X[ 6] , 8); + FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13); + FFF(bbb, ccc, ddd, eee, aaa, X[13] , 6); + FFF(aaa, bbb, ccc, ddd, eee, X[14] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15); + FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13); + FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11); + FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11); + + /* combine results */ + ddd += cc + md->rmd160.state[1]; /* final result for md->rmd160.state[0] */ + md->rmd160.state[1] = md->rmd160.state[2] + dd + eee; + md->rmd160.state[2] = md->rmd160.state[3] + ee + aaa; + md->rmd160.state[3] = md->rmd160.state[4] + aa + bbb; + md->rmd160.state[4] = md->rmd160.state[0] + bb + ccc; + md->rmd160.state[0] = ddd; +} + +#ifdef CLEAN_STACK +static void rmd160_compress(hash_state *md, unsigned char *buf) +{ + _rmd160_compress(md, buf); + burn_stack(sizeof(ulong32) * 26 + sizeof(int)); +} +#endif + +void rmd160_init(hash_state * md) +{ + _ARGCHK(md != NULL); + md->rmd160.state[0] = 0x67452301UL; + md->rmd160.state[1] = 0xefcdab89UL; + md->rmd160.state[2] = 0x98badcfeUL; + md->rmd160.state[3] = 0x10325476UL; + md->rmd160.state[4] = 0xc3d2e1f0UL; + md->rmd160.curlen = 0; + md->rmd160.length = 0; +} + +HASH_PROCESS(rmd160_process, rmd160_compress, rmd160, 64) + +int rmd160_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->rmd160.curlen >= sizeof(md->rmd160.buf)) { + return CRYPT_INVALID_ARG; + } + + + /* increase the length of the message */ + md->rmd160.length += md->rmd160.curlen * 8; + + /* append the '1' bit */ + md->rmd160.buf[md->rmd160.curlen++] = (unsigned char)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->rmd160.curlen > 56) { + while (md->rmd160.curlen < 64) { + md->rmd160.buf[md->rmd160.curlen++] = (unsigned char)0; + } + rmd160_compress(md, md->rmd160.buf); + md->rmd160.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->rmd160.curlen < 56) { + md->rmd160.buf[md->rmd160.curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64L(md->rmd160.length, md->rmd160.buf+56); + rmd160_compress(md, md->rmd160.buf); + + /* copy output */ + for (i = 0; i < 5; i++) { + STORE32L(md->rmd160.state[i], hash+(4*i)); + } +#ifdef CLEAN_STACK + zeromem(md, sizeof(hash_state)); +#endif + return CRYPT_OK; +} + +int rmd160_test(void) +{ +#ifndef LTC_TEST + return CRYPT_NOP; +#else + static const struct { + char *msg; + unsigned char md[20]; + } tests[] = { + { "", + { 0x9c, 0x11, 0x85, 0xa5, 0xc5, 0xe9, 0xfc, 0x54, 0x61, 0x28, + 0x08, 0x97, 0x7e, 0xe8, 0xf5, 0x48, 0xb2, 0x25, 0x8d, 0x31 } + }, + { "a", + { 0x0b, 0xdc, 0x9d, 0x2d, 0x25, 0x6b, 0x3e, 0xe9, 0xda, 0xae, + 0x34, 0x7b, 0xe6, 0xf4, 0xdc, 0x83, 0x5a, 0x46, 0x7f, 0xfe } + }, + { "abc", + { 0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, 0x9b, 0x04, + 0x4a, 0x8e, 0x98, 0xc6, 0xb0, 0x87, 0xf1, 0x5a, 0x0b, 0xfc } + }, + { "message digest", + { 0x5d, 0x06, 0x89, 0xef, 0x49, 0xd2, 0xfa, 0xe5, 0x72, 0xb8, + 0x81, 0xb1, 0x23, 0xa8, 0x5f, 0xfa, 0x21, 0x59, 0x5f, 0x36 } + }, + { "abcdefghijklmnopqrstuvwxyz", + { 0xf7, 0x1c, 0x27, 0x10, 0x9c, 0x69, 0x2c, 0x1b, 0x56, 0xbb, + 0xdc, 0xeb, 0x5b, 0x9d, 0x28, 0x65, 0xb3, 0x70, 0x8d, 0xbc } + }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + { 0x12, 0xa0, 0x53, 0x38, 0x4a, 0x9c, 0x0c, 0x88, 0xe4, 0x05, + 0xa0, 0x6c, 0x27, 0xdc, 0xf4, 0x9a, 0xda, 0x62, 0xeb, 0x2b } + } + }; + int x; + unsigned char buf[20]; + hash_state md; + + for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { + rmd160_init(&md); + rmd160_process(&md, (unsigned char *)tests[x].msg, strlen(tests[x].msg)); + rmd160_done(&md, buf); + if (memcmp(buf, tests[x].md, 20) != 0) { +#if 0 + printf("Failed test %d\n", x); +#endif + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; +#endif +} + +#endif + diff --git a/rng_get_bytes.c b/rng_get_bytes.c new file mode 100644 index 0000000..f3027cd --- /dev/null +++ b/rng_get_bytes.c @@ -0,0 +1,129 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* 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; + unsigned long 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; + } + + /* disable buffering */ + if (setvbuf(f, NULL, _IONBF, 0) != 0) { + fclose(f); + return 0; + } + + x = (unsigned long)fread(buf, 1, (size_t)len, f); + fclose(f); + return x; +#endif /* NO_FILE */ +} + +#endif /* DEVRANDOM */ + +/* on ANSI C platforms with 100 < CLOCKS_PER_SEC < 10000 */ +#if 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)) +{ + unsigned long x; + + _ARGCHK(buf != NULL); + +#if defined(DEVRANDOM) + x = rng_nix(buf, len, callback); if (x != 0) { return x; } +#endif +#ifdef WIN32 + x = rng_win32(buf, len, callback); if (x != 0) { return x; } +#endif +#ifdef ANSI_RNG + x = rng_ansic(buf, len, callback); if (x != 0) { return x; } +#endif + return 0; +} diff --git a/rng_make_prng.c b/rng_make_prng.c new file mode 100644 index 0000000..4c30e69 --- /dev/null +++ b/rng_make_prng.c @@ -0,0 +1,53 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +/* portable way to get secure random bits to feed a PRNG */ +#include "mycrypt.h" + +int rng_make_prng(int bits, int wprng, prng_state *prng, + void (*callback)(void)) +{ + unsigned char buf[256]; + int err; + + _ARGCHK(prng != NULL); + + /* check parameter */ + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + if (bits < 64 || bits > 1024) { + return CRYPT_INVALID_PRNGSIZE; + } + + if ((err = prng_descriptor[wprng].start(prng)) != CRYPT_OK) { + return err; + } + + bits = ((bits/8)+((bits&7)!=0?1:0)) * 2; + if (rng_get_bytes(buf, (unsigned long)bits, callback) != (unsigned long)bits) { + return CRYPT_ERROR_READPRNG; + } + + if ((err = prng_descriptor[wprng].add_entropy(buf, (unsigned long)bits, prng)) != CRYPT_OK) { + return err; + } + + if ((err = prng_descriptor[wprng].ready(prng)) != CRYPT_OK) { + return err; + } + + #ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); + #endif + return CRYPT_OK; +} + diff --git a/rsa.c b/rsa.c new file mode 100644 index 0000000..05190fd --- /dev/null +++ b/rsa.c @@ -0,0 +1,273 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* RSA Code by Tom St Denis */ +#include "mycrypt.h" + +#ifdef MRSA + +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 > MAX_RSA_SIZE/8) { + return CRYPT_PK_INVALID_SIZE; + } + + for (y = x = 0; x < inlen; x++) + out[y++] = (unsigned char)0xFF; + for (x = 0; x < inlen; x++) + out[y++] = in[x]; + for (x = 0; x < inlen; x++) + out[y++] = (unsigned char)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[3*(MAX_RSA_SIZE/8)]; + unsigned long x; + int err; + + _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 ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + /* check inlen */ + if (inlen > (MAX_RSA_SIZE/8)) { + 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 sandwhich + * + * 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] = out[inlen+inlen+inlen-1] = (unsigned char)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] != (unsigned char)0xFF || in[x+(inlen/3)+(inlen/3)] != (unsigned char)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; +} + +int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key) +{ + unsigned long y, z; + int err; + + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* can we store the static header? */ + if (*outlen < (PACKET_SIZE + 1)) { + return CRYPT_BUFFER_OVERFLOW; + } + + /* 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 */ + out[y++] = type; + + /* output modulus */ + OUTPUT_BIGNUM(&key->N, out, y, z); + + /* output public key */ + OUTPUT_BIGNUM(&key->e, out, y, z); + + if (type == PK_PRIVATE || type == PK_PRIVATE_OPTIMIZED) { + OUTPUT_BIGNUM(&key->d, out, y, z); + } + + if (type == PK_PRIVATE_OPTIMIZED) { + OUTPUT_BIGNUM(&key->dQ, out, y, z); + OUTPUT_BIGNUM(&key->dP, out, y, z); + OUTPUT_BIGNUM(&key->pQ, out, y, z); + OUTPUT_BIGNUM(&key->qP, out, y, z); + OUTPUT_BIGNUM(&key->p, out, y, z); + OUTPUT_BIGNUM(&key->q, out, y, z); + } + + /* store packet header */ + packet_store_header(out, PACKET_SECT_RSA, PACKET_SUB_KEY); + + /* copy to the user buffer */ + *outlen = y; + + /* clear stack and return */ + return CRYPT_OK; +} + +int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) +{ + unsigned long x, y; + int err; + + _ARGCHK(in != NULL); + _ARGCHK(key != NULL); + + /* check length */ + if (inlen < (1+PACKET_SIZE)) { + return CRYPT_INVALID_PACKET; + } + + /* test packet header */ + if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_KEY)) != CRYPT_OK) { + return err; + } + + /* init key */ + if ((err = 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 mpi_to_ltc_error(err); + } + + /* get key type */ + y = PACKET_SIZE; + key->type = (int)in[y++]; + + /* load the modulus */ + INPUT_BIGNUM(&key->N, in, x, y, inlen); + + /* load public exponent */ + INPUT_BIGNUM(&key->e, in, x, y, inlen); + + /* get private exponent */ + if (key->type == PK_PRIVATE || key->type == PK_PRIVATE_OPTIMIZED) { + INPUT_BIGNUM(&key->d, in, x, y, inlen); + } + + /* get CRT private data if required */ + if (key->type == PK_PRIVATE_OPTIMIZED) { + INPUT_BIGNUM(&key->dQ, in, x, y, inlen); + INPUT_BIGNUM(&key->dP, in, x, y, inlen); + INPUT_BIGNUM(&key->pQ, in, x, y, inlen); + INPUT_BIGNUM(&key->qP, in, x, y, inlen); + INPUT_BIGNUM(&key->p, in, x, y, inlen); + INPUT_BIGNUM(&key->q, in, x, y, inlen); + } + + /* free up ram not required */ + if (key->type != PK_PRIVATE_OPTIMIZED) { + mp_clear_multi(&key->dQ, &key->dP, &key->pQ, &key->qP, &key->p, &key->q, NULL); + } + if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) { + mp_clear(&key->d); + } + + return CRYPT_OK; +error: + mp_clear_multi(&key->d, &key->e, &key->N, &key->dQ, &key->dP, + &key->pQ, &key->qP, &key->p, &key->q, NULL); + return err; +} + +#include "rsa_sys.c" + +#endif /* RSA */ + + diff --git a/rsa_exptmod.c b/rsa_exptmod.c new file mode 100644 index 0000000..b794718 --- /dev/null +++ b/rsa_exptmod.c @@ -0,0 +1,87 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* RSA Code by Tom St Denis */ +#include "mycrypt.h" + +#ifdef MRSA + +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 err; + + _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; + } + + /* must be a private or public operation */ + if (which != PK_PRIVATE && which != PK_PUBLIC) { + return CRYPT_PK_INVALID_TYPE; + } + + /* init and copy into tmp */ + if ((err = mp_init_multi(&tmp, &tmpa, &tmpb, NULL)) != MP_OKAY) { goto error; } + if ((err = mp_read_unsigned_bin(&tmp, (unsigned char *)in, (int)inlen)) != MP_OKAY) { goto error; } + + /* sanity check on the input */ + if (mp_cmp(&key->N, &tmp) == MP_LT) { + err = 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 ((err = mp_exptmod(&tmp, &key->dP, &key->p, &tmpa)) != MP_OKAY) { goto error; } + + /* tmpb = tmp^dQ mod q */ + if ((err = mp_exptmod(&tmp, &key->dQ, &key->q, &tmpb)) != MP_OKAY) { goto error; } + + /* tmp = tmpa*qP + tmpb*pQ mod N */ + if ((err = mp_mul(&tmpa, &key->qP, &tmpa)) != MP_OKAY) { goto error; } + if ((err = mp_mul(&tmpb, &key->pQ, &tmpb)) != MP_OKAY) { goto error; } + if ((err = mp_addmod(&tmpa, &tmpb, &key->N, &tmp)) != MP_OKAY) { goto error; } + } else { + /* exptmod it */ + if ((err = mp_exptmod(&tmp, which==PK_PRIVATE?&key->d:&key->e, &key->N, &tmp)) != MP_OKAY) { goto error; } + } + + /* read it back */ + x = (unsigned long)mp_unsigned_bin_size(&tmp); + if (x > *outlen) { + err = CRYPT_BUFFER_OVERFLOW; + goto done; + } + *outlen = x; + + /* convert it */ + if ((err = mp_to_unsigned_bin(&tmp, out)) != MP_OKAY) { goto error; } + + /* clean up and return */ + err = CRYPT_OK; + goto done; +error: + err = mpi_to_ltc_error(err); +done: + mp_clear_multi(&tmp, &tmpa, &tmpb, NULL); + return err; +} + +#endif diff --git a/rsa_free.c b/rsa_free.c new file mode 100644 index 0000000..c97242b --- /dev/null +++ b/rsa_free.c @@ -0,0 +1,24 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* RSA Code by Tom St Denis */ +#include "mycrypt.h" + +#ifdef MRSA + +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); +} + +#endif diff --git a/rsa_make_key.c b/rsa_make_key.c new file mode 100644 index 0000000..56773ff --- /dev/null +++ b/rsa_make_key.c @@ -0,0 +1,113 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* RSA Code by Tom St Denis */ +#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 err; + + _ARGCHK(key != NULL); + + if ((size < (MIN_RSA_SIZE/8)) || (size > (MAX_RSA_SIZE/8))) { + return CRYPT_INVALID_KEYSIZE; + } + + if ((e < 3) || ((e & 1) == 0)) { + return CRYPT_INVALID_ARG; + } + + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != MP_OKAY) { + return mpi_to_ltc_error(err); + } + + /* make primes p and q (optimization provided by Wayne Scott) */ + if ((err = mp_set_int(&tmp3, e)) != MP_OKAY) { goto error; } /* tmp3 = e */ + + /* make prime "p" */ + do { + if ((err = rand_prime(&p, size*4, prng, wprng)) != CRYPT_OK) { goto done; } + if ((err = mp_sub_d(&p, 1, &tmp1)) != MP_OKAY) { goto error; } /* tmp1 = p-1 */ + if ((err = mp_gcd(&tmp1, &tmp3, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = gcd(p-1, e) */ + } while (mp_cmp_d(&tmp2, 1) != 0); /* while e divides p-1 */ + + /* make prime "q" */ + do { + if ((err = rand_prime(&q, size*4, prng, wprng)) != CRYPT_OK) { goto done; } + if ((err = mp_sub_d(&q, 1, &tmp1)) != MP_OKAY) { goto error; } /* tmp1 = q-1 */ + if ((err = mp_gcd(&tmp1, &tmp3, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = gcd(q-1, e) */ + } while (mp_cmp_d(&tmp2, 1) != 0); /* while e divides q-1 */ + + /* tmp1 = lcm(p-1, q-1) */ + if ((err = mp_sub_d(&p, 1, &tmp2)) != MP_OKAY) { goto error; } /* tmp2 = p-1 */ + /* tmp1 = q-1 (previous do/while loop) */ + if ((err = mp_lcm(&tmp1, &tmp2, &tmp1)) != MP_OKAY) { goto error; } /* tmp1 = lcm(p-1, q-1) */ + + /* make key */ + if ((err = 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; + } + + if ((err = mp_set_int(&key->e, e)) != MP_OKAY) { goto error2; } /* key->e = e */ + if ((err = mp_invmod(&key->e, &tmp1, &key->d)) != MP_OKAY) { goto error2; } /* key->d = 1/e mod lcm(p-1,q-1) */ + if ((err = 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 ((err = mp_sub_d(&p, 1, &tmp1)) != MP_OKAY) { goto error2; } /* tmp1 = q-1 */ + if ((err = mp_sub_d(&q, 1, &tmp2)) != MP_OKAY) { goto error2; } /* tmp2 = p-1 */ + + if ((err = mp_mod(&key->d, &tmp1, &key->dP)) != MP_OKAY) { goto error2; } /* dP = d mod p-1 */ + if ((err = mp_mod(&key->d, &tmp2, &key->dQ)) != MP_OKAY) { goto error2; } /* dQ = d mod q-1 */ + + if ((err = mp_invmod(&q, &p, &key->qP)) != MP_OKAY) { goto error2; } /* qP = 1/q mod p */ + if ((err = mp_mulmod(&key->qP, &q, &key->N, &key->qP)) != MP_OKAY) { goto error2; } /* qP = q * (1/q mod p) mod N */ + + if ((err = mp_invmod(&p, &q, &key->pQ)) != MP_OKAY) { goto error2; } /* pQ = 1/p mod q */ + if ((err = mp_mulmod(&key->pQ, &p, &key->N, &key->pQ)) != MP_OKAY) { goto error2; } /* pQ = p * (1/p mod q) mod N */ + + if ((err = mp_copy(&p, &key->p)) != MP_OKAY) { goto error2; } + if ((err = mp_copy(&q, &key->q)) != MP_OKAY) { goto error2; } + + /* shrink ram required */ + if ((err = mp_shrink(&key->e)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->d)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->N)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->dQ)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->dP)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->qP)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->pQ)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->p)) != MP_OKAY) { goto error2; } + if ((err = mp_shrink(&key->q)) != MP_OKAY) { goto error2; } + + err = 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: + err = mpi_to_ltc_error(err); +done: + mp_clear_multi(&tmp3, &tmp2, &tmp1, &p, &q, NULL); + return err; +} + +#endif diff --git a/rsa_sys.c b/rsa_sys.c new file mode 100644 index 0000000..fd3aa0a --- /dev/null +++ b/rsa_sys.c @@ -0,0 +1,274 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* 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[RSA_STACK], rsa_out[RSA_STACK]; + unsigned long x, y, rsa_size; + int err; + + _ARGCHK(inkey != NULL); + _ARGCHK(outkey != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* only allow keys from 64 to 256 bits */ + if (inlen < 8 || inlen > 32) { + return CRYPT_INVALID_ARG; + } + + /* are the parameters valid? */ + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + /* rsa_pad the symmetric key */ + y = (unsigned long)sizeof(rsa_in); + if ((err = rsa_pad(inkey, inlen, rsa_in, &y, wprng, prng)) != CRYPT_OK) { + return CRYPT_ERROR; + } + + /* rsa encrypt it */ + rsa_size = (unsigned long)sizeof(rsa_out); + if ((err = 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; + } + + /* store header */ + packet_store_header(outkey, PACKET_SECT_RSA, PACKET_SUB_ENC_KEY); + + /* 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]; + } + + *outlen = y; +#ifdef CLEAN_STACK + /* clean up */ + zeromem(rsa_in, sizeof(rsa_in)); + zeromem(rsa_out, sizeof(rsa_out)); +#endif + + return CRYPT_OK; +} + +int rsa_decrypt_key(const unsigned char *in, unsigned long inlen, + unsigned char *outkey, unsigned long *keylen, + rsa_key *key) +{ + unsigned char sym_key[MAXBLOCKSIZE], rsa_out[RSA_STACK]; + unsigned long x, y, z, i, rsa_size; + int err; + + _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; + } + + if (inlen < PACKET_SIZE+4) { + return CRYPT_INVALID_PACKET; + } else { + inlen -= PACKET_SIZE+4; + } + + /* check the header */ + if ((err = packet_valid_header((unsigned char *)in, PACKET_SECT_RSA, PACKET_SUB_ENC_KEY)) != CRYPT_OK) { + return err; + } + + /* grab length of the rsa key */ + y = PACKET_SIZE; + LOAD32L(rsa_size, (in+y)); + if (inlen < rsa_size) { + return CRYPT_INVALID_PACKET; + } else { + inlen -= rsa_size; + } + y += 4; + + /* decrypt it */ + x = (unsigned long)sizeof(rsa_out); + if ((err = rsa_exptmod(in+y, rsa_size, rsa_out, &x, PK_PRIVATE, key)) != CRYPT_OK) { + return err; + } + y += rsa_size; + + /* depad it */ + z = (unsigned long)sizeof(sym_key); + if ((err = rsa_depad(rsa_out, x, sym_key, &z)) != CRYPT_OK) { + return err; + } + + /* 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_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[RSA_STACK], rsa_out[RSA_STACK]; + int err; + + _ARGCHK(in != NULL); + _ARGCHK(out != NULL); + _ARGCHK(outlen != NULL); + _ARGCHK(key != NULL); + + /* reject nonsense sizes */ + if (inlen > (512/3) || inlen < 16) { + return CRYPT_INVALID_ARG; + } + + /* type of key? */ + if (key->type != PK_PRIVATE && key->type != PK_PRIVATE_OPTIMIZED) { + return CRYPT_PK_NOT_PRIVATE; + } + + /* pad it */ + x = (unsigned long)sizeof(rsa_out); + if ((err = rsa_signpad(in, inlen, rsa_out, &x)) != CRYPT_OK) { + return err; + } + + /* sign it */ + rsa_size = (unsigned long)sizeof(rsa_in); + if ((err = rsa_exptmod(rsa_out, x, rsa_in, &rsa_size, PK_PRIVATE, key)) != CRYPT_OK) { + return err; + } + + /* 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); + +#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, unsigned long siglen, + const unsigned char *md, int *stat, rsa_key *key) +{ + unsigned long rsa_size, x, y, z; + unsigned char rsa_in[RSA_STACK], rsa_out[RSA_STACK]; + int err; + + _ARGCHK(sig != NULL); + _ARGCHK(md != NULL); + _ARGCHK(stat != NULL); + _ARGCHK(key != NULL); + + /* always be incorrect by default */ + *stat = 0; + + if (siglen < PACKET_SIZE+4) { + return CRYPT_INVALID_PACKET; + } else { + siglen -= PACKET_SIZE+4; + } + + /* verify header */ + if ((err = packet_valid_header((unsigned char *)sig, PACKET_SECT_RSA, PACKET_SUB_SIGNED)) != CRYPT_OK) { + return err; + } + + /* get the len */ + y = PACKET_SIZE; + LOAD32L(rsa_size, (sig+y)); + if (siglen < rsa_size) { + return CRYPT_INVALID_PACKET; + } else { + siglen -= rsa_size; + } + y += 4; + + /* exptmod it */ + x = (unsigned long)sizeof(rsa_out); + if ((err = rsa_exptmod(sig+y, rsa_size, rsa_out, &x, PK_PUBLIC, key)) != CRYPT_OK) { + return err; + } + y += rsa_size; + + /* depad it */ + z = (unsigned long)sizeof(rsa_in); + if ((err = rsa_signdepad(rsa_out, x, rsa_in, &z)) != CRYPT_OK) { + return err; + } + + /* check? */ + if (memcmp(rsa_in, md, (size_t)z) == 0) { + *stat = 1; + } + +#ifdef CLEAN_STACK + zeromem(rsa_in, sizeof(rsa_in)); + zeromem(rsa_out, sizeof(rsa_out)); +#endif + return CRYPT_OK; +} + diff --git a/s_ocb_done.c b/s_ocb_done.c new file mode 100644 index 0000000..90ed65c --- /dev/null +++ b/s_ocb_done.c @@ -0,0 +1,102 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* OCB Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef OCB_MODE + +/* Since the last block is encrypted in CTR mode the same code can + * be used to finish a decrypt or encrypt stream. The only difference + * is we XOR the final ciphertext into the checksum so we have to xor it + * before we CTR [decrypt] or after [encrypt] + * + * the names pt/ptlen/ct really just mean in/inlen/out but this is the way I wrote it... + */ +int __ocb_done(ocb_state *ocb, const unsigned char *pt, unsigned long ptlen, + unsigned char *ct, unsigned char *tag, unsigned long *taglen, int mode) + +{ + unsigned char Z[MAXBLOCKSIZE], Y[MAXBLOCKSIZE], X[MAXBLOCKSIZE]; + int err, x; + + _ARGCHK(ocb != NULL); + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(tag != NULL); + _ARGCHK(taglen != NULL); + if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) { + return err; + } + if (ocb->block_len != cipher_descriptor[ocb->cipher].block_length || + (int)ptlen > ocb->block_len || (int)ptlen < 0) { + return CRYPT_INVALID_ARG; + } + + /* compute X[m] = len(pt[m]) XOR Lr XOR Z[m] */ + ocb_shift_xor(ocb, X); + memcpy(Z, X, ocb->block_len); + + X[ocb->block_len-1] ^= (ptlen*8)&255; + X[ocb->block_len-2] ^= ((ptlen*8)>>8)&255; + for (x = 0; x < ocb->block_len; x++) { + X[x] ^= ocb->Lr[x]; + } + + /* Y[m] = E(X[m])) */ + cipher_descriptor[ocb->cipher].ecb_encrypt(X, Y, &ocb->key); + + if (mode == 1) { + /* decrypt mode, so let's xor it first */ + /* xor C[m] into checksum */ + for (x = 0; x < (int)ptlen; x++) { + ocb->checksum[x] ^= ct[x]; + } + } + + /* C[m] = P[m] xor Y[m] */ + for (x = 0; x < (int)ptlen; x++) { + ct[x] = pt[x] ^ Y[x]; + } + + if (mode == 0) { + /* encrypt mode */ + /* xor C[m] into checksum */ + for (x = 0; x < (int)ptlen; x++) { + ocb->checksum[x] ^= ct[x]; + } + } + + /* xor Y[m] and Z[m] into checksum */ + for (x = 0; x < ocb->block_len; x++) { + ocb->checksum[x] ^= Y[x] ^ Z[x]; + } + + /* encrypt checksum, er... tag!! */ + cipher_descriptor[ocb->cipher].ecb_encrypt(ocb->checksum, X, &ocb->key); + + /* now store it */ + for (x = 0; x < ocb->block_len && x < (int)*taglen; x++) { + tag[x] = X[x]; + } + *taglen = x; + +#ifdef CLEAN_STACK + zeromem(X, sizeof(X)); + zeromem(Y, sizeof(Y)); + zeromem(Z, sizeof(Z)); + zeromem(ocb, sizeof(*ocb)); +#endif + return CRYPT_OK; +} + +#endif + diff --git a/safer.c b/safer.c new file mode 100644 index 0000000..580872a --- /dev/null +++ b/safer.c @@ -0,0 +1,468 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/******************************************************************************* +* +* 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, k; + 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] = (unsigned char)0; + kb[SAFER_BLOCK_LEN] = (unsigned char)0; + k = 0; + for (j = 0; j < SAFER_BLOCK_LEN; j++) { + ka[j] = ROL8(userkey_1[j], 5); + ka[SAFER_BLOCK_LEN] ^= ka[j]; + kb[j] = *key++ = userkey_2[j]; + kb[SAFER_BLOCK_LEN] ^= kb[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); + } + if (strengthened) { + k = 2 * i - 1; + while (k >= (SAFER_BLOCK_LEN + 1)) { k -= SAFER_BLOCK_LEN + 1; } + } + for (j = 0; j < SAFER_BLOCK_LEN; j++) { + if (strengthened) { + *key++ = (ka[k] + + safer_ebox[(int)safer_ebox[(int)((18 * i + j + 1)&0xFF)]]) & 0xFF; + if (++k == (SAFER_BLOCK_LEN + 1)) { k = 0; } + } else { + *key++ = (ka[j] + safer_ebox[(int)safer_ebox[(int)((18 * i + j + 1)&0xFF)]]) & 0xFF; + } + } + if (strengthened) { + k = 2 * i; + while (k >= (SAFER_BLOCK_LEN + 1)) { k -= SAFER_BLOCK_LEN + 1; } + } + for (j = 0; j < SAFER_BLOCK_LEN; j++) { + if (strengthened) { + *key++ = (kb[k] + + safer_ebox[(int)safer_ebox[(int)((18 * i + j + 10)&0xFF)]]) & 0xFF; + if (++k == (SAFER_BLOCK_LEN + 1)) { k = 0; } + } else { + *key++ = (kb[j] + safer_ebox[(int)safer_ebox[(int)((18 * i + j + 10)&0xFF)]]) & 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 != 0 && (numrounds < 6 || numrounds > SAFER_MAX_NOF_ROUNDS)) { + return CRYPT_INVALID_ROUNDS; + } + + if (keylen != 8) { + return CRYPT_INVALID_KEYSIZE; + } + + Safer_Expand_Userkey(key, key, (unsigned int)(numrounds != 0 ?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 != 0 && (numrounds < 6 || numrounds > SAFER_MAX_NOF_ROUNDS)) { + return CRYPT_INVALID_ROUNDS; + } + + if (keylen != 8) { + return CRYPT_INVALID_KEYSIZE; + } + + Safer_Expand_Userkey(key, key, (unsigned int)(numrounds != 0 ?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 != 0 && (numrounds < 6 || numrounds > SAFER_MAX_NOF_ROUNDS)) { + return CRYPT_INVALID_ROUNDS; + } + + if (keylen != 16) { + return CRYPT_INVALID_KEYSIZE; + } + + Safer_Expand_Userkey(key, key+8, (unsigned int)(numrounds != 0 ?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 != 0 && (numrounds < 6 || numrounds > SAFER_MAX_NOF_ROUNDS)) { + return CRYPT_INVALID_ROUNDS; + } + + if (keylen != 16) { + return CRYPT_INVALID_KEYSIZE; + } + + Safer_Expand_Userkey(key, key+8, (unsigned int)(numrounds != 0?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-- > 0) + { + 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) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + 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 err; + + /* test K64 */ + if ((err = safer_k64_setup(k64_key, 8, 6, &skey)) != CRYPT_OK) { + return err; + } + safer_ecb_encrypt(k64_pt, buf[0], &skey); + safer_ecb_decrypt(buf[0], buf[1], &skey); + + if (memcmp(buf[0], k64_ct, 8) != 0 || memcmp(buf[1], k64_pt, 8) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + + return CRYPT_OK; + #endif +} + + +int safer_sk64_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + 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 err, y; + + /* test SK64 */ + if ((err = safer_sk64_setup(sk64_key, 8, 6, &skey)) != CRYPT_OK) { + return err; + } + + safer_ecb_encrypt(sk64_pt, buf[0], &skey); + safer_ecb_decrypt(buf[0], buf[1], &skey); + + if (memcmp(buf[0], sk64_ct, 8) != 0 || memcmp(buf[1], sk64_pt, 8) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + + /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ + for (y = 0; y < 8; y++) buf[0][y] = 0; + for (y = 0; y < 1000; y++) safer_ecb_encrypt(buf[0], buf[0], &skey); + for (y = 0; y < 1000; y++) safer_ecb_decrypt(buf[0], buf[0], &skey); + for (y = 0; y < 8; y++) if (buf[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; + + return CRYPT_OK; + #endif +} + +int safer_sk128_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + 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 err, y; + + /* test SK128 */ + if ((err = safer_sk128_setup(sk128_key, 16, 0, &skey)) != CRYPT_OK) { + return err; + } + safer_ecb_encrypt(sk128_pt, buf[0], &skey); + safer_ecb_decrypt(buf[0], buf[1], &skey); + + if (memcmp(buf[0], sk128_ct, 8) != 0 || memcmp(buf[1], sk128_pt, 8) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + + /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ + for (y = 0; y < 8; y++) buf[0][y] = 0; + for (y = 0; y < 1000; y++) safer_ecb_encrypt(buf[0], buf[0], &skey); + for (y = 0; y < 1000; y++) safer_ecb_decrypt(buf[0], buf[0], &skey); + for (y = 0; y < 8; y++) if (buf[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; + return CRYPT_OK; + #endif +} + +#endif + + + diff --git a/safer_tab.c b/safer_tab.c new file mode 100644 index 0000000..06859db --- /dev/null +++ b/safer_tab.c @@ -0,0 +1,59 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +#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/saferp.c b/saferp.c new file mode 100644 index 0000000..8415deb --- /dev/null +++ b/saferp.c @@ -0,0 +1,510 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* SAFER+ Implementation by Tom St Denis */ +#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 SMALL_CODE + +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 */ +static 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, z; + 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 */ + z = x; + for (y = 0; y < 16; y++) { + skey->saferp.K[x][y] = (t[z] + safer_bias[x-1][y]) & 255; + if (++z == 17) { z = 0; } + } + } + 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 */ + z = x; + for (y = 0; y < 16; y++) { + skey->saferp.K[x][y] = (t[z] + safer_bias[x-1][y]) & 255; + if (++z == 25) { z = 0; } + } + } + 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 */ + z = x; + for (y = 0; y < 16; y++) { + skey->saferp.K[x][y] = (t[z] + safer_bias[x-1][y]) & 255; + if (++z == 33) { z = 0; } + } + } + 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) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + int keylen; + unsigned char key[32], pt[16], ct[16]; + } tests[] = { + { + 16, + { 41, 35, 190, 132, 225, 108, 214, 174, + 82, 144, 73, 241, 241, 187, 233, 235 }, + { 179, 166, 219, 60, 135, 12, 62, 153, + 36, 94, 13, 28, 6, 183, 71, 222 }, + { 224, 31, 182, 10, 12, 255, 84, 70, + 127, 13, 89, 249, 9, 57, 165, 220 } + }, { + 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 }, + { 123, 5, 21, 7, 59, 51, 130, 31, + 24, 112, 146, 218, 100, 84, 206, 177 }, + { 92, 136, 4, 63, 57, 95, 100, 0, + 150, 130, 130, 16, 193, 111, 219, 133 } + }, { + 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 }, + { 127, 112, 240, 167, 84, 134, 50, 149, + 170, 91, 104, 19, 11, 230, 252, 245 }, + { 88, 11, 25, 36, 172, 229, 202, 213, + 170, 65, 105, 153, 220, 104, 153, 138 } + } + }; + + unsigned char tmp[2][16]; + symmetric_key skey; + int err, i, y; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + if ((err = saferp_setup(tests[i].key, tests[i].keylen, 0, &skey)) != CRYPT_OK) { + return err; + } + saferp_ecb_encrypt(tests[i].pt, tmp[0], &skey); + saferp_ecb_decrypt(tmp[0], tmp[1], &skey); + + /* compare */ + if (memcmp(tmp[0], tests[i].ct, 16) || memcmp(tmp[1], tests[i].pt, 16)) { + return CRYPT_FAIL_TESTVECTOR; + } + + /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ + for (y = 0; y < 16; y++) tmp[0][y] = 0; + for (y = 0; y < 1000; y++) saferp_ecb_encrypt(tmp[0], tmp[0], &skey); + for (y = 0; y < 1000; y++) saferp_ecb_decrypt(tmp[0], tmp[0], &skey); + for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; + } + + return CRYPT_OK; + #endif +} + +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; + } else if (*desired_keysize < 32) { + *desired_keysize = 24; + } else { + *desired_keysize = 32; + } + return CRYPT_OK; +} + +#endif + + diff --git a/serpent.c b/serpent.c new file mode 100644 index 0000000..235ea11 --- /dev/null +++ b/serpent.c @@ -0,0 +1,698 @@ +#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++] = (unsigned char)0x01; + while (x < 32) { + buf[x++] = (unsigned char)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, err; + symmetric_key key; + + for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) { + /* setup key */ + if ((err = serpent_setup(tests[x].key, tests[x].keylen, 0, &key))!= CRYPT_OK) { + return err; + } + + /* 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) != 0 || memcmp(buf[1], tests[x].pt, 16) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + 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..98d2a49 --- /dev/null +++ b/sha1.c @@ -0,0 +1,223 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* SHA1 code by Tom St Denis */ +#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) (z ^ (x & (y ^ 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, unsigned char *buf) +#else +static void sha1_compress(hash_state *md, unsigned char *buf) +#endif +{ + ulong32 a,b,c,d,e,W[80],i; + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD32H(W[i], 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++) { + W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); + } + + /* compress */ + /* round one */ + #define FF0(a,b,c,d,e,i) e = (ROL(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROL(b, 30); + #define FF1(a,b,c,d,e,i) e = (ROL(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROL(b, 30); + #define FF2(a,b,c,d,e,i) e = (ROL(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROL(b, 30); + #define FF3(a,b,c,d,e,i) e = (ROL(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROL(b, 30); + + for (i = 0; i < 20; ) { + FF0(a,b,c,d,e,i++); + FF0(e,a,b,c,d,i++); + FF0(d,e,a,b,c,i++); + FF0(c,d,e,a,b,i++); + FF0(b,c,d,e,a,i++); + } + + /* round two */ + for (; i < 40; ) { + FF1(a,b,c,d,e,i++); + FF1(e,a,b,c,d,i++); + FF1(d,e,a,b,c,i++); + FF1(c,d,e,a,b,i++); + FF1(b,c,d,e,a,i++); + } + + /* round three */ + for (; i < 60; ) { + FF2(a,b,c,d,e,i++); + FF2(e,a,b,c,d,i++); + FF2(d,e,a,b,c,i++); + FF2(c,d,e,a,b,i++); + FF2(b,c,d,e,a,i++); + } + + /* round four */ + for (; i < 80; ) { + FF3(a,b,c,d,e,i++); + FF3(e,a,b,c,d,i++); + FF3(d,e,a,b,c,i++); + FF3(c,d,e,a,b,i++); + FF3(b,c,d,e,a,i++); + } + + #undef FF0 + #undef FF1 + #undef FF2 + #undef FF3 + + /* 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, unsigned char *buf) +{ + _sha1_compress(md, buf); + burn_stack(sizeof(ulong32) * 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; +} + +HASH_PROCESS(sha1_process, sha1_compress, sha1, 64) + +int sha1_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->sha1.curlen >= sizeof(md->sha1.buf)) { + return CRYPT_INVALID_ARG; + } + + /* increase the length of the message */ + md->sha1.length += md->sha1.curlen * 8; + + /* append the '1' bit */ + md->sha1.buf[md->sha1.curlen++] = (unsigned char)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++] = (unsigned char)0; + } + sha1_compress(md, md->sha1.buf); + md->sha1.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->sha1.curlen < 56) { + md->sha1.buf[md->sha1.curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64H(md->sha1.length, md->sha1.buf+56); + sha1_compress(md, md->sha1.buf); + + /* 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 + return CRYPT_OK; +} + +int sha1_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + 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 } + } + }; + + int i; + unsigned char tmp[20]; + hash_state md; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + sha1_init(&md); + sha1_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg)); + sha1_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 20) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + +#endif + + diff --git a/sha224.c b/sha224.c new file mode 100644 index 0000000..d564159 --- /dev/null +++ b/sha224.c @@ -0,0 +1,93 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* SHA-224 new NIST standard based off of SHA-256 truncated to 224 bits */ +const struct _hash_descriptor sha224_desc = +{ + "sha224", + 10, + 28, + 64, + &sha224_init, + &sha256_process, + &sha224_done, + &sha224_test +}; + +/* init the sha256 er... sha224 state ;-) */ +void sha224_init(hash_state * md) +{ + _ARGCHK(md != NULL); + + md->sha256.curlen = 0; + md->sha256.length = 0; + md->sha256.state[0] = 0xc1059ed8UL; + md->sha256.state[1] = 0x367cd507UL; + md->sha256.state[2] = 0x3070dd17UL; + md->sha256.state[3] = 0xf70e5939UL; + md->sha256.state[4] = 0xffc00b31UL; + md->sha256.state[5] = 0x68581511UL; + md->sha256.state[6] = 0x64f98fa7UL; + md->sha256.state[7] = 0xbefa4fa4UL; +} + +int sha224_done(hash_state * md, unsigned char *hash) +{ + unsigned char buf[32]; + int err; + + err = sha256_done(md, buf); + memcpy(hash, buf, 28); +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + return err; +} + +int sha224_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + char *msg; + unsigned char hash[28]; + } tests[] = { + { "abc", + { 0x23, 0x09, 0x7d, 0x22, 0x34, 0x05, 0xd8, + 0x22, 0x86, 0x42, 0xa4, 0x77, 0xbd, 0xa2, + 0x55, 0xb3, 0x2a, 0xad, 0xbc, 0xe4, 0xbd, + 0xa0, 0xb3, 0xf7, 0xe3, 0x6c, 0x9d, 0xa7 } + }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + { 0x75, 0x38, 0x8b, 0x16, 0x51, 0x27, 0x76, + 0xcc, 0x5d, 0xba, 0x5d, 0xa1, 0xfd, 0x89, + 0x01, 0x50, 0xb0, 0xc6, 0x45, 0x5c, 0xb4, + 0xf5, 0x8b, 0x19, 0x52, 0x52, 0x25, 0x25 } + }, + }; + + int i; + unsigned char tmp[28]; + hash_state md; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + sha224_init(&md); + sha224_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg)); + sha224_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 28) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + diff --git a/sha256.c b/sha256.c new file mode 100644 index 0000000..10eb663 --- /dev/null +++ b/sha256.c @@ -0,0 +1,305 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + + +/* SHA256 by Tom St Denis */ + +#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) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#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, unsigned char *buf) +#else +static void sha256_compress(hash_state * md, unsigned char *buf) +#endif +{ + ulong32 S[8], W[64], t0, t1; + int i; + + /* 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], 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 */ +#ifdef SMALL_CODE +#define RND(a,b,c,d,e,f,g,h,i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + for (i = 0; i < 64; i += 8) { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); + } +#else +#define RND(a,b,c,d,e,f,g,h,i,ki) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); + +#undef RND + +#endif + + /* 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, unsigned char *buf) +{ + _sha256_compress(md, buf); + burn_stack(sizeof(ulong32) * 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; +} + +HASH_PROCESS(sha256_process, sha256_compress, sha256, 64) + +int sha256_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->sha256.curlen >= sizeof(md->sha256.buf)) { + return CRYPT_INVALID_ARG; + } + + + /* increase the length of the message */ + md->sha256.length += md->sha256.curlen * 8; + + /* append the '1' bit */ + md->sha256.buf[md->sha256.curlen++] = (unsigned char)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++] = (unsigned char)0; + } + sha256_compress(md, md->sha256.buf); + md->sha256.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->sha256.curlen < 56) { + md->sha256.buf[md->sha256.curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64H(md->sha256.length, md->sha256.buf+56); + sha256_compress(md, md->sha256.buf); + + /* 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 + return CRYPT_OK; +} + +int sha256_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + 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 } + }, + }; + + int i; + unsigned char tmp[32]; + hash_state md; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + sha256_init(&md); + sha256_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg)); + sha256_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 32) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + +#ifdef SHA224 +#include "sha224.c" +#endif + +#endif + + diff --git a/sha384.c b/sha384.c new file mode 100644 index 0000000..98fb07d --- /dev/null +++ b/sha384.c @@ -0,0 +1,107 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* included in sha512.c */ + +const struct _hash_descriptor sha384_desc = +{ + "sha384", + 4, + 48, + 128, + &sha384_init, + &sha512_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); +} + +int sha384_done(hash_state * md, unsigned char *hash) +{ + unsigned char buf[64]; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->sha512.curlen >= sizeof(md->sha512.buf)) { + return CRYPT_INVALID_ARG; + } + + sha512_done(md, buf); + memcpy(hash, buf, 48); +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + return CRYPT_OK; +} + +int sha384_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + 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 } + }, + }; + + int i; + unsigned char tmp[48]; + hash_state md; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + sha384_init(&md); + sha384_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg)); + sha384_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 48) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + + + + + diff --git a/sha512.c b/sha512.c new file mode 100644 index 0000000..fa83a72 --- /dev/null +++ b/sha512.c @@ -0,0 +1,282 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* SHA512 by Tom St Denis */ + +#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) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#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, unsigned char *buf) +#else +static void sha512_compress(hash_state * md, unsigned char *buf) +#endif +{ + ulong64 S[8], W[80], t0, t1; + int i; + + /* 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], 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 */ +#ifdef SMALL_CODE + 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; + } +#else +#define RND(a,b,c,d,e,f,g,h,i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + for (i = 0; i < 80; i += 8) { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); + } +#endif + + + /* 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, unsigned char *buf) +{ + _sha512_compress(md, buf); + 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); +} + +HASH_PROCESS(sha512_process, sha512_compress, sha512, 128) + +int sha512_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->sha512.curlen >= sizeof(md->sha512.buf)) { + return CRYPT_INVALID_ARG; + } + + /* increase the length of the message */ + md->sha512.length += md->sha512.curlen * CONST64(8); + + /* append the '1' bit */ + md->sha512.buf[md->sha512.curlen++] = (unsigned char)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++] = (unsigned char)0; + } + sha512_compress(md, md->sha512.buf); + 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++] = (unsigned char)0; + } + + /* store length */ + STORE64H(md->sha512.length, md->sha512.buf+120); + sha512_compress(md, md->sha512.buf); + + /* 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 + return CRYPT_OK; +} + +int sha512_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + 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 } + }, + }; + + int i; + unsigned char tmp[64]; + hash_state md; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + sha512_init(&md); + sha512_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg)); + sha512_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 64) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + +#ifdef SHA384 + #include "sha384.c" +#endif + +#endif + + + diff --git a/skipjack.c b/skipjack.c new file mode 100644 index 0000000..a66efa1 --- /dev/null +++ b/skipjack.c @@ -0,0 +1,290 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* Skipjack Implementation by Tom St Denis */ +#include "mycrypt.h" + +#ifdef SKIPJACK + +const struct _cipher_descriptor skipjack_desc = +{ + "skipjack", + 17, + 10, 10, 8, 32, + &skipjack_setup, + &skipjack_ecb_encrypt, + &skipjack_ecb_decrypt, + &skipjack_test, + &skipjack_keysize +}; + +static const unsigned char sbox[256] = { + 0xa3,0xd7,0x09,0x83,0xf8,0x48,0xf6,0xf4,0xb3,0x21,0x15,0x78,0x99,0xb1,0xaf,0xf9, + 0xe7,0x2d,0x4d,0x8a,0xce,0x4c,0xca,0x2e,0x52,0x95,0xd9,0x1e,0x4e,0x38,0x44,0x28, + 0x0a,0xdf,0x02,0xa0,0x17,0xf1,0x60,0x68,0x12,0xb7,0x7a,0xc3,0xe9,0xfa,0x3d,0x53, + 0x96,0x84,0x6b,0xba,0xf2,0x63,0x9a,0x19,0x7c,0xae,0xe5,0xf5,0xf7,0x16,0x6a,0xa2, + 0x39,0xb6,0x7b,0x0f,0xc1,0x93,0x81,0x1b,0xee,0xb4,0x1a,0xea,0xd0,0x91,0x2f,0xb8, + 0x55,0xb9,0xda,0x85,0x3f,0x41,0xbf,0xe0,0x5a,0x58,0x80,0x5f,0x66,0x0b,0xd8,0x90, + 0x35,0xd5,0xc0,0xa7,0x33,0x06,0x65,0x69,0x45,0x00,0x94,0x56,0x6d,0x98,0x9b,0x76, + 0x97,0xfc,0xb2,0xc2,0xb0,0xfe,0xdb,0x20,0xe1,0xeb,0xd6,0xe4,0xdd,0x47,0x4a,0x1d, + 0x42,0xed,0x9e,0x6e,0x49,0x3c,0xcd,0x43,0x27,0xd2,0x07,0xd4,0xde,0xc7,0x67,0x18, + 0x89,0xcb,0x30,0x1f,0x8d,0xc6,0x8f,0xaa,0xc8,0x74,0xdc,0xc9,0x5d,0x5c,0x31,0xa4, + 0x70,0x88,0x61,0x2c,0x9f,0x0d,0x2b,0x87,0x50,0x82,0x54,0x64,0x26,0x7d,0x03,0x40, + 0x34,0x4b,0x1c,0x73,0xd1,0xc4,0xfd,0x3b,0xcc,0xfb,0x7f,0xab,0xe6,0x3e,0x5b,0xa5, + 0xad,0x04,0x23,0x9c,0x14,0x51,0x22,0xf0,0x29,0x79,0x71,0x7e,0xff,0x8c,0x0e,0xe2, + 0x0c,0xef,0xbc,0x72,0x75,0x6f,0x37,0xa1,0xec,0xd3,0x8e,0x62,0x8b,0x86,0x10,0xe8, + 0x08,0x77,0x11,0xbe,0x92,0x4f,0x24,0xc5,0x32,0x36,0x9d,0xcf,0xf3,0xa6,0xbb,0xac, + 0x5e,0x6c,0xa9,0x13,0x57,0x25,0xb5,0xe3,0xbd,0xa8,0x3a,0x01,0x05,0x59,0x2a,0x46 +}; + +/* simple x + 1 (mod 10) in one step. */ +static const int keystep[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + +/* simple x - 1 (mod 10) in one step */ +static const int ikeystep[] = { 9, 0, 1, 2, 3, 4, 5, 6, 7, 8 }; + +int skipjack_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) +{ + int x; + + _ARGCHK(key != NULL); + _ARGCHK(skey != NULL); + + if (keylen != 10) { + return CRYPT_INVALID_KEYSIZE; + } + + if (num_rounds != 32 && num_rounds != 0) { + return CRYPT_INVALID_ROUNDS; + } + + /* make sure the key is in range for platforms where CHAR_BIT != 8 */ + for (x = 0; x < 10; x++) { + skey->skipjack.key[x] = key[x] & 255; + } + + return CRYPT_OK; +} + +#define RULE_A \ + tmp = g_func(w1, &kp, key->skipjack.key); \ + w1 = tmp ^ w4 ^ x; \ + w4 = w3; w3 = w2; \ + w2 = tmp; + +#define RULE_B \ + tmp = g_func(w1, &kp, key->skipjack.key); \ + tmp1 = w4; w4 = w3; \ + w3 = w1 ^ w2 ^ x; \ + w1 = tmp1; w2 = tmp; + +#define RULE_A1 \ + tmp = w1 ^ w2 ^ x; \ + w1 = ig_func(w2, &kp, key->skipjack.key); \ + w2 = w3; w3 = w4; w4 = tmp; + +#define RULE_B1 \ + tmp = ig_func(w2, &kp, key->skipjack.key); \ + w2 = tmp ^ w3 ^ x; \ + w3 = w4; w4 = w1; w1 = tmp; + +static unsigned g_func(unsigned w, int *kp, unsigned char *key) +{ + unsigned char g1,g2; + + g1 = (w >> 8) & 255; g2 = w & 255; + g1 ^= sbox[g2^key[*kp]]; *kp = keystep[*kp]; + g2 ^= sbox[g1^key[*kp]]; *kp = keystep[*kp]; + g1 ^= sbox[g2^key[*kp]]; *kp = keystep[*kp]; + g2 ^= sbox[g1^key[*kp]]; *kp = keystep[*kp]; + return ((unsigned)g1<<8)|(unsigned)g2; +} + +static unsigned ig_func(unsigned w, int *kp, unsigned char *key) +{ + unsigned char g1,g2; + + g1 = (w >> 8) & 255; g2 = w & 255; + *kp = ikeystep[*kp]; g2 ^= sbox[g1^key[*kp]]; + *kp = ikeystep[*kp]; g1 ^= sbox[g2^key[*kp]]; + *kp = ikeystep[*kp]; g2 ^= sbox[g1^key[*kp]]; + *kp = ikeystep[*kp]; g1 ^= sbox[g2^key[*kp]]; + return ((unsigned)g1<<8)|(unsigned)g2; +} + +#ifdef CLEAN_STACK +static void _skipjack_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#else +void skipjack_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +#endif +{ + unsigned w1,w2,w3,w4,tmp,tmp1; + int x, kp; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + + /* load block */ + w1 = ((unsigned)pt[0]<<8)|pt[1]; + w2 = ((unsigned)pt[2]<<8)|pt[3]; + w3 = ((unsigned)pt[4]<<8)|pt[5]; + w4 = ((unsigned)pt[6]<<8)|pt[7]; + + /* 8 rounds of RULE A */ + for (x = 1, kp = 0; x < 9; x++) { + RULE_A; + } + + /* 8 rounds of RULE B */ + for (; x < 17; x++) { + RULE_B; + } + + /* 8 rounds of RULE A */ + for (; x < 25; x++) { + RULE_A; + } + + /* 8 rounds of RULE B */ + for (; x < 33; x++) { + RULE_B; + } + + /* store block */ + ct[0] = (w1>>8)&255; ct[1] = w1&255; + ct[2] = (w2>>8)&255; ct[3] = w2&255; + ct[4] = (w3>>8)&255; ct[5] = w3&255; + ct[6] = (w4>>8)&255; ct[7] = w4&255; +} + +#ifdef CLEAN_STACK +void skipjack_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + _skipjack_ecb_encrypt(pt, ct, key); + burn_stack(sizeof(unsigned) * 8 + sizeof(int) * 2); +} +#endif + +#ifdef CLEAN_STACK +static void _skipjack_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#else +void skipjack_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +#endif +{ + unsigned w1,w2,w3,w4,tmp; + int x, kp; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + + /* load block */ + w1 = ((unsigned)ct[0]<<8)|ct[1]; + w2 = ((unsigned)ct[2]<<8)|ct[3]; + w3 = ((unsigned)ct[4]<<8)|ct[5]; + w4 = ((unsigned)ct[6]<<8)|ct[7]; + + /* 8 rounds of RULE B^-1 + + Note the value "kp = 8" comes from "kp = (32 * 4) mod 10" where 32*4 is 128 which mod 10 is 8 + */ + for (x = 32, kp = 8; x > 24; x--) { + RULE_B1; + } + + /* 8 rounds of RULE A^-1 */ + for (; x > 16; x--) { + RULE_A1; + } + + + /* 8 rounds of RULE B^-1 */ + for (; x > 8; x--) { + RULE_B1; + } + + /* 8 rounds of RULE A^-1 */ + for (; x > 0; x--) { + RULE_A1; + } + + /* store block */ + pt[0] = (w1>>8)&255; pt[1] = w1&255; + pt[2] = (w2>>8)&255; pt[3] = w2&255; + pt[4] = (w3>>8)&255; pt[5] = w3&255; + pt[6] = (w4>>8)&255; pt[7] = w4&255; +} + +#ifdef CLEAN_STACK +void skipjack_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key) +{ + _skipjack_ecb_decrypt(ct, pt, key); + burn_stack(sizeof(unsigned) * 7 + sizeof(int) * 2); +} +#endif + +int skipjack_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + unsigned char key[10], pt[8], ct[8]; + } tests[] = { + { + { 0x00, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }, + { 0x33, 0x22, 0x11, 0x00, 0xdd, 0xcc, 0xbb, 0xaa }, + { 0x25, 0x87, 0xca, 0xe2, 0x7a, 0x12, 0xd3, 0x00 } + } + }; + unsigned char buf[2][8]; + int x, y, err; + symmetric_key key; + + for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) { + /* setup key */ + if ((err = skipjack_setup(tests[x].key, 10, 0, &key)) != CRYPT_OK) { + return err; + } + + /* encrypt and decrypt */ + skipjack_ecb_encrypt(tests[x].pt, buf[0], &key); + skipjack_ecb_decrypt(buf[0], buf[1], &key); + + /* compare */ + if (memcmp(buf[0], tests[x].ct, 8) != 0 || memcmp(buf[1], tests[x].pt, 8) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + + /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ + for (y = 0; y < 8; y++) buf[0][y] = 0; + for (y = 0; y < 1000; y++) skipjack_ecb_encrypt(buf[0], buf[0], &key); + for (y = 0; y < 1000; y++) skipjack_ecb_decrypt(buf[0], buf[0], &key); + for (y = 0; y < 8; y++) if (buf[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; + } + + return CRYPT_OK; + #endif +} + +int skipjack_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize != NULL); + if (*desired_keysize < 10) { + return CRYPT_INVALID_KEYSIZE; + } else if (*desired_keysize > 10) { + *desired_keysize = 10; + } + return CRYPT_OK; +} + +#endif diff --git a/sprng.c b/sprng.c new file mode 100644 index 0000000..db6e338 --- /dev/null +++ b/sprng.c @@ -0,0 +1,53 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* 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..b00cb63 --- /dev/null +++ b/strings.c @@ -0,0 +1,86 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* Future releases will make use of this */ +#include "mycrypt.h" + +static const char *err_2_str[] = +{ + "CRYPT_OK", + "CRYPT_ERROR", + "Non-fatal 'no-operation' requested.", + + "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.", + "File Not Found", + + "Invalid PK type.", + "Invalid PK system.", + "Duplicate PK key found on keyring.", + "Key not found in keyring.", + "Invalid sized parameter.", + + "Invalid size for prime.", + +}; + +#ifdef MPI +static const struct { + int mpi_code, ltc_code; +} mpi_to_ltc_codes[] = { + { MP_OKAY , CRYPT_OK}, + { MP_MEM , CRYPT_MEM}, + { MP_VAL , CRYPT_INVALID_ARG}, +}; +#endif + +const char *error_to_string(int err) +{ + if (err < 0 || err >= (int)(sizeof(err_2_str)/sizeof(err_2_str[0]))) { + return "Invalid error code."; + } else { + return err_2_str[err]; + } +} + +#ifdef MPI +/* convert a MPI error to a LTC error (Possibly the most powerful function ever! Oh wait... no) */ +int mpi_to_ltc_error(int err) +{ + int x; + + for (x = 0; x < (int)(sizeof(mpi_to_ltc_codes)/sizeof(mpi_to_ltc_codes[0])); x++) { + if (err == mpi_to_ltc_codes[x].mpi_code) { + return mpi_to_ltc_codes[x].ltc_code; + } + } + return CRYPT_ERROR; +} +#endif + diff --git a/tiger.c b/tiger.c new file mode 100644 index 0000000..6184fa3 --- /dev/null +++ b/tiger.c @@ -0,0 +1,772 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +#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) + +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 */}; + +#ifdef _MSC_VER + #define INLINE __inline +#else + #define INLINE +#endif + +/* one round of the hash function */ +INLINE static void round(ulong64 *a, ulong64 *b, ulong64 *c, ulong64 x, int mul) +{ + ulong64 tmp; + tmp = (*c ^= x); + *a -= t1[byte(tmp, 0)] ^ t2[byte(tmp, 2)] ^ t3[byte(tmp, 4)] ^ t4[byte(tmp, 6)]; + tmp = (*b += t4[byte(tmp, 1)] ^ t3[byte(tmp, 3)] ^ t2[byte(tmp,5)] ^ t1[byte(tmp,7)]); + switch (mul) { + case 5: *b = (tmp << 2) + tmp; break; + case 7: *b = (tmp << 3) - tmp; break; + case 9: *b = (tmp << 3) + tmp; break; + } +} + +/* one complete pass */ +static void pass(ulong64 *a, ulong64 *b, ulong64 *c, ulong64 *x, int 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, unsigned char *buf) +#else +static void tiger_compress(hash_state *md, unsigned char *buf) +#endif +{ + ulong64 a, b, c, x[8]; + unsigned long i; + + /* load words */ + for (i = 0; i < 8; i++) { + LOAD64L(x[i],&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, unsigned char *buf) +{ + _tiger_compress(md, buf); + 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; +} + +HASH_PROCESS(tiger_process, tiger_compress, tiger, 64) + +int tiger_done(hash_state * md, unsigned char *hash) +{ + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->tiger.curlen >= sizeof(md->tiger.buf)) { + return CRYPT_INVALID_ARG; + } + + /* increase the length of the message */ + md->tiger.length += md->tiger.curlen * 8; + + /* append the '1' bit */ + md->tiger.buf[md->tiger.curlen++] = (unsigned char)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++] = (unsigned char)0; + } + tiger_compress(md, md->tiger.buf); + md->tiger.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->tiger.curlen < 56) { + md->tiger.buf[md->tiger.curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64L(md->tiger.length, md->tiger.buf+56); + tiger_compress(md, md->tiger.buf); + + /* 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 + + return CRYPT_OK; +} + +int tiger_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + 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 } + }, + }; + + int i; + unsigned char tmp[24]; + hash_state md; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + tiger_init(&md); + tiger_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg)); + tiger_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 24) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + +#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/tommath.h b/tommath.h new file mode 100644 index 0000000..bc50ce9 --- /dev/null +++ b/tommath.h @@ -0,0 +1,558 @@ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org + */ +#ifndef BN_H_ +#define BN_H_ + +#include +#include +#include +#include +#include + +#define NO_LTM_TOOM 1 + +#undef MIN +#define MIN(x,y) ((x)<(y)?(x):(y)) +#undef MAX +#define MAX(x,y) ((x)>(y)?(x):(y)) + +#ifdef __cplusplus +extern "C" { + +/* C++ compilers don't like assigning void * to mp_digit * */ +#define OPT_CAST(x) (x *) + +#else + +/* C on the other hand doesn't care */ +#define OPT_CAST(x) + +#endif + +/* some default configurations. + * + * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits + * A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits + * + * At the very least a mp_digit must be able to hold 7 bits + * [any size beyond that is ok provided it doesn't overflow the data type] + */ +#ifdef MP_8BIT + typedef unsigned char mp_digit; + typedef unsigned short mp_word; +#elif defined(MP_16BIT) + typedef unsigned short mp_digit; + typedef unsigned long mp_word; +#elif defined(MP_64BIT) + /* for GCC only on supported platforms */ +#ifndef CRYPT + typedef unsigned long long ulong64; + typedef signed long long long64; +#endif + + typedef ulong64 mp_digit; + typedef unsigned long mp_word __attribute__ ((mode(TI))); + + #define DIGIT_BIT 60 +#else + /* this is the default case, 28-bit digits */ + + /* this is to make porting into LibTomCrypt easier :-) */ +#ifndef CRYPT + #if defined(_MSC_VER) || defined(__BORLANDC__) + typedef unsigned __int64 ulong64; + typedef signed __int64 long64; + #else + typedef unsigned long long ulong64; + typedef signed long long long64; + #endif +#endif + + typedef unsigned long mp_digit; + typedef ulong64 mp_word; + +#ifdef MP_31BIT + /* this is an extension that uses 31-bit digits */ + #define DIGIT_BIT 31 +#else + /* default case is 28-bit digits, defines MP_28BIT as a handy macro to test */ + #define DIGIT_BIT 28 + #define MP_28BIT +#endif +#endif + +/* define heap macros */ +#ifndef CRYPT + /* default to libc stuff */ + #ifndef XMALLOC + #define XMALLOC malloc + #define XFREE free + #define XREALLOC realloc + #define XCALLOC calloc + #else + /* prototypes for our heap functions */ + extern void *XMALLOC(size_t n); + extern void *REALLOC(void *p, size_t n); + extern void *XCALLOC(size_t n, size_t s); + extern void XFREE(void *p); + #endif +#endif + + +/* otherwise the bits per digit is calculated automatically from the size of a mp_digit */ +#ifndef DIGIT_BIT + #define DIGIT_BIT ((int)((CHAR_BIT * sizeof(mp_digit) - 1))) /* bits per digit */ +#endif + +#define MP_DIGIT_BIT DIGIT_BIT +#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) +#define MP_DIGIT_MAX MP_MASK + +/* equalities */ +#define MP_LT -1 /* less than */ +#define MP_EQ 0 /* equal to */ +#define MP_GT 1 /* greater than */ + +#define MP_ZPOS 0 /* positive integer */ +#define MP_NEG 1 /* negative */ + +#define MP_OKAY 0 /* ok result */ +#define MP_MEM -2 /* out of mem */ +#define MP_VAL -3 /* invalid input */ +#define MP_RANGE MP_VAL + +#define MP_YES 1 /* yes response */ +#define MP_NO 0 /* no response */ + +/* Primality generation flags */ +#define LTM_PRIME_BBS 0x0001 /* BBS style prime */ +#define LTM_PRIME_SAFE 0x0002 /* Safe prime (p-1)/2 == prime */ +#define LTM_PRIME_2MSB_OFF 0x0004 /* force 2nd MSB to 0 */ +#define LTM_PRIME_2MSB_ON 0x0008 /* force 2nd MSB to 1 */ + +typedef int mp_err; + +/* you'll have to tune these... */ +extern int KARATSUBA_MUL_CUTOFF, + KARATSUBA_SQR_CUTOFF, + TOOM_MUL_CUTOFF, + TOOM_SQR_CUTOFF; + +/* define this to use lower memory usage routines (exptmods mostly) */ +/* #define MP_LOW_MEM */ + +/* default precision */ +#ifndef MP_PREC + #ifdef MP_LOW_MEM + #define MP_PREC 64 /* default digits of precision */ + #else + #define MP_PREC 8 /* default digits of precision */ + #endif +#endif + +/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */ +#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1)) + +/* the infamous mp_int structure */ +typedef struct { + int used, alloc, sign; + mp_digit *dp; +} mp_int; + +/* callback for mp_prime_random, should fill dst with random bytes and return how many read [upto len] */ +typedef int ltm_prime_callback(unsigned char *dst, int len, void *dat); + + +#define USED(m) ((m)->used) +#define DIGIT(m,k) ((m)->dp[(k)]) +#define SIGN(m) ((m)->sign) + +/* error code to char* string */ +char *mp_error_to_string(int code); + +/* ---> init and deinit bignum functions <--- */ +/* init a bignum */ +int mp_init(mp_int *a); + +/* free a bignum */ +void mp_clear(mp_int *a); + +/* init a null terminated series of arguments */ +int mp_init_multi(mp_int *mp, ...); + +/* clear a null terminated series of arguments */ +void mp_clear_multi(mp_int *mp, ...); + +/* exchange two ints */ +void mp_exch(mp_int *a, mp_int *b); + +/* shrink ram required for a bignum */ +int mp_shrink(mp_int *a); + +/* grow an int to a given size */ +int mp_grow(mp_int *a, int size); + +/* init to a given number of digits */ +int mp_init_size(mp_int *a, int size); + +/* ---> Basic Manipulations <--- */ +#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO) +#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO) +#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO) + +/* set to zero */ +void mp_zero(mp_int *a); + +/* set to a digit */ +void mp_set(mp_int *a, mp_digit b); + +/* set a 32-bit const */ +int mp_set_int(mp_int *a, unsigned long b); + +/* get a 32-bit value */ +unsigned long mp_get_int(mp_int * a); + +/* initialize and set a digit */ +int mp_init_set (mp_int * a, mp_digit b); + +/* initialize and set 32-bit value */ +int mp_init_set_int (mp_int * a, unsigned long b); + +/* copy, b = a */ +int mp_copy(mp_int *a, mp_int *b); + +/* inits and copies, a = b */ +int mp_init_copy(mp_int *a, mp_int *b); + +/* trim unused digits */ +void mp_clamp(mp_int *a); + +/* ---> digit manipulation <--- */ + +/* right shift by "b" digits */ +void mp_rshd(mp_int *a, int b); + +/* left shift by "b" digits */ +int mp_lshd(mp_int *a, int b); + +/* c = a / 2**b */ +int mp_div_2d(mp_int *a, int b, mp_int *c, mp_int *d); + +/* b = a/2 */ +int mp_div_2(mp_int *a, mp_int *b); + +/* c = a * 2**b */ +int mp_mul_2d(mp_int *a, int b, mp_int *c); + +/* b = a*2 */ +int mp_mul_2(mp_int *a, mp_int *b); + +/* c = a mod 2**d */ +int mp_mod_2d(mp_int *a, int b, mp_int *c); + +/* computes a = 2**b */ +int mp_2expt(mp_int *a, int b); + +/* Counts the number of lsbs which are zero before the first zero bit */ +int mp_cnt_lsb(mp_int *a); + +/* I Love Earth! */ + +/* makes a pseudo-random int of a given size */ +int mp_rand(mp_int *a, int digits); + +/* ---> binary operations <--- */ +/* c = a XOR b */ +int mp_xor(mp_int *a, mp_int *b, mp_int *c); + +/* c = a OR b */ +int mp_or(mp_int *a, mp_int *b, mp_int *c); + +/* c = a AND b */ +int mp_and(mp_int *a, mp_int *b, mp_int *c); + +/* ---> Basic arithmetic <--- */ + +/* b = -a */ +int mp_neg(mp_int *a, mp_int *b); + +/* b = |a| */ +int mp_abs(mp_int *a, mp_int *b); + +/* compare a to b */ +int mp_cmp(mp_int *a, mp_int *b); + +/* compare |a| to |b| */ +int mp_cmp_mag(mp_int *a, mp_int *b); + +/* c = a + b */ +int mp_add(mp_int *a, mp_int *b, mp_int *c); + +/* c = a - b */ +int mp_sub(mp_int *a, mp_int *b, mp_int *c); + +/* c = a * b */ +int mp_mul(mp_int *a, mp_int *b, mp_int *c); + +/* b = a*a */ +int mp_sqr(mp_int *a, mp_int *b); + +/* a/b => cb + d == a */ +int mp_div(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* c = a mod b, 0 <= c < b */ +int mp_mod(mp_int *a, mp_int *b, mp_int *c); + +/* ---> single digit functions <--- */ + +/* compare against a single digit */ +int mp_cmp_d(mp_int *a, mp_digit b); + +/* c = a + b */ +int mp_add_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a - b */ +int mp_sub_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a * b */ +int mp_mul_d(mp_int *a, mp_digit b, mp_int *c); + +/* a/b => cb + d == a */ +int mp_div_d(mp_int *a, mp_digit b, mp_int *c, mp_digit *d); + +/* a/3 => 3c + d == a */ +int mp_div_3(mp_int *a, mp_int *c, mp_digit *d); + +/* c = a**b */ +int mp_expt_d(mp_int *a, mp_digit b, mp_int *c); + +/* c = a mod b, 0 <= c < b */ +int mp_mod_d(mp_int *a, mp_digit b, mp_digit *c); + +/* ---> number theory <--- */ + +/* d = a + b (mod c) */ +int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* d = a - b (mod c) */ +int mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* d = a * b (mod c) */ +int mp_mulmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* c = a * a (mod b) */ +int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c); + +/* c = 1/a (mod b) */ +int mp_invmod(mp_int *a, mp_int *b, mp_int *c); + +/* c = (a, b) */ +int mp_gcd(mp_int *a, mp_int *b, mp_int *c); + +/* produces value such that U1*a + U2*b = U3 */ +int mp_exteuclid(mp_int *a, mp_int *b, mp_int *U1, mp_int *U2, mp_int *U3); + +/* c = [a, b] or (a*b)/(a, b) */ +int mp_lcm(mp_int *a, mp_int *b, mp_int *c); + +/* finds one of the b'th root of a, such that |c|**b <= |a| + * + * returns error if a < 0 and b is even + */ +int mp_n_root(mp_int *a, mp_digit b, mp_int *c); + +/* special sqrt algo */ +int mp_sqrt(mp_int *arg, mp_int *ret); + +/* is number a square? */ +int mp_is_square(mp_int *arg, int *ret); + +/* computes the jacobi c = (a | n) (or Legendre if b is prime) */ +int mp_jacobi(mp_int *a, mp_int *n, int *c); + +/* used to setup the Barrett reduction for a given modulus b */ +int mp_reduce_setup(mp_int *a, mp_int *b); + +/* Barrett Reduction, computes a (mod b) with a precomputed value c + * + * Assumes that 0 < a <= b*b, note if 0 > a > -(b*b) then you can merely + * compute the reduction as -1 * mp_reduce(mp_abs(a)) [pseudo code]. + */ +int mp_reduce(mp_int *a, mp_int *b, mp_int *c); + +/* setups the montgomery reduction */ +int mp_montgomery_setup(mp_int *a, mp_digit *mp); + +/* computes a = B**n mod b without division or multiplication useful for + * normalizing numbers in a Montgomery system. + */ +int mp_montgomery_calc_normalization(mp_int *a, mp_int *b); + +/* computes x/R == x (mod N) via Montgomery Reduction */ +int mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp); + +/* returns 1 if a is a valid DR modulus */ +int mp_dr_is_modulus(mp_int *a); + +/* sets the value of "d" required for mp_dr_reduce */ +void mp_dr_setup(mp_int *a, mp_digit *d); + +/* reduces a modulo b using the Diminished Radix method */ +int mp_dr_reduce(mp_int *a, mp_int *b, mp_digit mp); + +/* returns true if a can be reduced with mp_reduce_2k */ +int mp_reduce_is_2k(mp_int *a); + +/* determines k value for 2k reduction */ +int mp_reduce_2k_setup(mp_int *a, mp_digit *d); + +/* reduces a modulo b where b is of the form 2**p - k [0 <= a] */ +int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d); + +/* d = a**b (mod c) */ +int mp_exptmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); + +/* ---> Primes <--- */ + +/* number of primes */ +#ifdef MP_8BIT + #define PRIME_SIZE 31 +#else + #define PRIME_SIZE 256 +#endif + +/* table of first PRIME_SIZE primes */ +extern const mp_digit __prime_tab[]; + +/* result=1 if a is divisible by one of the first PRIME_SIZE primes */ +int mp_prime_is_divisible(mp_int *a, int *result); + +/* performs one Fermat test of "a" using base "b". + * Sets result to 0 if composite or 1 if probable prime + */ +int mp_prime_fermat(mp_int *a, mp_int *b, int *result); + +/* performs one Miller-Rabin test of "a" using base "b". + * Sets result to 0 if composite or 1 if probable prime + */ +int mp_prime_miller_rabin(mp_int *a, mp_int *b, int *result); + +/* This gives [for a given bit size] the number of trials required + * such that Miller-Rabin gives a prob of failure lower than 2^-96 + */ +int mp_prime_rabin_miller_trials(int size); + +/* performs t rounds of Miller-Rabin on "a" using the first + * t prime bases. Also performs an initial sieve of trial + * division. Determines if "a" is prime with probability + * of error no more than (1/4)**t. + * + * Sets result to 1 if probably prime, 0 otherwise + */ +int mp_prime_is_prime(mp_int *a, int t, int *result); + +/* finds the next prime after the number "a" using "t" trials + * of Miller-Rabin. + * + * bbs_style = 1 means the prime must be congruent to 3 mod 4 + */ +int mp_prime_next_prime(mp_int *a, int t, int bbs_style); + +/* makes a truly random prime of a given size (bytes), + * call with bbs = 1 if you want it to be congruent to 3 mod 4 + * + * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can + * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself + * so it can be NULL + * + * The prime generated will be larger than 2^(8*size). + */ +#define mp_prime_random(a, t, size, bbs, cb, dat) mp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?LTM_PRIME_BBS:0, cb, dat) + +/* makes a truly random prime of a given size (bits), + * + * Flags are as follows: + * + * LTM_PRIME_BBS - make prime congruent to 3 mod 4 + * LTM_PRIME_SAFE - make sure (p-1)/2 is prime as well (implies LTM_PRIME_BBS) + * LTM_PRIME_2MSB_OFF - make the 2nd highest bit zero + * LTM_PRIME_2MSB_ON - make the 2nd highest bit one + * + * You have to supply a callback which fills in a buffer with random bytes. "dat" is a parameter you can + * have passed to the callback (e.g. a state or something). This function doesn't use "dat" itself + * so it can be NULL + * + */ +int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat); + +/* ---> radix conversion <--- */ +int mp_count_bits(mp_int *a); + +int mp_unsigned_bin_size(mp_int *a); +int mp_read_unsigned_bin(mp_int *a, unsigned char *b, int c); +int mp_to_unsigned_bin(mp_int *a, unsigned char *b); + +int mp_signed_bin_size(mp_int *a); +int mp_read_signed_bin(mp_int *a, unsigned char *b, int c); +int mp_to_signed_bin(mp_int *a, unsigned char *b); + +int mp_read_radix(mp_int *a, char *str, int radix); +int mp_toradix(mp_int *a, char *str, int radix); +int mp_toradix_n(mp_int * a, char *str, int radix, int maxlen); +int mp_radix_size(mp_int *a, int radix, int *size); + +int mp_fread(mp_int *a, int radix, FILE *stream); +int mp_fwrite(mp_int *a, int radix, FILE *stream); + +#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)) + +#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) + +/* lowlevel functions, do not call! */ +int s_mp_add(mp_int *a, mp_int *b, mp_int *c); +int s_mp_sub(mp_int *a, mp_int *b, mp_int *c); +#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) +int fast_s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +int s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +int fast_s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +int s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs); +int fast_s_mp_sqr(mp_int *a, mp_int *b); +int s_mp_sqr(mp_int *a, mp_int *b); +int mp_karatsuba_mul(mp_int *a, mp_int *b, mp_int *c); +int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c); +int mp_karatsuba_sqr(mp_int *a, mp_int *b); +int mp_toom_sqr(mp_int *a, mp_int *b); +int fast_mp_invmod(mp_int *a, mp_int *b, mp_int *c); +int fast_mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp); +int mp_exptmod_fast(mp_int *G, mp_int *X, mp_int *P, mp_int *Y, int mode); +int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y); +void bn_reverse(unsigned char *s, int len); + +extern const char *mp_s_rmap; + +#ifdef __cplusplus + } +#endif + +#endif + diff --git a/twofish.c b/twofish.c new file mode 100644 index 0000000..b618b98 --- /dev/null +++ b/twofish.c @@ -0,0 +1,661 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* Implementation of Twofish by Tom St Denis */ +#include "mycrypt.h" + +#ifdef TWOFISH + +/* first TWOFISH_ALL_TABLES must ensure TWOFISH_TABLES is defined */ +#ifdef TWOFISH_ALL_TABLES +#ifndef TWOFISH_TABLES +#define TWOFISH_TABLES +#endif +#endif + +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 + +#include "twofish_tab.c" + +#define sbox(i, x) ((ulong32)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 ulong32 _sbox(int i, ulong32 x) +#else +static ulong32 sbox(int i, ulong32 x) +#endif +{ + unsigned char a0,b0,a1,b1,a2,b2,a3,b3,a4,b4,y; + + /* a0,b0 = [x/16], x mod 16 */ + a0 = (unsigned char)((x>>4)&15); + b0 = (unsigned char)((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][(int)a1]; + b2 = qbox[i][1][(int)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][(int)a3]; + b4 = qbox[i][3][(int)b3]; + + /* y = 16b4 + a4 */ + y = (b4 << 4) + a4; + + /* return result */ + return (ulong32)y; +} + +#ifdef CLEAN_STACK +static ulong32 sbox(int i, ulong32 x) +{ + ulong32 y; + y = _sbox(i, x); + burn_stack(sizeof(unsigned char) * 11); + return y; +} +#endif /* CLEAN_STACK */ + +#endif /* TWOFISH_TABLES */ + +/* computes ab mod p */ +static ulong32 gf_mult(ulong32 a, ulong32 b, ulong32 p) +{ + ulong32 result, B[2], P[2]; + + P[1] = p; + B[1] = b; + result = P[0] = B[0] = 0; + + /* unrolled branchless GF multiplier */ + result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1); + result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1); + result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1); + result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1); + result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1); + result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1); + result ^= B[a&1]; a >>= 1; B[1] = P[B[1]>>7] ^ (B[1] << 1); + result ^= B[a&1]; + + return result; +} + +/* computes [y0 y1 y2 y3] = MDS . [x0] */ +#ifndef TWOFISH_TABLES +static ulong32 mds_column_mult(unsigned char in, int col) +{ + ulong32 x01, x5B, xEF; + + x01 = in; + x5B = gf_mult(in, 0x5B, MDS_POLY); + xEF = gf_mult(in, 0xEF, MDS_POLY); + + 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; +} + +#else /* !TWOFISH_TABLES */ + +#define mds_column_mult(x, i) mds_tab[i][x] + +#endif /* TWOFISH_TABLES */ + +/* Computes [y0 y1 y2 y3] = MDS . [x0 x1 x2 x3] */ +static void mds_mult(const unsigned char *in, unsigned char *out) +{ + int x; + ulong32 tmp; + for (tmp = x = 0; x < 4; x++) { + tmp ^= mds_column_mult(in[x], x); + } + STORE32L(tmp, out); +} + +#ifdef TWOFISH_ALL_TABLES +/* 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) +{ + ulong32 tmp; + tmp = rs_tab0[in[0]] ^ rs_tab1[in[1]] ^ rs_tab2[in[2]] ^ rs_tab3[in[3]] ^ + rs_tab4[in[4]] ^ rs_tab5[in[5]] ^ rs_tab6[in[6]] ^ rs_tab7[in[7]]; + STORE32L(tmp, out); +} + +#else /* !TWOFISH_ALL_TABLES */ + +/* 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; + for (x = 0; x < 4; x++) { + out[x] = 0; + for (y = 0; y < 8; y++) { + out[x] ^= gf_mult(in[y], RS[x][y], RS_POLY); + } + } +} + +#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] = (unsigned char)(sbox(1, (ulong32)y[0]) ^ M[4 * (6 + offset) + 0]); + y[1] = (unsigned char)(sbox(0, (ulong32)y[1]) ^ M[4 * (6 + offset) + 1]); + y[2] = (unsigned char)(sbox(0, (ulong32)y[2]) ^ M[4 * (6 + offset) + 2]); + y[3] = (unsigned char)(sbox(1, (ulong32)y[3]) ^ M[4 * (6 + offset) + 3]); + case 3: + y[0] = (unsigned char)(sbox(1, (ulong32)y[0]) ^ M[4 * (4 + offset) + 0]); + y[1] = (unsigned char)(sbox(1, (ulong32)y[1]) ^ M[4 * (4 + offset) + 1]); + y[2] = (unsigned char)(sbox(0, (ulong32)y[2]) ^ M[4 * (4 + offset) + 2]); + y[3] = (unsigned char)(sbox(0, (ulong32)y[3]) ^ M[4 * (4 + offset) + 3]); + case 2: + y[0] = (unsigned char)(sbox(1, sbox(0, sbox(0, (ulong32)y[0]) ^ M[4 * (2 + offset) + 0]) ^ M[4 * (0 + offset) + 0])); + y[1] = (unsigned char)(sbox(0, sbox(0, sbox(1, (ulong32)y[1]) ^ M[4 * (2 + offset) + 1]) ^ M[4 * (0 + offset) + 1])); + y[2] = (unsigned char)(sbox(1, sbox(1, sbox(0, (ulong32)y[2]) ^ M[4 * (2 + offset) + 2]) ^ M[4 * (0 + offset) + 2])); + y[3] = (unsigned char)(sbox(0, sbox(1, sbox(1, (ulong32)y[3]) ^ M[4 * (2 + offset) + 3]) ^ M[4 * (0 + offset) + 3])); + } + mds_mult(y, out); +} + +#ifndef TWOFISH_SMALL + +/* for GCC we don't use pointer aliases */ +#if defined(__GNUC__) + #define S1 key->twofish.S[0] + #define S2 key->twofish.S[1] + #define S3 key->twofish.S[2] + #define S4 key->twofish.S[3] +#endif + +/* the G function */ +#define g_func(x, dum) (S1[byte(x,0)] ^ S2[byte(x,1)] ^ S3[byte(x,2)] ^ S4[byte(x,3)]) +#define g1_func(x, dum) (S2[byte(x,0)] ^ S3[byte(x,1)] ^ S4[byte(x,2)] ^ S1[byte(x,3)]) + +#else + +#ifdef CLEAN_STACK +static ulong32 _g_func(ulong32 x, symmetric_key *key) +#else +static ulong32 g_func(ulong32 x, symmetric_key *key) +#endif +{ + unsigned char g, i, y, z; + ulong32 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; +} + +#define g1_func(x, key) g_func(ROL(x, 8), key) + +#ifdef CLEAN_STACK +static ulong32 g_func(ulong32 x, symmetric_key *key) +{ + ulong32 y; + y = _g_func(x, key); + burn_stack(sizeof(unsigned char) * 4 + sizeof(ulong32)); + return y; +} +#endif /* CLEAN_STACK */ + +#endif /* TWOFISH_SMALL */ + +#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 + unsigned char S[4*4], tmpx0, tmpx1; +#endif + int k, x, y; + unsigned char tmp[4], tmp2[4], M[8*4]; + ulong32 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] & 255; + } + + /* 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] = (unsigned char)(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); + } + +#ifndef TWOFISH_SMALL + /* make the sboxes (large ram variant) */ + if (k == 2) { + for (x = 0; x < 256; x++) { + tmpx0 = sbox(0, x); + tmpx1 = sbox(1, x); + skey->twofish.S[0][x] = mds_column_mult(sbox(1, (sbox(0, tmpx0 ^ S[0]) ^ S[4])),0); + skey->twofish.S[1][x] = mds_column_mult(sbox(0, (sbox(0, tmpx1 ^ S[1]) ^ S[5])),1); + skey->twofish.S[2][x] = mds_column_mult(sbox(1, (sbox(1, tmpx0 ^ S[2]) ^ S[6])),2); + skey->twofish.S[3][x] = mds_column_mult(sbox(0, (sbox(1, tmpx1 ^ S[3]) ^ S[7])),3); + } + } else if (k == 3) { + for (x = 0; x < 256; x++) { + tmpx0 = sbox(0, x); + tmpx1 = sbox(1, x); + skey->twofish.S[0][x] = mds_column_mult(sbox(1, (sbox(0, sbox(0, tmpx1 ^ S[0]) ^ S[4]) ^ S[8])),0); + skey->twofish.S[1][x] = mds_column_mult(sbox(0, (sbox(0, sbox(1, tmpx1 ^ S[1]) ^ S[5]) ^ S[9])),1); + skey->twofish.S[2][x] = mds_column_mult(sbox(1, (sbox(1, sbox(0, tmpx0 ^ S[2]) ^ S[6]) ^ S[10])),2); + skey->twofish.S[3][x] = mds_column_mult(sbox(0, (sbox(1, sbox(1, tmpx0 ^ S[3]) ^ S[7]) ^ S[11])),3); + } + } else { + for (x = 0; x < 256; x++) { + tmpx0 = sbox(0, x); + tmpx1 = sbox(1, x); + skey->twofish.S[0][x] = mds_column_mult(sbox(1, (sbox(0, sbox(0, sbox(1, tmpx1 ^ S[0]) ^ S[4]) ^ S[8]) ^ S[12])),0); + skey->twofish.S[1][x] = mds_column_mult(sbox(0, (sbox(0, sbox(1, sbox(1, tmpx0 ^ S[1]) ^ S[5]) ^ S[9]) ^ S[13])),1); + skey->twofish.S[2][x] = mds_column_mult(sbox(1, (sbox(1, sbox(0, sbox(0, tmpx0 ^ S[2]) ^ S[6]) ^ S[10]) ^ S[14])),2); + skey->twofish.S[3][x] = mds_column_mult(sbox(0, (sbox(1, sbox(1, sbox(0, tmpx1 ^ S[3]) ^ S[7]) ^ S[11]) ^ S[15])),3); + } + } +#else + /* where to start in the sbox layers */ + /* small ram variant */ + switch (k) { + case 4 : skey->twofish.start = 0; break; + case 3 : skey->twofish.start = 1; break; + default: skey->twofish.start = 2; break; + } +#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(ulong32) * 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 +{ + ulong32 a,b,c,d,ta,tb,tc,td,t1,t2, *k; + int r; +#if !defined(TWOFISH_SMALL) && !defined(__GNUC__) + ulong32 *S1, *S2, *S3, *S4; +#endif + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + +#if !defined(TWOFISH_SMALL) && !defined(__GNUC__) + S1 = key->twofish.S[0]; + S2 = key->twofish.S[1]; + S3 = key->twofish.S[2]; + S4 = key->twofish.S[3]; +#endif + + 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]; + + k = key->twofish.K + 8; + for (r = 8; r != 0; --r) { + t2 = g1_func(b, key); + t1 = g_func(a, key) + t2; + c = ROR(c ^ (t1 + k[0]), 1); + d = ROL(d, 1) ^ (t2 + t1 + k[1]); + + t2 = g1_func(d, key); + t1 = g_func(c, key) + t2; + a = ROR(a ^ (t1 + k[2]), 1); + b = ROL(b, 1) ^ (t2 + t1 + k[3]); + k += 4; + } + + /* 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(ulong32) * 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 +{ + ulong32 a,b,c,d,ta,tb,tc,td,t1,t2, *k; + int r; +#if !defined(TWOFISH_SMALL) && !defined(__GNUC__) + ulong32 *S1, *S2, *S3, *S4; +#endif + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + +#if !defined(TWOFISH_SMALL) && !defined(__GNUC__) + S1 = key->twofish.S[0]; + S2 = key->twofish.S[1]; + S3 = key->twofish.S[2]; + S4 = key->twofish.S[3]; +#endif + + /* 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]; + + k = key->twofish.K + 36; + for (r = 8; r != 0; --r) { + t2 = g1_func(d, key); + t1 = g_func(c, key) + t2; + a = ROL(a, 1) ^ (t1 + k[2]); + b = ROR(b ^ (t2 + t1 + k[3]), 1); + + t2 = g1_func(b, key); + t1 = g_func(a, key) + t2; + c = ROL(c, 1) ^ (t1 + k[0]); + d = ROR(d ^ (t2 + t1 + k[1]), 1); + k -= 4; + } + + /* 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(ulong32) * 10 + sizeof(int)); +} +#endif + +int twofish_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + int keylen; + unsigned char key[32], pt[16], ct[16]; + } tests[] = { + { 16, + { 0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, + 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A }, + { 0xD4, 0x91, 0xDB, 0x16, 0xE7, 0xB1, 0xC3, 0x9E, + 0x86, 0xCB, 0x08, 0x6B, 0x78, 0x9F, 0x54, 0x19 }, + { 0x01, 0x9F, 0x98, 0x09, 0xDE, 0x17, 0x11, 0x85, + 0x8F, 0xAA, 0xC3, 0xA3, 0xBA, 0x20, 0xFB, 0xC3 } + }, { + 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 }, + { 0x39, 0xDA, 0x69, 0xD6, 0xBA, 0x49, 0x97, 0xD5, + 0x85, 0xB6, 0xDC, 0x07, 0x3C, 0xA3, 0x41, 0xB2 }, + { 0x18, 0x2B, 0x02, 0xD8, 0x14, 0x97, 0xEA, 0x45, + 0xF9, 0xDA, 0xAC, 0xDC, 0x29, 0x19, 0x3A, 0x65 } + }, { + 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 }, + { 0x90, 0xAF, 0xE9, 0x1B, 0xB2, 0x88, 0x54, 0x4F, + 0x2C, 0x32, 0xDC, 0x23, 0x9B, 0x26, 0x35, 0xE6 }, + { 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 err, i, y; + + for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) { + if ((err = twofish_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) { + return err; + } + twofish_ecb_encrypt(tests[i].pt, tmp[0], &key); + twofish_ecb_decrypt(tmp[0], tmp[1], &key); + if (memcmp(tmp[0], tests[i].ct, 16) != 0 || memcmp(tmp[1], tests[i].pt, 16) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ + for (y = 0; y < 16; y++) tmp[0][y] = 0; + for (y = 0; y < 1000; y++) twofish_ecb_encrypt(tmp[0], tmp[0], &key); + for (y = 0; y < 1000; y++) twofish_ecb_decrypt(tmp[0], tmp[0], &key); + for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; + } + return CRYPT_OK; +#endif +} + +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/twofish_tab.c b/twofish_tab.c new file mode 100644 index 0000000..5a2bb5b --- /dev/null +++ b/twofish_tab.c @@ -0,0 +1,488 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +#ifdef TWOFISH_TABLES + +/* pre generated 8x8 tables from the four 4x4s */ +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} +}; + +/* the 4x4 MDS in a nicer format */ +static const ulong32 mds_tab[4][256] = { +{ +0x00000000UL, 0xefef5b01UL, 0xb7b7b602UL, 0x5858ed03UL, 0x07070504UL, 0xe8e85e05UL, 0xb0b0b306UL, 0x5f5fe807UL, +0x0e0e0a08UL, 0xe1e15109UL, 0xb9b9bc0aUL, 0x5656e70bUL, 0x09090f0cUL, 0xe6e6540dUL, 0xbebeb90eUL, 0x5151e20fUL, +0x1c1c1410UL, 0xf3f34f11UL, 0xababa212UL, 0x4444f913UL, 0x1b1b1114UL, 0xf4f44a15UL, 0xacaca716UL, 0x4343fc17UL, +0x12121e18UL, 0xfdfd4519UL, 0xa5a5a81aUL, 0x4a4af31bUL, 0x15151b1cUL, 0xfafa401dUL, 0xa2a2ad1eUL, 0x4d4df61fUL, +0x38382820UL, 0xd7d77321UL, 0x8f8f9e22UL, 0x6060c523UL, 0x3f3f2d24UL, 0xd0d07625UL, 0x88889b26UL, 0x6767c027UL, +0x36362228UL, 0xd9d97929UL, 0x8181942aUL, 0x6e6ecf2bUL, 0x3131272cUL, 0xdede7c2dUL, 0x8686912eUL, 0x6969ca2fUL, +0x24243c30UL, 0xcbcb6731UL, 0x93938a32UL, 0x7c7cd133UL, 0x23233934UL, 0xcccc6235UL, 0x94948f36UL, 0x7b7bd437UL, +0x2a2a3638UL, 0xc5c56d39UL, 0x9d9d803aUL, 0x7272db3bUL, 0x2d2d333cUL, 0xc2c2683dUL, 0x9a9a853eUL, 0x7575de3fUL, +0x70705040UL, 0x9f9f0b41UL, 0xc7c7e642UL, 0x2828bd43UL, 0x77775544UL, 0x98980e45UL, 0xc0c0e346UL, 0x2f2fb847UL, +0x7e7e5a48UL, 0x91910149UL, 0xc9c9ec4aUL, 0x2626b74bUL, 0x79795f4cUL, 0x9696044dUL, 0xcecee94eUL, 0x2121b24fUL, +0x6c6c4450UL, 0x83831f51UL, 0xdbdbf252UL, 0x3434a953UL, 0x6b6b4154UL, 0x84841a55UL, 0xdcdcf756UL, 0x3333ac57UL, +0x62624e58UL, 0x8d8d1559UL, 0xd5d5f85aUL, 0x3a3aa35bUL, 0x65654b5cUL, 0x8a8a105dUL, 0xd2d2fd5eUL, 0x3d3da65fUL, +0x48487860UL, 0xa7a72361UL, 0xffffce62UL, 0x10109563UL, 0x4f4f7d64UL, 0xa0a02665UL, 0xf8f8cb66UL, 0x17179067UL, +0x46467268UL, 0xa9a92969UL, 0xf1f1c46aUL, 0x1e1e9f6bUL, 0x4141776cUL, 0xaeae2c6dUL, 0xf6f6c16eUL, 0x19199a6fUL, +0x54546c70UL, 0xbbbb3771UL, 0xe3e3da72UL, 0x0c0c8173UL, 0x53536974UL, 0xbcbc3275UL, 0xe4e4df76UL, 0x0b0b8477UL, +0x5a5a6678UL, 0xb5b53d79UL, 0xededd07aUL, 0x02028b7bUL, 0x5d5d637cUL, 0xb2b2387dUL, 0xeaead57eUL, 0x05058e7fUL, +0xe0e0a080UL, 0x0f0ffb81UL, 0x57571682UL, 0xb8b84d83UL, 0xe7e7a584UL, 0x0808fe85UL, 0x50501386UL, 0xbfbf4887UL, +0xeeeeaa88UL, 0x0101f189UL, 0x59591c8aUL, 0xb6b6478bUL, 0xe9e9af8cUL, 0x0606f48dUL, 0x5e5e198eUL, 0xb1b1428fUL, +0xfcfcb490UL, 0x1313ef91UL, 0x4b4b0292UL, 0xa4a45993UL, 0xfbfbb194UL, 0x1414ea95UL, 0x4c4c0796UL, 0xa3a35c97UL, +0xf2f2be98UL, 0x1d1de599UL, 0x4545089aUL, 0xaaaa539bUL, 0xf5f5bb9cUL, 0x1a1ae09dUL, 0x42420d9eUL, 0xadad569fUL, +0xd8d888a0UL, 0x3737d3a1UL, 0x6f6f3ea2UL, 0x808065a3UL, 0xdfdf8da4UL, 0x3030d6a5UL, 0x68683ba6UL, 0x878760a7UL, +0xd6d682a8UL, 0x3939d9a9UL, 0x616134aaUL, 0x8e8e6fabUL, 0xd1d187acUL, 0x3e3edcadUL, 0x666631aeUL, 0x89896aafUL, +0xc4c49cb0UL, 0x2b2bc7b1UL, 0x73732ab2UL, 0x9c9c71b3UL, 0xc3c399b4UL, 0x2c2cc2b5UL, 0x74742fb6UL, 0x9b9b74b7UL, +0xcaca96b8UL, 0x2525cdb9UL, 0x7d7d20baUL, 0x92927bbbUL, 0xcdcd93bcUL, 0x2222c8bdUL, 0x7a7a25beUL, 0x95957ebfUL, +0x9090f0c0UL, 0x7f7fabc1UL, 0x272746c2UL, 0xc8c81dc3UL, 0x9797f5c4UL, 0x7878aec5UL, 0x202043c6UL, 0xcfcf18c7UL, +0x9e9efac8UL, 0x7171a1c9UL, 0x29294ccaUL, 0xc6c617cbUL, 0x9999ffccUL, 0x7676a4cdUL, 0x2e2e49ceUL, 0xc1c112cfUL, +0x8c8ce4d0UL, 0x6363bfd1UL, 0x3b3b52d2UL, 0xd4d409d3UL, 0x8b8be1d4UL, 0x6464bad5UL, 0x3c3c57d6UL, 0xd3d30cd7UL, +0x8282eed8UL, 0x6d6db5d9UL, 0x353558daUL, 0xdada03dbUL, 0x8585ebdcUL, 0x6a6ab0ddUL, 0x32325ddeUL, 0xdddd06dfUL, +0xa8a8d8e0UL, 0x474783e1UL, 0x1f1f6ee2UL, 0xf0f035e3UL, 0xafafdde4UL, 0x404086e5UL, 0x18186be6UL, 0xf7f730e7UL, +0xa6a6d2e8UL, 0x494989e9UL, 0x111164eaUL, 0xfefe3febUL, 0xa1a1d7ecUL, 0x4e4e8cedUL, 0x161661eeUL, 0xf9f93aefUL, +0xb4b4ccf0UL, 0x5b5b97f1UL, 0x03037af2UL, 0xecec21f3UL, 0xb3b3c9f4UL, 0x5c5c92f5UL, 0x04047ff6UL, 0xebeb24f7UL, +0xbabac6f8UL, 0x55559df9UL, 0x0d0d70faUL, 0xe2e22bfbUL, 0xbdbdc3fcUL, 0x525298fdUL, 0x0a0a75feUL, 0xe5e52effUL +}, +{ +0x00000000UL, 0x015befefUL, 0x02b6b7b7UL, 0x03ed5858UL, 0x04050707UL, 0x055ee8e8UL, 0x06b3b0b0UL, 0x07e85f5fUL, +0x080a0e0eUL, 0x0951e1e1UL, 0x0abcb9b9UL, 0x0be75656UL, 0x0c0f0909UL, 0x0d54e6e6UL, 0x0eb9bebeUL, 0x0fe25151UL, +0x10141c1cUL, 0x114ff3f3UL, 0x12a2ababUL, 0x13f94444UL, 0x14111b1bUL, 0x154af4f4UL, 0x16a7acacUL, 0x17fc4343UL, +0x181e1212UL, 0x1945fdfdUL, 0x1aa8a5a5UL, 0x1bf34a4aUL, 0x1c1b1515UL, 0x1d40fafaUL, 0x1eada2a2UL, 0x1ff64d4dUL, +0x20283838UL, 0x2173d7d7UL, 0x229e8f8fUL, 0x23c56060UL, 0x242d3f3fUL, 0x2576d0d0UL, 0x269b8888UL, 0x27c06767UL, +0x28223636UL, 0x2979d9d9UL, 0x2a948181UL, 0x2bcf6e6eUL, 0x2c273131UL, 0x2d7cdedeUL, 0x2e918686UL, 0x2fca6969UL, +0x303c2424UL, 0x3167cbcbUL, 0x328a9393UL, 0x33d17c7cUL, 0x34392323UL, 0x3562ccccUL, 0x368f9494UL, 0x37d47b7bUL, +0x38362a2aUL, 0x396dc5c5UL, 0x3a809d9dUL, 0x3bdb7272UL, 0x3c332d2dUL, 0x3d68c2c2UL, 0x3e859a9aUL, 0x3fde7575UL, +0x40507070UL, 0x410b9f9fUL, 0x42e6c7c7UL, 0x43bd2828UL, 0x44557777UL, 0x450e9898UL, 0x46e3c0c0UL, 0x47b82f2fUL, +0x485a7e7eUL, 0x49019191UL, 0x4aecc9c9UL, 0x4bb72626UL, 0x4c5f7979UL, 0x4d049696UL, 0x4ee9ceceUL, 0x4fb22121UL, +0x50446c6cUL, 0x511f8383UL, 0x52f2dbdbUL, 0x53a93434UL, 0x54416b6bUL, 0x551a8484UL, 0x56f7dcdcUL, 0x57ac3333UL, +0x584e6262UL, 0x59158d8dUL, 0x5af8d5d5UL, 0x5ba33a3aUL, 0x5c4b6565UL, 0x5d108a8aUL, 0x5efdd2d2UL, 0x5fa63d3dUL, +0x60784848UL, 0x6123a7a7UL, 0x62ceffffUL, 0x63951010UL, 0x647d4f4fUL, 0x6526a0a0UL, 0x66cbf8f8UL, 0x67901717UL, +0x68724646UL, 0x6929a9a9UL, 0x6ac4f1f1UL, 0x6b9f1e1eUL, 0x6c774141UL, 0x6d2caeaeUL, 0x6ec1f6f6UL, 0x6f9a1919UL, +0x706c5454UL, 0x7137bbbbUL, 0x72dae3e3UL, 0x73810c0cUL, 0x74695353UL, 0x7532bcbcUL, 0x76dfe4e4UL, 0x77840b0bUL, +0x78665a5aUL, 0x793db5b5UL, 0x7ad0ededUL, 0x7b8b0202UL, 0x7c635d5dUL, 0x7d38b2b2UL, 0x7ed5eaeaUL, 0x7f8e0505UL, +0x80a0e0e0UL, 0x81fb0f0fUL, 0x82165757UL, 0x834db8b8UL, 0x84a5e7e7UL, 0x85fe0808UL, 0x86135050UL, 0x8748bfbfUL, +0x88aaeeeeUL, 0x89f10101UL, 0x8a1c5959UL, 0x8b47b6b6UL, 0x8cafe9e9UL, 0x8df40606UL, 0x8e195e5eUL, 0x8f42b1b1UL, +0x90b4fcfcUL, 0x91ef1313UL, 0x92024b4bUL, 0x9359a4a4UL, 0x94b1fbfbUL, 0x95ea1414UL, 0x96074c4cUL, 0x975ca3a3UL, +0x98bef2f2UL, 0x99e51d1dUL, 0x9a084545UL, 0x9b53aaaaUL, 0x9cbbf5f5UL, 0x9de01a1aUL, 0x9e0d4242UL, 0x9f56adadUL, +0xa088d8d8UL, 0xa1d33737UL, 0xa23e6f6fUL, 0xa3658080UL, 0xa48ddfdfUL, 0xa5d63030UL, 0xa63b6868UL, 0xa7608787UL, +0xa882d6d6UL, 0xa9d93939UL, 0xaa346161UL, 0xab6f8e8eUL, 0xac87d1d1UL, 0xaddc3e3eUL, 0xae316666UL, 0xaf6a8989UL, +0xb09cc4c4UL, 0xb1c72b2bUL, 0xb22a7373UL, 0xb3719c9cUL, 0xb499c3c3UL, 0xb5c22c2cUL, 0xb62f7474UL, 0xb7749b9bUL, +0xb896cacaUL, 0xb9cd2525UL, 0xba207d7dUL, 0xbb7b9292UL, 0xbc93cdcdUL, 0xbdc82222UL, 0xbe257a7aUL, 0xbf7e9595UL, +0xc0f09090UL, 0xc1ab7f7fUL, 0xc2462727UL, 0xc31dc8c8UL, 0xc4f59797UL, 0xc5ae7878UL, 0xc6432020UL, 0xc718cfcfUL, +0xc8fa9e9eUL, 0xc9a17171UL, 0xca4c2929UL, 0xcb17c6c6UL, 0xccff9999UL, 0xcda47676UL, 0xce492e2eUL, 0xcf12c1c1UL, +0xd0e48c8cUL, 0xd1bf6363UL, 0xd2523b3bUL, 0xd309d4d4UL, 0xd4e18b8bUL, 0xd5ba6464UL, 0xd6573c3cUL, 0xd70cd3d3UL, +0xd8ee8282UL, 0xd9b56d6dUL, 0xda583535UL, 0xdb03dadaUL, 0xdceb8585UL, 0xddb06a6aUL, 0xde5d3232UL, 0xdf06ddddUL, +0xe0d8a8a8UL, 0xe1834747UL, 0xe26e1f1fUL, 0xe335f0f0UL, 0xe4ddafafUL, 0xe5864040UL, 0xe66b1818UL, 0xe730f7f7UL, +0xe8d2a6a6UL, 0xe9894949UL, 0xea641111UL, 0xeb3ffefeUL, 0xecd7a1a1UL, 0xed8c4e4eUL, 0xee611616UL, 0xef3af9f9UL, +0xf0ccb4b4UL, 0xf1975b5bUL, 0xf27a0303UL, 0xf321ececUL, 0xf4c9b3b3UL, 0xf5925c5cUL, 0xf67f0404UL, 0xf724ebebUL, +0xf8c6babaUL, 0xf99d5555UL, 0xfa700d0dUL, 0xfb2be2e2UL, 0xfcc3bdbdUL, 0xfd985252UL, 0xfe750a0aUL, 0xff2ee5e5UL +}, +{ +0x00000000UL, 0xef01ef5bUL, 0xb702b7b6UL, 0x580358edUL, 0x07040705UL, 0xe805e85eUL, 0xb006b0b3UL, 0x5f075fe8UL, +0x0e080e0aUL, 0xe109e151UL, 0xb90ab9bcUL, 0x560b56e7UL, 0x090c090fUL, 0xe60de654UL, 0xbe0ebeb9UL, 0x510f51e2UL, +0x1c101c14UL, 0xf311f34fUL, 0xab12aba2UL, 0x441344f9UL, 0x1b141b11UL, 0xf415f44aUL, 0xac16aca7UL, 0x431743fcUL, +0x1218121eUL, 0xfd19fd45UL, 0xa51aa5a8UL, 0x4a1b4af3UL, 0x151c151bUL, 0xfa1dfa40UL, 0xa21ea2adUL, 0x4d1f4df6UL, +0x38203828UL, 0xd721d773UL, 0x8f228f9eUL, 0x602360c5UL, 0x3f243f2dUL, 0xd025d076UL, 0x8826889bUL, 0x672767c0UL, +0x36283622UL, 0xd929d979UL, 0x812a8194UL, 0x6e2b6ecfUL, 0x312c3127UL, 0xde2dde7cUL, 0x862e8691UL, 0x692f69caUL, +0x2430243cUL, 0xcb31cb67UL, 0x9332938aUL, 0x7c337cd1UL, 0x23342339UL, 0xcc35cc62UL, 0x9436948fUL, 0x7b377bd4UL, +0x2a382a36UL, 0xc539c56dUL, 0x9d3a9d80UL, 0x723b72dbUL, 0x2d3c2d33UL, 0xc23dc268UL, 0x9a3e9a85UL, 0x753f75deUL, +0x70407050UL, 0x9f419f0bUL, 0xc742c7e6UL, 0x284328bdUL, 0x77447755UL, 0x9845980eUL, 0xc046c0e3UL, 0x2f472fb8UL, +0x7e487e5aUL, 0x91499101UL, 0xc94ac9ecUL, 0x264b26b7UL, 0x794c795fUL, 0x964d9604UL, 0xce4ecee9UL, 0x214f21b2UL, +0x6c506c44UL, 0x8351831fUL, 0xdb52dbf2UL, 0x345334a9UL, 0x6b546b41UL, 0x8455841aUL, 0xdc56dcf7UL, 0x335733acUL, +0x6258624eUL, 0x8d598d15UL, 0xd55ad5f8UL, 0x3a5b3aa3UL, 0x655c654bUL, 0x8a5d8a10UL, 0xd25ed2fdUL, 0x3d5f3da6UL, +0x48604878UL, 0xa761a723UL, 0xff62ffceUL, 0x10631095UL, 0x4f644f7dUL, 0xa065a026UL, 0xf866f8cbUL, 0x17671790UL, +0x46684672UL, 0xa969a929UL, 0xf16af1c4UL, 0x1e6b1e9fUL, 0x416c4177UL, 0xae6dae2cUL, 0xf66ef6c1UL, 0x196f199aUL, +0x5470546cUL, 0xbb71bb37UL, 0xe372e3daUL, 0x0c730c81UL, 0x53745369UL, 0xbc75bc32UL, 0xe476e4dfUL, 0x0b770b84UL, +0x5a785a66UL, 0xb579b53dUL, 0xed7aedd0UL, 0x027b028bUL, 0x5d7c5d63UL, 0xb27db238UL, 0xea7eead5UL, 0x057f058eUL, +0xe080e0a0UL, 0x0f810ffbUL, 0x57825716UL, 0xb883b84dUL, 0xe784e7a5UL, 0x088508feUL, 0x50865013UL, 0xbf87bf48UL, +0xee88eeaaUL, 0x018901f1UL, 0x598a591cUL, 0xb68bb647UL, 0xe98ce9afUL, 0x068d06f4UL, 0x5e8e5e19UL, 0xb18fb142UL, +0xfc90fcb4UL, 0x139113efUL, 0x4b924b02UL, 0xa493a459UL, 0xfb94fbb1UL, 0x149514eaUL, 0x4c964c07UL, 0xa397a35cUL, +0xf298f2beUL, 0x1d991de5UL, 0x459a4508UL, 0xaa9baa53UL, 0xf59cf5bbUL, 0x1a9d1ae0UL, 0x429e420dUL, 0xad9fad56UL, +0xd8a0d888UL, 0x37a137d3UL, 0x6fa26f3eUL, 0x80a38065UL, 0xdfa4df8dUL, 0x30a530d6UL, 0x68a6683bUL, 0x87a78760UL, +0xd6a8d682UL, 0x39a939d9UL, 0x61aa6134UL, 0x8eab8e6fUL, 0xd1acd187UL, 0x3ead3edcUL, 0x66ae6631UL, 0x89af896aUL, +0xc4b0c49cUL, 0x2bb12bc7UL, 0x73b2732aUL, 0x9cb39c71UL, 0xc3b4c399UL, 0x2cb52cc2UL, 0x74b6742fUL, 0x9bb79b74UL, +0xcab8ca96UL, 0x25b925cdUL, 0x7dba7d20UL, 0x92bb927bUL, 0xcdbccd93UL, 0x22bd22c8UL, 0x7abe7a25UL, 0x95bf957eUL, +0x90c090f0UL, 0x7fc17fabUL, 0x27c22746UL, 0xc8c3c81dUL, 0x97c497f5UL, 0x78c578aeUL, 0x20c62043UL, 0xcfc7cf18UL, +0x9ec89efaUL, 0x71c971a1UL, 0x29ca294cUL, 0xc6cbc617UL, 0x99cc99ffUL, 0x76cd76a4UL, 0x2ece2e49UL, 0xc1cfc112UL, +0x8cd08ce4UL, 0x63d163bfUL, 0x3bd23b52UL, 0xd4d3d409UL, 0x8bd48be1UL, 0x64d564baUL, 0x3cd63c57UL, 0xd3d7d30cUL, +0x82d882eeUL, 0x6dd96db5UL, 0x35da3558UL, 0xdadbda03UL, 0x85dc85ebUL, 0x6add6ab0UL, 0x32de325dUL, 0xdddfdd06UL, +0xa8e0a8d8UL, 0x47e14783UL, 0x1fe21f6eUL, 0xf0e3f035UL, 0xafe4afddUL, 0x40e54086UL, 0x18e6186bUL, 0xf7e7f730UL, +0xa6e8a6d2UL, 0x49e94989UL, 0x11ea1164UL, 0xfeebfe3fUL, 0xa1eca1d7UL, 0x4eed4e8cUL, 0x16ee1661UL, 0xf9eff93aUL, +0xb4f0b4ccUL, 0x5bf15b97UL, 0x03f2037aUL, 0xecf3ec21UL, 0xb3f4b3c9UL, 0x5cf55c92UL, 0x04f6047fUL, 0xebf7eb24UL, +0xbaf8bac6UL, 0x55f9559dUL, 0x0dfa0d70UL, 0xe2fbe22bUL, 0xbdfcbdc3UL, 0x52fd5298UL, 0x0afe0a75UL, 0xe5ffe52eUL +}, +{ +0x00000000UL, 0x5bef015bUL, 0xb6b702b6UL, 0xed5803edUL, 0x05070405UL, 0x5ee8055eUL, 0xb3b006b3UL, 0xe85f07e8UL, +0x0a0e080aUL, 0x51e10951UL, 0xbcb90abcUL, 0xe7560be7UL, 0x0f090c0fUL, 0x54e60d54UL, 0xb9be0eb9UL, 0xe2510fe2UL, +0x141c1014UL, 0x4ff3114fUL, 0xa2ab12a2UL, 0xf94413f9UL, 0x111b1411UL, 0x4af4154aUL, 0xa7ac16a7UL, 0xfc4317fcUL, +0x1e12181eUL, 0x45fd1945UL, 0xa8a51aa8UL, 0xf34a1bf3UL, 0x1b151c1bUL, 0x40fa1d40UL, 0xada21eadUL, 0xf64d1ff6UL, +0x28382028UL, 0x73d72173UL, 0x9e8f229eUL, 0xc56023c5UL, 0x2d3f242dUL, 0x76d02576UL, 0x9b88269bUL, 0xc06727c0UL, +0x22362822UL, 0x79d92979UL, 0x94812a94UL, 0xcf6e2bcfUL, 0x27312c27UL, 0x7cde2d7cUL, 0x91862e91UL, 0xca692fcaUL, +0x3c24303cUL, 0x67cb3167UL, 0x8a93328aUL, 0xd17c33d1UL, 0x39233439UL, 0x62cc3562UL, 0x8f94368fUL, 0xd47b37d4UL, +0x362a3836UL, 0x6dc5396dUL, 0x809d3a80UL, 0xdb723bdbUL, 0x332d3c33UL, 0x68c23d68UL, 0x859a3e85UL, 0xde753fdeUL, +0x50704050UL, 0x0b9f410bUL, 0xe6c742e6UL, 0xbd2843bdUL, 0x55774455UL, 0x0e98450eUL, 0xe3c046e3UL, 0xb82f47b8UL, +0x5a7e485aUL, 0x01914901UL, 0xecc94aecUL, 0xb7264bb7UL, 0x5f794c5fUL, 0x04964d04UL, 0xe9ce4ee9UL, 0xb2214fb2UL, +0x446c5044UL, 0x1f83511fUL, 0xf2db52f2UL, 0xa93453a9UL, 0x416b5441UL, 0x1a84551aUL, 0xf7dc56f7UL, 0xac3357acUL, +0x4e62584eUL, 0x158d5915UL, 0xf8d55af8UL, 0xa33a5ba3UL, 0x4b655c4bUL, 0x108a5d10UL, 0xfdd25efdUL, 0xa63d5fa6UL, +0x78486078UL, 0x23a76123UL, 0xceff62ceUL, 0x95106395UL, 0x7d4f647dUL, 0x26a06526UL, 0xcbf866cbUL, 0x90176790UL, +0x72466872UL, 0x29a96929UL, 0xc4f16ac4UL, 0x9f1e6b9fUL, 0x77416c77UL, 0x2cae6d2cUL, 0xc1f66ec1UL, 0x9a196f9aUL, +0x6c54706cUL, 0x37bb7137UL, 0xdae372daUL, 0x810c7381UL, 0x69537469UL, 0x32bc7532UL, 0xdfe476dfUL, 0x840b7784UL, +0x665a7866UL, 0x3db5793dUL, 0xd0ed7ad0UL, 0x8b027b8bUL, 0x635d7c63UL, 0x38b27d38UL, 0xd5ea7ed5UL, 0x8e057f8eUL, +0xa0e080a0UL, 0xfb0f81fbUL, 0x16578216UL, 0x4db8834dUL, 0xa5e784a5UL, 0xfe0885feUL, 0x13508613UL, 0x48bf8748UL, +0xaaee88aaUL, 0xf10189f1UL, 0x1c598a1cUL, 0x47b68b47UL, 0xafe98cafUL, 0xf4068df4UL, 0x195e8e19UL, 0x42b18f42UL, +0xb4fc90b4UL, 0xef1391efUL, 0x024b9202UL, 0x59a49359UL, 0xb1fb94b1UL, 0xea1495eaUL, 0x074c9607UL, 0x5ca3975cUL, +0xbef298beUL, 0xe51d99e5UL, 0x08459a08UL, 0x53aa9b53UL, 0xbbf59cbbUL, 0xe01a9de0UL, 0x0d429e0dUL, 0x56ad9f56UL, +0x88d8a088UL, 0xd337a1d3UL, 0x3e6fa23eUL, 0x6580a365UL, 0x8ddfa48dUL, 0xd630a5d6UL, 0x3b68a63bUL, 0x6087a760UL, +0x82d6a882UL, 0xd939a9d9UL, 0x3461aa34UL, 0x6f8eab6fUL, 0x87d1ac87UL, 0xdc3eaddcUL, 0x3166ae31UL, 0x6a89af6aUL, +0x9cc4b09cUL, 0xc72bb1c7UL, 0x2a73b22aUL, 0x719cb371UL, 0x99c3b499UL, 0xc22cb5c2UL, 0x2f74b62fUL, 0x749bb774UL, +0x96cab896UL, 0xcd25b9cdUL, 0x207dba20UL, 0x7b92bb7bUL, 0x93cdbc93UL, 0xc822bdc8UL, 0x257abe25UL, 0x7e95bf7eUL, +0xf090c0f0UL, 0xab7fc1abUL, 0x4627c246UL, 0x1dc8c31dUL, 0xf597c4f5UL, 0xae78c5aeUL, 0x4320c643UL, 0x18cfc718UL, +0xfa9ec8faUL, 0xa171c9a1UL, 0x4c29ca4cUL, 0x17c6cb17UL, 0xff99ccffUL, 0xa476cda4UL, 0x492ece49UL, 0x12c1cf12UL, +0xe48cd0e4UL, 0xbf63d1bfUL, 0x523bd252UL, 0x09d4d309UL, 0xe18bd4e1UL, 0xba64d5baUL, 0x573cd657UL, 0x0cd3d70cUL, +0xee82d8eeUL, 0xb56dd9b5UL, 0x5835da58UL, 0x03dadb03UL, 0xeb85dcebUL, 0xb06addb0UL, 0x5d32de5dUL, 0x06dddf06UL, +0xd8a8e0d8UL, 0x8347e183UL, 0x6e1fe26eUL, 0x35f0e335UL, 0xddafe4ddUL, 0x8640e586UL, 0x6b18e66bUL, 0x30f7e730UL, +0xd2a6e8d2UL, 0x8949e989UL, 0x6411ea64UL, 0x3ffeeb3fUL, 0xd7a1ecd7UL, 0x8c4eed8cUL, 0x6116ee61UL, 0x3af9ef3aUL, +0xccb4f0ccUL, 0x975bf197UL, 0x7a03f27aUL, 0x21ecf321UL, 0xc9b3f4c9UL, 0x925cf592UL, 0x7f04f67fUL, 0x24ebf724UL, +0xc6baf8c6UL, 0x9d55f99dUL, 0x700dfa70UL, 0x2be2fb2bUL, 0xc3bdfcc3UL, 0x9852fd98UL, 0x750afe75UL, 0x2ee5ff2eUL +}}; + +#ifdef TWOFISH_ALL_TABLES + +/* the 4x8 RS transform */ +static const ulong32 rs_tab0[256] = { +0x00000000LU, 0xa402a401LU, 0x05040502LU, 0xa106a103LU, 0x0a080a04LU, 0xae0aae05LU, 0x0f0c0f06LU, 0xab0eab07LU, +0x14101408LU, 0xb012b009LU, 0x1114110aLU, 0xb516b50bLU, 0x1e181e0cLU, 0xba1aba0dLU, 0x1b1c1b0eLU, 0xbf1ebf0fLU, +0x28202810LU, 0x8c228c11LU, 0x2d242d12LU, 0x89268913LU, 0x22282214LU, 0x862a8615LU, 0x272c2716LU, 0x832e8317LU, +0x3c303c18LU, 0x98329819LU, 0x3934391aLU, 0x9d369d1bLU, 0x3638361cLU, 0x923a921dLU, 0x333c331eLU, 0x973e971fLU, +0x50405020LU, 0xf442f421LU, 0x55445522LU, 0xf146f123LU, 0x5a485a24LU, 0xfe4afe25LU, 0x5f4c5f26LU, 0xfb4efb27LU, +0x44504428LU, 0xe052e029LU, 0x4154412aLU, 0xe556e52bLU, 0x4e584e2cLU, 0xea5aea2dLU, 0x4b5c4b2eLU, 0xef5eef2fLU, +0x78607830LU, 0xdc62dc31LU, 0x7d647d32LU, 0xd966d933LU, 0x72687234LU, 0xd66ad635LU, 0x776c7736LU, 0xd36ed337LU, +0x6c706c38LU, 0xc872c839LU, 0x6974693aLU, 0xcd76cd3bLU, 0x6678663cLU, 0xc27ac23dLU, 0x637c633eLU, 0xc77ec73fLU, +0xa080a040LU, 0x04820441LU, 0xa584a542LU, 0x01860143LU, 0xaa88aa44LU, 0x0e8a0e45LU, 0xaf8caf46LU, 0x0b8e0b47LU, +0xb490b448LU, 0x10921049LU, 0xb194b14aLU, 0x1596154bLU, 0xbe98be4cLU, 0x1a9a1a4dLU, 0xbb9cbb4eLU, 0x1f9e1f4fLU, +0x88a08850LU, 0x2ca22c51LU, 0x8da48d52LU, 0x29a62953LU, 0x82a88254LU, 0x26aa2655LU, 0x87ac8756LU, 0x23ae2357LU, +0x9cb09c58LU, 0x38b23859LU, 0x99b4995aLU, 0x3db63d5bLU, 0x96b8965cLU, 0x32ba325dLU, 0x93bc935eLU, 0x37be375fLU, +0xf0c0f060LU, 0x54c25461LU, 0xf5c4f562LU, 0x51c65163LU, 0xfac8fa64LU, 0x5eca5e65LU, 0xffccff66LU, 0x5bce5b67LU, +0xe4d0e468LU, 0x40d24069LU, 0xe1d4e16aLU, 0x45d6456bLU, 0xeed8ee6cLU, 0x4ada4a6dLU, 0xebdceb6eLU, 0x4fde4f6fLU, +0xd8e0d870LU, 0x7ce27c71LU, 0xdde4dd72LU, 0x79e67973LU, 0xd2e8d274LU, 0x76ea7675LU, 0xd7ecd776LU, 0x73ee7377LU, +0xccf0cc78LU, 0x68f26879LU, 0xc9f4c97aLU, 0x6df66d7bLU, 0xc6f8c67cLU, 0x62fa627dLU, 0xc3fcc37eLU, 0x67fe677fLU, +0x0d4d0d80LU, 0xa94fa981LU, 0x08490882LU, 0xac4bac83LU, 0x07450784LU, 0xa347a385LU, 0x02410286LU, 0xa643a687LU, +0x195d1988LU, 0xbd5fbd89LU, 0x1c591c8aLU, 0xb85bb88bLU, 0x1355138cLU, 0xb757b78dLU, 0x1651168eLU, 0xb253b28fLU, +0x256d2590LU, 0x816f8191LU, 0x20692092LU, 0x846b8493LU, 0x2f652f94LU, 0x8b678b95LU, 0x2a612a96LU, 0x8e638e97LU, +0x317d3198LU, 0x957f9599LU, 0x3479349aLU, 0x907b909bLU, 0x3b753b9cLU, 0x9f779f9dLU, 0x3e713e9eLU, 0x9a739a9fLU, +0x5d0d5da0LU, 0xf90ff9a1LU, 0x580958a2LU, 0xfc0bfca3LU, 0x570557a4LU, 0xf307f3a5LU, 0x520152a6LU, 0xf603f6a7LU, +0x491d49a8LU, 0xed1feda9LU, 0x4c194caaLU, 0xe81be8abLU, 0x431543acLU, 0xe717e7adLU, 0x461146aeLU, 0xe213e2afLU, +0x752d75b0LU, 0xd12fd1b1LU, 0x702970b2LU, 0xd42bd4b3LU, 0x7f257fb4LU, 0xdb27dbb5LU, 0x7a217ab6LU, 0xde23deb7LU, +0x613d61b8LU, 0xc53fc5b9LU, 0x643964baLU, 0xc03bc0bbLU, 0x6b356bbcLU, 0xcf37cfbdLU, 0x6e316ebeLU, 0xca33cabfLU, +0xadcdadc0LU, 0x09cf09c1LU, 0xa8c9a8c2LU, 0x0ccb0cc3LU, 0xa7c5a7c4LU, 0x03c703c5LU, 0xa2c1a2c6LU, 0x06c306c7LU, +0xb9ddb9c8LU, 0x1ddf1dc9LU, 0xbcd9bccaLU, 0x18db18cbLU, 0xb3d5b3ccLU, 0x17d717cdLU, 0xb6d1b6ceLU, 0x12d312cfLU, +0x85ed85d0LU, 0x21ef21d1LU, 0x80e980d2LU, 0x24eb24d3LU, 0x8fe58fd4LU, 0x2be72bd5LU, 0x8ae18ad6LU, 0x2ee32ed7LU, +0x91fd91d8LU, 0x35ff35d9LU, 0x94f994daLU, 0x30fb30dbLU, 0x9bf59bdcLU, 0x3ff73fddLU, 0x9ef19edeLU, 0x3af33adfLU, +0xfd8dfde0LU, 0x598f59e1LU, 0xf889f8e2LU, 0x5c8b5ce3LU, 0xf785f7e4LU, 0x538753e5LU, 0xf281f2e6LU, 0x568356e7LU, +0xe99de9e8LU, 0x4d9f4de9LU, 0xec99eceaLU, 0x489b48ebLU, 0xe395e3ecLU, 0x479747edLU, 0xe691e6eeLU, 0x429342efLU, +0xd5add5f0LU, 0x71af71f1LU, 0xd0a9d0f2LU, 0x74ab74f3LU, 0xdfa5dff4LU, 0x7ba77bf5LU, 0xdaa1daf6LU, 0x7ea37ef7LU, +0xc1bdc1f8LU, 0x65bf65f9LU, 0xc4b9c4faLU, 0x60bb60fbLU, 0xcbb5cbfcLU, 0x6fb76ffdLU, 0xceb1cefeLU, 0x6ab36affLU }; + +static const ulong32 rs_tab1[256] = { +0x00000000LU, 0x55a156a4LU, 0xaa0fac05LU, 0xffaefaa1LU, 0x191e150aLU, 0x4cbf43aeLU, 0xb311b90fLU, 0xe6b0efabLU, +0x323c2a14LU, 0x679d7cb0LU, 0x98338611LU, 0xcd92d0b5LU, 0x2b223f1eLU, 0x7e8369baLU, 0x812d931bLU, 0xd48cc5bfLU, +0x64785428LU, 0x31d9028cLU, 0xce77f82dLU, 0x9bd6ae89LU, 0x7d664122LU, 0x28c71786LU, 0xd769ed27LU, 0x82c8bb83LU, +0x56447e3cLU, 0x03e52898LU, 0xfc4bd239LU, 0xa9ea849dLU, 0x4f5a6b36LU, 0x1afb3d92LU, 0xe555c733LU, 0xb0f49197LU, +0xc8f0a850LU, 0x9d51fef4LU, 0x62ff0455LU, 0x375e52f1LU, 0xd1eebd5aLU, 0x844febfeLU, 0x7be1115fLU, 0x2e4047fbLU, +0xfacc8244LU, 0xaf6dd4e0LU, 0x50c32e41LU, 0x056278e5LU, 0xe3d2974eLU, 0xb673c1eaLU, 0x49dd3b4bLU, 0x1c7c6defLU, +0xac88fc78LU, 0xf929aadcLU, 0x0687507dLU, 0x532606d9LU, 0xb596e972LU, 0xe037bfd6LU, 0x1f994577LU, 0x4a3813d3LU, +0x9eb4d66cLU, 0xcb1580c8LU, 0x34bb7a69LU, 0x611a2ccdLU, 0x87aac366LU, 0xd20b95c2LU, 0x2da56f63LU, 0x780439c7LU, +0xddad1da0LU, 0x880c4b04LU, 0x77a2b1a5LU, 0x2203e701LU, 0xc4b308aaLU, 0x91125e0eLU, 0x6ebca4afLU, 0x3b1df20bLU, +0xef9137b4LU, 0xba306110LU, 0x459e9bb1LU, 0x103fcd15LU, 0xf68f22beLU, 0xa32e741aLU, 0x5c808ebbLU, 0x0921d81fLU, +0xb9d54988LU, 0xec741f2cLU, 0x13dae58dLU, 0x467bb329LU, 0xa0cb5c82LU, 0xf56a0a26LU, 0x0ac4f087LU, 0x5f65a623LU, +0x8be9639cLU, 0xde483538LU, 0x21e6cf99LU, 0x7447993dLU, 0x92f77696LU, 0xc7562032LU, 0x38f8da93LU, 0x6d598c37LU, +0x155db5f0LU, 0x40fce354LU, 0xbf5219f5LU, 0xeaf34f51LU, 0x0c43a0faLU, 0x59e2f65eLU, 0xa64c0cffLU, 0xf3ed5a5bLU, +0x27619fe4LU, 0x72c0c940LU, 0x8d6e33e1LU, 0xd8cf6545LU, 0x3e7f8aeeLU, 0x6bdedc4aLU, 0x947026ebLU, 0xc1d1704fLU, +0x7125e1d8LU, 0x2484b77cLU, 0xdb2a4dddLU, 0x8e8b1b79LU, 0x683bf4d2LU, 0x3d9aa276LU, 0xc23458d7LU, 0x97950e73LU, +0x4319cbccLU, 0x16b89d68LU, 0xe91667c9LU, 0xbcb7316dLU, 0x5a07dec6LU, 0x0fa68862LU, 0xf00872c3LU, 0xa5a92467LU, +0xf7173a0dLU, 0xa2b66ca9LU, 0x5d189608LU, 0x08b9c0acLU, 0xee092f07LU, 0xbba879a3LU, 0x44068302LU, 0x11a7d5a6LU, +0xc52b1019LU, 0x908a46bdLU, 0x6f24bc1cLU, 0x3a85eab8LU, 0xdc350513LU, 0x899453b7LU, 0x763aa916LU, 0x239bffb2LU, +0x936f6e25LU, 0xc6ce3881LU, 0x3960c220LU, 0x6cc19484LU, 0x8a717b2fLU, 0xdfd02d8bLU, 0x207ed72aLU, 0x75df818eLU, +0xa1534431LU, 0xf4f21295LU, 0x0b5ce834LU, 0x5efdbe90LU, 0xb84d513bLU, 0xedec079fLU, 0x1242fd3eLU, 0x47e3ab9aLU, +0x3fe7925dLU, 0x6a46c4f9LU, 0x95e83e58LU, 0xc04968fcLU, 0x26f98757LU, 0x7358d1f3LU, 0x8cf62b52LU, 0xd9577df6LU, +0x0ddbb849LU, 0x587aeeedLU, 0xa7d4144cLU, 0xf27542e8LU, 0x14c5ad43LU, 0x4164fbe7LU, 0xbeca0146LU, 0xeb6b57e2LU, +0x5b9fc675LU, 0x0e3e90d1LU, 0xf1906a70LU, 0xa4313cd4LU, 0x4281d37fLU, 0x172085dbLU, 0xe88e7f7aLU, 0xbd2f29deLU, +0x69a3ec61LU, 0x3c02bac5LU, 0xc3ac4064LU, 0x960d16c0LU, 0x70bdf96bLU, 0x251cafcfLU, 0xdab2556eLU, 0x8f1303caLU, +0x2aba27adLU, 0x7f1b7109LU, 0x80b58ba8LU, 0xd514dd0cLU, 0x33a432a7LU, 0x66056403LU, 0x99ab9ea2LU, 0xcc0ac806LU, +0x18860db9LU, 0x4d275b1dLU, 0xb289a1bcLU, 0xe728f718LU, 0x019818b3LU, 0x54394e17LU, 0xab97b4b6LU, 0xfe36e212LU, +0x4ec27385LU, 0x1b632521LU, 0xe4cddf80LU, 0xb16c8924LU, 0x57dc668fLU, 0x027d302bLU, 0xfdd3ca8aLU, 0xa8729c2eLU, +0x7cfe5991LU, 0x295f0f35LU, 0xd6f1f594LU, 0x8350a330LU, 0x65e04c9bLU, 0x30411a3fLU, 0xcfefe09eLU, 0x9a4eb63aLU, +0xe24a8ffdLU, 0xb7ebd959LU, 0x484523f8LU, 0x1de4755cLU, 0xfb549af7LU, 0xaef5cc53LU, 0x515b36f2LU, 0x04fa6056LU, +0xd076a5e9LU, 0x85d7f34dLU, 0x7a7909ecLU, 0x2fd85f48LU, 0xc968b0e3LU, 0x9cc9e647LU, 0x63671ce6LU, 0x36c64a42LU, +0x8632dbd5LU, 0xd3938d71LU, 0x2c3d77d0LU, 0x799c2174LU, 0x9f2ccedfLU, 0xca8d987bLU, 0x352362daLU, 0x6082347eLU, +0xb40ef1c1LU, 0xe1afa765LU, 0x1e015dc4LU, 0x4ba00b60LU, 0xad10e4cbLU, 0xf8b1b26fLU, 0x071f48ceLU, 0x52be1e6aLU }; + +static const ulong32 rs_tab2[256] = { +0x00000000LU, 0x87fc8255LU, 0x43b549aaLU, 0xc449cbffLU, 0x86279219LU, 0x01db104cLU, 0xc592dbb3LU, 0x426e59e6LU, +0x414e6932LU, 0xc6b2eb67LU, 0x02fb2098LU, 0x8507a2cdLU, 0xc769fb2bLU, 0x4095797eLU, 0x84dcb281LU, 0x032030d4LU, +0x829cd264LU, 0x05605031LU, 0xc1299bceLU, 0x46d5199bLU, 0x04bb407dLU, 0x8347c228LU, 0x470e09d7LU, 0xc0f28b82LU, +0xc3d2bb56LU, 0x442e3903LU, 0x8067f2fcLU, 0x079b70a9LU, 0x45f5294fLU, 0xc209ab1aLU, 0x064060e5LU, 0x81bce2b0LU, +0x4975e9c8LU, 0xce896b9dLU, 0x0ac0a062LU, 0x8d3c2237LU, 0xcf527bd1LU, 0x48aef984LU, 0x8ce7327bLU, 0x0b1bb02eLU, +0x083b80faLU, 0x8fc702afLU, 0x4b8ec950LU, 0xcc724b05LU, 0x8e1c12e3LU, 0x09e090b6LU, 0xcda95b49LU, 0x4a55d91cLU, +0xcbe93bacLU, 0x4c15b9f9LU, 0x885c7206LU, 0x0fa0f053LU, 0x4dcea9b5LU, 0xca322be0LU, 0x0e7be01fLU, 0x8987624aLU, +0x8aa7529eLU, 0x0d5bd0cbLU, 0xc9121b34LU, 0x4eee9961LU, 0x0c80c087LU, 0x8b7c42d2LU, 0x4f35892dLU, 0xc8c90b78LU, +0x92ea9fddLU, 0x15161d88LU, 0xd15fd677LU, 0x56a35422LU, 0x14cd0dc4LU, 0x93318f91LU, 0x5778446eLU, 0xd084c63bLU, +0xd3a4f6efLU, 0x545874baLU, 0x9011bf45LU, 0x17ed3d10LU, 0x558364f6LU, 0xd27fe6a3LU, 0x16362d5cLU, 0x91caaf09LU, +0x10764db9LU, 0x978acfecLU, 0x53c30413LU, 0xd43f8646LU, 0x9651dfa0LU, 0x11ad5df5LU, 0xd5e4960aLU, 0x5218145fLU, +0x5138248bLU, 0xd6c4a6deLU, 0x128d6d21LU, 0x9571ef74LU, 0xd71fb692LU, 0x50e334c7LU, 0x94aaff38LU, 0x13567d6dLU, +0xdb9f7615LU, 0x5c63f440LU, 0x982a3fbfLU, 0x1fd6bdeaLU, 0x5db8e40cLU, 0xda446659LU, 0x1e0dada6LU, 0x99f12ff3LU, +0x9ad11f27LU, 0x1d2d9d72LU, 0xd964568dLU, 0x5e98d4d8LU, 0x1cf68d3eLU, 0x9b0a0f6bLU, 0x5f43c494LU, 0xd8bf46c1LU, +0x5903a471LU, 0xdeff2624LU, 0x1ab6eddbLU, 0x9d4a6f8eLU, 0xdf243668LU, 0x58d8b43dLU, 0x9c917fc2LU, 0x1b6dfd97LU, +0x184dcd43LU, 0x9fb14f16LU, 0x5bf884e9LU, 0xdc0406bcLU, 0x9e6a5f5aLU, 0x1996dd0fLU, 0xdddf16f0LU, 0x5a2394a5LU, +0x699973f7LU, 0xee65f1a2LU, 0x2a2c3a5dLU, 0xadd0b808LU, 0xefbee1eeLU, 0x684263bbLU, 0xac0ba844LU, 0x2bf72a11LU, +0x28d71ac5LU, 0xaf2b9890LU, 0x6b62536fLU, 0xec9ed13aLU, 0xaef088dcLU, 0x290c0a89LU, 0xed45c176LU, 0x6ab94323LU, +0xeb05a193LU, 0x6cf923c6LU, 0xa8b0e839LU, 0x2f4c6a6cLU, 0x6d22338aLU, 0xeadeb1dfLU, 0x2e977a20LU, 0xa96bf875LU, +0xaa4bc8a1LU, 0x2db74af4LU, 0xe9fe810bLU, 0x6e02035eLU, 0x2c6c5ab8LU, 0xab90d8edLU, 0x6fd91312LU, 0xe8259147LU, +0x20ec9a3fLU, 0xa710186aLU, 0x6359d395LU, 0xe4a551c0LU, 0xa6cb0826LU, 0x21378a73LU, 0xe57e418cLU, 0x6282c3d9LU, +0x61a2f30dLU, 0xe65e7158LU, 0x2217baa7LU, 0xa5eb38f2LU, 0xe7856114LU, 0x6079e341LU, 0xa43028beLU, 0x23ccaaebLU, +0xa270485bLU, 0x258cca0eLU, 0xe1c501f1LU, 0x663983a4LU, 0x2457da42LU, 0xa3ab5817LU, 0x67e293e8LU, 0xe01e11bdLU, +0xe33e2169LU, 0x64c2a33cLU, 0xa08b68c3LU, 0x2777ea96LU, 0x6519b370LU, 0xe2e53125LU, 0x26acfadaLU, 0xa150788fLU, +0xfb73ec2aLU, 0x7c8f6e7fLU, 0xb8c6a580LU, 0x3f3a27d5LU, 0x7d547e33LU, 0xfaa8fc66LU, 0x3ee13799LU, 0xb91db5ccLU, +0xba3d8518LU, 0x3dc1074dLU, 0xf988ccb2LU, 0x7e744ee7LU, 0x3c1a1701LU, 0xbbe69554LU, 0x7faf5eabLU, 0xf853dcfeLU, +0x79ef3e4eLU, 0xfe13bc1bLU, 0x3a5a77e4LU, 0xbda6f5b1LU, 0xffc8ac57LU, 0x78342e02LU, 0xbc7de5fdLU, 0x3b8167a8LU, +0x38a1577cLU, 0xbf5dd529LU, 0x7b141ed6LU, 0xfce89c83LU, 0xbe86c565LU, 0x397a4730LU, 0xfd338ccfLU, 0x7acf0e9aLU, +0xb20605e2LU, 0x35fa87b7LU, 0xf1b34c48LU, 0x764fce1dLU, 0x342197fbLU, 0xb3dd15aeLU, 0x7794de51LU, 0xf0685c04LU, +0xf3486cd0LU, 0x74b4ee85LU, 0xb0fd257aLU, 0x3701a72fLU, 0x756ffec9LU, 0xf2937c9cLU, 0x36dab763LU, 0xb1263536LU, +0x309ad786LU, 0xb76655d3LU, 0x732f9e2cLU, 0xf4d31c79LU, 0xb6bd459fLU, 0x3141c7caLU, 0xf5080c35LU, 0x72f48e60LU, +0x71d4beb4LU, 0xf6283ce1LU, 0x3261f71eLU, 0xb59d754bLU, 0xf7f32cadLU, 0x700faef8LU, 0xb4466507LU, 0x33bae752LU }; + +static const ulong32 rs_tab3[256] = { +0x00000000LU, 0x5ac1f387LU, 0xb4cfab43LU, 0xee0e58c4LU, 0x25d31b86LU, 0x7f12e801LU, 0x911cb0c5LU, 0xcbdd4342LU, +0x4aeb3641LU, 0x102ac5c6LU, 0xfe249d02LU, 0xa4e56e85LU, 0x6f382dc7LU, 0x35f9de40LU, 0xdbf78684LU, 0x81367503LU, +0x949b6c82LU, 0xce5a9f05LU, 0x2054c7c1LU, 0x7a953446LU, 0xb1487704LU, 0xeb898483LU, 0x0587dc47LU, 0x5f462fc0LU, +0xde705ac3LU, 0x84b1a944LU, 0x6abff180LU, 0x307e0207LU, 0xfba34145LU, 0xa162b2c2LU, 0x4f6cea06LU, 0x15ad1981LU, +0x657bd849LU, 0x3fba2bceLU, 0xd1b4730aLU, 0x8b75808dLU, 0x40a8c3cfLU, 0x1a693048LU, 0xf467688cLU, 0xaea69b0bLU, +0x2f90ee08LU, 0x75511d8fLU, 0x9b5f454bLU, 0xc19eb6ccLU, 0x0a43f58eLU, 0x50820609LU, 0xbe8c5ecdLU, 0xe44dad4aLU, +0xf1e0b4cbLU, 0xab21474cLU, 0x452f1f88LU, 0x1feeec0fLU, 0xd433af4dLU, 0x8ef25ccaLU, 0x60fc040eLU, 0x3a3df789LU, +0xbb0b828aLU, 0xe1ca710dLU, 0x0fc429c9LU, 0x5505da4eLU, 0x9ed8990cLU, 0xc4196a8bLU, 0x2a17324fLU, 0x70d6c1c8LU, +0xcaf6fd92LU, 0x90370e15LU, 0x7e3956d1LU, 0x24f8a556LU, 0xef25e614LU, 0xb5e41593LU, 0x5bea4d57LU, 0x012bbed0LU, +0x801dcbd3LU, 0xdadc3854LU, 0x34d26090LU, 0x6e139317LU, 0xa5ced055LU, 0xff0f23d2LU, 0x11017b16LU, 0x4bc08891LU, +0x5e6d9110LU, 0x04ac6297LU, 0xeaa23a53LU, 0xb063c9d4LU, 0x7bbe8a96LU, 0x217f7911LU, 0xcf7121d5LU, 0x95b0d252LU, +0x1486a751LU, 0x4e4754d6LU, 0xa0490c12LU, 0xfa88ff95LU, 0x3155bcd7LU, 0x6b944f50LU, 0x859a1794LU, 0xdf5be413LU, +0xaf8d25dbLU, 0xf54cd65cLU, 0x1b428e98LU, 0x41837d1fLU, 0x8a5e3e5dLU, 0xd09fcddaLU, 0x3e91951eLU, 0x64506699LU, +0xe566139aLU, 0xbfa7e01dLU, 0x51a9b8d9LU, 0x0b684b5eLU, 0xc0b5081cLU, 0x9a74fb9bLU, 0x747aa35fLU, 0x2ebb50d8LU, +0x3b164959LU, 0x61d7badeLU, 0x8fd9e21aLU, 0xd518119dLU, 0x1ec552dfLU, 0x4404a158LU, 0xaa0af99cLU, 0xf0cb0a1bLU, +0x71fd7f18LU, 0x2b3c8c9fLU, 0xc532d45bLU, 0x9ff327dcLU, 0x542e649eLU, 0x0eef9719LU, 0xe0e1cfddLU, 0xba203c5aLU, +0xd9a1b769LU, 0x836044eeLU, 0x6d6e1c2aLU, 0x37afefadLU, 0xfc72acefLU, 0xa6b35f68LU, 0x48bd07acLU, 0x127cf42bLU, +0x934a8128LU, 0xc98b72afLU, 0x27852a6bLU, 0x7d44d9ecLU, 0xb6999aaeLU, 0xec586929LU, 0x025631edLU, 0x5897c26aLU, +0x4d3adbebLU, 0x17fb286cLU, 0xf9f570a8LU, 0xa334832fLU, 0x68e9c06dLU, 0x322833eaLU, 0xdc266b2eLU, 0x86e798a9LU, +0x07d1edaaLU, 0x5d101e2dLU, 0xb31e46e9LU, 0xe9dfb56eLU, 0x2202f62cLU, 0x78c305abLU, 0x96cd5d6fLU, 0xcc0caee8LU, +0xbcda6f20LU, 0xe61b9ca7LU, 0x0815c463LU, 0x52d437e4LU, 0x990974a6LU, 0xc3c88721LU, 0x2dc6dfe5LU, 0x77072c62LU, +0xf6315961LU, 0xacf0aae6LU, 0x42fef222LU, 0x183f01a5LU, 0xd3e242e7LU, 0x8923b160LU, 0x672de9a4LU, 0x3dec1a23LU, +0x284103a2LU, 0x7280f025LU, 0x9c8ea8e1LU, 0xc64f5b66LU, 0x0d921824LU, 0x5753eba3LU, 0xb95db367LU, 0xe39c40e0LU, +0x62aa35e3LU, 0x386bc664LU, 0xd6659ea0LU, 0x8ca46d27LU, 0x47792e65LU, 0x1db8dde2LU, 0xf3b68526LU, 0xa97776a1LU, +0x13574afbLU, 0x4996b97cLU, 0xa798e1b8LU, 0xfd59123fLU, 0x3684517dLU, 0x6c45a2faLU, 0x824bfa3eLU, 0xd88a09b9LU, +0x59bc7cbaLU, 0x037d8f3dLU, 0xed73d7f9LU, 0xb7b2247eLU, 0x7c6f673cLU, 0x26ae94bbLU, 0xc8a0cc7fLU, 0x92613ff8LU, +0x87cc2679LU, 0xdd0dd5feLU, 0x33038d3aLU, 0x69c27ebdLU, 0xa21f3dffLU, 0xf8dece78LU, 0x16d096bcLU, 0x4c11653bLU, +0xcd271038LU, 0x97e6e3bfLU, 0x79e8bb7bLU, 0x232948fcLU, 0xe8f40bbeLU, 0xb235f839LU, 0x5c3ba0fdLU, 0x06fa537aLU, +0x762c92b2LU, 0x2ced6135LU, 0xc2e339f1LU, 0x9822ca76LU, 0x53ff8934LU, 0x093e7ab3LU, 0xe7302277LU, 0xbdf1d1f0LU, +0x3cc7a4f3LU, 0x66065774LU, 0x88080fb0LU, 0xd2c9fc37LU, 0x1914bf75LU, 0x43d54cf2LU, 0xaddb1436LU, 0xf71ae7b1LU, +0xe2b7fe30LU, 0xb8760db7LU, 0x56785573LU, 0x0cb9a6f4LU, 0xc764e5b6LU, 0x9da51631LU, 0x73ab4ef5LU, 0x296abd72LU, +0xa85cc871LU, 0xf29d3bf6LU, 0x1c936332LU, 0x465290b5LU, 0x8d8fd3f7LU, 0xd74e2070LU, 0x394078b4LU, 0x63818b33LU }; + +static const ulong32 rs_tab4[256] = { +0x00000000LU, 0x58471e5aLU, 0xb08e3cb4LU, 0xe8c922eeLU, 0x2d517825LU, 0x7516667fLU, 0x9ddf4491LU, 0xc5985acbLU, +0x5aa2f04aLU, 0x02e5ee10LU, 0xea2cccfeLU, 0xb26bd2a4LU, 0x77f3886fLU, 0x2fb49635LU, 0xc77db4dbLU, 0x9f3aaa81LU, +0xb409ad94LU, 0xec4eb3ceLU, 0x04879120LU, 0x5cc08f7aLU, 0x9958d5b1LU, 0xc11fcbebLU, 0x29d6e905LU, 0x7191f75fLU, +0xeeab5ddeLU, 0xb6ec4384LU, 0x5e25616aLU, 0x06627f30LU, 0xc3fa25fbLU, 0x9bbd3ba1LU, 0x7374194fLU, 0x2b330715LU, +0x25121765LU, 0x7d55093fLU, 0x959c2bd1LU, 0xcddb358bLU, 0x08436f40LU, 0x5004711aLU, 0xb8cd53f4LU, 0xe08a4daeLU, +0x7fb0e72fLU, 0x27f7f975LU, 0xcf3edb9bLU, 0x9779c5c1LU, 0x52e19f0aLU, 0x0aa68150LU, 0xe26fa3beLU, 0xba28bde4LU, +0x911bbaf1LU, 0xc95ca4abLU, 0x21958645LU, 0x79d2981fLU, 0xbc4ac2d4LU, 0xe40ddc8eLU, 0x0cc4fe60LU, 0x5483e03aLU, +0xcbb94abbLU, 0x93fe54e1LU, 0x7b37760fLU, 0x23706855LU, 0xe6e8329eLU, 0xbeaf2cc4LU, 0x56660e2aLU, 0x0e211070LU, +0x4a242ecaLU, 0x12633090LU, 0xfaaa127eLU, 0xa2ed0c24LU, 0x677556efLU, 0x3f3248b5LU, 0xd7fb6a5bLU, 0x8fbc7401LU, +0x1086de80LU, 0x48c1c0daLU, 0xa008e234LU, 0xf84ffc6eLU, 0x3dd7a6a5LU, 0x6590b8ffLU, 0x8d599a11LU, 0xd51e844bLU, +0xfe2d835eLU, 0xa66a9d04LU, 0x4ea3bfeaLU, 0x16e4a1b0LU, 0xd37cfb7bLU, 0x8b3be521LU, 0x63f2c7cfLU, 0x3bb5d995LU, +0xa48f7314LU, 0xfcc86d4eLU, 0x14014fa0LU, 0x4c4651faLU, 0x89de0b31LU, 0xd199156bLU, 0x39503785LU, 0x611729dfLU, +0x6f3639afLU, 0x377127f5LU, 0xdfb8051bLU, 0x87ff1b41LU, 0x4267418aLU, 0x1a205fd0LU, 0xf2e97d3eLU, 0xaaae6364LU, +0x3594c9e5LU, 0x6dd3d7bfLU, 0x851af551LU, 0xdd5deb0bLU, 0x18c5b1c0LU, 0x4082af9aLU, 0xa84b8d74LU, 0xf00c932eLU, +0xdb3f943bLU, 0x83788a61LU, 0x6bb1a88fLU, 0x33f6b6d5LU, 0xf66eec1eLU, 0xae29f244LU, 0x46e0d0aaLU, 0x1ea7cef0LU, +0x819d6471LU, 0xd9da7a2bLU, 0x311358c5LU, 0x6954469fLU, 0xaccc1c54LU, 0xf48b020eLU, 0x1c4220e0LU, 0x44053ebaLU, +0x94485cd9LU, 0xcc0f4283LU, 0x24c6606dLU, 0x7c817e37LU, 0xb91924fcLU, 0xe15e3aa6LU, 0x09971848LU, 0x51d00612LU, +0xceeaac93LU, 0x96adb2c9LU, 0x7e649027LU, 0x26238e7dLU, 0xe3bbd4b6LU, 0xbbfccaecLU, 0x5335e802LU, 0x0b72f658LU, +0x2041f14dLU, 0x7806ef17LU, 0x90cfcdf9LU, 0xc888d3a3LU, 0x0d108968LU, 0x55579732LU, 0xbd9eb5dcLU, 0xe5d9ab86LU, +0x7ae30107LU, 0x22a41f5dLU, 0xca6d3db3LU, 0x922a23e9LU, 0x57b27922LU, 0x0ff56778LU, 0xe73c4596LU, 0xbf7b5bccLU, +0xb15a4bbcLU, 0xe91d55e6LU, 0x01d47708LU, 0x59936952LU, 0x9c0b3399LU, 0xc44c2dc3LU, 0x2c850f2dLU, 0x74c21177LU, +0xebf8bbf6LU, 0xb3bfa5acLU, 0x5b768742LU, 0x03319918LU, 0xc6a9c3d3LU, 0x9eeedd89LU, 0x7627ff67LU, 0x2e60e13dLU, +0x0553e628LU, 0x5d14f872LU, 0xb5ddda9cLU, 0xed9ac4c6LU, 0x28029e0dLU, 0x70458057LU, 0x988ca2b9LU, 0xc0cbbce3LU, +0x5ff11662LU, 0x07b60838LU, 0xef7f2ad6LU, 0xb738348cLU, 0x72a06e47LU, 0x2ae7701dLU, 0xc22e52f3LU, 0x9a694ca9LU, +0xde6c7213LU, 0x862b6c49LU, 0x6ee24ea7LU, 0x36a550fdLU, 0xf33d0a36LU, 0xab7a146cLU, 0x43b33682LU, 0x1bf428d8LU, +0x84ce8259LU, 0xdc899c03LU, 0x3440beedLU, 0x6c07a0b7LU, 0xa99ffa7cLU, 0xf1d8e426LU, 0x1911c6c8LU, 0x4156d892LU, +0x6a65df87LU, 0x3222c1ddLU, 0xdaebe333LU, 0x82acfd69LU, 0x4734a7a2LU, 0x1f73b9f8LU, 0xf7ba9b16LU, 0xaffd854cLU, +0x30c72fcdLU, 0x68803197LU, 0x80491379LU, 0xd80e0d23LU, 0x1d9657e8LU, 0x45d149b2LU, 0xad186b5cLU, 0xf55f7506LU, +0xfb7e6576LU, 0xa3397b2cLU, 0x4bf059c2LU, 0x13b74798LU, 0xd62f1d53LU, 0x8e680309LU, 0x66a121e7LU, 0x3ee63fbdLU, +0xa1dc953cLU, 0xf99b8b66LU, 0x1152a988LU, 0x4915b7d2LU, 0x8c8ded19LU, 0xd4caf343LU, 0x3c03d1adLU, 0x6444cff7LU, +0x4f77c8e2LU, 0x1730d6b8LU, 0xfff9f456LU, 0xa7beea0cLU, 0x6226b0c7LU, 0x3a61ae9dLU, 0xd2a88c73LU, 0x8aef9229LU, +0x15d538a8LU, 0x4d9226f2LU, 0xa55b041cLU, 0xfd1c1a46LU, 0x3884408dLU, 0x60c35ed7LU, 0x880a7c39LU, 0xd04d6263LU }; + +static const ulong32 rs_tab5[256] = { +0x00000000LU, 0xdbaec658LU, 0xfb11c1b0LU, 0x20bf07e8LU, 0xbb22cf2dLU, 0x608c0975LU, 0x40330e9dLU, 0x9b9dc8c5LU, +0x3b44d35aLU, 0xe0ea1502LU, 0xc05512eaLU, 0x1bfbd4b2LU, 0x80661c77LU, 0x5bc8da2fLU, 0x7b77ddc7LU, 0xa0d91b9fLU, +0x7688ebb4LU, 0xad262decLU, 0x8d992a04LU, 0x5637ec5cLU, 0xcdaa2499LU, 0x1604e2c1LU, 0x36bbe529LU, 0xed152371LU, +0x4dcc38eeLU, 0x9662feb6LU, 0xb6ddf95eLU, 0x6d733f06LU, 0xf6eef7c3LU, 0x2d40319bLU, 0x0dff3673LU, 0xd651f02bLU, +0xec5d9b25LU, 0x37f35d7dLU, 0x174c5a95LU, 0xcce29ccdLU, 0x577f5408LU, 0x8cd19250LU, 0xac6e95b8LU, 0x77c053e0LU, +0xd719487fLU, 0x0cb78e27LU, 0x2c0889cfLU, 0xf7a64f97LU, 0x6c3b8752LU, 0xb795410aLU, 0x972a46e2LU, 0x4c8480baLU, +0x9ad57091LU, 0x417bb6c9LU, 0x61c4b121LU, 0xba6a7779LU, 0x21f7bfbcLU, 0xfa5979e4LU, 0xdae67e0cLU, 0x0148b854LU, +0xa191a3cbLU, 0x7a3f6593LU, 0x5a80627bLU, 0x812ea423LU, 0x1ab36ce6LU, 0xc11daabeLU, 0xe1a2ad56LU, 0x3a0c6b0eLU, +0x95ba7b4aLU, 0x4e14bd12LU, 0x6eabbafaLU, 0xb5057ca2LU, 0x2e98b467LU, 0xf536723fLU, 0xd58975d7LU, 0x0e27b38fLU, +0xaefea810LU, 0x75506e48LU, 0x55ef69a0LU, 0x8e41aff8LU, 0x15dc673dLU, 0xce72a165LU, 0xeecda68dLU, 0x356360d5LU, +0xe33290feLU, 0x389c56a6LU, 0x1823514eLU, 0xc38d9716LU, 0x58105fd3LU, 0x83be998bLU, 0xa3019e63LU, 0x78af583bLU, +0xd87643a4LU, 0x03d885fcLU, 0x23678214LU, 0xf8c9444cLU, 0x63548c89LU, 0xb8fa4ad1LU, 0x98454d39LU, 0x43eb8b61LU, +0x79e7e06fLU, 0xa2492637LU, 0x82f621dfLU, 0x5958e787LU, 0xc2c52f42LU, 0x196be91aLU, 0x39d4eef2LU, 0xe27a28aaLU, +0x42a33335LU, 0x990df56dLU, 0xb9b2f285LU, 0x621c34ddLU, 0xf981fc18LU, 0x222f3a40LU, 0x02903da8LU, 0xd93efbf0LU, +0x0f6f0bdbLU, 0xd4c1cd83LU, 0xf47eca6bLU, 0x2fd00c33LU, 0xb44dc4f6LU, 0x6fe302aeLU, 0x4f5c0546LU, 0x94f2c31eLU, +0x342bd881LU, 0xef851ed9LU, 0xcf3a1931LU, 0x1494df69LU, 0x8f0917acLU, 0x54a7d1f4LU, 0x7418d61cLU, 0xafb61044LU, +0x6739f694LU, 0xbc9730ccLU, 0x9c283724LU, 0x4786f17cLU, 0xdc1b39b9LU, 0x07b5ffe1LU, 0x270af809LU, 0xfca43e51LU, +0x5c7d25ceLU, 0x87d3e396LU, 0xa76ce47eLU, 0x7cc22226LU, 0xe75feae3LU, 0x3cf12cbbLU, 0x1c4e2b53LU, 0xc7e0ed0bLU, +0x11b11d20LU, 0xca1fdb78LU, 0xeaa0dc90LU, 0x310e1ac8LU, 0xaa93d20dLU, 0x713d1455LU, 0x518213bdLU, 0x8a2cd5e5LU, +0x2af5ce7aLU, 0xf15b0822LU, 0xd1e40fcaLU, 0x0a4ac992LU, 0x91d70157LU, 0x4a79c70fLU, 0x6ac6c0e7LU, 0xb16806bfLU, +0x8b646db1LU, 0x50caabe9LU, 0x7075ac01LU, 0xabdb6a59LU, 0x3046a29cLU, 0xebe864c4LU, 0xcb57632cLU, 0x10f9a574LU, +0xb020beebLU, 0x6b8e78b3LU, 0x4b317f5bLU, 0x909fb903LU, 0x0b0271c6LU, 0xd0acb79eLU, 0xf013b076LU, 0x2bbd762eLU, +0xfdec8605LU, 0x2642405dLU, 0x06fd47b5LU, 0xdd5381edLU, 0x46ce4928LU, 0x9d608f70LU, 0xbddf8898LU, 0x66714ec0LU, +0xc6a8555fLU, 0x1d069307LU, 0x3db994efLU, 0xe61752b7LU, 0x7d8a9a72LU, 0xa6245c2aLU, 0x869b5bc2LU, 0x5d359d9aLU, +0xf2838ddeLU, 0x292d4b86LU, 0x09924c6eLU, 0xd23c8a36LU, 0x49a142f3LU, 0x920f84abLU, 0xb2b08343LU, 0x691e451bLU, +0xc9c75e84LU, 0x126998dcLU, 0x32d69f34LU, 0xe978596cLU, 0x72e591a9LU, 0xa94b57f1LU, 0x89f45019LU, 0x525a9641LU, +0x840b666aLU, 0x5fa5a032LU, 0x7f1aa7daLU, 0xa4b46182LU, 0x3f29a947LU, 0xe4876f1fLU, 0xc43868f7LU, 0x1f96aeafLU, +0xbf4fb530LU, 0x64e17368LU, 0x445e7480LU, 0x9ff0b2d8LU, 0x046d7a1dLU, 0xdfc3bc45LU, 0xff7cbbadLU, 0x24d27df5LU, +0x1ede16fbLU, 0xc570d0a3LU, 0xe5cfd74bLU, 0x3e611113LU, 0xa5fcd9d6LU, 0x7e521f8eLU, 0x5eed1866LU, 0x8543de3eLU, +0x259ac5a1LU, 0xfe3403f9LU, 0xde8b0411LU, 0x0525c249LU, 0x9eb80a8cLU, 0x4516ccd4LU, 0x65a9cb3cLU, 0xbe070d64LU, +0x6856fd4fLU, 0xb3f83b17LU, 0x93473cffLU, 0x48e9faa7LU, 0xd3743262LU, 0x08daf43aLU, 0x2865f3d2LU, 0xf3cb358aLU, +0x53122e15LU, 0x88bce84dLU, 0xa803efa5LU, 0x73ad29fdLU, 0xe830e138LU, 0x339e2760LU, 0x13212088LU, 0xc88fe6d0LU }; + +static const ulong32 rs_tab6[256] = { +0x00000000LU, 0x9e3d68dbLU, 0x717ad0fbLU, 0xef47b820LU, 0xe2f4edbbLU, 0x7cc98560LU, 0x938e3d40LU, 0x0db3559bLU, +0x89a5973bLU, 0x1798ffe0LU, 0xf8df47c0LU, 0x66e22f1bLU, 0x6b517a80LU, 0xf56c125bLU, 0x1a2baa7bLU, 0x8416c2a0LU, +0x5f076376LU, 0xc13a0badLU, 0x2e7db38dLU, 0xb040db56LU, 0xbdf38ecdLU, 0x23cee616LU, 0xcc895e36LU, 0x52b436edLU, +0xd6a2f44dLU, 0x489f9c96LU, 0xa7d824b6LU, 0x39e54c6dLU, 0x345619f6LU, 0xaa6b712dLU, 0x452cc90dLU, 0xdb11a1d6LU, +0xbe0ec6ecLU, 0x2033ae37LU, 0xcf741617LU, 0x51497eccLU, 0x5cfa2b57LU, 0xc2c7438cLU, 0x2d80fbacLU, 0xb3bd9377LU, +0x37ab51d7LU, 0xa996390cLU, 0x46d1812cLU, 0xd8ece9f7LU, 0xd55fbc6cLU, 0x4b62d4b7LU, 0xa4256c97LU, 0x3a18044cLU, +0xe109a59aLU, 0x7f34cd41LU, 0x90737561LU, 0x0e4e1dbaLU, 0x03fd4821LU, 0x9dc020faLU, 0x728798daLU, 0xecbaf001LU, +0x68ac32a1LU, 0xf6915a7aLU, 0x19d6e25aLU, 0x87eb8a81LU, 0x8a58df1aLU, 0x1465b7c1LU, 0xfb220fe1LU, 0x651f673aLU, +0x311cc195LU, 0xaf21a94eLU, 0x4066116eLU, 0xde5b79b5LU, 0xd3e82c2eLU, 0x4dd544f5LU, 0xa292fcd5LU, 0x3caf940eLU, +0xb8b956aeLU, 0x26843e75LU, 0xc9c38655LU, 0x57feee8eLU, 0x5a4dbb15LU, 0xc470d3ceLU, 0x2b376beeLU, 0xb50a0335LU, +0x6e1ba2e3LU, 0xf026ca38LU, 0x1f617218LU, 0x815c1ac3LU, 0x8cef4f58LU, 0x12d22783LU, 0xfd959fa3LU, 0x63a8f778LU, +0xe7be35d8LU, 0x79835d03LU, 0x96c4e523LU, 0x08f98df8LU, 0x054ad863LU, 0x9b77b0b8LU, 0x74300898LU, 0xea0d6043LU, +0x8f120779LU, 0x112f6fa2LU, 0xfe68d782LU, 0x6055bf59LU, 0x6de6eac2LU, 0xf3db8219LU, 0x1c9c3a39LU, 0x82a152e2LU, +0x06b79042LU, 0x988af899LU, 0x77cd40b9LU, 0xe9f02862LU, 0xe4437df9LU, 0x7a7e1522LU, 0x9539ad02LU, 0x0b04c5d9LU, +0xd015640fLU, 0x4e280cd4LU, 0xa16fb4f4LU, 0x3f52dc2fLU, 0x32e189b4LU, 0xacdce16fLU, 0x439b594fLU, 0xdda63194LU, +0x59b0f334LU, 0xc78d9befLU, 0x28ca23cfLU, 0xb6f74b14LU, 0xbb441e8fLU, 0x25797654LU, 0xca3ece74LU, 0x5403a6afLU, +0x6238cf67LU, 0xfc05a7bcLU, 0x13421f9cLU, 0x8d7f7747LU, 0x80cc22dcLU, 0x1ef14a07LU, 0xf1b6f227LU, 0x6f8b9afcLU, +0xeb9d585cLU, 0x75a03087LU, 0x9ae788a7LU, 0x04dae07cLU, 0x0969b5e7LU, 0x9754dd3cLU, 0x7813651cLU, 0xe62e0dc7LU, +0x3d3fac11LU, 0xa302c4caLU, 0x4c457ceaLU, 0xd2781431LU, 0xdfcb41aaLU, 0x41f62971LU, 0xaeb19151LU, 0x308cf98aLU, +0xb49a3b2aLU, 0x2aa753f1LU, 0xc5e0ebd1LU, 0x5bdd830aLU, 0x566ed691LU, 0xc853be4aLU, 0x2714066aLU, 0xb9296eb1LU, +0xdc36098bLU, 0x420b6150LU, 0xad4cd970LU, 0x3371b1abLU, 0x3ec2e430LU, 0xa0ff8cebLU, 0x4fb834cbLU, 0xd1855c10LU, +0x55939eb0LU, 0xcbaef66bLU, 0x24e94e4bLU, 0xbad42690LU, 0xb767730bLU, 0x295a1bd0LU, 0xc61da3f0LU, 0x5820cb2bLU, +0x83316afdLU, 0x1d0c0226LU, 0xf24bba06LU, 0x6c76d2ddLU, 0x61c58746LU, 0xfff8ef9dLU, 0x10bf57bdLU, 0x8e823f66LU, +0x0a94fdc6LU, 0x94a9951dLU, 0x7bee2d3dLU, 0xe5d345e6LU, 0xe860107dLU, 0x765d78a6LU, 0x991ac086LU, 0x0727a85dLU, +0x53240ef2LU, 0xcd196629LU, 0x225ede09LU, 0xbc63b6d2LU, 0xb1d0e349LU, 0x2fed8b92LU, 0xc0aa33b2LU, 0x5e975b69LU, +0xda8199c9LU, 0x44bcf112LU, 0xabfb4932LU, 0x35c621e9LU, 0x38757472LU, 0xa6481ca9LU, 0x490fa489LU, 0xd732cc52LU, +0x0c236d84LU, 0x921e055fLU, 0x7d59bd7fLU, 0xe364d5a4LU, 0xeed7803fLU, 0x70eae8e4LU, 0x9fad50c4LU, 0x0190381fLU, +0x8586fabfLU, 0x1bbb9264LU, 0xf4fc2a44LU, 0x6ac1429fLU, 0x67721704LU, 0xf94f7fdfLU, 0x1608c7ffLU, 0x8835af24LU, +0xed2ac81eLU, 0x7317a0c5LU, 0x9c5018e5LU, 0x026d703eLU, 0x0fde25a5LU, 0x91e34d7eLU, 0x7ea4f55eLU, 0xe0999d85LU, +0x648f5f25LU, 0xfab237feLU, 0x15f58fdeLU, 0x8bc8e705LU, 0x867bb29eLU, 0x1846da45LU, 0xf7016265LU, 0x693c0abeLU, +0xb22dab68LU, 0x2c10c3b3LU, 0xc3577b93LU, 0x5d6a1348LU, 0x50d946d3LU, 0xcee42e08LU, 0x21a39628LU, 0xbf9efef3LU, +0x3b883c53LU, 0xa5b55488LU, 0x4af2eca8LU, 0xd4cf8473LU, 0xd97cd1e8LU, 0x4741b933LU, 0xa8060113LU, 0x363b69c8LU }; + +static const ulong32 rs_tab7[256] = { +0x00000000LU, 0x0319e59eLU, 0x06328771LU, 0x052b62efLU, 0x0c6443e2LU, 0x0f7da67cLU, 0x0a56c493LU, 0x094f210dLU, +0x18c88689LU, 0x1bd16317LU, 0x1efa01f8LU, 0x1de3e466LU, 0x14acc56bLU, 0x17b520f5LU, 0x129e421aLU, 0x1187a784LU, +0x30dd415fLU, 0x33c4a4c1LU, 0x36efc62eLU, 0x35f623b0LU, 0x3cb902bdLU, 0x3fa0e723LU, 0x3a8b85ccLU, 0x39926052LU, +0x2815c7d6LU, 0x2b0c2248LU, 0x2e2740a7LU, 0x2d3ea539LU, 0x24718434LU, 0x276861aaLU, 0x22430345LU, 0x215ae6dbLU, +0x60f782beLU, 0x63ee6720LU, 0x66c505cfLU, 0x65dce051LU, 0x6c93c15cLU, 0x6f8a24c2LU, 0x6aa1462dLU, 0x69b8a3b3LU, +0x783f0437LU, 0x7b26e1a9LU, 0x7e0d8346LU, 0x7d1466d8LU, 0x745b47d5LU, 0x7742a24bLU, 0x7269c0a4LU, 0x7170253aLU, +0x502ac3e1LU, 0x5333267fLU, 0x56184490LU, 0x5501a10eLU, 0x5c4e8003LU, 0x5f57659dLU, 0x5a7c0772LU, 0x5965e2ecLU, +0x48e24568LU, 0x4bfba0f6LU, 0x4ed0c219LU, 0x4dc92787LU, 0x4486068aLU, 0x479fe314LU, 0x42b481fbLU, 0x41ad6465LU, +0xc0a34931LU, 0xc3baacafLU, 0xc691ce40LU, 0xc5882bdeLU, 0xccc70ad3LU, 0xcfdeef4dLU, 0xcaf58da2LU, 0xc9ec683cLU, +0xd86bcfb8LU, 0xdb722a26LU, 0xde5948c9LU, 0xdd40ad57LU, 0xd40f8c5aLU, 0xd71669c4LU, 0xd23d0b2bLU, 0xd124eeb5LU, +0xf07e086eLU, 0xf367edf0LU, 0xf64c8f1fLU, 0xf5556a81LU, 0xfc1a4b8cLU, 0xff03ae12LU, 0xfa28ccfdLU, 0xf9312963LU, +0xe8b68ee7LU, 0xebaf6b79LU, 0xee840996LU, 0xed9dec08LU, 0xe4d2cd05LU, 0xe7cb289bLU, 0xe2e04a74LU, 0xe1f9afeaLU, +0xa054cb8fLU, 0xa34d2e11LU, 0xa6664cfeLU, 0xa57fa960LU, 0xac30886dLU, 0xaf296df3LU, 0xaa020f1cLU, 0xa91bea82LU, +0xb89c4d06LU, 0xbb85a898LU, 0xbeaeca77LU, 0xbdb72fe9LU, 0xb4f80ee4LU, 0xb7e1eb7aLU, 0xb2ca8995LU, 0xb1d36c0bLU, +0x90898ad0LU, 0x93906f4eLU, 0x96bb0da1LU, 0x95a2e83fLU, 0x9cedc932LU, 0x9ff42cacLU, 0x9adf4e43LU, 0x99c6abddLU, +0x88410c59LU, 0x8b58e9c7LU, 0x8e738b28LU, 0x8d6a6eb6LU, 0x84254fbbLU, 0x873caa25LU, 0x8217c8caLU, 0x810e2d54LU, +0xcd0b9262LU, 0xce1277fcLU, 0xcb391513LU, 0xc820f08dLU, 0xc16fd180LU, 0xc276341eLU, 0xc75d56f1LU, 0xc444b36fLU, +0xd5c314ebLU, 0xd6daf175LU, 0xd3f1939aLU, 0xd0e87604LU, 0xd9a75709LU, 0xdabeb297LU, 0xdf95d078LU, 0xdc8c35e6LU, +0xfdd6d33dLU, 0xfecf36a3LU, 0xfbe4544cLU, 0xf8fdb1d2LU, 0xf1b290dfLU, 0xf2ab7541LU, 0xf78017aeLU, 0xf499f230LU, +0xe51e55b4LU, 0xe607b02aLU, 0xe32cd2c5LU, 0xe035375bLU, 0xe97a1656LU, 0xea63f3c8LU, 0xef489127LU, 0xec5174b9LU, +0xadfc10dcLU, 0xaee5f542LU, 0xabce97adLU, 0xa8d77233LU, 0xa198533eLU, 0xa281b6a0LU, 0xa7aad44fLU, 0xa4b331d1LU, +0xb5349655LU, 0xb62d73cbLU, 0xb3061124LU, 0xb01ff4baLU, 0xb950d5b7LU, 0xba493029LU, 0xbf6252c6LU, 0xbc7bb758LU, +0x9d215183LU, 0x9e38b41dLU, 0x9b13d6f2LU, 0x980a336cLU, 0x91451261LU, 0x925cf7ffLU, 0x97779510LU, 0x946e708eLU, +0x85e9d70aLU, 0x86f03294LU, 0x83db507bLU, 0x80c2b5e5LU, 0x898d94e8LU, 0x8a947176LU, 0x8fbf1399LU, 0x8ca6f607LU, +0x0da8db53LU, 0x0eb13ecdLU, 0x0b9a5c22LU, 0x0883b9bcLU, 0x01cc98b1LU, 0x02d57d2fLU, 0x07fe1fc0LU, 0x04e7fa5eLU, +0x15605ddaLU, 0x1679b844LU, 0x1352daabLU, 0x104b3f35LU, 0x19041e38LU, 0x1a1dfba6LU, 0x1f369949LU, 0x1c2f7cd7LU, +0x3d759a0cLU, 0x3e6c7f92LU, 0x3b471d7dLU, 0x385ef8e3LU, 0x3111d9eeLU, 0x32083c70LU, 0x37235e9fLU, 0x343abb01LU, +0x25bd1c85LU, 0x26a4f91bLU, 0x238f9bf4LU, 0x20967e6aLU, 0x29d95f67LU, 0x2ac0baf9LU, 0x2febd816LU, 0x2cf23d88LU, +0x6d5f59edLU, 0x6e46bc73LU, 0x6b6dde9cLU, 0x68743b02LU, 0x613b1a0fLU, 0x6222ff91LU, 0x67099d7eLU, 0x641078e0LU, +0x7597df64LU, 0x768e3afaLU, 0x73a55815LU, 0x70bcbd8bLU, 0x79f39c86LU, 0x7aea7918LU, 0x7fc11bf7LU, 0x7cd8fe69LU, +0x5d8218b2LU, 0x5e9bfd2cLU, 0x5bb09fc3LU, 0x58a97a5dLU, 0x51e65b50LU, 0x52ffbeceLU, 0x57d4dc21LU, 0x54cd39bfLU, +0x454a9e3bLU, 0x46537ba5LU, 0x4378194aLU, 0x4061fcd4LU, 0x492eddd9LU, 0x4a373847LU, 0x4f1c5aa8LU, 0x4c05bf36LU }; + +#endif /* TWOFISH_ALL_TABLES */ + +#endif diff --git a/whirl.c b/whirl.c new file mode 100644 index 0000000..72b81cc --- /dev/null +++ b/whirl.c @@ -0,0 +1,275 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* WHIRLPOOL (using their new sbox) hash function by Tom St Denis */ + +#include "mycrypt.h" + +#ifdef WHIRLPOOL + +const struct _hash_descriptor whirlpool_desc = +{ + "whirlpool", + 11, + 64, + 64, + &whirlpool_init, + &whirlpool_process, + &whirlpool_done, + &whirlpool_test +}; + +/* the sboxes */ +#include "whirltab.c" + +/* get a_{i,j} */ +#define GB(a,i,j) ((a[(i) & 7] >> (8 * (j))) & 255) + +/* shortcut macro to perform three functions at once */ +#define theta_pi_gamma(a, i) \ + SB0(GB(a, i-0, 7)) ^ \ + SB1(GB(a, i-1, 6)) ^ \ + SB2(GB(a, i-2, 5)) ^ \ + SB3(GB(a, i-3, 4)) ^ \ + SB4(GB(a, i-4, 3)) ^ \ + SB5(GB(a, i-5, 2)) ^ \ + SB6(GB(a, i-6, 1)) ^ \ + SB7(GB(a, i-7, 0)) + +#ifdef CLEAN_STACK +static void _whirlpool_compress(hash_state *md, unsigned char *buf) +#else +static void whirlpool_compress(hash_state *md, unsigned char *buf) +#endif +{ + ulong64 K[2][8], T[3][8]; + int x, y; + + /* load the block/state */ + for (x = 0; x < 8; x++) { + K[0][x] = md->whirlpool.state[x]; + + LOAD64H(T[0][x], buf + (8 * x)); + T[2][x] = T[0][x]; + T[0][x] ^= K[0][x]; + } + + /* do rounds 1..10 */ + for (x = 0; x < 10; x += 2) { + /* odd round */ + /* apply main transform to K[0] into K[1] */ + for (y = 0; y < 8; y++) { + K[1][y] = theta_pi_gamma(K[0], y); + } + /* xor the constant */ + K[1][0] ^= cont[x]; + + /* apply main transform to T[0] into T[1] */ + for (y = 0; y < 8; y++) { + T[1][y] = theta_pi_gamma(T[0], y) ^ K[1][y]; + } + + /* even round */ + /* apply main transform to K[1] into K[0] */ + for (y = 0; y < 8; y++) { + K[0][y] = theta_pi_gamma(K[1], y); + } + /* xor the constant */ + K[0][0] ^= cont[x+1]; + + /* apply main transform to T[0] into T[1] */ + for (y = 0; y < 8; y++) { + T[0][y] = theta_pi_gamma(T[1], y) ^ K[0][y]; + } + } + + /* store state */ + for (x = 0; x < 8; x++) { + md->whirlpool.state[x] ^= T[0][x] ^ T[2][x]; + } +} + + +#ifdef CLEAN_STACK +static void whirlpool_compress(hash_state *md, unsigned char *buf) +{ + _whirlpool_compress(md, buf); + burn_stack((5 * 8 * sizeof(ulong64)) + (2 * sizeof(int))); +} +#endif + + +void whirlpool_init(hash_state * md) +{ + _ARGCHK(md != NULL); + zeromem(&md->whirlpool, sizeof(md->whirlpool)); +} + +HASH_PROCESS(whirlpool_process, whirlpool_compress, whirlpool, 64) + +int whirlpool_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->whirlpool.curlen >= sizeof(md->whirlpool.buf)) { + return CRYPT_INVALID_ARG; + } + + /* increase the length of the message */ + md->whirlpool.length += md->whirlpool.curlen * 8; + + /* append the '1' bit */ + md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0x80; + + /* if the length is currently above 32 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->whirlpool.curlen > 32) { + while (md->whirlpool.curlen < 64) { + md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0; + } + whirlpool_compress(md, md->whirlpool.buf); + md->whirlpool.curlen = 0; + } + + /* pad upto 56 bytes of zeroes (should be 32 but we only support 64-bit lengths) */ + while (md->whirlpool.curlen < 56) { + md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64H(md->whirlpool.length, md->whirlpool.buf+56); + whirlpool_compress(md, md->whirlpool.buf); + + /* copy output */ + for (i = 0; i < 8; i++) { + STORE64H(md->whirlpool.state[i], hash+(8*i)); + } +#ifdef CLEAN_STACK + zeromem(md, sizeof(*md)); +#endif + return CRYPT_OK; +} + + +int whirlpool_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + int len; + unsigned char msg[128], hash[64]; + } tests[] = { + + /* NULL Message */ +{ + 0, + { 0x00 }, + { 0x19, 0xFA, 0x61, 0xD7, 0x55, 0x22, 0xA4, 0x66, 0x9B, 0x44, 0xE3, 0x9C, 0x1D, 0x2E, 0x17, 0x26, + 0xC5, 0x30, 0x23, 0x21, 0x30, 0xD4, 0x07, 0xF8, 0x9A, 0xFE, 0xE0, 0x96, 0x49, 0x97, 0xF7, 0xA7, + 0x3E, 0x83, 0xBE, 0x69, 0x8B, 0x28, 0x8F, 0xEB, 0xCF, 0x88, 0xE3, 0xE0, 0x3C, 0x4F, 0x07, 0x57, + 0xEA, 0x89, 0x64, 0xE5, 0x9B, 0x63, 0xD9, 0x37, 0x08, 0xB1, 0x38, 0xCC, 0x42, 0xA6, 0x6E, 0xB3 } +}, + + + /* 448-bits of 0 bits */ +{ + + 56, + { 0x00 }, + { 0x0B, 0x3F, 0x53, 0x78, 0xEB, 0xED, 0x2B, 0xF4, 0xD7, 0xBE, 0x3C, 0xFD, 0x81, 0x8C, 0x1B, 0x03, + 0xB6, 0xBB, 0x03, 0xD3, 0x46, 0x94, 0x8B, 0x04, 0xF4, 0xF4, 0x0C, 0x72, 0x6F, 0x07, 0x58, 0x70, + 0x2A, 0x0F, 0x1E, 0x22, 0x58, 0x80, 0xE3, 0x8D, 0xD5, 0xF6, 0xED, 0x6D, 0xE9, 0xB1, 0xE9, 0x61, + 0xE4, 0x9F, 0xC1, 0x31, 0x8D, 0x7C, 0xB7, 0x48, 0x22, 0xF3, 0xD0, 0xE2, 0xE9, 0xA7, 0xE7, 0xB0 } +}, + + /* 520-bits of 0 bits */ +{ + 65, + { 0x00 }, + { 0x85, 0xE1, 0x24, 0xC4, 0x41, 0x5B, 0xCF, 0x43, 0x19, 0x54, 0x3E, 0x3A, 0x63, 0xFF, 0x57, 0x1D, + 0x09, 0x35, 0x4C, 0xEE, 0xBE, 0xE1, 0xE3, 0x25, 0x30, 0x8C, 0x90, 0x69, 0xF4, 0x3E, 0x2A, 0xE4, + 0xD0, 0xE5, 0x1D, 0x4E, 0xB1, 0xE8, 0x64, 0x28, 0x70, 0x19, 0x4E, 0x95, 0x30, 0xD8, 0xD8, 0xAF, + 0x65, 0x89, 0xD1, 0xBF, 0x69, 0x49, 0xDD, 0xF9, 0x0A, 0x7F, 0x12, 0x08, 0x62, 0x37, 0x95, 0xB9 } +}, + + /* 512-bits, leading set */ +{ + 64, + { 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, 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 }, + { 0x10, 0x3E, 0x00, 0x55, 0xA9, 0xB0, 0x90, 0xE1, 0x1C, 0x8F, 0xDD, 0xEB, 0xBA, 0x06, 0xC0, 0x5A, + 0xCE, 0x8B, 0x64, 0xB8, 0x96, 0x12, 0x8F, 0x6E, 0xED, 0x30, 0x71, 0xFC, 0xF3, 0xDC, 0x16, 0x94, + 0x67, 0x78, 0xE0, 0x72, 0x23, 0x23, 0x3F, 0xD1, 0x80, 0xFC, 0x40, 0xCC, 0xDB, 0x84, 0x30, 0xA6, + 0x40, 0xE3, 0x76, 0x34, 0x27, 0x1E, 0x65, 0x5C, 0xA1, 0x67, 0x4E, 0xBF, 0xF5, 0x07, 0xF8, 0xCB } +}, + + /* 512-bits, leading set of second byte */ +{ + 64, + { 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, 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 }, + { 0x35, 0x7B, 0x42, 0xEA, 0x79, 0xBC, 0x97, 0x86, 0x97, 0x5A, 0x3C, 0x44, 0x70, 0xAA, 0xB2, 0x3E, + 0x62, 0x29, 0x79, 0x7B, 0xAD, 0xBD, 0x54, 0x36, 0x5B, 0x54, 0x96, 0xE5, 0x5D, 0x9D, 0xD7, 0x9F, + 0xE9, 0x62, 0x4F, 0xB4, 0x22, 0x66, 0x93, 0x0A, 0x62, 0x8E, 0xD4, 0xDB, 0x08, 0xF9, 0xDD, 0x35, + 0xEF, 0x1B, 0xE1, 0x04, 0x53, 0xFC, 0x18, 0xF4, 0x2C, 0x7F, 0x5E, 0x1F, 0x9B, 0xAE, 0x55, 0xE0 } +}, + + /* 512-bits, leading set of last byte */ +{ + 64, + { 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, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, + { 0x8B, 0x39, 0x04, 0xDD, 0x19, 0x81, 0x41, 0x26, 0xFD, 0x02, 0x74, 0xAB, 0x49, 0xC5, 0x97, 0xF6, + 0xD7, 0x75, 0x33, 0x52, 0xA2, 0xDD, 0x91, 0xFD, 0x8F, 0x9F, 0x54, 0x05, 0x4C, 0x54, 0xBF, 0x0F, + 0x06, 0xDB, 0x4F, 0xF7, 0x08, 0xA3, 0xA2, 0x8B, 0xC3, 0x7A, 0x92, 0x1E, 0xEE, 0x11, 0xED, 0x7B, + 0x6A, 0x53, 0x79, 0x32, 0xCC, 0x5E, 0x94, 0xEE, 0x1E, 0xA6, 0x57, 0x60, 0x7E, 0x36, 0xC9, 0xF7 } +}, + +}; + + int i; + unsigned char tmp[64]; + hash_state md; + + for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) { + whirlpool_init(&md); + whirlpool_process(&md, (unsigned char *)tests[i].msg, tests[i].len); + whirlpool_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 64) != 0) { +#if 0 + printf("\nFailed test %d\n", i); + for (i = 0; i < 64; ) { + printf("%02x ", tmp[i]); + if (!(++i & 15)) printf("\n"); + } +#endif + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + + +#endif + diff --git a/whirltab.c b/whirltab.c new file mode 100644 index 0000000..031c643 --- /dev/null +++ b/whirltab.c @@ -0,0 +1,575 @@ +static const ulong64 sbox0[] = { +CONST64(0x18186018c07830d8), CONST64(0x23238c2305af4626), CONST64(0xc6c63fc67ef991b8), CONST64(0xe8e887e8136fcdfb), +CONST64(0x878726874ca113cb), CONST64(0xb8b8dab8a9626d11), CONST64(0x0101040108050209), CONST64(0x4f4f214f426e9e0d), +CONST64(0x3636d836adee6c9b), CONST64(0xa6a6a2a6590451ff), CONST64(0xd2d26fd2debdb90c), CONST64(0xf5f5f3f5fb06f70e), +CONST64(0x7979f979ef80f296), CONST64(0x6f6fa16f5fcede30), CONST64(0x91917e91fcef3f6d), CONST64(0x52525552aa07a4f8), +CONST64(0x60609d6027fdc047), CONST64(0xbcbccabc89766535), CONST64(0x9b9b569baccd2b37), CONST64(0x8e8e028e048c018a), +CONST64(0xa3a3b6a371155bd2), CONST64(0x0c0c300c603c186c), CONST64(0x7b7bf17bff8af684), CONST64(0x3535d435b5e16a80), +CONST64(0x1d1d741de8693af5), CONST64(0xe0e0a7e05347ddb3), CONST64(0xd7d77bd7f6acb321), CONST64(0xc2c22fc25eed999c), +CONST64(0x2e2eb82e6d965c43), CONST64(0x4b4b314b627a9629), CONST64(0xfefedffea321e15d), CONST64(0x575741578216aed5), +CONST64(0x15155415a8412abd), CONST64(0x7777c1779fb6eee8), CONST64(0x3737dc37a5eb6e92), CONST64(0xe5e5b3e57b56d79e), +CONST64(0x9f9f469f8cd92313), CONST64(0xf0f0e7f0d317fd23), CONST64(0x4a4a354a6a7f9420), CONST64(0xdada4fda9e95a944), +CONST64(0x58587d58fa25b0a2), CONST64(0xc9c903c906ca8fcf), CONST64(0x2929a429558d527c), CONST64(0x0a0a280a5022145a), +CONST64(0xb1b1feb1e14f7f50), CONST64(0xa0a0baa0691a5dc9), CONST64(0x6b6bb16b7fdad614), CONST64(0x85852e855cab17d9), +CONST64(0xbdbdcebd8173673c), CONST64(0x5d5d695dd234ba8f), CONST64(0x1010401080502090), CONST64(0xf4f4f7f4f303f507), +CONST64(0xcbcb0bcb16c08bdd), CONST64(0x3e3ef83eedc67cd3), CONST64(0x0505140528110a2d), CONST64(0x676781671fe6ce78), +CONST64(0xe4e4b7e47353d597), CONST64(0x27279c2725bb4e02), CONST64(0x4141194132588273), CONST64(0x8b8b168b2c9d0ba7), +CONST64(0xa7a7a6a7510153f6), CONST64(0x7d7de97dcf94fab2), CONST64(0x95956e95dcfb3749), CONST64(0xd8d847d88e9fad56), +CONST64(0xfbfbcbfb8b30eb70), CONST64(0xeeee9fee2371c1cd), CONST64(0x7c7ced7cc791f8bb), CONST64(0x6666856617e3cc71), +CONST64(0xdddd53dda68ea77b), CONST64(0x17175c17b84b2eaf), CONST64(0x4747014702468e45), CONST64(0x9e9e429e84dc211a), +CONST64(0xcaca0fca1ec589d4), CONST64(0x2d2db42d75995a58), CONST64(0xbfbfc6bf9179632e), CONST64(0x07071c07381b0e3f), +CONST64(0xadad8ead012347ac), CONST64(0x5a5a755aea2fb4b0), CONST64(0x838336836cb51bef), CONST64(0x3333cc3385ff66b6), +CONST64(0x636391633ff2c65c), CONST64(0x02020802100a0412), CONST64(0xaaaa92aa39384993), CONST64(0x7171d971afa8e2de), +CONST64(0xc8c807c80ecf8dc6), CONST64(0x19196419c87d32d1), CONST64(0x494939497270923b), CONST64(0xd9d943d9869aaf5f), +CONST64(0xf2f2eff2c31df931), CONST64(0xe3e3abe34b48dba8), CONST64(0x5b5b715be22ab6b9), CONST64(0x88881a8834920dbc), +CONST64(0x9a9a529aa4c8293e), CONST64(0x262698262dbe4c0b), CONST64(0x3232c8328dfa64bf), CONST64(0xb0b0fab0e94a7d59), +CONST64(0xe9e983e91b6acff2), CONST64(0x0f0f3c0f78331e77), CONST64(0xd5d573d5e6a6b733), CONST64(0x80803a8074ba1df4), +CONST64(0xbebec2be997c6127), CONST64(0xcdcd13cd26de87eb), CONST64(0x3434d034bde46889), CONST64(0x48483d487a759032), +CONST64(0xffffdbffab24e354), CONST64(0x7a7af57af78ff48d), CONST64(0x90907a90f4ea3d64), CONST64(0x5f5f615fc23ebe9d), +CONST64(0x202080201da0403d), CONST64(0x6868bd6867d5d00f), CONST64(0x1a1a681ad07234ca), CONST64(0xaeae82ae192c41b7), +CONST64(0xb4b4eab4c95e757d), CONST64(0x54544d549a19a8ce), CONST64(0x93937693ece53b7f), CONST64(0x222288220daa442f), +CONST64(0x64648d6407e9c863), CONST64(0xf1f1e3f1db12ff2a), CONST64(0x7373d173bfa2e6cc), CONST64(0x12124812905a2482), +CONST64(0x40401d403a5d807a), CONST64(0x0808200840281048), CONST64(0xc3c32bc356e89b95), CONST64(0xecec97ec337bc5df), +CONST64(0xdbdb4bdb9690ab4d), CONST64(0xa1a1bea1611f5fc0), CONST64(0x8d8d0e8d1c830791), CONST64(0x3d3df43df5c97ac8), +CONST64(0x97976697ccf1335b), CONST64(0x0000000000000000), CONST64(0xcfcf1bcf36d483f9), CONST64(0x2b2bac2b4587566e), +CONST64(0x7676c57697b3ece1), CONST64(0x8282328264b019e6), CONST64(0xd6d67fd6fea9b128), CONST64(0x1b1b6c1bd87736c3), +CONST64(0xb5b5eeb5c15b7774), CONST64(0xafaf86af112943be), CONST64(0x6a6ab56a77dfd41d), CONST64(0x50505d50ba0da0ea), +CONST64(0x45450945124c8a57), CONST64(0xf3f3ebf3cb18fb38), CONST64(0x3030c0309df060ad), CONST64(0xefef9bef2b74c3c4), +CONST64(0x3f3ffc3fe5c37eda), CONST64(0x55554955921caac7), CONST64(0xa2a2b2a2791059db), CONST64(0xeaea8fea0365c9e9), +CONST64(0x656589650fecca6a), CONST64(0xbabad2bab9686903), CONST64(0x2f2fbc2f65935e4a), CONST64(0xc0c027c04ee79d8e), +CONST64(0xdede5fdebe81a160), CONST64(0x1c1c701ce06c38fc), CONST64(0xfdfdd3fdbb2ee746), CONST64(0x4d4d294d52649a1f), +CONST64(0x92927292e4e03976), CONST64(0x7575c9758fbceafa), CONST64(0x06061806301e0c36), CONST64(0x8a8a128a249809ae), +CONST64(0xb2b2f2b2f940794b), CONST64(0xe6e6bfe66359d185), CONST64(0x0e0e380e70361c7e), CONST64(0x1f1f7c1ff8633ee7), +CONST64(0x6262956237f7c455), CONST64(0xd4d477d4eea3b53a), CONST64(0xa8a89aa829324d81), CONST64(0x96966296c4f43152), +CONST64(0xf9f9c3f99b3aef62), CONST64(0xc5c533c566f697a3), CONST64(0x2525942535b14a10), CONST64(0x59597959f220b2ab), +CONST64(0x84842a8454ae15d0), CONST64(0x7272d572b7a7e4c5), CONST64(0x3939e439d5dd72ec), CONST64(0x4c4c2d4c5a619816), +CONST64(0x5e5e655eca3bbc94), CONST64(0x7878fd78e785f09f), CONST64(0x3838e038ddd870e5), CONST64(0x8c8c0a8c14860598), +CONST64(0xd1d163d1c6b2bf17), CONST64(0xa5a5aea5410b57e4), CONST64(0xe2e2afe2434dd9a1), CONST64(0x616199612ff8c24e), +CONST64(0xb3b3f6b3f1457b42), CONST64(0x2121842115a54234), CONST64(0x9c9c4a9c94d62508), CONST64(0x1e1e781ef0663cee), +CONST64(0x4343114322528661), CONST64(0xc7c73bc776fc93b1), CONST64(0xfcfcd7fcb32be54f), CONST64(0x0404100420140824), +CONST64(0x51515951b208a2e3), CONST64(0x99995e99bcc72f25), CONST64(0x6d6da96d4fc4da22), CONST64(0x0d0d340d68391a65), +CONST64(0xfafacffa8335e979), CONST64(0xdfdf5bdfb684a369), CONST64(0x7e7ee57ed79bfca9), CONST64(0x242490243db44819), +CONST64(0x3b3bec3bc5d776fe), CONST64(0xabab96ab313d4b9a), CONST64(0xcece1fce3ed181f0), CONST64(0x1111441188552299), +CONST64(0x8f8f068f0c890383), CONST64(0x4e4e254e4a6b9c04), CONST64(0xb7b7e6b7d1517366), CONST64(0xebeb8beb0b60cbe0), +CONST64(0x3c3cf03cfdcc78c1), CONST64(0x81813e817cbf1ffd), CONST64(0x94946a94d4fe3540), CONST64(0xf7f7fbf7eb0cf31c), +CONST64(0xb9b9deb9a1676f18), CONST64(0x13134c13985f268b), CONST64(0x2c2cb02c7d9c5851), CONST64(0xd3d36bd3d6b8bb05), +CONST64(0xe7e7bbe76b5cd38c), CONST64(0x6e6ea56e57cbdc39), CONST64(0xc4c437c46ef395aa), CONST64(0x03030c03180f061b), +CONST64(0x565645568a13acdc), CONST64(0x44440d441a49885e), CONST64(0x7f7fe17fdf9efea0), CONST64(0xa9a99ea921374f88), +CONST64(0x2a2aa82a4d825467), CONST64(0xbbbbd6bbb16d6b0a), CONST64(0xc1c123c146e29f87), CONST64(0x53535153a202a6f1), +CONST64(0xdcdc57dcae8ba572), CONST64(0x0b0b2c0b58271653), CONST64(0x9d9d4e9d9cd32701), CONST64(0x6c6cad6c47c1d82b), +CONST64(0x3131c43195f562a4), CONST64(0x7474cd7487b9e8f3), CONST64(0xf6f6fff6e309f115), CONST64(0x464605460a438c4c), +CONST64(0xacac8aac092645a5), CONST64(0x89891e893c970fb5), CONST64(0x14145014a04428b4), CONST64(0xe1e1a3e15b42dfba), +CONST64(0x16165816b04e2ca6), CONST64(0x3a3ae83acdd274f7), CONST64(0x6969b9696fd0d206), CONST64(0x09092409482d1241), +CONST64(0x7070dd70a7ade0d7), CONST64(0xb6b6e2b6d954716f), CONST64(0xd0d067d0ceb7bd1e), CONST64(0xeded93ed3b7ec7d6), +CONST64(0xcccc17cc2edb85e2), CONST64(0x424215422a578468), CONST64(0x98985a98b4c22d2c), CONST64(0xa4a4aaa4490e55ed), +CONST64(0x2828a0285d885075), CONST64(0x5c5c6d5cda31b886), CONST64(0xf8f8c7f8933fed6b), CONST64(0x8686228644a411c2) +}; + +#ifdef SMALL_CODE + +#define SB0(x) sbox0[x] +#define SB1(x) ROR64(sbox0[x], 8) +#define SB2(x) ROR64(sbox0[x], 16) +#define SB3(x) ROR64(sbox0[x], 24) +#define SB4(x) ROR64(sbox0[x], 32) +#define SB5(x) ROR64(sbox0[x], 40) +#define SB6(x) ROR64(sbox0[x], 48) +#define SB7(x) ROR64(sbox0[x], 56) + +#else + +#define SB0(x) sbox0[x] +#define SB1(x) sbox1[x] +#define SB2(x) sbox2[x] +#define SB3(x) sbox3[x] +#define SB4(x) sbox4[x] +#define SB5(x) sbox5[x] +#define SB6(x) sbox6[x] +#define SB7(x) sbox7[x] + + +static const ulong64 sbox1[] = { +CONST64(0xd818186018c07830), CONST64(0x2623238c2305af46), CONST64(0xb8c6c63fc67ef991), CONST64(0xfbe8e887e8136fcd), +CONST64(0xcb878726874ca113), CONST64(0x11b8b8dab8a9626d), CONST64(0x0901010401080502), CONST64(0x0d4f4f214f426e9e), +CONST64(0x9b3636d836adee6c), CONST64(0xffa6a6a2a6590451), CONST64(0x0cd2d26fd2debdb9), CONST64(0x0ef5f5f3f5fb06f7), +CONST64(0x967979f979ef80f2), CONST64(0x306f6fa16f5fcede), CONST64(0x6d91917e91fcef3f), CONST64(0xf852525552aa07a4), +CONST64(0x4760609d6027fdc0), CONST64(0x35bcbccabc897665), CONST64(0x379b9b569baccd2b), CONST64(0x8a8e8e028e048c01), +CONST64(0xd2a3a3b6a371155b), CONST64(0x6c0c0c300c603c18), CONST64(0x847b7bf17bff8af6), CONST64(0x803535d435b5e16a), +CONST64(0xf51d1d741de8693a), CONST64(0xb3e0e0a7e05347dd), CONST64(0x21d7d77bd7f6acb3), CONST64(0x9cc2c22fc25eed99), +CONST64(0x432e2eb82e6d965c), CONST64(0x294b4b314b627a96), CONST64(0x5dfefedffea321e1), CONST64(0xd5575741578216ae), +CONST64(0xbd15155415a8412a), CONST64(0xe87777c1779fb6ee), CONST64(0x923737dc37a5eb6e), CONST64(0x9ee5e5b3e57b56d7), +CONST64(0x139f9f469f8cd923), CONST64(0x23f0f0e7f0d317fd), CONST64(0x204a4a354a6a7f94), CONST64(0x44dada4fda9e95a9), +CONST64(0xa258587d58fa25b0), CONST64(0xcfc9c903c906ca8f), CONST64(0x7c2929a429558d52), CONST64(0x5a0a0a280a502214), +CONST64(0x50b1b1feb1e14f7f), CONST64(0xc9a0a0baa0691a5d), CONST64(0x146b6bb16b7fdad6), CONST64(0xd985852e855cab17), +CONST64(0x3cbdbdcebd817367), CONST64(0x8f5d5d695dd234ba), CONST64(0x9010104010805020), CONST64(0x07f4f4f7f4f303f5), +CONST64(0xddcbcb0bcb16c08b), CONST64(0xd33e3ef83eedc67c), CONST64(0x2d0505140528110a), CONST64(0x78676781671fe6ce), +CONST64(0x97e4e4b7e47353d5), CONST64(0x0227279c2725bb4e), CONST64(0x7341411941325882), CONST64(0xa78b8b168b2c9d0b), +CONST64(0xf6a7a7a6a7510153), CONST64(0xb27d7de97dcf94fa), CONST64(0x4995956e95dcfb37), CONST64(0x56d8d847d88e9fad), +CONST64(0x70fbfbcbfb8b30eb), CONST64(0xcdeeee9fee2371c1), CONST64(0xbb7c7ced7cc791f8), CONST64(0x716666856617e3cc), +CONST64(0x7bdddd53dda68ea7), CONST64(0xaf17175c17b84b2e), CONST64(0x454747014702468e), CONST64(0x1a9e9e429e84dc21), +CONST64(0xd4caca0fca1ec589), CONST64(0x582d2db42d75995a), CONST64(0x2ebfbfc6bf917963), CONST64(0x3f07071c07381b0e), +CONST64(0xacadad8ead012347), CONST64(0xb05a5a755aea2fb4), CONST64(0xef838336836cb51b), CONST64(0xb63333cc3385ff66), +CONST64(0x5c636391633ff2c6), CONST64(0x1202020802100a04), CONST64(0x93aaaa92aa393849), CONST64(0xde7171d971afa8e2), +CONST64(0xc6c8c807c80ecf8d), CONST64(0xd119196419c87d32), CONST64(0x3b49493949727092), CONST64(0x5fd9d943d9869aaf), +CONST64(0x31f2f2eff2c31df9), CONST64(0xa8e3e3abe34b48db), CONST64(0xb95b5b715be22ab6), CONST64(0xbc88881a8834920d), +CONST64(0x3e9a9a529aa4c829), CONST64(0x0b262698262dbe4c), CONST64(0xbf3232c8328dfa64), CONST64(0x59b0b0fab0e94a7d), +CONST64(0xf2e9e983e91b6acf), CONST64(0x770f0f3c0f78331e), CONST64(0x33d5d573d5e6a6b7), CONST64(0xf480803a8074ba1d), +CONST64(0x27bebec2be997c61), CONST64(0xebcdcd13cd26de87), CONST64(0x893434d034bde468), CONST64(0x3248483d487a7590), +CONST64(0x54ffffdbffab24e3), CONST64(0x8d7a7af57af78ff4), CONST64(0x6490907a90f4ea3d), CONST64(0x9d5f5f615fc23ebe), +CONST64(0x3d202080201da040), CONST64(0x0f6868bd6867d5d0), CONST64(0xca1a1a681ad07234), CONST64(0xb7aeae82ae192c41), +CONST64(0x7db4b4eab4c95e75), CONST64(0xce54544d549a19a8), CONST64(0x7f93937693ece53b), CONST64(0x2f222288220daa44), +CONST64(0x6364648d6407e9c8), CONST64(0x2af1f1e3f1db12ff), CONST64(0xcc7373d173bfa2e6), CONST64(0x8212124812905a24), +CONST64(0x7a40401d403a5d80), CONST64(0x4808082008402810), CONST64(0x95c3c32bc356e89b), CONST64(0xdfecec97ec337bc5), +CONST64(0x4ddbdb4bdb9690ab), CONST64(0xc0a1a1bea1611f5f), CONST64(0x918d8d0e8d1c8307), CONST64(0xc83d3df43df5c97a), +CONST64(0x5b97976697ccf133), CONST64(0x0000000000000000), CONST64(0xf9cfcf1bcf36d483), CONST64(0x6e2b2bac2b458756), +CONST64(0xe17676c57697b3ec), CONST64(0xe68282328264b019), CONST64(0x28d6d67fd6fea9b1), CONST64(0xc31b1b6c1bd87736), +CONST64(0x74b5b5eeb5c15b77), CONST64(0xbeafaf86af112943), CONST64(0x1d6a6ab56a77dfd4), CONST64(0xea50505d50ba0da0), +CONST64(0x5745450945124c8a), CONST64(0x38f3f3ebf3cb18fb), CONST64(0xad3030c0309df060), CONST64(0xc4efef9bef2b74c3), +CONST64(0xda3f3ffc3fe5c37e), CONST64(0xc755554955921caa), CONST64(0xdba2a2b2a2791059), CONST64(0xe9eaea8fea0365c9), +CONST64(0x6a656589650fecca), CONST64(0x03babad2bab96869), CONST64(0x4a2f2fbc2f65935e), CONST64(0x8ec0c027c04ee79d), +CONST64(0x60dede5fdebe81a1), CONST64(0xfc1c1c701ce06c38), CONST64(0x46fdfdd3fdbb2ee7), CONST64(0x1f4d4d294d52649a), +CONST64(0x7692927292e4e039), CONST64(0xfa7575c9758fbcea), CONST64(0x3606061806301e0c), CONST64(0xae8a8a128a249809), +CONST64(0x4bb2b2f2b2f94079), CONST64(0x85e6e6bfe66359d1), CONST64(0x7e0e0e380e70361c), CONST64(0xe71f1f7c1ff8633e), +CONST64(0x556262956237f7c4), CONST64(0x3ad4d477d4eea3b5), CONST64(0x81a8a89aa829324d), CONST64(0x5296966296c4f431), +CONST64(0x62f9f9c3f99b3aef), CONST64(0xa3c5c533c566f697), CONST64(0x102525942535b14a), CONST64(0xab59597959f220b2), +CONST64(0xd084842a8454ae15), CONST64(0xc57272d572b7a7e4), CONST64(0xec3939e439d5dd72), CONST64(0x164c4c2d4c5a6198), +CONST64(0x945e5e655eca3bbc), CONST64(0x9f7878fd78e785f0), CONST64(0xe53838e038ddd870), CONST64(0x988c8c0a8c148605), +CONST64(0x17d1d163d1c6b2bf), CONST64(0xe4a5a5aea5410b57), CONST64(0xa1e2e2afe2434dd9), CONST64(0x4e616199612ff8c2), +CONST64(0x42b3b3f6b3f1457b), CONST64(0x342121842115a542), CONST64(0x089c9c4a9c94d625), CONST64(0xee1e1e781ef0663c), +CONST64(0x6143431143225286), CONST64(0xb1c7c73bc776fc93), CONST64(0x4ffcfcd7fcb32be5), CONST64(0x2404041004201408), +CONST64(0xe351515951b208a2), CONST64(0x2599995e99bcc72f), CONST64(0x226d6da96d4fc4da), CONST64(0x650d0d340d68391a), +CONST64(0x79fafacffa8335e9), CONST64(0x69dfdf5bdfb684a3), CONST64(0xa97e7ee57ed79bfc), CONST64(0x19242490243db448), +CONST64(0xfe3b3bec3bc5d776), CONST64(0x9aabab96ab313d4b), CONST64(0xf0cece1fce3ed181), CONST64(0x9911114411885522), +CONST64(0x838f8f068f0c8903), CONST64(0x044e4e254e4a6b9c), CONST64(0x66b7b7e6b7d15173), CONST64(0xe0ebeb8beb0b60cb), +CONST64(0xc13c3cf03cfdcc78), CONST64(0xfd81813e817cbf1f), CONST64(0x4094946a94d4fe35), CONST64(0x1cf7f7fbf7eb0cf3), +CONST64(0x18b9b9deb9a1676f), CONST64(0x8b13134c13985f26), CONST64(0x512c2cb02c7d9c58), CONST64(0x05d3d36bd3d6b8bb), +CONST64(0x8ce7e7bbe76b5cd3), CONST64(0x396e6ea56e57cbdc), CONST64(0xaac4c437c46ef395), CONST64(0x1b03030c03180f06), +CONST64(0xdc565645568a13ac), CONST64(0x5e44440d441a4988), CONST64(0xa07f7fe17fdf9efe), CONST64(0x88a9a99ea921374f), +CONST64(0x672a2aa82a4d8254), CONST64(0x0abbbbd6bbb16d6b), CONST64(0x87c1c123c146e29f), CONST64(0xf153535153a202a6), +CONST64(0x72dcdc57dcae8ba5), CONST64(0x530b0b2c0b582716), CONST64(0x019d9d4e9d9cd327), CONST64(0x2b6c6cad6c47c1d8), +CONST64(0xa43131c43195f562), CONST64(0xf37474cd7487b9e8), CONST64(0x15f6f6fff6e309f1), CONST64(0x4c464605460a438c), +CONST64(0xa5acac8aac092645), CONST64(0xb589891e893c970f), CONST64(0xb414145014a04428), CONST64(0xbae1e1a3e15b42df), +CONST64(0xa616165816b04e2c), CONST64(0xf73a3ae83acdd274), CONST64(0x066969b9696fd0d2), CONST64(0x4109092409482d12), +CONST64(0xd77070dd70a7ade0), CONST64(0x6fb6b6e2b6d95471), CONST64(0x1ed0d067d0ceb7bd), CONST64(0xd6eded93ed3b7ec7), +CONST64(0xe2cccc17cc2edb85), CONST64(0x68424215422a5784), CONST64(0x2c98985a98b4c22d), CONST64(0xeda4a4aaa4490e55), +CONST64(0x752828a0285d8850), CONST64(0x865c5c6d5cda31b8), CONST64(0x6bf8f8c7f8933fed), CONST64(0xc28686228644a411) +}; + +static const ulong64 sbox2[] = { +CONST64(0x30d818186018c078), CONST64(0x462623238c2305af), CONST64(0x91b8c6c63fc67ef9), CONST64(0xcdfbe8e887e8136f), +CONST64(0x13cb878726874ca1), CONST64(0x6d11b8b8dab8a962), CONST64(0x0209010104010805), CONST64(0x9e0d4f4f214f426e), +CONST64(0x6c9b3636d836adee), CONST64(0x51ffa6a6a2a65904), CONST64(0xb90cd2d26fd2debd), CONST64(0xf70ef5f5f3f5fb06), +CONST64(0xf2967979f979ef80), CONST64(0xde306f6fa16f5fce), CONST64(0x3f6d91917e91fcef), CONST64(0xa4f852525552aa07), +CONST64(0xc04760609d6027fd), CONST64(0x6535bcbccabc8976), CONST64(0x2b379b9b569baccd), CONST64(0x018a8e8e028e048c), +CONST64(0x5bd2a3a3b6a37115), CONST64(0x186c0c0c300c603c), CONST64(0xf6847b7bf17bff8a), CONST64(0x6a803535d435b5e1), +CONST64(0x3af51d1d741de869), CONST64(0xddb3e0e0a7e05347), CONST64(0xb321d7d77bd7f6ac), CONST64(0x999cc2c22fc25eed), +CONST64(0x5c432e2eb82e6d96), CONST64(0x96294b4b314b627a), CONST64(0xe15dfefedffea321), CONST64(0xaed5575741578216), +CONST64(0x2abd15155415a841), CONST64(0xeee87777c1779fb6), CONST64(0x6e923737dc37a5eb), CONST64(0xd79ee5e5b3e57b56), +CONST64(0x23139f9f469f8cd9), CONST64(0xfd23f0f0e7f0d317), CONST64(0x94204a4a354a6a7f), CONST64(0xa944dada4fda9e95), +CONST64(0xb0a258587d58fa25), CONST64(0x8fcfc9c903c906ca), CONST64(0x527c2929a429558d), CONST64(0x145a0a0a280a5022), +CONST64(0x7f50b1b1feb1e14f), CONST64(0x5dc9a0a0baa0691a), CONST64(0xd6146b6bb16b7fda), CONST64(0x17d985852e855cab), +CONST64(0x673cbdbdcebd8173), CONST64(0xba8f5d5d695dd234), CONST64(0x2090101040108050), CONST64(0xf507f4f4f7f4f303), +CONST64(0x8bddcbcb0bcb16c0), CONST64(0x7cd33e3ef83eedc6), CONST64(0x0a2d050514052811), CONST64(0xce78676781671fe6), +CONST64(0xd597e4e4b7e47353), CONST64(0x4e0227279c2725bb), CONST64(0x8273414119413258), CONST64(0x0ba78b8b168b2c9d), +CONST64(0x53f6a7a7a6a75101), CONST64(0xfab27d7de97dcf94), CONST64(0x374995956e95dcfb), CONST64(0xad56d8d847d88e9f), +CONST64(0xeb70fbfbcbfb8b30), CONST64(0xc1cdeeee9fee2371), CONST64(0xf8bb7c7ced7cc791), CONST64(0xcc716666856617e3), +CONST64(0xa77bdddd53dda68e), CONST64(0x2eaf17175c17b84b), CONST64(0x8e45474701470246), CONST64(0x211a9e9e429e84dc), +CONST64(0x89d4caca0fca1ec5), CONST64(0x5a582d2db42d7599), CONST64(0x632ebfbfc6bf9179), CONST64(0x0e3f07071c07381b), +CONST64(0x47acadad8ead0123), CONST64(0xb4b05a5a755aea2f), CONST64(0x1bef838336836cb5), CONST64(0x66b63333cc3385ff), +CONST64(0xc65c636391633ff2), CONST64(0x041202020802100a), CONST64(0x4993aaaa92aa3938), CONST64(0xe2de7171d971afa8), +CONST64(0x8dc6c8c807c80ecf), CONST64(0x32d119196419c87d), CONST64(0x923b494939497270), CONST64(0xaf5fd9d943d9869a), +CONST64(0xf931f2f2eff2c31d), CONST64(0xdba8e3e3abe34b48), CONST64(0xb6b95b5b715be22a), CONST64(0x0dbc88881a883492), +CONST64(0x293e9a9a529aa4c8), CONST64(0x4c0b262698262dbe), CONST64(0x64bf3232c8328dfa), CONST64(0x7d59b0b0fab0e94a), +CONST64(0xcff2e9e983e91b6a), CONST64(0x1e770f0f3c0f7833), CONST64(0xb733d5d573d5e6a6), CONST64(0x1df480803a8074ba), +CONST64(0x6127bebec2be997c), CONST64(0x87ebcdcd13cd26de), CONST64(0x68893434d034bde4), CONST64(0x903248483d487a75), +CONST64(0xe354ffffdbffab24), CONST64(0xf48d7a7af57af78f), CONST64(0x3d6490907a90f4ea), CONST64(0xbe9d5f5f615fc23e), +CONST64(0x403d202080201da0), CONST64(0xd00f6868bd6867d5), CONST64(0x34ca1a1a681ad072), CONST64(0x41b7aeae82ae192c), +CONST64(0x757db4b4eab4c95e), CONST64(0xa8ce54544d549a19), CONST64(0x3b7f93937693ece5), CONST64(0x442f222288220daa), +CONST64(0xc86364648d6407e9), CONST64(0xff2af1f1e3f1db12), CONST64(0xe6cc7373d173bfa2), CONST64(0x248212124812905a), +CONST64(0x807a40401d403a5d), CONST64(0x1048080820084028), CONST64(0x9b95c3c32bc356e8), CONST64(0xc5dfecec97ec337b), +CONST64(0xab4ddbdb4bdb9690), CONST64(0x5fc0a1a1bea1611f), CONST64(0x07918d8d0e8d1c83), CONST64(0x7ac83d3df43df5c9), +CONST64(0x335b97976697ccf1), CONST64(0x0000000000000000), CONST64(0x83f9cfcf1bcf36d4), CONST64(0x566e2b2bac2b4587), +CONST64(0xece17676c57697b3), CONST64(0x19e68282328264b0), CONST64(0xb128d6d67fd6fea9), CONST64(0x36c31b1b6c1bd877), +CONST64(0x7774b5b5eeb5c15b), CONST64(0x43beafaf86af1129), CONST64(0xd41d6a6ab56a77df), CONST64(0xa0ea50505d50ba0d), +CONST64(0x8a5745450945124c), CONST64(0xfb38f3f3ebf3cb18), CONST64(0x60ad3030c0309df0), CONST64(0xc3c4efef9bef2b74), +CONST64(0x7eda3f3ffc3fe5c3), CONST64(0xaac755554955921c), CONST64(0x59dba2a2b2a27910), CONST64(0xc9e9eaea8fea0365), +CONST64(0xca6a656589650fec), CONST64(0x6903babad2bab968), CONST64(0x5e4a2f2fbc2f6593), CONST64(0x9d8ec0c027c04ee7), +CONST64(0xa160dede5fdebe81), CONST64(0x38fc1c1c701ce06c), CONST64(0xe746fdfdd3fdbb2e), CONST64(0x9a1f4d4d294d5264), +CONST64(0x397692927292e4e0), CONST64(0xeafa7575c9758fbc), CONST64(0x0c3606061806301e), CONST64(0x09ae8a8a128a2498), +CONST64(0x794bb2b2f2b2f940), CONST64(0xd185e6e6bfe66359), CONST64(0x1c7e0e0e380e7036), CONST64(0x3ee71f1f7c1ff863), +CONST64(0xc4556262956237f7), CONST64(0xb53ad4d477d4eea3), CONST64(0x4d81a8a89aa82932), CONST64(0x315296966296c4f4), +CONST64(0xef62f9f9c3f99b3a), CONST64(0x97a3c5c533c566f6), CONST64(0x4a102525942535b1), CONST64(0xb2ab59597959f220), +CONST64(0x15d084842a8454ae), CONST64(0xe4c57272d572b7a7), CONST64(0x72ec3939e439d5dd), CONST64(0x98164c4c2d4c5a61), +CONST64(0xbc945e5e655eca3b), CONST64(0xf09f7878fd78e785), CONST64(0x70e53838e038ddd8), CONST64(0x05988c8c0a8c1486), +CONST64(0xbf17d1d163d1c6b2), CONST64(0x57e4a5a5aea5410b), CONST64(0xd9a1e2e2afe2434d), CONST64(0xc24e616199612ff8), +CONST64(0x7b42b3b3f6b3f145), CONST64(0x42342121842115a5), CONST64(0x25089c9c4a9c94d6), CONST64(0x3cee1e1e781ef066), +CONST64(0x8661434311432252), CONST64(0x93b1c7c73bc776fc), CONST64(0xe54ffcfcd7fcb32b), CONST64(0x0824040410042014), +CONST64(0xa2e351515951b208), CONST64(0x2f2599995e99bcc7), CONST64(0xda226d6da96d4fc4), CONST64(0x1a650d0d340d6839), +CONST64(0xe979fafacffa8335), CONST64(0xa369dfdf5bdfb684), CONST64(0xfca97e7ee57ed79b), CONST64(0x4819242490243db4), +CONST64(0x76fe3b3bec3bc5d7), CONST64(0x4b9aabab96ab313d), CONST64(0x81f0cece1fce3ed1), CONST64(0x2299111144118855), +CONST64(0x03838f8f068f0c89), CONST64(0x9c044e4e254e4a6b), CONST64(0x7366b7b7e6b7d151), CONST64(0xcbe0ebeb8beb0b60), +CONST64(0x78c13c3cf03cfdcc), CONST64(0x1ffd81813e817cbf), CONST64(0x354094946a94d4fe), CONST64(0xf31cf7f7fbf7eb0c), +CONST64(0x6f18b9b9deb9a167), CONST64(0x268b13134c13985f), CONST64(0x58512c2cb02c7d9c), CONST64(0xbb05d3d36bd3d6b8), +CONST64(0xd38ce7e7bbe76b5c), CONST64(0xdc396e6ea56e57cb), CONST64(0x95aac4c437c46ef3), CONST64(0x061b03030c03180f), +CONST64(0xacdc565645568a13), CONST64(0x885e44440d441a49), CONST64(0xfea07f7fe17fdf9e), CONST64(0x4f88a9a99ea92137), +CONST64(0x54672a2aa82a4d82), CONST64(0x6b0abbbbd6bbb16d), CONST64(0x9f87c1c123c146e2), CONST64(0xa6f153535153a202), +CONST64(0xa572dcdc57dcae8b), CONST64(0x16530b0b2c0b5827), CONST64(0x27019d9d4e9d9cd3), CONST64(0xd82b6c6cad6c47c1), +CONST64(0x62a43131c43195f5), CONST64(0xe8f37474cd7487b9), CONST64(0xf115f6f6fff6e309), CONST64(0x8c4c464605460a43), +CONST64(0x45a5acac8aac0926), CONST64(0x0fb589891e893c97), CONST64(0x28b414145014a044), CONST64(0xdfbae1e1a3e15b42), +CONST64(0x2ca616165816b04e), CONST64(0x74f73a3ae83acdd2), CONST64(0xd2066969b9696fd0), CONST64(0x124109092409482d), +CONST64(0xe0d77070dd70a7ad), CONST64(0x716fb6b6e2b6d954), CONST64(0xbd1ed0d067d0ceb7), CONST64(0xc7d6eded93ed3b7e), +CONST64(0x85e2cccc17cc2edb), CONST64(0x8468424215422a57), CONST64(0x2d2c98985a98b4c2), CONST64(0x55eda4a4aaa4490e), +CONST64(0x50752828a0285d88), CONST64(0xb8865c5c6d5cda31), CONST64(0xed6bf8f8c7f8933f), CONST64(0x11c28686228644a4) +}; + +static const ulong64 sbox3[] = { +CONST64(0x7830d818186018c0), CONST64(0xaf462623238c2305), CONST64(0xf991b8c6c63fc67e), CONST64(0x6fcdfbe8e887e813), +CONST64(0xa113cb878726874c), CONST64(0x626d11b8b8dab8a9), CONST64(0x0502090101040108), CONST64(0x6e9e0d4f4f214f42), +CONST64(0xee6c9b3636d836ad), CONST64(0x0451ffa6a6a2a659), CONST64(0xbdb90cd2d26fd2de), CONST64(0x06f70ef5f5f3f5fb), +CONST64(0x80f2967979f979ef), CONST64(0xcede306f6fa16f5f), CONST64(0xef3f6d91917e91fc), CONST64(0x07a4f852525552aa), +CONST64(0xfdc04760609d6027), CONST64(0x766535bcbccabc89), CONST64(0xcd2b379b9b569bac), CONST64(0x8c018a8e8e028e04), +CONST64(0x155bd2a3a3b6a371), CONST64(0x3c186c0c0c300c60), CONST64(0x8af6847b7bf17bff), CONST64(0xe16a803535d435b5), +CONST64(0x693af51d1d741de8), CONST64(0x47ddb3e0e0a7e053), CONST64(0xacb321d7d77bd7f6), CONST64(0xed999cc2c22fc25e), +CONST64(0x965c432e2eb82e6d), CONST64(0x7a96294b4b314b62), CONST64(0x21e15dfefedffea3), CONST64(0x16aed55757415782), +CONST64(0x412abd15155415a8), CONST64(0xb6eee87777c1779f), CONST64(0xeb6e923737dc37a5), CONST64(0x56d79ee5e5b3e57b), +CONST64(0xd923139f9f469f8c), CONST64(0x17fd23f0f0e7f0d3), CONST64(0x7f94204a4a354a6a), CONST64(0x95a944dada4fda9e), +CONST64(0x25b0a258587d58fa), CONST64(0xca8fcfc9c903c906), CONST64(0x8d527c2929a42955), CONST64(0x22145a0a0a280a50), +CONST64(0x4f7f50b1b1feb1e1), CONST64(0x1a5dc9a0a0baa069), CONST64(0xdad6146b6bb16b7f), CONST64(0xab17d985852e855c), +CONST64(0x73673cbdbdcebd81), CONST64(0x34ba8f5d5d695dd2), CONST64(0x5020901010401080), CONST64(0x03f507f4f4f7f4f3), +CONST64(0xc08bddcbcb0bcb16), CONST64(0xc67cd33e3ef83eed), CONST64(0x110a2d0505140528), CONST64(0xe6ce78676781671f), +CONST64(0x53d597e4e4b7e473), CONST64(0xbb4e0227279c2725), CONST64(0x5882734141194132), CONST64(0x9d0ba78b8b168b2c), +CONST64(0x0153f6a7a7a6a751), CONST64(0x94fab27d7de97dcf), CONST64(0xfb374995956e95dc), CONST64(0x9fad56d8d847d88e), +CONST64(0x30eb70fbfbcbfb8b), CONST64(0x71c1cdeeee9fee23), CONST64(0x91f8bb7c7ced7cc7), CONST64(0xe3cc716666856617), +CONST64(0x8ea77bdddd53dda6), CONST64(0x4b2eaf17175c17b8), CONST64(0x468e454747014702), CONST64(0xdc211a9e9e429e84), +CONST64(0xc589d4caca0fca1e), CONST64(0x995a582d2db42d75), CONST64(0x79632ebfbfc6bf91), CONST64(0x1b0e3f07071c0738), +CONST64(0x2347acadad8ead01), CONST64(0x2fb4b05a5a755aea), CONST64(0xb51bef838336836c), CONST64(0xff66b63333cc3385), +CONST64(0xf2c65c636391633f), CONST64(0x0a04120202080210), CONST64(0x384993aaaa92aa39), CONST64(0xa8e2de7171d971af), +CONST64(0xcf8dc6c8c807c80e), CONST64(0x7d32d119196419c8), CONST64(0x70923b4949394972), CONST64(0x9aaf5fd9d943d986), +CONST64(0x1df931f2f2eff2c3), CONST64(0x48dba8e3e3abe34b), CONST64(0x2ab6b95b5b715be2), CONST64(0x920dbc88881a8834), +CONST64(0xc8293e9a9a529aa4), CONST64(0xbe4c0b262698262d), CONST64(0xfa64bf3232c8328d), CONST64(0x4a7d59b0b0fab0e9), +CONST64(0x6acff2e9e983e91b), CONST64(0x331e770f0f3c0f78), CONST64(0xa6b733d5d573d5e6), CONST64(0xba1df480803a8074), +CONST64(0x7c6127bebec2be99), CONST64(0xde87ebcdcd13cd26), CONST64(0xe468893434d034bd), CONST64(0x75903248483d487a), +CONST64(0x24e354ffffdbffab), CONST64(0x8ff48d7a7af57af7), CONST64(0xea3d6490907a90f4), CONST64(0x3ebe9d5f5f615fc2), +CONST64(0xa0403d202080201d), CONST64(0xd5d00f6868bd6867), CONST64(0x7234ca1a1a681ad0), CONST64(0x2c41b7aeae82ae19), +CONST64(0x5e757db4b4eab4c9), CONST64(0x19a8ce54544d549a), CONST64(0xe53b7f93937693ec), CONST64(0xaa442f222288220d), +CONST64(0xe9c86364648d6407), CONST64(0x12ff2af1f1e3f1db), CONST64(0xa2e6cc7373d173bf), CONST64(0x5a24821212481290), +CONST64(0x5d807a40401d403a), CONST64(0x2810480808200840), CONST64(0xe89b95c3c32bc356), CONST64(0x7bc5dfecec97ec33), +CONST64(0x90ab4ddbdb4bdb96), CONST64(0x1f5fc0a1a1bea161), CONST64(0x8307918d8d0e8d1c), CONST64(0xc97ac83d3df43df5), +CONST64(0xf1335b97976697cc), CONST64(0x0000000000000000), CONST64(0xd483f9cfcf1bcf36), CONST64(0x87566e2b2bac2b45), +CONST64(0xb3ece17676c57697), CONST64(0xb019e68282328264), CONST64(0xa9b128d6d67fd6fe), CONST64(0x7736c31b1b6c1bd8), +CONST64(0x5b7774b5b5eeb5c1), CONST64(0x2943beafaf86af11), CONST64(0xdfd41d6a6ab56a77), CONST64(0x0da0ea50505d50ba), +CONST64(0x4c8a574545094512), CONST64(0x18fb38f3f3ebf3cb), CONST64(0xf060ad3030c0309d), CONST64(0x74c3c4efef9bef2b), +CONST64(0xc37eda3f3ffc3fe5), CONST64(0x1caac75555495592), CONST64(0x1059dba2a2b2a279), CONST64(0x65c9e9eaea8fea03), +CONST64(0xecca6a656589650f), CONST64(0x686903babad2bab9), CONST64(0x935e4a2f2fbc2f65), CONST64(0xe79d8ec0c027c04e), +CONST64(0x81a160dede5fdebe), CONST64(0x6c38fc1c1c701ce0), CONST64(0x2ee746fdfdd3fdbb), CONST64(0x649a1f4d4d294d52), +CONST64(0xe0397692927292e4), CONST64(0xbceafa7575c9758f), CONST64(0x1e0c360606180630), CONST64(0x9809ae8a8a128a24), +CONST64(0x40794bb2b2f2b2f9), CONST64(0x59d185e6e6bfe663), CONST64(0x361c7e0e0e380e70), CONST64(0x633ee71f1f7c1ff8), +CONST64(0xf7c4556262956237), CONST64(0xa3b53ad4d477d4ee), CONST64(0x324d81a8a89aa829), CONST64(0xf4315296966296c4), +CONST64(0x3aef62f9f9c3f99b), CONST64(0xf697a3c5c533c566), CONST64(0xb14a102525942535), CONST64(0x20b2ab59597959f2), +CONST64(0xae15d084842a8454), CONST64(0xa7e4c57272d572b7), CONST64(0xdd72ec3939e439d5), CONST64(0x6198164c4c2d4c5a), +CONST64(0x3bbc945e5e655eca), CONST64(0x85f09f7878fd78e7), CONST64(0xd870e53838e038dd), CONST64(0x8605988c8c0a8c14), +CONST64(0xb2bf17d1d163d1c6), CONST64(0x0b57e4a5a5aea541), CONST64(0x4dd9a1e2e2afe243), CONST64(0xf8c24e616199612f), +CONST64(0x457b42b3b3f6b3f1), CONST64(0xa542342121842115), CONST64(0xd625089c9c4a9c94), CONST64(0x663cee1e1e781ef0), +CONST64(0x5286614343114322), CONST64(0xfc93b1c7c73bc776), CONST64(0x2be54ffcfcd7fcb3), CONST64(0x1408240404100420), +CONST64(0x08a2e351515951b2), CONST64(0xc72f2599995e99bc), CONST64(0xc4da226d6da96d4f), CONST64(0x391a650d0d340d68), +CONST64(0x35e979fafacffa83), CONST64(0x84a369dfdf5bdfb6), CONST64(0x9bfca97e7ee57ed7), CONST64(0xb44819242490243d), +CONST64(0xd776fe3b3bec3bc5), CONST64(0x3d4b9aabab96ab31), CONST64(0xd181f0cece1fce3e), CONST64(0x5522991111441188), +CONST64(0x8903838f8f068f0c), CONST64(0x6b9c044e4e254e4a), CONST64(0x517366b7b7e6b7d1), CONST64(0x60cbe0ebeb8beb0b), +CONST64(0xcc78c13c3cf03cfd), CONST64(0xbf1ffd81813e817c), CONST64(0xfe354094946a94d4), CONST64(0x0cf31cf7f7fbf7eb), +CONST64(0x676f18b9b9deb9a1), CONST64(0x5f268b13134c1398), CONST64(0x9c58512c2cb02c7d), CONST64(0xb8bb05d3d36bd3d6), +CONST64(0x5cd38ce7e7bbe76b), CONST64(0xcbdc396e6ea56e57), CONST64(0xf395aac4c437c46e), CONST64(0x0f061b03030c0318), +CONST64(0x13acdc565645568a), CONST64(0x49885e44440d441a), CONST64(0x9efea07f7fe17fdf), CONST64(0x374f88a9a99ea921), +CONST64(0x8254672a2aa82a4d), CONST64(0x6d6b0abbbbd6bbb1), CONST64(0xe29f87c1c123c146), CONST64(0x02a6f153535153a2), +CONST64(0x8ba572dcdc57dcae), CONST64(0x2716530b0b2c0b58), CONST64(0xd327019d9d4e9d9c), CONST64(0xc1d82b6c6cad6c47), +CONST64(0xf562a43131c43195), CONST64(0xb9e8f37474cd7487), CONST64(0x09f115f6f6fff6e3), CONST64(0x438c4c464605460a), +CONST64(0x2645a5acac8aac09), CONST64(0x970fb589891e893c), CONST64(0x4428b414145014a0), CONST64(0x42dfbae1e1a3e15b), +CONST64(0x4e2ca616165816b0), CONST64(0xd274f73a3ae83acd), CONST64(0xd0d2066969b9696f), CONST64(0x2d12410909240948), +CONST64(0xade0d77070dd70a7), CONST64(0x54716fb6b6e2b6d9), CONST64(0xb7bd1ed0d067d0ce), CONST64(0x7ec7d6eded93ed3b), +CONST64(0xdb85e2cccc17cc2e), CONST64(0x578468424215422a), CONST64(0xc22d2c98985a98b4), CONST64(0x0e55eda4a4aaa449), +CONST64(0x8850752828a0285d), CONST64(0x31b8865c5c6d5cda), CONST64(0x3fed6bf8f8c7f893), CONST64(0xa411c28686228644) +}; + +static const ulong64 sbox4[] = { +CONST64(0xc07830d818186018), CONST64(0x05af462623238c23), CONST64(0x7ef991b8c6c63fc6), CONST64(0x136fcdfbe8e887e8), +CONST64(0x4ca113cb87872687), CONST64(0xa9626d11b8b8dab8), CONST64(0x0805020901010401), CONST64(0x426e9e0d4f4f214f), +CONST64(0xadee6c9b3636d836), CONST64(0x590451ffa6a6a2a6), CONST64(0xdebdb90cd2d26fd2), CONST64(0xfb06f70ef5f5f3f5), +CONST64(0xef80f2967979f979), CONST64(0x5fcede306f6fa16f), CONST64(0xfcef3f6d91917e91), CONST64(0xaa07a4f852525552), +CONST64(0x27fdc04760609d60), CONST64(0x89766535bcbccabc), CONST64(0xaccd2b379b9b569b), CONST64(0x048c018a8e8e028e), +CONST64(0x71155bd2a3a3b6a3), CONST64(0x603c186c0c0c300c), CONST64(0xff8af6847b7bf17b), CONST64(0xb5e16a803535d435), +CONST64(0xe8693af51d1d741d), CONST64(0x5347ddb3e0e0a7e0), CONST64(0xf6acb321d7d77bd7), CONST64(0x5eed999cc2c22fc2), +CONST64(0x6d965c432e2eb82e), CONST64(0x627a96294b4b314b), CONST64(0xa321e15dfefedffe), CONST64(0x8216aed557574157), +CONST64(0xa8412abd15155415), CONST64(0x9fb6eee87777c177), CONST64(0xa5eb6e923737dc37), CONST64(0x7b56d79ee5e5b3e5), +CONST64(0x8cd923139f9f469f), CONST64(0xd317fd23f0f0e7f0), CONST64(0x6a7f94204a4a354a), CONST64(0x9e95a944dada4fda), +CONST64(0xfa25b0a258587d58), CONST64(0x06ca8fcfc9c903c9), CONST64(0x558d527c2929a429), CONST64(0x5022145a0a0a280a), +CONST64(0xe14f7f50b1b1feb1), CONST64(0x691a5dc9a0a0baa0), CONST64(0x7fdad6146b6bb16b), CONST64(0x5cab17d985852e85), +CONST64(0x8173673cbdbdcebd), CONST64(0xd234ba8f5d5d695d), CONST64(0x8050209010104010), CONST64(0xf303f507f4f4f7f4), +CONST64(0x16c08bddcbcb0bcb), CONST64(0xedc67cd33e3ef83e), CONST64(0x28110a2d05051405), CONST64(0x1fe6ce7867678167), +CONST64(0x7353d597e4e4b7e4), CONST64(0x25bb4e0227279c27), CONST64(0x3258827341411941), CONST64(0x2c9d0ba78b8b168b), +CONST64(0x510153f6a7a7a6a7), CONST64(0xcf94fab27d7de97d), CONST64(0xdcfb374995956e95), CONST64(0x8e9fad56d8d847d8), +CONST64(0x8b30eb70fbfbcbfb), CONST64(0x2371c1cdeeee9fee), CONST64(0xc791f8bb7c7ced7c), CONST64(0x17e3cc7166668566), +CONST64(0xa68ea77bdddd53dd), CONST64(0xb84b2eaf17175c17), CONST64(0x02468e4547470147), CONST64(0x84dc211a9e9e429e), +CONST64(0x1ec589d4caca0fca), CONST64(0x75995a582d2db42d), CONST64(0x9179632ebfbfc6bf), CONST64(0x381b0e3f07071c07), +CONST64(0x012347acadad8ead), CONST64(0xea2fb4b05a5a755a), CONST64(0x6cb51bef83833683), CONST64(0x85ff66b63333cc33), +CONST64(0x3ff2c65c63639163), CONST64(0x100a041202020802), CONST64(0x39384993aaaa92aa), CONST64(0xafa8e2de7171d971), +CONST64(0x0ecf8dc6c8c807c8), CONST64(0xc87d32d119196419), CONST64(0x7270923b49493949), CONST64(0x869aaf5fd9d943d9), +CONST64(0xc31df931f2f2eff2), CONST64(0x4b48dba8e3e3abe3), CONST64(0xe22ab6b95b5b715b), CONST64(0x34920dbc88881a88), +CONST64(0xa4c8293e9a9a529a), CONST64(0x2dbe4c0b26269826), CONST64(0x8dfa64bf3232c832), CONST64(0xe94a7d59b0b0fab0), +CONST64(0x1b6acff2e9e983e9), CONST64(0x78331e770f0f3c0f), CONST64(0xe6a6b733d5d573d5), CONST64(0x74ba1df480803a80), +CONST64(0x997c6127bebec2be), CONST64(0x26de87ebcdcd13cd), CONST64(0xbde468893434d034), CONST64(0x7a75903248483d48), +CONST64(0xab24e354ffffdbff), CONST64(0xf78ff48d7a7af57a), CONST64(0xf4ea3d6490907a90), CONST64(0xc23ebe9d5f5f615f), +CONST64(0x1da0403d20208020), CONST64(0x67d5d00f6868bd68), CONST64(0xd07234ca1a1a681a), CONST64(0x192c41b7aeae82ae), +CONST64(0xc95e757db4b4eab4), CONST64(0x9a19a8ce54544d54), CONST64(0xece53b7f93937693), CONST64(0x0daa442f22228822), +CONST64(0x07e9c86364648d64), CONST64(0xdb12ff2af1f1e3f1), CONST64(0xbfa2e6cc7373d173), CONST64(0x905a248212124812), +CONST64(0x3a5d807a40401d40), CONST64(0x4028104808082008), CONST64(0x56e89b95c3c32bc3), CONST64(0x337bc5dfecec97ec), +CONST64(0x9690ab4ddbdb4bdb), CONST64(0x611f5fc0a1a1bea1), CONST64(0x1c8307918d8d0e8d), CONST64(0xf5c97ac83d3df43d), +CONST64(0xccf1335b97976697), CONST64(0x0000000000000000), CONST64(0x36d483f9cfcf1bcf), CONST64(0x4587566e2b2bac2b), +CONST64(0x97b3ece17676c576), CONST64(0x64b019e682823282), CONST64(0xfea9b128d6d67fd6), CONST64(0xd87736c31b1b6c1b), +CONST64(0xc15b7774b5b5eeb5), CONST64(0x112943beafaf86af), CONST64(0x77dfd41d6a6ab56a), CONST64(0xba0da0ea50505d50), +CONST64(0x124c8a5745450945), CONST64(0xcb18fb38f3f3ebf3), CONST64(0x9df060ad3030c030), CONST64(0x2b74c3c4efef9bef), +CONST64(0xe5c37eda3f3ffc3f), CONST64(0x921caac755554955), CONST64(0x791059dba2a2b2a2), CONST64(0x0365c9e9eaea8fea), +CONST64(0x0fecca6a65658965), CONST64(0xb9686903babad2ba), CONST64(0x65935e4a2f2fbc2f), CONST64(0x4ee79d8ec0c027c0), +CONST64(0xbe81a160dede5fde), CONST64(0xe06c38fc1c1c701c), CONST64(0xbb2ee746fdfdd3fd), CONST64(0x52649a1f4d4d294d), +CONST64(0xe4e0397692927292), CONST64(0x8fbceafa7575c975), CONST64(0x301e0c3606061806), CONST64(0x249809ae8a8a128a), +CONST64(0xf940794bb2b2f2b2), CONST64(0x6359d185e6e6bfe6), CONST64(0x70361c7e0e0e380e), CONST64(0xf8633ee71f1f7c1f), +CONST64(0x37f7c45562629562), CONST64(0xeea3b53ad4d477d4), CONST64(0x29324d81a8a89aa8), CONST64(0xc4f4315296966296), +CONST64(0x9b3aef62f9f9c3f9), CONST64(0x66f697a3c5c533c5), CONST64(0x35b14a1025259425), CONST64(0xf220b2ab59597959), +CONST64(0x54ae15d084842a84), CONST64(0xb7a7e4c57272d572), CONST64(0xd5dd72ec3939e439), CONST64(0x5a6198164c4c2d4c), +CONST64(0xca3bbc945e5e655e), CONST64(0xe785f09f7878fd78), CONST64(0xddd870e53838e038), CONST64(0x148605988c8c0a8c), +CONST64(0xc6b2bf17d1d163d1), CONST64(0x410b57e4a5a5aea5), CONST64(0x434dd9a1e2e2afe2), CONST64(0x2ff8c24e61619961), +CONST64(0xf1457b42b3b3f6b3), CONST64(0x15a5423421218421), CONST64(0x94d625089c9c4a9c), CONST64(0xf0663cee1e1e781e), +CONST64(0x2252866143431143), CONST64(0x76fc93b1c7c73bc7), CONST64(0xb32be54ffcfcd7fc), CONST64(0x2014082404041004), +CONST64(0xb208a2e351515951), CONST64(0xbcc72f2599995e99), CONST64(0x4fc4da226d6da96d), CONST64(0x68391a650d0d340d), +CONST64(0x8335e979fafacffa), CONST64(0xb684a369dfdf5bdf), CONST64(0xd79bfca97e7ee57e), CONST64(0x3db4481924249024), +CONST64(0xc5d776fe3b3bec3b), CONST64(0x313d4b9aabab96ab), CONST64(0x3ed181f0cece1fce), CONST64(0x8855229911114411), +CONST64(0x0c8903838f8f068f), CONST64(0x4a6b9c044e4e254e), CONST64(0xd1517366b7b7e6b7), CONST64(0x0b60cbe0ebeb8beb), +CONST64(0xfdcc78c13c3cf03c), CONST64(0x7cbf1ffd81813e81), CONST64(0xd4fe354094946a94), CONST64(0xeb0cf31cf7f7fbf7), +CONST64(0xa1676f18b9b9deb9), CONST64(0x985f268b13134c13), CONST64(0x7d9c58512c2cb02c), CONST64(0xd6b8bb05d3d36bd3), +CONST64(0x6b5cd38ce7e7bbe7), CONST64(0x57cbdc396e6ea56e), CONST64(0x6ef395aac4c437c4), CONST64(0x180f061b03030c03), +CONST64(0x8a13acdc56564556), CONST64(0x1a49885e44440d44), CONST64(0xdf9efea07f7fe17f), CONST64(0x21374f88a9a99ea9), +CONST64(0x4d8254672a2aa82a), CONST64(0xb16d6b0abbbbd6bb), CONST64(0x46e29f87c1c123c1), CONST64(0xa202a6f153535153), +CONST64(0xae8ba572dcdc57dc), CONST64(0x582716530b0b2c0b), CONST64(0x9cd327019d9d4e9d), CONST64(0x47c1d82b6c6cad6c), +CONST64(0x95f562a43131c431), CONST64(0x87b9e8f37474cd74), CONST64(0xe309f115f6f6fff6), CONST64(0x0a438c4c46460546), +CONST64(0x092645a5acac8aac), CONST64(0x3c970fb589891e89), CONST64(0xa04428b414145014), CONST64(0x5b42dfbae1e1a3e1), +CONST64(0xb04e2ca616165816), CONST64(0xcdd274f73a3ae83a), CONST64(0x6fd0d2066969b969), CONST64(0x482d124109092409), +CONST64(0xa7ade0d77070dd70), CONST64(0xd954716fb6b6e2b6), CONST64(0xceb7bd1ed0d067d0), CONST64(0x3b7ec7d6eded93ed), +CONST64(0x2edb85e2cccc17cc), CONST64(0x2a57846842421542), CONST64(0xb4c22d2c98985a98), CONST64(0x490e55eda4a4aaa4), +CONST64(0x5d8850752828a028), CONST64(0xda31b8865c5c6d5c), CONST64(0x933fed6bf8f8c7f8), CONST64(0x44a411c286862286) +}; + +static const ulong64 sbox5[] = { +CONST64(0x18c07830d8181860), CONST64(0x2305af462623238c), CONST64(0xc67ef991b8c6c63f), CONST64(0xe8136fcdfbe8e887), +CONST64(0x874ca113cb878726), CONST64(0xb8a9626d11b8b8da), CONST64(0x0108050209010104), CONST64(0x4f426e9e0d4f4f21), +CONST64(0x36adee6c9b3636d8), CONST64(0xa6590451ffa6a6a2), CONST64(0xd2debdb90cd2d26f), CONST64(0xf5fb06f70ef5f5f3), +CONST64(0x79ef80f2967979f9), CONST64(0x6f5fcede306f6fa1), CONST64(0x91fcef3f6d91917e), CONST64(0x52aa07a4f8525255), +CONST64(0x6027fdc04760609d), CONST64(0xbc89766535bcbcca), CONST64(0x9baccd2b379b9b56), CONST64(0x8e048c018a8e8e02), +CONST64(0xa371155bd2a3a3b6), CONST64(0x0c603c186c0c0c30), CONST64(0x7bff8af6847b7bf1), CONST64(0x35b5e16a803535d4), +CONST64(0x1de8693af51d1d74), CONST64(0xe05347ddb3e0e0a7), CONST64(0xd7f6acb321d7d77b), CONST64(0xc25eed999cc2c22f), +CONST64(0x2e6d965c432e2eb8), CONST64(0x4b627a96294b4b31), CONST64(0xfea321e15dfefedf), CONST64(0x578216aed5575741), +CONST64(0x15a8412abd151554), CONST64(0x779fb6eee87777c1), CONST64(0x37a5eb6e923737dc), CONST64(0xe57b56d79ee5e5b3), +CONST64(0x9f8cd923139f9f46), CONST64(0xf0d317fd23f0f0e7), CONST64(0x4a6a7f94204a4a35), CONST64(0xda9e95a944dada4f), +CONST64(0x58fa25b0a258587d), CONST64(0xc906ca8fcfc9c903), CONST64(0x29558d527c2929a4), CONST64(0x0a5022145a0a0a28), +CONST64(0xb1e14f7f50b1b1fe), CONST64(0xa0691a5dc9a0a0ba), CONST64(0x6b7fdad6146b6bb1), CONST64(0x855cab17d985852e), +CONST64(0xbd8173673cbdbdce), CONST64(0x5dd234ba8f5d5d69), CONST64(0x1080502090101040), CONST64(0xf4f303f507f4f4f7), +CONST64(0xcb16c08bddcbcb0b), CONST64(0x3eedc67cd33e3ef8), CONST64(0x0528110a2d050514), CONST64(0x671fe6ce78676781), +CONST64(0xe47353d597e4e4b7), CONST64(0x2725bb4e0227279c), CONST64(0x4132588273414119), CONST64(0x8b2c9d0ba78b8b16), +CONST64(0xa7510153f6a7a7a6), CONST64(0x7dcf94fab27d7de9), CONST64(0x95dcfb374995956e), CONST64(0xd88e9fad56d8d847), +CONST64(0xfb8b30eb70fbfbcb), CONST64(0xee2371c1cdeeee9f), CONST64(0x7cc791f8bb7c7ced), CONST64(0x6617e3cc71666685), +CONST64(0xdda68ea77bdddd53), CONST64(0x17b84b2eaf17175c), CONST64(0x4702468e45474701), CONST64(0x9e84dc211a9e9e42), +CONST64(0xca1ec589d4caca0f), CONST64(0x2d75995a582d2db4), CONST64(0xbf9179632ebfbfc6), CONST64(0x07381b0e3f07071c), +CONST64(0xad012347acadad8e), CONST64(0x5aea2fb4b05a5a75), CONST64(0x836cb51bef838336), CONST64(0x3385ff66b63333cc), +CONST64(0x633ff2c65c636391), CONST64(0x02100a0412020208), CONST64(0xaa39384993aaaa92), CONST64(0x71afa8e2de7171d9), +CONST64(0xc80ecf8dc6c8c807), CONST64(0x19c87d32d1191964), CONST64(0x497270923b494939), CONST64(0xd9869aaf5fd9d943), +CONST64(0xf2c31df931f2f2ef), CONST64(0xe34b48dba8e3e3ab), CONST64(0x5be22ab6b95b5b71), CONST64(0x8834920dbc88881a), +CONST64(0x9aa4c8293e9a9a52), CONST64(0x262dbe4c0b262698), CONST64(0x328dfa64bf3232c8), CONST64(0xb0e94a7d59b0b0fa), +CONST64(0xe91b6acff2e9e983), CONST64(0x0f78331e770f0f3c), CONST64(0xd5e6a6b733d5d573), CONST64(0x8074ba1df480803a), +CONST64(0xbe997c6127bebec2), CONST64(0xcd26de87ebcdcd13), CONST64(0x34bde468893434d0), CONST64(0x487a75903248483d), +CONST64(0xffab24e354ffffdb), CONST64(0x7af78ff48d7a7af5), CONST64(0x90f4ea3d6490907a), CONST64(0x5fc23ebe9d5f5f61), +CONST64(0x201da0403d202080), CONST64(0x6867d5d00f6868bd), CONST64(0x1ad07234ca1a1a68), CONST64(0xae192c41b7aeae82), +CONST64(0xb4c95e757db4b4ea), CONST64(0x549a19a8ce54544d), CONST64(0x93ece53b7f939376), CONST64(0x220daa442f222288), +CONST64(0x6407e9c86364648d), CONST64(0xf1db12ff2af1f1e3), CONST64(0x73bfa2e6cc7373d1), CONST64(0x12905a2482121248), +CONST64(0x403a5d807a40401d), CONST64(0x0840281048080820), CONST64(0xc356e89b95c3c32b), CONST64(0xec337bc5dfecec97), +CONST64(0xdb9690ab4ddbdb4b), CONST64(0xa1611f5fc0a1a1be), CONST64(0x8d1c8307918d8d0e), CONST64(0x3df5c97ac83d3df4), +CONST64(0x97ccf1335b979766), CONST64(0x0000000000000000), CONST64(0xcf36d483f9cfcf1b), CONST64(0x2b4587566e2b2bac), +CONST64(0x7697b3ece17676c5), CONST64(0x8264b019e6828232), CONST64(0xd6fea9b128d6d67f), CONST64(0x1bd87736c31b1b6c), +CONST64(0xb5c15b7774b5b5ee), CONST64(0xaf112943beafaf86), CONST64(0x6a77dfd41d6a6ab5), CONST64(0x50ba0da0ea50505d), +CONST64(0x45124c8a57454509), CONST64(0xf3cb18fb38f3f3eb), CONST64(0x309df060ad3030c0), CONST64(0xef2b74c3c4efef9b), +CONST64(0x3fe5c37eda3f3ffc), CONST64(0x55921caac7555549), CONST64(0xa2791059dba2a2b2), CONST64(0xea0365c9e9eaea8f), +CONST64(0x650fecca6a656589), CONST64(0xbab9686903babad2), CONST64(0x2f65935e4a2f2fbc), CONST64(0xc04ee79d8ec0c027), +CONST64(0xdebe81a160dede5f), CONST64(0x1ce06c38fc1c1c70), CONST64(0xfdbb2ee746fdfdd3), CONST64(0x4d52649a1f4d4d29), +CONST64(0x92e4e03976929272), CONST64(0x758fbceafa7575c9), CONST64(0x06301e0c36060618), CONST64(0x8a249809ae8a8a12), +CONST64(0xb2f940794bb2b2f2), CONST64(0xe66359d185e6e6bf), CONST64(0x0e70361c7e0e0e38), CONST64(0x1ff8633ee71f1f7c), +CONST64(0x6237f7c455626295), CONST64(0xd4eea3b53ad4d477), CONST64(0xa829324d81a8a89a), CONST64(0x96c4f43152969662), +CONST64(0xf99b3aef62f9f9c3), CONST64(0xc566f697a3c5c533), CONST64(0x2535b14a10252594), CONST64(0x59f220b2ab595979), +CONST64(0x8454ae15d084842a), CONST64(0x72b7a7e4c57272d5), CONST64(0x39d5dd72ec3939e4), CONST64(0x4c5a6198164c4c2d), +CONST64(0x5eca3bbc945e5e65), CONST64(0x78e785f09f7878fd), CONST64(0x38ddd870e53838e0), CONST64(0x8c148605988c8c0a), +CONST64(0xd1c6b2bf17d1d163), CONST64(0xa5410b57e4a5a5ae), CONST64(0xe2434dd9a1e2e2af), CONST64(0x612ff8c24e616199), +CONST64(0xb3f1457b42b3b3f6), CONST64(0x2115a54234212184), CONST64(0x9c94d625089c9c4a), CONST64(0x1ef0663cee1e1e78), +CONST64(0x4322528661434311), CONST64(0xc776fc93b1c7c73b), CONST64(0xfcb32be54ffcfcd7), CONST64(0x0420140824040410), +CONST64(0x51b208a2e3515159), CONST64(0x99bcc72f2599995e), CONST64(0x6d4fc4da226d6da9), CONST64(0x0d68391a650d0d34), +CONST64(0xfa8335e979fafacf), CONST64(0xdfb684a369dfdf5b), CONST64(0x7ed79bfca97e7ee5), CONST64(0x243db44819242490), +CONST64(0x3bc5d776fe3b3bec), CONST64(0xab313d4b9aabab96), CONST64(0xce3ed181f0cece1f), CONST64(0x1188552299111144), +CONST64(0x8f0c8903838f8f06), CONST64(0x4e4a6b9c044e4e25), CONST64(0xb7d1517366b7b7e6), CONST64(0xeb0b60cbe0ebeb8b), +CONST64(0x3cfdcc78c13c3cf0), CONST64(0x817cbf1ffd81813e), CONST64(0x94d4fe354094946a), CONST64(0xf7eb0cf31cf7f7fb), +CONST64(0xb9a1676f18b9b9de), CONST64(0x13985f268b13134c), CONST64(0x2c7d9c58512c2cb0), CONST64(0xd3d6b8bb05d3d36b), +CONST64(0xe76b5cd38ce7e7bb), CONST64(0x6e57cbdc396e6ea5), CONST64(0xc46ef395aac4c437), CONST64(0x03180f061b03030c), +CONST64(0x568a13acdc565645), CONST64(0x441a49885e44440d), CONST64(0x7fdf9efea07f7fe1), CONST64(0xa921374f88a9a99e), +CONST64(0x2a4d8254672a2aa8), CONST64(0xbbb16d6b0abbbbd6), CONST64(0xc146e29f87c1c123), CONST64(0x53a202a6f1535351), +CONST64(0xdcae8ba572dcdc57), CONST64(0x0b582716530b0b2c), CONST64(0x9d9cd327019d9d4e), CONST64(0x6c47c1d82b6c6cad), +CONST64(0x3195f562a43131c4), CONST64(0x7487b9e8f37474cd), CONST64(0xf6e309f115f6f6ff), CONST64(0x460a438c4c464605), +CONST64(0xac092645a5acac8a), CONST64(0x893c970fb589891e), CONST64(0x14a04428b4141450), CONST64(0xe15b42dfbae1e1a3), +CONST64(0x16b04e2ca6161658), CONST64(0x3acdd274f73a3ae8), CONST64(0x696fd0d2066969b9), CONST64(0x09482d1241090924), +CONST64(0x70a7ade0d77070dd), CONST64(0xb6d954716fb6b6e2), CONST64(0xd0ceb7bd1ed0d067), CONST64(0xed3b7ec7d6eded93), +CONST64(0xcc2edb85e2cccc17), CONST64(0x422a578468424215), CONST64(0x98b4c22d2c98985a), CONST64(0xa4490e55eda4a4aa), +CONST64(0x285d8850752828a0), CONST64(0x5cda31b8865c5c6d), CONST64(0xf8933fed6bf8f8c7), CONST64(0x8644a411c2868622) +}; + +static const ulong64 sbox6[] = { +CONST64(0x6018c07830d81818), CONST64(0x8c2305af46262323), CONST64(0x3fc67ef991b8c6c6), CONST64(0x87e8136fcdfbe8e8), +CONST64(0x26874ca113cb8787), CONST64(0xdab8a9626d11b8b8), CONST64(0x0401080502090101), CONST64(0x214f426e9e0d4f4f), +CONST64(0xd836adee6c9b3636), CONST64(0xa2a6590451ffa6a6), CONST64(0x6fd2debdb90cd2d2), CONST64(0xf3f5fb06f70ef5f5), +CONST64(0xf979ef80f2967979), CONST64(0xa16f5fcede306f6f), CONST64(0x7e91fcef3f6d9191), CONST64(0x5552aa07a4f85252), +CONST64(0x9d6027fdc0476060), CONST64(0xcabc89766535bcbc), CONST64(0x569baccd2b379b9b), CONST64(0x028e048c018a8e8e), +CONST64(0xb6a371155bd2a3a3), CONST64(0x300c603c186c0c0c), CONST64(0xf17bff8af6847b7b), CONST64(0xd435b5e16a803535), +CONST64(0x741de8693af51d1d), CONST64(0xa7e05347ddb3e0e0), CONST64(0x7bd7f6acb321d7d7), CONST64(0x2fc25eed999cc2c2), +CONST64(0xb82e6d965c432e2e), CONST64(0x314b627a96294b4b), CONST64(0xdffea321e15dfefe), CONST64(0x41578216aed55757), +CONST64(0x5415a8412abd1515), CONST64(0xc1779fb6eee87777), CONST64(0xdc37a5eb6e923737), CONST64(0xb3e57b56d79ee5e5), +CONST64(0x469f8cd923139f9f), CONST64(0xe7f0d317fd23f0f0), CONST64(0x354a6a7f94204a4a), CONST64(0x4fda9e95a944dada), +CONST64(0x7d58fa25b0a25858), CONST64(0x03c906ca8fcfc9c9), CONST64(0xa429558d527c2929), CONST64(0x280a5022145a0a0a), +CONST64(0xfeb1e14f7f50b1b1), CONST64(0xbaa0691a5dc9a0a0), CONST64(0xb16b7fdad6146b6b), CONST64(0x2e855cab17d98585), +CONST64(0xcebd8173673cbdbd), CONST64(0x695dd234ba8f5d5d), CONST64(0x4010805020901010), CONST64(0xf7f4f303f507f4f4), +CONST64(0x0bcb16c08bddcbcb), CONST64(0xf83eedc67cd33e3e), CONST64(0x140528110a2d0505), CONST64(0x81671fe6ce786767), +CONST64(0xb7e47353d597e4e4), CONST64(0x9c2725bb4e022727), CONST64(0x1941325882734141), CONST64(0x168b2c9d0ba78b8b), +CONST64(0xa6a7510153f6a7a7), CONST64(0xe97dcf94fab27d7d), CONST64(0x6e95dcfb37499595), CONST64(0x47d88e9fad56d8d8), +CONST64(0xcbfb8b30eb70fbfb), CONST64(0x9fee2371c1cdeeee), CONST64(0xed7cc791f8bb7c7c), CONST64(0x856617e3cc716666), +CONST64(0x53dda68ea77bdddd), CONST64(0x5c17b84b2eaf1717), CONST64(0x014702468e454747), CONST64(0x429e84dc211a9e9e), +CONST64(0x0fca1ec589d4caca), CONST64(0xb42d75995a582d2d), CONST64(0xc6bf9179632ebfbf), CONST64(0x1c07381b0e3f0707), +CONST64(0x8ead012347acadad), CONST64(0x755aea2fb4b05a5a), CONST64(0x36836cb51bef8383), CONST64(0xcc3385ff66b63333), +CONST64(0x91633ff2c65c6363), CONST64(0x0802100a04120202), CONST64(0x92aa39384993aaaa), CONST64(0xd971afa8e2de7171), +CONST64(0x07c80ecf8dc6c8c8), CONST64(0x6419c87d32d11919), CONST64(0x39497270923b4949), CONST64(0x43d9869aaf5fd9d9), +CONST64(0xeff2c31df931f2f2), CONST64(0xabe34b48dba8e3e3), CONST64(0x715be22ab6b95b5b), CONST64(0x1a8834920dbc8888), +CONST64(0x529aa4c8293e9a9a), CONST64(0x98262dbe4c0b2626), CONST64(0xc8328dfa64bf3232), CONST64(0xfab0e94a7d59b0b0), +CONST64(0x83e91b6acff2e9e9), CONST64(0x3c0f78331e770f0f), CONST64(0x73d5e6a6b733d5d5), CONST64(0x3a8074ba1df48080), +CONST64(0xc2be997c6127bebe), CONST64(0x13cd26de87ebcdcd), CONST64(0xd034bde468893434), CONST64(0x3d487a7590324848), +CONST64(0xdbffab24e354ffff), CONST64(0xf57af78ff48d7a7a), CONST64(0x7a90f4ea3d649090), CONST64(0x615fc23ebe9d5f5f), +CONST64(0x80201da0403d2020), CONST64(0xbd6867d5d00f6868), CONST64(0x681ad07234ca1a1a), CONST64(0x82ae192c41b7aeae), +CONST64(0xeab4c95e757db4b4), CONST64(0x4d549a19a8ce5454), CONST64(0x7693ece53b7f9393), CONST64(0x88220daa442f2222), +CONST64(0x8d6407e9c8636464), CONST64(0xe3f1db12ff2af1f1), CONST64(0xd173bfa2e6cc7373), CONST64(0x4812905a24821212), +CONST64(0x1d403a5d807a4040), CONST64(0x2008402810480808), CONST64(0x2bc356e89b95c3c3), CONST64(0x97ec337bc5dfecec), +CONST64(0x4bdb9690ab4ddbdb), CONST64(0xbea1611f5fc0a1a1), CONST64(0x0e8d1c8307918d8d), CONST64(0xf43df5c97ac83d3d), +CONST64(0x6697ccf1335b9797), CONST64(0x0000000000000000), CONST64(0x1bcf36d483f9cfcf), CONST64(0xac2b4587566e2b2b), +CONST64(0xc57697b3ece17676), CONST64(0x328264b019e68282), CONST64(0x7fd6fea9b128d6d6), CONST64(0x6c1bd87736c31b1b), +CONST64(0xeeb5c15b7774b5b5), CONST64(0x86af112943beafaf), CONST64(0xb56a77dfd41d6a6a), CONST64(0x5d50ba0da0ea5050), +CONST64(0x0945124c8a574545), CONST64(0xebf3cb18fb38f3f3), CONST64(0xc0309df060ad3030), CONST64(0x9bef2b74c3c4efef), +CONST64(0xfc3fe5c37eda3f3f), CONST64(0x4955921caac75555), CONST64(0xb2a2791059dba2a2), CONST64(0x8fea0365c9e9eaea), +CONST64(0x89650fecca6a6565), CONST64(0xd2bab9686903baba), CONST64(0xbc2f65935e4a2f2f), CONST64(0x27c04ee79d8ec0c0), +CONST64(0x5fdebe81a160dede), CONST64(0x701ce06c38fc1c1c), CONST64(0xd3fdbb2ee746fdfd), CONST64(0x294d52649a1f4d4d), +CONST64(0x7292e4e039769292), CONST64(0xc9758fbceafa7575), CONST64(0x1806301e0c360606), CONST64(0x128a249809ae8a8a), +CONST64(0xf2b2f940794bb2b2), CONST64(0xbfe66359d185e6e6), CONST64(0x380e70361c7e0e0e), CONST64(0x7c1ff8633ee71f1f), +CONST64(0x956237f7c4556262), CONST64(0x77d4eea3b53ad4d4), CONST64(0x9aa829324d81a8a8), CONST64(0x6296c4f431529696), +CONST64(0xc3f99b3aef62f9f9), CONST64(0x33c566f697a3c5c5), CONST64(0x942535b14a102525), CONST64(0x7959f220b2ab5959), +CONST64(0x2a8454ae15d08484), CONST64(0xd572b7a7e4c57272), CONST64(0xe439d5dd72ec3939), CONST64(0x2d4c5a6198164c4c), +CONST64(0x655eca3bbc945e5e), CONST64(0xfd78e785f09f7878), CONST64(0xe038ddd870e53838), CONST64(0x0a8c148605988c8c), +CONST64(0x63d1c6b2bf17d1d1), CONST64(0xaea5410b57e4a5a5), CONST64(0xafe2434dd9a1e2e2), CONST64(0x99612ff8c24e6161), +CONST64(0xf6b3f1457b42b3b3), CONST64(0x842115a542342121), CONST64(0x4a9c94d625089c9c), CONST64(0x781ef0663cee1e1e), +CONST64(0x1143225286614343), CONST64(0x3bc776fc93b1c7c7), CONST64(0xd7fcb32be54ffcfc), CONST64(0x1004201408240404), +CONST64(0x5951b208a2e35151), CONST64(0x5e99bcc72f259999), CONST64(0xa96d4fc4da226d6d), CONST64(0x340d68391a650d0d), +CONST64(0xcffa8335e979fafa), CONST64(0x5bdfb684a369dfdf), CONST64(0xe57ed79bfca97e7e), CONST64(0x90243db448192424), +CONST64(0xec3bc5d776fe3b3b), CONST64(0x96ab313d4b9aabab), CONST64(0x1fce3ed181f0cece), CONST64(0x4411885522991111), +CONST64(0x068f0c8903838f8f), CONST64(0x254e4a6b9c044e4e), CONST64(0xe6b7d1517366b7b7), CONST64(0x8beb0b60cbe0ebeb), +CONST64(0xf03cfdcc78c13c3c), CONST64(0x3e817cbf1ffd8181), CONST64(0x6a94d4fe35409494), CONST64(0xfbf7eb0cf31cf7f7), +CONST64(0xdeb9a1676f18b9b9), CONST64(0x4c13985f268b1313), CONST64(0xb02c7d9c58512c2c), CONST64(0x6bd3d6b8bb05d3d3), +CONST64(0xbbe76b5cd38ce7e7), CONST64(0xa56e57cbdc396e6e), CONST64(0x37c46ef395aac4c4), CONST64(0x0c03180f061b0303), +CONST64(0x45568a13acdc5656), CONST64(0x0d441a49885e4444), CONST64(0xe17fdf9efea07f7f), CONST64(0x9ea921374f88a9a9), +CONST64(0xa82a4d8254672a2a), CONST64(0xd6bbb16d6b0abbbb), CONST64(0x23c146e29f87c1c1), CONST64(0x5153a202a6f15353), +CONST64(0x57dcae8ba572dcdc), CONST64(0x2c0b582716530b0b), CONST64(0x4e9d9cd327019d9d), CONST64(0xad6c47c1d82b6c6c), +CONST64(0xc43195f562a43131), CONST64(0xcd7487b9e8f37474), CONST64(0xfff6e309f115f6f6), CONST64(0x05460a438c4c4646), +CONST64(0x8aac092645a5acac), CONST64(0x1e893c970fb58989), CONST64(0x5014a04428b41414), CONST64(0xa3e15b42dfbae1e1), +CONST64(0x5816b04e2ca61616), CONST64(0xe83acdd274f73a3a), CONST64(0xb9696fd0d2066969), CONST64(0x2409482d12410909), +CONST64(0xdd70a7ade0d77070), CONST64(0xe2b6d954716fb6b6), CONST64(0x67d0ceb7bd1ed0d0), CONST64(0x93ed3b7ec7d6eded), +CONST64(0x17cc2edb85e2cccc), CONST64(0x15422a5784684242), CONST64(0x5a98b4c22d2c9898), CONST64(0xaaa4490e55eda4a4), +CONST64(0xa0285d8850752828), CONST64(0x6d5cda31b8865c5c), CONST64(0xc7f8933fed6bf8f8), CONST64(0x228644a411c28686) +}; + +static const ulong64 sbox7[] = { +CONST64(0x186018c07830d818), CONST64(0x238c2305af462623), CONST64(0xc63fc67ef991b8c6), CONST64(0xe887e8136fcdfbe8), +CONST64(0x8726874ca113cb87), CONST64(0xb8dab8a9626d11b8), CONST64(0x0104010805020901), CONST64(0x4f214f426e9e0d4f), +CONST64(0x36d836adee6c9b36), CONST64(0xa6a2a6590451ffa6), CONST64(0xd26fd2debdb90cd2), CONST64(0xf5f3f5fb06f70ef5), +CONST64(0x79f979ef80f29679), CONST64(0x6fa16f5fcede306f), CONST64(0x917e91fcef3f6d91), CONST64(0x525552aa07a4f852), +CONST64(0x609d6027fdc04760), CONST64(0xbccabc89766535bc), CONST64(0x9b569baccd2b379b), CONST64(0x8e028e048c018a8e), +CONST64(0xa3b6a371155bd2a3), CONST64(0x0c300c603c186c0c), CONST64(0x7bf17bff8af6847b), CONST64(0x35d435b5e16a8035), +CONST64(0x1d741de8693af51d), CONST64(0xe0a7e05347ddb3e0), CONST64(0xd77bd7f6acb321d7), CONST64(0xc22fc25eed999cc2), +CONST64(0x2eb82e6d965c432e), CONST64(0x4b314b627a96294b), CONST64(0xfedffea321e15dfe), CONST64(0x5741578216aed557), +CONST64(0x155415a8412abd15), CONST64(0x77c1779fb6eee877), CONST64(0x37dc37a5eb6e9237), CONST64(0xe5b3e57b56d79ee5), +CONST64(0x9f469f8cd923139f), CONST64(0xf0e7f0d317fd23f0), CONST64(0x4a354a6a7f94204a), CONST64(0xda4fda9e95a944da), +CONST64(0x587d58fa25b0a258), CONST64(0xc903c906ca8fcfc9), CONST64(0x29a429558d527c29), CONST64(0x0a280a5022145a0a), +CONST64(0xb1feb1e14f7f50b1), CONST64(0xa0baa0691a5dc9a0), CONST64(0x6bb16b7fdad6146b), CONST64(0x852e855cab17d985), +CONST64(0xbdcebd8173673cbd), CONST64(0x5d695dd234ba8f5d), CONST64(0x1040108050209010), CONST64(0xf4f7f4f303f507f4), +CONST64(0xcb0bcb16c08bddcb), CONST64(0x3ef83eedc67cd33e), CONST64(0x05140528110a2d05), CONST64(0x6781671fe6ce7867), +CONST64(0xe4b7e47353d597e4), CONST64(0x279c2725bb4e0227), CONST64(0x4119413258827341), CONST64(0x8b168b2c9d0ba78b), +CONST64(0xa7a6a7510153f6a7), CONST64(0x7de97dcf94fab27d), CONST64(0x956e95dcfb374995), CONST64(0xd847d88e9fad56d8), +CONST64(0xfbcbfb8b30eb70fb), CONST64(0xee9fee2371c1cdee), CONST64(0x7ced7cc791f8bb7c), CONST64(0x66856617e3cc7166), +CONST64(0xdd53dda68ea77bdd), CONST64(0x175c17b84b2eaf17), CONST64(0x47014702468e4547), CONST64(0x9e429e84dc211a9e), +CONST64(0xca0fca1ec589d4ca), CONST64(0x2db42d75995a582d), CONST64(0xbfc6bf9179632ebf), CONST64(0x071c07381b0e3f07), +CONST64(0xad8ead012347acad), CONST64(0x5a755aea2fb4b05a), CONST64(0x8336836cb51bef83), CONST64(0x33cc3385ff66b633), +CONST64(0x6391633ff2c65c63), CONST64(0x020802100a041202), CONST64(0xaa92aa39384993aa), CONST64(0x71d971afa8e2de71), +CONST64(0xc807c80ecf8dc6c8), CONST64(0x196419c87d32d119), CONST64(0x4939497270923b49), CONST64(0xd943d9869aaf5fd9), +CONST64(0xf2eff2c31df931f2), CONST64(0xe3abe34b48dba8e3), CONST64(0x5b715be22ab6b95b), CONST64(0x881a8834920dbc88), +CONST64(0x9a529aa4c8293e9a), CONST64(0x2698262dbe4c0b26), CONST64(0x32c8328dfa64bf32), CONST64(0xb0fab0e94a7d59b0), +CONST64(0xe983e91b6acff2e9), CONST64(0x0f3c0f78331e770f), CONST64(0xd573d5e6a6b733d5), CONST64(0x803a8074ba1df480), +CONST64(0xbec2be997c6127be), CONST64(0xcd13cd26de87ebcd), CONST64(0x34d034bde4688934), CONST64(0x483d487a75903248), +CONST64(0xffdbffab24e354ff), CONST64(0x7af57af78ff48d7a), CONST64(0x907a90f4ea3d6490), CONST64(0x5f615fc23ebe9d5f), +CONST64(0x2080201da0403d20), CONST64(0x68bd6867d5d00f68), CONST64(0x1a681ad07234ca1a), CONST64(0xae82ae192c41b7ae), +CONST64(0xb4eab4c95e757db4), CONST64(0x544d549a19a8ce54), CONST64(0x937693ece53b7f93), CONST64(0x2288220daa442f22), +CONST64(0x648d6407e9c86364), CONST64(0xf1e3f1db12ff2af1), CONST64(0x73d173bfa2e6cc73), CONST64(0x124812905a248212), +CONST64(0x401d403a5d807a40), CONST64(0x0820084028104808), CONST64(0xc32bc356e89b95c3), CONST64(0xec97ec337bc5dfec), +CONST64(0xdb4bdb9690ab4ddb), CONST64(0xa1bea1611f5fc0a1), CONST64(0x8d0e8d1c8307918d), CONST64(0x3df43df5c97ac83d), +CONST64(0x976697ccf1335b97), CONST64(0x0000000000000000), CONST64(0xcf1bcf36d483f9cf), CONST64(0x2bac2b4587566e2b), +CONST64(0x76c57697b3ece176), CONST64(0x82328264b019e682), CONST64(0xd67fd6fea9b128d6), CONST64(0x1b6c1bd87736c31b), +CONST64(0xb5eeb5c15b7774b5), CONST64(0xaf86af112943beaf), CONST64(0x6ab56a77dfd41d6a), CONST64(0x505d50ba0da0ea50), +CONST64(0x450945124c8a5745), CONST64(0xf3ebf3cb18fb38f3), CONST64(0x30c0309df060ad30), CONST64(0xef9bef2b74c3c4ef), +CONST64(0x3ffc3fe5c37eda3f), CONST64(0x554955921caac755), CONST64(0xa2b2a2791059dba2), CONST64(0xea8fea0365c9e9ea), +CONST64(0x6589650fecca6a65), CONST64(0xbad2bab9686903ba), CONST64(0x2fbc2f65935e4a2f), CONST64(0xc027c04ee79d8ec0), +CONST64(0xde5fdebe81a160de), CONST64(0x1c701ce06c38fc1c), CONST64(0xfdd3fdbb2ee746fd), CONST64(0x4d294d52649a1f4d), +CONST64(0x927292e4e0397692), CONST64(0x75c9758fbceafa75), CONST64(0x061806301e0c3606), CONST64(0x8a128a249809ae8a), +CONST64(0xb2f2b2f940794bb2), CONST64(0xe6bfe66359d185e6), CONST64(0x0e380e70361c7e0e), CONST64(0x1f7c1ff8633ee71f), +CONST64(0x62956237f7c45562), CONST64(0xd477d4eea3b53ad4), CONST64(0xa89aa829324d81a8), CONST64(0x966296c4f4315296), +CONST64(0xf9c3f99b3aef62f9), CONST64(0xc533c566f697a3c5), CONST64(0x25942535b14a1025), CONST64(0x597959f220b2ab59), +CONST64(0x842a8454ae15d084), CONST64(0x72d572b7a7e4c572), CONST64(0x39e439d5dd72ec39), CONST64(0x4c2d4c5a6198164c), +CONST64(0x5e655eca3bbc945e), CONST64(0x78fd78e785f09f78), CONST64(0x38e038ddd870e538), CONST64(0x8c0a8c148605988c), +CONST64(0xd163d1c6b2bf17d1), CONST64(0xa5aea5410b57e4a5), CONST64(0xe2afe2434dd9a1e2), CONST64(0x6199612ff8c24e61), +CONST64(0xb3f6b3f1457b42b3), CONST64(0x21842115a5423421), CONST64(0x9c4a9c94d625089c), CONST64(0x1e781ef0663cee1e), +CONST64(0x4311432252866143), CONST64(0xc73bc776fc93b1c7), CONST64(0xfcd7fcb32be54ffc), CONST64(0x0410042014082404), +CONST64(0x515951b208a2e351), CONST64(0x995e99bcc72f2599), CONST64(0x6da96d4fc4da226d), CONST64(0x0d340d68391a650d), +CONST64(0xfacffa8335e979fa), CONST64(0xdf5bdfb684a369df), CONST64(0x7ee57ed79bfca97e), CONST64(0x2490243db4481924), +CONST64(0x3bec3bc5d776fe3b), CONST64(0xab96ab313d4b9aab), CONST64(0xce1fce3ed181f0ce), CONST64(0x1144118855229911), +CONST64(0x8f068f0c8903838f), CONST64(0x4e254e4a6b9c044e), CONST64(0xb7e6b7d1517366b7), CONST64(0xeb8beb0b60cbe0eb), +CONST64(0x3cf03cfdcc78c13c), CONST64(0x813e817cbf1ffd81), CONST64(0x946a94d4fe354094), CONST64(0xf7fbf7eb0cf31cf7), +CONST64(0xb9deb9a1676f18b9), CONST64(0x134c13985f268b13), CONST64(0x2cb02c7d9c58512c), CONST64(0xd36bd3d6b8bb05d3), +CONST64(0xe7bbe76b5cd38ce7), CONST64(0x6ea56e57cbdc396e), CONST64(0xc437c46ef395aac4), CONST64(0x030c03180f061b03), +CONST64(0x5645568a13acdc56), CONST64(0x440d441a49885e44), CONST64(0x7fe17fdf9efea07f), CONST64(0xa99ea921374f88a9), +CONST64(0x2aa82a4d8254672a), CONST64(0xbbd6bbb16d6b0abb), CONST64(0xc123c146e29f87c1), CONST64(0x535153a202a6f153), +CONST64(0xdc57dcae8ba572dc), CONST64(0x0b2c0b582716530b), CONST64(0x9d4e9d9cd327019d), CONST64(0x6cad6c47c1d82b6c), +CONST64(0x31c43195f562a431), CONST64(0x74cd7487b9e8f374), CONST64(0xf6fff6e309f115f6), CONST64(0x4605460a438c4c46), +CONST64(0xac8aac092645a5ac), CONST64(0x891e893c970fb589), CONST64(0x145014a04428b414), CONST64(0xe1a3e15b42dfbae1), +CONST64(0x165816b04e2ca616), CONST64(0x3ae83acdd274f73a), CONST64(0x69b9696fd0d20669), CONST64(0x092409482d124109), +CONST64(0x70dd70a7ade0d770), CONST64(0xb6e2b6d954716fb6), CONST64(0xd067d0ceb7bd1ed0), CONST64(0xed93ed3b7ec7d6ed), +CONST64(0xcc17cc2edb85e2cc), CONST64(0x4215422a57846842), CONST64(0x985a98b4c22d2c98), CONST64(0xa4aaa4490e55eda4), +CONST64(0x28a0285d88507528), CONST64(0x5c6d5cda31b8865c), CONST64(0xf8c7f8933fed6bf8), CONST64(0x86228644a411c286) +}; + +#endif + +static const ulong64 cont[] = { +CONST64(0x1823c6e887b8014f), +CONST64(0x36a6d2f5796f9152), +CONST64(0x60bc9b8ea30c7b35), +CONST64(0x1de0d7c22e4bfe57), +CONST64(0x157737e59ff04ada), +CONST64(0x58c9290ab1a06b85), +CONST64(0xbd5d10f4cb3e0567), +CONST64(0xe427418ba77d95d8), +CONST64(0xfbee7c66dd17479e), +CONST64(0xca2dbf07ad5a8333), +CONST64(0x6302aa71c81949d9), +}; + diff --git a/xtea.c b/xtea.c new file mode 100644 index 0000000..1434149 --- /dev/null +++ b/xtea.c @@ -0,0 +1,169 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +#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) +{ + unsigned long x, sum, K[4]; + + _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(K[0], key+0); + LOAD32L(K[1], key+4); + LOAD32L(K[2], key+8); + LOAD32L(K[3], key+12); + + for (x = sum = 0; x < 32; x++) { + skey->xtea.A[x] = (sum + K[sum&3]) & 0xFFFFFFFFUL; + sum = (sum + 0x9E3779B9UL) & 0xFFFFFFFFUL; + skey->xtea.B[x] = (sum + K[(sum>>11)&3]) & 0xFFFFFFFFUL; + } + +#ifdef CLEAN_STACK + zeromem(&K, sizeof(K)); +#endif + + return CRYPT_OK; +} + +void xtea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key) +{ + unsigned long y, z; + int r; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + + LOAD32L(y, &pt[0]); + LOAD32L(z, &pt[4]); + for (r = 0; r < 32; r += 4) { + y = (y + ((((z<<4)^(z>>5)) + z) ^ key->xtea.A[r])) & 0xFFFFFFFFUL; + z = (z + ((((y<<4)^(y>>5)) + y) ^ key->xtea.B[r])) & 0xFFFFFFFFUL; + + y = (y + ((((z<<4)^(z>>5)) + z) ^ key->xtea.A[r+1])) & 0xFFFFFFFFUL; + z = (z + ((((y<<4)^(y>>5)) + y) ^ key->xtea.B[r+1])) & 0xFFFFFFFFUL; + + y = (y + ((((z<<4)^(z>>5)) + z) ^ key->xtea.A[r+2])) & 0xFFFFFFFFUL; + z = (z + ((((y<<4)^(y>>5)) + y) ^ key->xtea.B[r+2])) & 0xFFFFFFFFUL; + + y = (y + ((((z<<4)^(z>>5)) + z) ^ key->xtea.A[r+3])) & 0xFFFFFFFFUL; + z = (z + ((((y<<4)^(y>>5)) + y) ^ key->xtea.B[r+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; + int r; + + _ARGCHK(pt != NULL); + _ARGCHK(ct != NULL); + _ARGCHK(key != NULL); + + LOAD32L(y, &ct[0]); + LOAD32L(z, &ct[4]); + for (r = 31; r >= 0; r -= 4) { + z = (z - ((((y<<4)^(y>>5)) + y) ^ key->xtea.B[r])) & 0xFFFFFFFFUL; + y = (y - ((((z<<4)^(z>>5)) + z) ^ key->xtea.A[r])) & 0xFFFFFFFFUL; + + z = (z - ((((y<<4)^(y>>5)) + y) ^ key->xtea.B[r-1])) & 0xFFFFFFFFUL; + y = (y - ((((z<<4)^(z>>5)) + z) ^ key->xtea.A[r-1])) & 0xFFFFFFFFUL; + + z = (z - ((((y<<4)^(y>>5)) + y) ^ key->xtea.B[r-2])) & 0xFFFFFFFFUL; + y = (y - ((((z<<4)^(z>>5)) + z) ^ key->xtea.A[r-2])) & 0xFFFFFFFFUL; + + z = (z - ((((y<<4)^(y>>5)) + y) ^ key->xtea.B[r-3])) & 0xFFFFFFFFUL; + y = (y - ((((z<<4)^(z>>5)) + z) ^ key->xtea.A[r-3])) & 0xFFFFFFFFUL; + } + STORE32L(y, &pt[0]); + STORE32L(z, &pt[4]); +} + +int xtea_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + 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 err, y; + + if ((err = xtea_setup(key, 16, 0, &skey)) != CRYPT_OK) { + return err; + } + xtea_ecb_encrypt(pt, tmp[0], &skey); + xtea_ecb_decrypt(tmp[0], tmp[1], &skey); + + if (memcmp(tmp[0], ct, 8) != 0 || memcmp(tmp[1], pt, 8) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + + /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ + for (y = 0; y < 8; y++) tmp[0][y] = 0; + for (y = 0; y < 1000; y++) xtea_ecb_encrypt(tmp[0], tmp[0], &skey); + for (y = 0; y < 1000; y++) xtea_ecb_decrypt(tmp[0], tmp[0], &skey); + for (y = 0; y < 8; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; + + return CRYPT_OK; + #endif +} + +int xtea_keysize(int *desired_keysize) +{ + _ARGCHK(desired_keysize != NULL); + 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..0cc0ad5 --- /dev/null +++ b/yarrow.c @@ -0,0 +1,167 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +#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 err; + + _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(RC6) + prng->yarrow.cipher = register_cipher(&rc6_desc); +#elif defined(RC5) + prng->yarrow.cipher = register_cipher(&rc5_desc); +#elif defined(SAFERP) + prng->yarrow.cipher = register_cipher(&saferp_desc); +#elif defined(RC2) + prng->yarrow.cipher = register_cipher(&rc2_desc); +#elif defined(NOEKEON) + prng->yarrow.cipher = register_cipher(&noekeon_desc); +#elif defined(CAST5) + prng->yarrow.cipher = register_cipher(&cast5_desc); +#elif defined(XTEA) + prng->yarrow.cipher = register_cipher(&xtea_desc); +#elif defined(SAFER) + prng->yarrow.cipher = register_cipher(&safer_sk128_desc); +#elif defined(DES) + prng->yarrow.cipher = register_cipher(&des3_desc); +#elif + #error YARROW needs at least one CIPHER +#endif + if ((err = cipher_is_valid(prng->yarrow.cipher)) != CRYPT_OK) { + return err; + } + +#ifdef SHA256 + prng->yarrow.hash = register_hash(&sha256_desc); +#elif defined(SHA512) + prng->yarrow.hash = register_hash(&sha512_desc); +#elif defined(TIGER) + prng->yarrow.hash = register_hash(&tiger_desc); +#elif defined(SHA1) + prng->yarrow.hash = register_hash(&sha1_desc); +#elif defined(RIPEMD160) + prng->yarrow.hash = register_hash(&rmd160_desc); +#elif defined(RIPEMD128) + prng->yarrow.hash = register_hash(&rmd128_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 ((err = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) { + return err; + } + + /* 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 err; + + _ARGCHK(buf != NULL); + _ARGCHK(prng != NULL); + + if ((err = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) { + return err; + } + + /* 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, err; + + _ARGCHK(prng != NULL); + + if ((err = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) { + return err; + } + + if ((err = cipher_is_valid(prng->yarrow.cipher)) != CRYPT_OK) { + return err; + } + + /* setup CTR mode using the "pool" as the key */ + ks = (int)hash_descriptor[prng->yarrow.hash].hashsize; + if ((err = cipher_descriptor[prng->yarrow.cipher].keysize(&ks)) != CRYPT_OK) { + return err; + } + + if ((err = ctr_start(prng->yarrow.cipher, /* what cipher to use */ + prng->yarrow.pool, /* IV */ + prng->yarrow.pool, ks, /* KEY and key size */ + 0, /* number of rounds */ + &prng->yarrow.ctr)) != CRYPT_OK) { + return err; + } + return CRYPT_OK; +} + +unsigned long yarrow_read(unsigned char *buf, unsigned long len, prng_state *prng) +{ + _ARGCHK(buf != NULL); + _ARGCHK(prng != NULL); + + /* put buf in predictable state first */ + zeromem(buf, len); + + /* now randomize it */ + if (ctr_encrypt(buf, buf, len, &prng->yarrow.ctr) != CRYPT_OK) { + return 0; + } + return len; +} + +#endif + diff --git a/zeromem.c b/zeromem.c new file mode 100644 index 0000000..15181ac --- /dev/null +++ b/zeromem.c @@ -0,0 +1,19 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +void zeromem(void *dst, size_t len) +{ + unsigned char *mem = (unsigned char *)dst; + _ARGCHK(dst != NULL); + while (len-- > 0) + *mem++ = 0; +} From a923823e6297248cc0425ec9508be885343d93ca Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 2 Jun 2004 08:31:25 +0000 Subject: [PATCH 2/9] Missing ranlib in makefile for library --HG-- branch : libtomcrypt extra : convert_revision : da041e04c62e2628db3c49282c4d8185e884f459 --- makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/makefile b/makefile index 25e4324..70ba136 100644 --- a/makefile +++ b/makefile @@ -158,6 +158,7 @@ library: $(LIBNAME) $(LIBNAME): $(OBJECTS) $(AR) $(ARFLAGS) $@ $(OBJECTS) + $(RANLIB) $(LIBNAME) #This rule makes the test program included with libtomcrypt test: library $(TESTOBJECTS) From 900a5eb418a957299643808a62adb3766b429b8f Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 15 Jun 2004 14:32:29 +0000 Subject: [PATCH 3/9] Removed PDFs, if people want them there's the .tex --HG-- branch : libtomcrypt extra : convert_revision : 897b1aaba9b009816bbb20b639d6a6a8b5bb4cde --- crypt.out | 88 -------------------------------------------------- crypt.pdf | Bin 404940 -> 0 bytes doc/crypt.pdf | Bin 398293 -> 0 bytes 3 files changed, 88 deletions(-) delete mode 100644 crypt.out delete mode 100644 crypt.pdf delete mode 100644 doc/crypt.pdf diff --git a/crypt.out b/crypt.out deleted file mode 100644 index 0b8ba59..0000000 --- a/crypt.out +++ /dev/null @@ -1,88 +0,0 @@ -\BOOKMARK [0][-]{chapter.1}{Introduction}{} -\BOOKMARK [1][-]{section.1.1}{What is the LibTomCrypt?}{chapter.1} -\BOOKMARK [2][-]{subsection.1.1.1}{What the library IS for?}{section.1.1} -\BOOKMARK [2][-]{subsection.1.1.2}{What the library IS NOT for?}{section.1.1} -\BOOKMARK [1][-]{section.1.2}{Why did I write it?}{chapter.1} -\BOOKMARK [2][-]{subsection.1.2.1}{Modular}{section.1.2} -\BOOKMARK [1][-]{section.1.3}{License}{chapter.1} -\BOOKMARK [1][-]{section.1.4}{Patent Disclosure}{chapter.1} -\BOOKMARK [1][-]{section.1.5}{Building the library}{chapter.1} -\BOOKMARK [1][-]{section.1.6}{Building against the library}{chapter.1} -\BOOKMARK [1][-]{section.1.7}{Thanks}{chapter.1} -\BOOKMARK [0][-]{chapter.2}{The Application Programming Interface \(API\)}{} -\BOOKMARK [1][-]{section.2.1}{Introduction}{chapter.2} -\BOOKMARK [1][-]{section.2.2}{Macros}{chapter.2} -\BOOKMARK [1][-]{section.2.3}{Functions with Variable Length Output}{chapter.2} -\BOOKMARK [1][-]{section.2.4}{Functions that need a PRNG}{chapter.2} -\BOOKMARK [1][-]{section.2.5}{Functions that use Arrays of Octets}{chapter.2} -\BOOKMARK [0][-]{chapter.3}{Symmetric Block Ciphers}{} -\BOOKMARK [1][-]{section.3.1}{Core Functions}{chapter.3} -\BOOKMARK [1][-]{section.3.2}{Key Sizes and Number of Rounds}{chapter.3} -\BOOKMARK [1][-]{section.3.3}{The Cipher Descriptors}{chapter.3} -\BOOKMARK [2][-]{subsection.3.3.1}{Notes}{section.3.3} -\BOOKMARK [1][-]{section.3.4}{Symmetric Modes of Operations}{chapter.3} -\BOOKMARK [2][-]{subsection.3.4.1}{Background}{section.3.4} -\BOOKMARK [2][-]{subsection.3.4.2}{Choice of Mode}{section.3.4} -\BOOKMARK [2][-]{subsection.3.4.3}{Implementation}{section.3.4} -\BOOKMARK [1][-]{section.3.5}{Encrypt and Authenticate Modes}{chapter.3} -\BOOKMARK [2][-]{subsection.3.5.1}{EAX Mode}{section.3.5} -\BOOKMARK [2][-]{subsection.3.5.2}{OCB Mode}{section.3.5} -\BOOKMARK [0][-]{chapter.4}{One-Way Cryptographic Hash Functions}{} -\BOOKMARK [1][-]{section.4.1}{Core Functions}{chapter.4} -\BOOKMARK [1][-]{section.4.2}{Hash Descriptors}{chapter.4} -\BOOKMARK [2][-]{subsection.4.2.1}{Notice}{section.4.2} -\BOOKMARK [0][-]{chapter.5}{Message Authentication Codes}{} -\BOOKMARK [1][-]{section.5.1}{HMAC Protocol}{chapter.5} -\BOOKMARK [1][-]{section.5.2}{OMAC Support}{chapter.5} -\BOOKMARK [1][-]{section.5.3}{PMAC Support}{chapter.5} -\BOOKMARK [0][-]{chapter.6}{Pseudo-Random Number Generators}{} -\BOOKMARK [1][-]{section.6.1}{Core Functions}{chapter.6} -\BOOKMARK [2][-]{subsection.6.1.1}{Remarks}{section.6.1} -\BOOKMARK [2][-]{subsection.6.1.2}{Example}{section.6.1} -\BOOKMARK [1][-]{section.6.2}{PRNG Descriptors}{chapter.6} -\BOOKMARK [1][-]{section.6.3}{The Secure RNG}{chapter.6} -\BOOKMARK [2][-]{subsection.6.3.1}{The Secure PRNG Interface}{section.6.3} -\BOOKMARK [0][-]{chapter.7}{RSA Routines}{} -\BOOKMARK [1][-]{section.7.1}{Background}{chapter.7} -\BOOKMARK [1][-]{section.7.2}{Core Functions}{chapter.7} -\BOOKMARK [1][-]{section.7.3}{Packet Routines}{chapter.7} -\BOOKMARK [1][-]{section.7.4}{Remarks}{chapter.7} -\BOOKMARK [0][-]{chapter.8}{Diffie-Hellman Key Exchange}{} -\BOOKMARK [1][-]{section.8.1}{Background}{chapter.8} -\BOOKMARK [1][-]{section.8.2}{Core Functions}{chapter.8} -\BOOKMARK [2][-]{subsection.8.2.1}{Remarks on Usage}{section.8.2} -\BOOKMARK [2][-]{subsection.8.2.2}{Remarks on The Snippet}{section.8.2} -\BOOKMARK [1][-]{section.8.3}{Other Diffie-Hellman Functions}{chapter.8} -\BOOKMARK [1][-]{section.8.4}{DH Packet}{chapter.8} -\BOOKMARK [0][-]{chapter.9}{Elliptic Curve Cryptography}{} -\BOOKMARK [1][-]{section.9.1}{Background}{chapter.9} -\BOOKMARK [1][-]{section.9.2}{Core Functions}{chapter.9} -\BOOKMARK [1][-]{section.9.3}{ECC Packet}{chapter.9} -\BOOKMARK [1][-]{section.9.4}{ECC Keysizes}{chapter.9} -\BOOKMARK [0][-]{chapter.10}{Digital Signature Algorithm}{} -\BOOKMARK [1][-]{section.10.1}{Introduction}{chapter.10} -\BOOKMARK [1][-]{section.10.2}{Key Generation}{chapter.10} -\BOOKMARK [1][-]{section.10.3}{Key Verification}{chapter.10} -\BOOKMARK [1][-]{section.10.4}{Signatures}{chapter.10} -\BOOKMARK [1][-]{section.10.5}{Import and Export}{chapter.10} -\BOOKMARK [0][-]{chapter.11}{Public Keyrings}{} -\BOOKMARK [1][-]{section.11.1}{Introduction}{chapter.11} -\BOOKMARK [1][-]{section.11.2}{The Keyring API}{chapter.11} -\BOOKMARK [0][-]{chapter.12}{GF\(2w\) Math Routines}{} -\BOOKMARK [0][-]{chapter.13}{Miscellaneous}{} -\BOOKMARK [1][-]{section.13.1}{Base64 Encoding and Decoding}{chapter.13} -\BOOKMARK [1][-]{section.13.2}{The Multiple Precision Integer Library \(MPI\)}{chapter.13} -\BOOKMARK [2][-]{subsection.13.2.1}{Binary Forms of ``mp\137int'' Variables}{section.13.2} -\BOOKMARK [2][-]{subsection.13.2.2}{Primality Testing}{section.13.2} -\BOOKMARK [0][-]{chapter.14}{Programming Guidelines}{} -\BOOKMARK [1][-]{section.14.1}{Secure Pseudo Random Number Generators}{chapter.14} -\BOOKMARK [1][-]{section.14.2}{Preventing Trivial Errors}{chapter.14} -\BOOKMARK [1][-]{section.14.3}{Registering Your Algorithms}{chapter.14} -\BOOKMARK [1][-]{section.14.4}{Key Sizes}{chapter.14} -\BOOKMARK [2][-]{subsection.14.4.1}{Symmetric Ciphers}{section.14.4} -\BOOKMARK [2][-]{subsection.14.4.2}{Assymetric Ciphers}{section.14.4} -\BOOKMARK [1][-]{section.14.5}{Thread Safety}{chapter.14} -\BOOKMARK [0][-]{chapter.15}{Configuring the Library}{} -\BOOKMARK [1][-]{section.15.1}{Introduction}{chapter.15} -\BOOKMARK [1][-]{section.15.2}{mycrypt\137cfg.h}{chapter.15} -\BOOKMARK [1][-]{section.15.3}{The Configure Script}{chapter.15} diff --git a/crypt.pdf b/crypt.pdf deleted file mode 100644 index 749b9da772d279a3fe0ebe9c3e06c195c49f24fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 404940 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

^Hgqnya3crJzj>Q=2W5!P}8e$<`h6t@p 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 ZF8jYYau%$;uTf2K?|1C)R?&w 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

Y~xccqPx=HfMkSCE3C5tzfUgf&nm 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

q>H^p0W4&#cwjf36p2Vy4{~-uDzK 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

4h+Mm(TRDZK+?4!@Ew&xh~h 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 z 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 StE87CzEoYLNEPp@n*Rl7@mYod From d407fec95387f5291d91f03a584361c688e2f0e4 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 15 Jun 2004 14:34:07 +0000 Subject: [PATCH 4/9] makefile --HG-- branch : libtomcrypt extra : convert_revision : 7fd8a0313edb710f4a3bef7eae0df50b8b94deae --- makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/makefile b/makefile index f2b4b8d..f3447aa 100644 --- a/makefile +++ b/makefile @@ -160,6 +160,7 @@ library: $(LIBNAME) $(LIBNAME): $(OBJECTS) $(AR) $(ARFLAGS) $@ $(OBJECTS) + $(RANLIB) $@ #This rule makes the hash program included with libtomcrypt hashsum: library $(HASHOBJECTS) From 3aa21f813d46edfb956bd6b49944392d262325c0 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 15 Jun 2004 16:47:55 +0000 Subject: [PATCH 5/9] Include files accidentally zeroed when merging 0.96 release --HG-- branch : libtomcrypt extra : convert_revision : 947de25878b9466872d1428ec1dd57a1b8b90477 --- crypt_hash_descriptor.c | 17 + demos/small.c | 11 + makefile.msvc | 88 +++++ sha224.c | 98 +++++ sha256.c | 312 ++++++++++++++++ sha384.c | 114 ++++++ sha512.c | 289 +++++++++++++++ tiger.c | 779 ++++++++++++++++++++++++++++++++++++++++ whirl.c | 280 +++++++++++++++ yarrow.c | 184 ++++++++++ 10 files changed, 2172 insertions(+) diff --git a/crypt_hash_descriptor.c b/crypt_hash_descriptor.c index e69de29..697de38 100644 --- a/crypt_hash_descriptor.c +++ b/crypt_hash_descriptor.c @@ -0,0 +1,17 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ +#include "mycrypt.h" + +struct _hash_descriptor hash_descriptor[TAB_SIZE] = { +{ NULL, 0, 0, 0, { 0x00 }, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, { 0x00 }, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, { 0x00 }, 0, NULL, NULL, NULL, NULL }, +{ NULL, 0, 0, 0, { 0x00 }, 0, NULL, NULL, NULL, NULL } }; diff --git a/demos/small.c b/demos/small.c index e69de29..f5a0d43 100644 --- a/demos/small.c +++ 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_enc_desc); + register_prng(&yarrow_desc); + register_hash(&sha256_desc); + return 0; +} diff --git a/makefile.msvc b/makefile.msvc index e69de29..aa8a9bc 100644 --- a/makefile.msvc +++ b/makefile.msvc @@ -0,0 +1,88 @@ +#MSVC Makefile [tested with MSVC 6.00 with SP5] +# +#Tom St Denis +CFLAGS = /I. /Ox /DWIN32 /W3 + +default: library + +# leave this blank and link against libtommath if you want better link resolution +MPIOBJECT=mpi.obj + +OBJECTS=error_to_string.obj mpi_to_ltc_error.obj base64_encode.obj base64_decode.obj \ +\ +crypt.obj crypt_find_cipher.obj crypt_find_hash_any.obj \ +crypt_hash_is_valid.obj crypt_register_hash.obj crypt_unregister_prng.obj \ +crypt_argchk.obj crypt_find_cipher_any.obj crypt_find_hash_id.obj \ +crypt_prng_descriptor.obj crypt_register_prng.obj crypt_cipher_descriptor.obj \ +crypt_find_cipher_id.obj crypt_find_prng.obj crypt_prng_is_valid.obj \ +crypt_unregister_cipher.obj crypt_cipher_is_valid.obj crypt_find_hash.obj \ +crypt_hash_descriptor.obj crypt_register_cipher.obj crypt_unregister_hash.obj \ +\ +sprng.obj yarrow.obj rc4.obj rng_get_bytes.obj rng_make_prng.obj \ +\ +rand_prime.obj is_prime.obj \ +\ +ecc.obj dh.obj \ +\ +rsa_decrypt_key.obj rsa_encrypt_key.obj rsa_exptmod.obj rsa_free.obj rsa_make_key.obj \ +rsa_sign_hash.obj rsa_verify_hash.obj rsa_export.obj rsa_import.obj tim_exptmod.obj \ +\ +dsa_export.obj dsa_free.obj dsa_import.obj dsa_make_key.obj dsa_sign_hash.obj \ +dsa_verify_hash.obj dsa_verify_key.obj \ +\ +aes.obj aes_enc.obj \ +\ +blowfish.obj des.obj safer_tab.obj safer.obj saferp.obj rc2.obj xtea.obj \ +rc6.obj rc5.obj cast5.obj noekeon.obj twofish.obj skipjack.obj \ +\ +md2.obj md4.obj md5.obj sha1.obj sha256.obj sha512.obj tiger.obj whirl.obj \ +rmd128.obj rmd160.obj \ +\ +packet_store_header.obj packet_valid_header.obj \ +\ +eax_addheader.obj eax_decrypt.obj eax_decrypt_verify_memory.obj eax_done.obj eax_encrypt.obj \ +eax_encrypt_authenticate_memory.obj eax_init.obj eax_test.obj \ +\ +ocb_decrypt.obj ocb_decrypt_verify_memory.obj ocb_done_decrypt.obj ocb_done_encrypt.obj \ +ocb_encrypt.obj ocb_encrypt_authenticate_memory.obj ocb_init.obj ocb_ntz.obj \ +ocb_shift_xor.obj ocb_test.obj s_ocb_done.obj \ +\ +omac_done.obj omac_file.obj omac_init.obj omac_memory.obj omac_process.obj omac_test.obj \ +\ +pmac_done.obj pmac_file.obj pmac_init.obj pmac_memory.obj pmac_ntz.obj pmac_process.obj \ +pmac_shift_xor.obj pmac_test.obj \ +\ +cbc_start.obj cbc_encrypt.obj cbc_decrypt.obj cbc_getiv.obj cbc_setiv.obj \ +cfb_start.obj cfb_encrypt.obj cfb_decrypt.obj cfb_getiv.obj cfb_setiv.obj \ +ofb_start.obj ofb_encrypt.obj ofb_decrypt.obj ofb_getiv.obj ofb_setiv.obj \ +ctr_start.obj ctr_encrypt.obj ctr_decrypt.obj ctr_getiv.obj ctr_setiv.obj \ +ecb_start.obj ecb_encrypt.obj ecb_decrypt.obj \ +\ +hash_file.obj hash_filehandle.obj hash_memory.obj \ +\ +hmac_done.obj hmac_file.obj hmac_init.obj hmac_memory.obj hmac_process.obj hmac_test.obj \ +\ +pkcs_1_mgf1.obj pkcs_1_oaep_encode.obj pkcs_1_oaep_decode.obj \ +pkcs_1_pss_encode.obj pkcs_1_pss_decode.obj pkcs_1_i2osp.obj pkcs_1_os2ip.obj \ +pkcs_1_v15_es_encode.obj pkcs_1_v15_es_decode.obj pkcs_1_v15_sa_encode.obj pkcs_1_v15_sa_decode.obj \ +\ +pkcs_5_1.obj pkcs_5_2.obj \ +\ +burn_stack.obj zeromem.obj \ +$(MPIOBJECT) + +#ciphers come in two flavours... enc+dec and enc +aes_enc.obj: aes.c aes_tab.c + $(CC) $(CFLAGS) /DENCRYPT_ONLY /c aes.c /Foaes_enc.obj + +library: $(OBJECTS) + lib /out:tomcrypt.lib $(OBJECTS) + +x86_prof: demos/x86_prof.c library + cl $(CFLAGS) demos/x86_prof.c tomcrypt.lib advapi32.lib + +tv_gen: demos/tv_gen.c library + cl $(CFLAGS) demos/tv_gen.c tomcrypt.lib advapi32.lib + +hashsum: demos/hashsum.c library + cl $(CFLAGS) demos/hashsum.c tomcrypt.lib advapi32.lib diff --git a/sha224.c b/sha224.c index e69de29..d013551 100644 --- a/sha224.c +++ b/sha224.c @@ -0,0 +1,98 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* SHA-224 new NIST standard based off of SHA-256 truncated to 224 bits */ +const struct _hash_descriptor sha224_desc = +{ + "sha224", + 10, + 28, + 64, + + /* DER identifier (not supported) */ + { 0x00 }, + 0, + + &sha224_init, + &sha256_process, + &sha224_done, + &sha224_test +}; + +/* init the sha256 er... sha224 state ;-) */ +void sha224_init(hash_state * md) +{ + _ARGCHK(md != NULL); + + md->sha256.curlen = 0; + md->sha256.length = 0; + md->sha256.state[0] = 0xc1059ed8UL; + md->sha256.state[1] = 0x367cd507UL; + md->sha256.state[2] = 0x3070dd17UL; + md->sha256.state[3] = 0xf70e5939UL; + md->sha256.state[4] = 0xffc00b31UL; + md->sha256.state[5] = 0x68581511UL; + md->sha256.state[6] = 0x64f98fa7UL; + md->sha256.state[7] = 0xbefa4fa4UL; +} + +int sha224_done(hash_state * md, unsigned char *hash) +{ + unsigned char buf[32]; + int err; + + err = sha256_done(md, buf); + memcpy(hash, buf, 28); +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + return err; +} + +int sha224_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + char *msg; + unsigned char hash[28]; + } tests[] = { + { "abc", + { 0x23, 0x09, 0x7d, 0x22, 0x34, 0x05, 0xd8, + 0x22, 0x86, 0x42, 0xa4, 0x77, 0xbd, 0xa2, + 0x55, 0xb3, 0x2a, 0xad, 0xbc, 0xe4, 0xbd, + 0xa0, 0xb3, 0xf7, 0xe3, 0x6c, 0x9d, 0xa7 } + }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + { 0x75, 0x38, 0x8b, 0x16, 0x51, 0x27, 0x76, + 0xcc, 0x5d, 0xba, 0x5d, 0xa1, 0xfd, 0x89, + 0x01, 0x50, 0xb0, 0xc6, 0x45, 0x5c, 0xb4, + 0xf5, 0x8b, 0x19, 0x52, 0x52, 0x25, 0x25 } + }, + }; + + int i; + unsigned char tmp[28]; + hash_state md; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + sha224_init(&md); + sha224_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg)); + sha224_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 28) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + diff --git a/sha256.c b/sha256.c index e69de29..ef2ae5e 100644 --- a/sha256.c +++ b/sha256.c @@ -0,0 +1,312 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + + +/* SHA256 by Tom St Denis */ + +#include "mycrypt.h" + +#ifdef SHA256 + +const struct _hash_descriptor sha256_desc = +{ + "sha256", + 0, + 32, + 64, + + /* DER identifier */ + { 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, + 0x00, 0x04, 0x20 }, + 19, + + &sha256_init, + &sha256_process, + &sha256_done, + &sha256_test +}; + +#ifdef SMALL_CODE +/* 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 +}; +#endif + +/* Various logical functions */ +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#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, unsigned char *buf) +#else +static void sha256_compress(hash_state * md, unsigned char *buf) +#endif +{ + ulong32 S[8], W[64], t0, t1; +#ifdef SMALL_CODE + ulong32 t; +#endif + int i; + + /* 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], 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 */ +#ifdef SMALL_CODE +#define RND(a,b,c,d,e,f,g,h,i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + for (i = 0; i < 64; ++i) { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i); + t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; + S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; + } +#else +#define RND(a,b,c,d,e,f,g,h,i,ki) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); + +#undef RND + +#endif + + /* 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, unsigned char *buf) +{ + _sha256_compress(md, buf); + burn_stack(sizeof(ulong32) * 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; +} + +HASH_PROCESS(sha256_process, sha256_compress, sha256, 64) + +int sha256_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->sha256.curlen >= sizeof(md->sha256.buf)) { + return CRYPT_INVALID_ARG; + } + + + /* increase the length of the message */ + md->sha256.length += md->sha256.curlen * 8; + + /* append the '1' bit */ + md->sha256.buf[md->sha256.curlen++] = (unsigned char)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++] = (unsigned char)0; + } + sha256_compress(md, md->sha256.buf); + md->sha256.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->sha256.curlen < 56) { + md->sha256.buf[md->sha256.curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64H(md->sha256.length, md->sha256.buf+56); + sha256_compress(md, md->sha256.buf); + + /* 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 + return CRYPT_OK; +} + +int sha256_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + 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 } + }, + }; + + int i; + unsigned char tmp[32]; + hash_state md; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + sha256_init(&md); + sha256_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg)); + sha256_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 32) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + +#ifdef SHA224 +#include "sha224.c" +#endif + +#endif + + diff --git a/sha384.c b/sha384.c index e69de29..120289a 100644 --- a/sha384.c +++ b/sha384.c @@ -0,0 +1,114 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* included in sha512.c */ + +const struct _hash_descriptor sha384_desc = +{ + "sha384", + 4, + 48, + 128, + + /* DER identifier */ + { 0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, + 0x00, 0x04, 0x30 }, + 19, + + &sha384_init, + &sha512_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); +} + +int sha384_done(hash_state * md, unsigned char *hash) +{ + unsigned char buf[64]; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->sha512.curlen >= sizeof(md->sha512.buf)) { + return CRYPT_INVALID_ARG; + } + + sha512_done(md, buf); + memcpy(hash, buf, 48); +#ifdef CLEAN_STACK + zeromem(buf, sizeof(buf)); +#endif + return CRYPT_OK; +} + +int sha384_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + 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 } + }, + }; + + int i; + unsigned char tmp[48]; + hash_state md; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + sha384_init(&md); + sha384_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg)); + sha384_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 48) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + + + + + diff --git a/sha512.c b/sha512.c index e69de29..9b5ddad 100644 --- a/sha512.c +++ b/sha512.c @@ -0,0 +1,289 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* SHA512 by Tom St Denis */ + +#include "mycrypt.h" + +#ifdef SHA512 + +const struct _hash_descriptor sha512_desc = +{ + "sha512", + 5, + 64, + 128, + + /* DER identifier */ + { 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, + 0x00, 0x04, 0x40 }, + 19, + + &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) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#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, unsigned char *buf) +#else +static void sha512_compress(hash_state * md, unsigned char *buf) +#endif +{ + ulong64 S[8], W[80], t0, t1; + int i; + + /* 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], 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 */ +#ifdef SMALL_CODE + 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; + } +#else +#define RND(a,b,c,d,e,f,g,h,i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + for (i = 0; i < 80; i += 8) { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); + } +#endif + + + /* 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, unsigned char *buf) +{ + _sha512_compress(md, buf); + 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); +} + +HASH_PROCESS(sha512_process, sha512_compress, sha512, 128) + +int sha512_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->sha512.curlen >= sizeof(md->sha512.buf)) { + return CRYPT_INVALID_ARG; + } + + /* increase the length of the message */ + md->sha512.length += md->sha512.curlen * CONST64(8); + + /* append the '1' bit */ + md->sha512.buf[md->sha512.curlen++] = (unsigned char)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++] = (unsigned char)0; + } + sha512_compress(md, md->sha512.buf); + 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++] = (unsigned char)0; + } + + /* store length */ + STORE64H(md->sha512.length, md->sha512.buf+120); + sha512_compress(md, md->sha512.buf); + + /* 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 + return CRYPT_OK; +} + +int sha512_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + 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 } + }, + }; + + int i; + unsigned char tmp[64]; + hash_state md; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + sha512_init(&md); + sha512_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg)); + sha512_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 64) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + +#ifdef SHA384 + #include "sha384.c" +#endif + +#endif + + + diff --git a/tiger.c b/tiger.c index e69de29..09ba9b3 100644 --- a/tiger.c +++ b/tiger.c @@ -0,0 +1,779 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +#include "mycrypt.h" + +#ifdef TIGER + +const struct _hash_descriptor tiger_desc = +{ + "tiger", + 1, + 24, + 64, + + /* DER identifier */ + { 0x30, 0x29, 0x30, 0x0D, 0x06, 0x09, 0x2B, 0x06, + 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0C, 0x02, 0x05, + 0x00, 0x04, 0x18 }, + 19, + + &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) + +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 */}; + +#ifdef _MSC_VER + #define INLINE __inline +#else + #define INLINE +#endif + +/* one round of the hash function */ +INLINE static void round(ulong64 *a, ulong64 *b, ulong64 *c, ulong64 x, int mul) +{ + ulong64 tmp; + tmp = (*c ^= x); + *a -= t1[byte(tmp, 0)] ^ t2[byte(tmp, 2)] ^ t3[byte(tmp, 4)] ^ t4[byte(tmp, 6)]; + tmp = (*b += t4[byte(tmp, 1)] ^ t3[byte(tmp, 3)] ^ t2[byte(tmp,5)] ^ t1[byte(tmp,7)]); + switch (mul) { + case 5: *b = (tmp << 2) + tmp; break; + case 7: *b = (tmp << 3) - tmp; break; + case 9: *b = (tmp << 3) + tmp; break; + } +} + +/* one complete pass */ +static void pass(ulong64 *a, ulong64 *b, ulong64 *c, ulong64 *x, int 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, unsigned char *buf) +#else +static void tiger_compress(hash_state *md, unsigned char *buf) +#endif +{ + ulong64 a, b, c, x[8]; + unsigned long i; + + /* load words */ + for (i = 0; i < 8; i++) { + LOAD64L(x[i],&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, unsigned char *buf) +{ + _tiger_compress(md, buf); + 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; +} + +HASH_PROCESS(tiger_process, tiger_compress, tiger, 64) + +int tiger_done(hash_state * md, unsigned char *hash) +{ + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->tiger.curlen >= sizeof(md->tiger.buf)) { + return CRYPT_INVALID_ARG; + } + + /* increase the length of the message */ + md->tiger.length += md->tiger.curlen * 8; + + /* append the '1' bit */ + md->tiger.buf[md->tiger.curlen++] = (unsigned char)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++] = (unsigned char)0; + } + tiger_compress(md, md->tiger.buf); + md->tiger.curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->tiger.curlen < 56) { + md->tiger.buf[md->tiger.curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64L(md->tiger.length, md->tiger.buf+56); + tiger_compress(md, md->tiger.buf); + + /* 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 + + return CRYPT_OK; +} + +int tiger_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + 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 } + }, + }; + + int i; + unsigned char tmp[24]; + hash_state md; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + tiger_init(&md); + tiger_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg)); + tiger_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 24) != 0) { + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + +#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/whirl.c b/whirl.c index e69de29..5233c47 100644 --- a/whirl.c +++ b/whirl.c @@ -0,0 +1,280 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +/* WHIRLPOOL (using their new sbox) hash function by Tom St Denis */ + +#include "mycrypt.h" + +#ifdef WHIRLPOOL + +const struct _hash_descriptor whirlpool_desc = +{ + "whirlpool", + 11, + 64, + 64, + + /* DER encoding (not yet supported) */ + { 0x00 }, + 0, + + &whirlpool_init, + &whirlpool_process, + &whirlpool_done, + &whirlpool_test +}; + +/* the sboxes */ +#include "whirltab.c" + +/* get a_{i,j} */ +#define GB(a,i,j) ((a[(i) & 7] >> (8 * (j))) & 255) + +/* shortcut macro to perform three functions at once */ +#define theta_pi_gamma(a, i) \ + SB0(GB(a, i-0, 7)) ^ \ + SB1(GB(a, i-1, 6)) ^ \ + SB2(GB(a, i-2, 5)) ^ \ + SB3(GB(a, i-3, 4)) ^ \ + SB4(GB(a, i-4, 3)) ^ \ + SB5(GB(a, i-5, 2)) ^ \ + SB6(GB(a, i-6, 1)) ^ \ + SB7(GB(a, i-7, 0)) + +#ifdef CLEAN_STACK +static void _whirlpool_compress(hash_state *md, unsigned char *buf) +#else +static void whirlpool_compress(hash_state *md, unsigned char *buf) +#endif +{ + ulong64 K[2][8], T[3][8]; + int x, y; + + /* load the block/state */ + for (x = 0; x < 8; x++) { + K[0][x] = md->whirlpool.state[x]; + + LOAD64H(T[0][x], buf + (8 * x)); + T[2][x] = T[0][x]; + T[0][x] ^= K[0][x]; + } + + /* do rounds 1..10 */ + for (x = 0; x < 10; x += 2) { + /* odd round */ + /* apply main transform to K[0] into K[1] */ + for (y = 0; y < 8; y++) { + K[1][y] = theta_pi_gamma(K[0], y); + } + /* xor the constant */ + K[1][0] ^= cont[x]; + + /* apply main transform to T[0] into T[1] */ + for (y = 0; y < 8; y++) { + T[1][y] = theta_pi_gamma(T[0], y) ^ K[1][y]; + } + + /* even round */ + /* apply main transform to K[1] into K[0] */ + for (y = 0; y < 8; y++) { + K[0][y] = theta_pi_gamma(K[1], y); + } + /* xor the constant */ + K[0][0] ^= cont[x+1]; + + /* apply main transform to T[0] into T[1] */ + for (y = 0; y < 8; y++) { + T[0][y] = theta_pi_gamma(T[1], y) ^ K[0][y]; + } + } + + /* store state */ + for (x = 0; x < 8; x++) { + md->whirlpool.state[x] ^= T[0][x] ^ T[2][x]; + } +} + + +#ifdef CLEAN_STACK +static void whirlpool_compress(hash_state *md, unsigned char *buf) +{ + _whirlpool_compress(md, buf); + burn_stack((5 * 8 * sizeof(ulong64)) + (2 * sizeof(int))); +} +#endif + + +void whirlpool_init(hash_state * md) +{ + _ARGCHK(md != NULL); + zeromem(&md->whirlpool, sizeof(md->whirlpool)); +} + +HASH_PROCESS(whirlpool_process, whirlpool_compress, whirlpool, 64) + +int whirlpool_done(hash_state * md, unsigned char *hash) +{ + int i; + + _ARGCHK(md != NULL); + _ARGCHK(hash != NULL); + + if (md->whirlpool.curlen >= sizeof(md->whirlpool.buf)) { + return CRYPT_INVALID_ARG; + } + + /* increase the length of the message */ + md->whirlpool.length += md->whirlpool.curlen * 8; + + /* append the '1' bit */ + md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0x80; + + /* if the length is currently above 32 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->whirlpool.curlen > 32) { + while (md->whirlpool.curlen < 64) { + md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0; + } + whirlpool_compress(md, md->whirlpool.buf); + md->whirlpool.curlen = 0; + } + + /* pad upto 56 bytes of zeroes (should be 32 but we only support 64-bit lengths) */ + while (md->whirlpool.curlen < 56) { + md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64H(md->whirlpool.length, md->whirlpool.buf+56); + whirlpool_compress(md, md->whirlpool.buf); + + /* copy output */ + for (i = 0; i < 8; i++) { + STORE64H(md->whirlpool.state[i], hash+(8*i)); + } +#ifdef CLEAN_STACK + zeromem(md, sizeof(*md)); +#endif + return CRYPT_OK; +} + + +int whirlpool_test(void) +{ + #ifndef LTC_TEST + return CRYPT_NOP; + #else + static const struct { + int len; + unsigned char msg[128], hash[64]; + } tests[] = { + + /* NULL Message */ +{ + 0, + { 0x00 }, + { 0x19, 0xFA, 0x61, 0xD7, 0x55, 0x22, 0xA4, 0x66, 0x9B, 0x44, 0xE3, 0x9C, 0x1D, 0x2E, 0x17, 0x26, + 0xC5, 0x30, 0x23, 0x21, 0x30, 0xD4, 0x07, 0xF8, 0x9A, 0xFE, 0xE0, 0x96, 0x49, 0x97, 0xF7, 0xA7, + 0x3E, 0x83, 0xBE, 0x69, 0x8B, 0x28, 0x8F, 0xEB, 0xCF, 0x88, 0xE3, 0xE0, 0x3C, 0x4F, 0x07, 0x57, + 0xEA, 0x89, 0x64, 0xE5, 0x9B, 0x63, 0xD9, 0x37, 0x08, 0xB1, 0x38, 0xCC, 0x42, 0xA6, 0x6E, 0xB3 } +}, + + + /* 448-bits of 0 bits */ +{ + + 56, + { 0x00 }, + { 0x0B, 0x3F, 0x53, 0x78, 0xEB, 0xED, 0x2B, 0xF4, 0xD7, 0xBE, 0x3C, 0xFD, 0x81, 0x8C, 0x1B, 0x03, + 0xB6, 0xBB, 0x03, 0xD3, 0x46, 0x94, 0x8B, 0x04, 0xF4, 0xF4, 0x0C, 0x72, 0x6F, 0x07, 0x58, 0x70, + 0x2A, 0x0F, 0x1E, 0x22, 0x58, 0x80, 0xE3, 0x8D, 0xD5, 0xF6, 0xED, 0x6D, 0xE9, 0xB1, 0xE9, 0x61, + 0xE4, 0x9F, 0xC1, 0x31, 0x8D, 0x7C, 0xB7, 0x48, 0x22, 0xF3, 0xD0, 0xE2, 0xE9, 0xA7, 0xE7, 0xB0 } +}, + + /* 520-bits of 0 bits */ +{ + 65, + { 0x00 }, + { 0x85, 0xE1, 0x24, 0xC4, 0x41, 0x5B, 0xCF, 0x43, 0x19, 0x54, 0x3E, 0x3A, 0x63, 0xFF, 0x57, 0x1D, + 0x09, 0x35, 0x4C, 0xEE, 0xBE, 0xE1, 0xE3, 0x25, 0x30, 0x8C, 0x90, 0x69, 0xF4, 0x3E, 0x2A, 0xE4, + 0xD0, 0xE5, 0x1D, 0x4E, 0xB1, 0xE8, 0x64, 0x28, 0x70, 0x19, 0x4E, 0x95, 0x30, 0xD8, 0xD8, 0xAF, + 0x65, 0x89, 0xD1, 0xBF, 0x69, 0x49, 0xDD, 0xF9, 0x0A, 0x7F, 0x12, 0x08, 0x62, 0x37, 0x95, 0xB9 } +}, + + /* 512-bits, leading set */ +{ + 64, + { 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, 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 }, + { 0x10, 0x3E, 0x00, 0x55, 0xA9, 0xB0, 0x90, 0xE1, 0x1C, 0x8F, 0xDD, 0xEB, 0xBA, 0x06, 0xC0, 0x5A, + 0xCE, 0x8B, 0x64, 0xB8, 0x96, 0x12, 0x8F, 0x6E, 0xED, 0x30, 0x71, 0xFC, 0xF3, 0xDC, 0x16, 0x94, + 0x67, 0x78, 0xE0, 0x72, 0x23, 0x23, 0x3F, 0xD1, 0x80, 0xFC, 0x40, 0xCC, 0xDB, 0x84, 0x30, 0xA6, + 0x40, 0xE3, 0x76, 0x34, 0x27, 0x1E, 0x65, 0x5C, 0xA1, 0x67, 0x4E, 0xBF, 0xF5, 0x07, 0xF8, 0xCB } +}, + + /* 512-bits, leading set of second byte */ +{ + 64, + { 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, 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 }, + { 0x35, 0x7B, 0x42, 0xEA, 0x79, 0xBC, 0x97, 0x86, 0x97, 0x5A, 0x3C, 0x44, 0x70, 0xAA, 0xB2, 0x3E, + 0x62, 0x29, 0x79, 0x7B, 0xAD, 0xBD, 0x54, 0x36, 0x5B, 0x54, 0x96, 0xE5, 0x5D, 0x9D, 0xD7, 0x9F, + 0xE9, 0x62, 0x4F, 0xB4, 0x22, 0x66, 0x93, 0x0A, 0x62, 0x8E, 0xD4, 0xDB, 0x08, 0xF9, 0xDD, 0x35, + 0xEF, 0x1B, 0xE1, 0x04, 0x53, 0xFC, 0x18, 0xF4, 0x2C, 0x7F, 0x5E, 0x1F, 0x9B, 0xAE, 0x55, 0xE0 } +}, + + /* 512-bits, leading set of last byte */ +{ + 64, + { 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, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 }, + { 0x8B, 0x39, 0x04, 0xDD, 0x19, 0x81, 0x41, 0x26, 0xFD, 0x02, 0x74, 0xAB, 0x49, 0xC5, 0x97, 0xF6, + 0xD7, 0x75, 0x33, 0x52, 0xA2, 0xDD, 0x91, 0xFD, 0x8F, 0x9F, 0x54, 0x05, 0x4C, 0x54, 0xBF, 0x0F, + 0x06, 0xDB, 0x4F, 0xF7, 0x08, 0xA3, 0xA2, 0x8B, 0xC3, 0x7A, 0x92, 0x1E, 0xEE, 0x11, 0xED, 0x7B, + 0x6A, 0x53, 0x79, 0x32, 0xCC, 0x5E, 0x94, 0xEE, 0x1E, 0xA6, 0x57, 0x60, 0x7E, 0x36, 0xC9, 0xF7 } +}, + +}; + + int i; + unsigned char tmp[64]; + hash_state md; + + for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) { + whirlpool_init(&md); + whirlpool_process(&md, (unsigned char *)tests[i].msg, tests[i].len); + whirlpool_done(&md, tmp); + if (memcmp(tmp, tests[i].hash, 64) != 0) { +#if 0 + printf("\nFailed test %d\n", i); + for (i = 0; i < 64; ) { + printf("%02x ", tmp[i]); + if (!(++i & 15)) printf("\n"); + } +#endif + return CRYPT_FAIL_TESTVECTOR; + } + } + return CRYPT_OK; + #endif +} + + +#endif + diff --git a/yarrow.c b/yarrow.c index e69de29..4415f78 100644 --- a/yarrow.c +++ b/yarrow.c @@ -0,0 +1,184 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + +#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 err; + + _ARGCHK(prng != NULL); + + /* these are the default hash/cipher combo used */ +#ifdef RIJNDAEL +#if YARROW_AES==0 + prng->yarrow.cipher = register_cipher(&rijndael_enc_desc); +#elif YARROW_AES==1 + prng->yarrow.cipher = register_cipher(&aes_enc_desc); +#elif YARROW_AES==2 + prng->yarrow.cipher = register_cipher(&rijndael_desc); +#elif YARROW_AES==3 + prng->yarrow.cipher = register_cipher(&aes_desc); +#endif +#elif defined(BLOWFISH) + prng->yarrow.cipher = register_cipher(&blowfish_desc); +#elif defined(TWOFISH) + prng->yarrow.cipher = register_cipher(&twofish_desc); +#elif defined(RC6) + prng->yarrow.cipher = register_cipher(&rc6_desc); +#elif defined(RC5) + prng->yarrow.cipher = register_cipher(&rc5_desc); +#elif defined(SAFERP) + prng->yarrow.cipher = register_cipher(&saferp_desc); +#elif defined(RC2) + prng->yarrow.cipher = register_cipher(&rc2_desc); +#elif defined(NOEKEON) + prng->yarrow.cipher = register_cipher(&noekeon_desc); +#elif defined(CAST5) + prng->yarrow.cipher = register_cipher(&cast5_desc); +#elif defined(XTEA) + prng->yarrow.cipher = register_cipher(&xtea_desc); +#elif defined(SAFER) + prng->yarrow.cipher = register_cipher(&safer_sk128_desc); +#elif defined(DES) + prng->yarrow.cipher = register_cipher(&des3_desc); +#elif + #error YARROW needs at least one CIPHER +#endif + if ((err = cipher_is_valid(prng->yarrow.cipher)) != CRYPT_OK) { + return err; + } + +#ifdef SHA256 + prng->yarrow.hash = register_hash(&sha256_desc); +#elif defined(SHA512) + prng->yarrow.hash = register_hash(&sha512_desc); +#elif defined(TIGER) + prng->yarrow.hash = register_hash(&tiger_desc); +#elif defined(SHA1) + prng->yarrow.hash = register_hash(&sha1_desc); +#elif defined(RIPEMD160) + prng->yarrow.hash = register_hash(&rmd160_desc); +#elif defined(RIPEMD128) + prng->yarrow.hash = register_hash(&rmd128_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); +#elif defined(WHIRLPOOL) + prng->yarrow.hash = register_hash(&whirlpool_desc); +#else + #error YARROW needs at least one HASH +#endif + if ((err = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) { + return err; + } + + /* 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 err; + + _ARGCHK(buf != NULL); + _ARGCHK(prng != NULL); + + if ((err = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) { + return err; + } + + /* start the hash */ + hash_descriptor[prng->yarrow.hash].init(&md); + + /* hash the current pool */ + if ((err = hash_descriptor[prng->yarrow.hash].process(&md, prng->yarrow.pool, + hash_descriptor[prng->yarrow.hash].hashsize)) != CRYPT_OK) { + return err; + } + + /* add the new entropy */ + if ((err = hash_descriptor[prng->yarrow.hash].process(&md, buf, len)) != CRYPT_OK) { + return err; + } + + /* store result */ + if ((err = hash_descriptor[prng->yarrow.hash].done(&md, prng->yarrow.pool)) != CRYPT_OK) { + return err; + } + + return CRYPT_OK; +} + +int yarrow_ready(prng_state *prng) +{ + int ks, err; + + _ARGCHK(prng != NULL); + + if ((err = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) { + return err; + } + + if ((err = cipher_is_valid(prng->yarrow.cipher)) != CRYPT_OK) { + return err; + } + + /* setup CTR mode using the "pool" as the key */ + ks = (int)hash_descriptor[prng->yarrow.hash].hashsize; + if ((err = cipher_descriptor[prng->yarrow.cipher].keysize(&ks)) != CRYPT_OK) { + return err; + } + + if ((err = ctr_start(prng->yarrow.cipher, /* what cipher to use */ + prng->yarrow.pool, /* IV */ + prng->yarrow.pool, ks, /* KEY and key size */ + 0, /* number of rounds */ + &prng->yarrow.ctr)) != CRYPT_OK) { + return err; + } + return CRYPT_OK; +} + +unsigned long yarrow_read(unsigned char *buf, unsigned long len, prng_state *prng) +{ + _ARGCHK(buf != NULL); + _ARGCHK(prng != NULL); + + /* put buf in predictable state first */ + zeromem(buf, len); + + /* now randomize it */ + if (ctr_encrypt(buf, buf, len, &prng->yarrow.ctr) != CRYPT_OK) { + return 0; + } + return len; +} + +#endif + From 5044b24c63cec600ea7a567217f42c16da2bde30 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sat, 7 Aug 2004 16:33:31 +0000 Subject: [PATCH 6/9] Merge of the normal Dropbear makefile: - Don't include mpi.o, since it does Bad Things (tm) (wrt LTM) - Don't try to make clean in tests if it doesn't exist (infinite looping makefiles, mmmmm) --HG-- branch : libtomcrypt extra : convert_revision : 2e048f798d212ab751471d7c19b5893745ce0e19 --- makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index f3447aa..a9d4cc6 100644 --- a/makefile +++ b/makefile @@ -58,7 +58,9 @@ DATAPATH=/usr/share/doc/libtomcrypt/pdf #List of objects to compile. #Leave MPI built-in or force developer to link against libtommath? -MPIOBJECT=mpi.o +#MPIOBJECT=mpi.o +#Dropbear uses libtommath +MPIOBJECT= OBJECTS=error_to_string.o mpi_to_ltc_error.o base64_encode.o base64_decode.o \ \ @@ -198,7 +200,7 @@ clean: rm -f $(TEST) $(HASH) $(COMPRESSED) $(PROFS) $(PROF) $(TVS) $(TV) rm -f *.a *.dll *stackdump *.lib *.exe *.obj demos/*.obj demos/*.o *.bat *.txt *.il *.da demos/*.il demos/*.da *.dyn *.dpi \ *.gcda *.gcno demos/*.gcno demos/*.gcda *~ doc/* - cd demos/test ; make clean + cd demos/test && make clean #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 From 86d817f825bad154dbe6e0ba15d50fe079e04cb1 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 2 Sep 2004 15:34:30 +0000 Subject: [PATCH 7/9] Fix typo in the big-endian macros --HG-- branch : libtomcrypt extra : convert_revision : 20b064e5f8948be5d302e84a8d51ed9a2039a13b --- mycrypt_macros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mycrypt_macros.h b/mycrypt_macros.h index 9fa6899..6cbaf7c 100644 --- a/mycrypt_macros.h +++ b/mycrypt_macros.h @@ -125,7 +125,7 @@ typedef unsigned long ulong32; #ifdef ENDIAN_BIG #define STORE32L(x, y) \ - { (y)[z0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ + { (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) \ From be3ddd9dd38ef9959fba613c1e2b1075f8e8aec6 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 3 Sep 2004 08:31:12 +0000 Subject: [PATCH 8/9] Fix for big-endian load/store macros --HG-- branch : libtomcrypt extra : convert_revision : 7e16f2d7b4546915812c8f17989e68c37c222c0d --- mycrypt_macros.h | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/mycrypt_macros.h b/mycrypt_macros.h index 6cbaf7c..969a961 100644 --- a/mycrypt_macros.h +++ b/mycrypt_macros.h @@ -125,26 +125,26 @@ typedef unsigned long ulong32; #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); } + { (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)[0] & 255)<<24) | \ - ((unsigned long)((y)[1] & 255)<<16) | \ - ((unsigned long)((y)[2] & 255)<<8) | \ - ((unsigned long)((y)[3] & 255)); } + { 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)[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); } + { (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)[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))); } +#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))); } #ifdef ENDIAN_32BITWORD @@ -155,16 +155,16 @@ typedef unsigned long ulong32; 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); } + { (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)[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 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))); } #else /* 64-bit words then */ From 33dcdb70442b405bcf187ba1662525ffece30812 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 17 Dec 2004 06:27:09 +0000 Subject: [PATCH 9/9] Pristine compilation works --HG-- branch : libtomcrypt extra : convert_revision : d547b52bc79c7809a9e1c90faead1411c9a10a9a --- makefile => Makefile.in | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) rename makefile => Makefile.in (93%) diff --git a/makefile b/Makefile.in similarity index 93% rename from makefile rename to Makefile.in index a9d4cc6..7aebfed 100644 --- a/makefile +++ b/Makefile.in @@ -11,6 +11,9 @@ # The version VERSION=0.96 +VPATH=@srcdir@ +srcdir=@srcdir@ + # Compiler and Linker Names #CC=gcc #LD=ld @@ -21,7 +24,7 @@ VERSION=0.96 # Compilation flags. Note the += does not write over the user's CFLAGS! # The rest of the flags come from the parent Dropbear makefile -CFLAGS += -c -I./ +CFLAGS += -c -I$(srcdir) # -Werror # optimize for SPEED @@ -149,7 +152,7 @@ default:library #ciphers come in two flavours... enc+dec and enc aes_enc.o: aes.c aes_tab.c - $(CC) $(CFLAGS) -DENCRYPT_ONLY -c aes.c -o aes_enc.o + $(CC) $(CFLAGS) -DENCRYPT_ONLY -c $(srcdir)/aes.c -o aes_enc.o #These are the rules to make certain object files. ecc.o: ecc.c ecc_sys.c @@ -196,18 +199,18 @@ install: library docs #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) $(PROFS) $(PROF) $(TVS) $(TV) - rm -f *.a *.dll *stackdump *.lib *.exe *.obj demos/*.obj demos/*.o *.bat *.txt *.il *.da demos/*.il demos/*.da *.dyn *.dpi \ + -rm -f $(OBJECTS) $(TESTOBJECTS) $(HASHOBJECTS) $(CRYPTOBJECTS) $(SMALLOBJECTS) $(LEFTOVERS) $(LIBNAME) + -rm -f $(TEST) $(HASH) $(COMPRESSED) $(PROFS) $(PROF) $(TVS) $(TV) + -rm -f *.a *.dll *stackdump *.lib *.exe *.obj demos/*.obj demos/*.o *.bat *.txt *.il *.da demos/*.il demos/*.da *.dyn *.dpi \ *.gcda *.gcno demos/*.gcno demos/*.gcda *~ doc/* - cd demos/test && make clean + -cd demos/test && make clean #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 doc/crypt.pdf $(LEFTOVERS) + -rm -f doc/crypt.pdf $(LEFTOVERS) echo "hello" > crypt.ind latex crypt > /dev/null makeindex crypt > /dev/null @@ -215,7 +218,7 @@ docs: crypt.tex latex crypt > /dev/null dvipdf crypt mv -ivf crypt.pdf doc/crypt.pdf - rm -f $(LEFTOVERS) + -rm -f $(LEFTOVERS) docdvi: crypt.tex echo hello > crypt.ind