diff --git a/changes b/changes index c0436a8..d29871b 100644 --- a/changes +++ b/changes @@ -1,3 +1,18 @@ +June 23rd, 2004 +v0.97a ++ Fixed several potentially crippling bugs... [read on] + -- Fixed bug in OAEP decoder that would incorrectly report + buffer overflows. [Zhi Chen] + -- Fixed headers which had various C++ missing [extern "C"]'s + -- Added "extern" to sha384_desc descriptor which I removed by mistake + -- Fixed bugs in ENDIAN_BIG macros using the wrong byte order [Matt Johnston] + -- Updated tiger.c and des.c to not shadow "round" which is intrinsic on + some C compilers. + -- Updated demos/test/rsa_test.c to test the RSA functionality better + ++ This update has been tested with GCC [v3.3.3], ICC [v8] and MSVC [v6+SP6] + all on a x86 P4 [GCC/ICC tested in Gentoo Linux, MSVC in WinXP] + ++ Outcome: The bug Zhi Chen pointed out has been fixed. So have the bugs + that Matt Johnston found. + June 19th, 2004 v0.97 -- Removed spurious unused files [arrg!] -- Patched buffer overflow in tim_exptmod() diff --git a/crypt.tex b/crypt.tex index d2f557f..e3b40af 100644 --- a/crypt.tex +++ b/crypt.tex @@ -47,7 +47,7 @@ \def\gap{\vspace{0.5ex}} \makeindex \begin{document} -\title{LibTomCrypt \\ Version 0.97} +\title{LibTomCrypt \\ Version 0.97a} \author{Tom St Denis \\ \\ tomstdenis@iahu.ca \\ diff --git a/demos/test/rsa_test.c b/demos/test/rsa_test.c index 772550a..3e72e44 100644 --- a/demos/test/rsa_test.c +++ b/demos/test/rsa_test.c @@ -1,11 +1,14 @@ #include "test.h" +#define RSA_MSGSIZE 78 + + int rsa_test(void) { unsigned char in[1024], out[1024], tmp[1024]; rsa_key key; int hash_idx, prng_idx, stat, stat2; - unsigned long len, len2; + unsigned long rsa_msgsize, len, len2; static unsigned char lparam[] = { 0x01, 0x02, 0x03, 0x04 }; hash_idx = find_hash("sha1"); @@ -15,48 +18,82 @@ int rsa_test(void) return 1; } - /* make a random key/msg */ - yarrow_read(in, 20, &test_yarrow); - /* make a random key */ DO(rsa_make_key(&test_yarrow, prng_idx, 1024/8, 65537, &key)); /* encrypt the key (without lparam) */ - len = sizeof(out); - len2 = sizeof(tmp); - DO(rsa_encrypt_key(in, 20, out, &len, NULL, 0, &test_yarrow, prng_idx, hash_idx, &key)); - /* change a byte */ - out[0] ^= 1; - DO(rsa_decrypt_key(out, len, tmp, &len2, NULL, 0, &test_yarrow, prng_idx, hash_idx, &stat2, &key)); - /* change a byte back */ - out[0] ^= 1; - DO(rsa_decrypt_key(out, len, tmp, &len2, NULL, 0, &test_yarrow, prng_idx, hash_idx, &stat, &key)); - if (!(stat == 1 && stat2 == 0)) { - printf("rsa_decrypt_key failed"); - return 1; - } - if (len2 != 20 || memcmp(tmp, in, 20)) { - printf("rsa_decrypt_key mismatch len %lu", len2); - return 1; + for (rsa_msgsize = 1; rsa_msgsize <= 86; rsa_msgsize++) { + /* make a random key/msg */ + yarrow_read(in, rsa_msgsize, &test_yarrow); + + len = sizeof(out); + len2 = rsa_msgsize; + + DO(rsa_encrypt_key(in, rsa_msgsize, out, &len, NULL, 0, &test_yarrow, prng_idx, hash_idx, &key)); + /* change a byte */ + out[8] ^= 1; + DO(rsa_decrypt_key(out, len, tmp, &len2, NULL, 0, &test_yarrow, prng_idx, hash_idx, &stat2, &key)); + /* change a byte back */ + out[8] ^= 1; + if (len2 != rsa_msgsize) { + printf("\nrsa_decrypt_key mismatch len %lu (first decrypt)", len2); + return 1; + } + + len2 = rsa_msgsize; + DO(rsa_decrypt_key(out, len, tmp, &len2, NULL, 0, &test_yarrow, prng_idx, hash_idx, &stat, &key)); + if (!(stat == 1 && stat2 == 0)) { + printf("rsa_decrypt_key failed"); + return 1; + } + if (len2 != rsa_msgsize || memcmp(tmp, in, rsa_msgsize)) { + int x; + printf("\nrsa_decrypt_key mismatch, len %lu (second decrypt)\n", len2); + printf("Original contents: \n"); + for (x = 0; x < rsa_msgsize; ) { + printf("%02x ", in[x]); + if (!(++x % 16)) { + printf("\n"); + } + } + printf("\n"); + printf("Output contents: \n"); + for (x = 0; x < rsa_msgsize; ) { + printf("%02x ", out[x]); + if (!(++x % 16)) { + printf("\n"); + } + } + printf("\n"); + return 1; + } } /* encrypt the key (with lparam) */ - len = sizeof(out); - len2 = sizeof(tmp); - DO(rsa_encrypt_key(in, 20, out, &len, lparam, sizeof(lparam), &test_yarrow, prng_idx, hash_idx, &key)); - /* change a byte */ - out[0] ^= 1; - DO(rsa_decrypt_key(out, len, tmp, &len2, lparam, sizeof(lparam), &test_yarrow, prng_idx, hash_idx, &stat2, &key)); - /* change a byte back */ - out[0] ^= 1; - DO(rsa_decrypt_key(out, len, tmp, &len2, lparam, sizeof(lparam), &test_yarrow, prng_idx, hash_idx, &stat, &key)); - if (!(stat == 1 && stat2 == 0)) { - printf("rsa_decrypt_key failed"); - return 1; - } - if (len2 != 20 || memcmp(tmp, in, 20)) { - printf("rsa_decrypt_key mismatch len %lu", len2); - return 1; + for (rsa_msgsize = 1; rsa_msgsize <= 86; rsa_msgsize++) { + len = sizeof(out); + len2 = rsa_msgsize; + DO(rsa_encrypt_key(in, rsa_msgsize, out, &len, lparam, sizeof(lparam), &test_yarrow, prng_idx, hash_idx, &key)); + /* change a byte */ + out[8] ^= 1; + DO(rsa_decrypt_key(out, len, tmp, &len2, lparam, sizeof(lparam), &test_yarrow, prng_idx, hash_idx, &stat2, &key)); + if (len2 != rsa_msgsize) { + printf("\nrsa_decrypt_key mismatch len %lu (first decrypt)", len2); + return 1; + } + /* change a byte back */ + out[8] ^= 1; + + len2 = rsa_msgsize; + DO(rsa_decrypt_key(out, len, tmp, &len2, lparam, sizeof(lparam), &test_yarrow, prng_idx, hash_idx, &stat, &key)); + if (!(stat == 1 && stat2 == 0)) { + printf("rsa_decrypt_key failed"); + return 1; + } + if (len2 != rsa_msgsize || memcmp(tmp, in, rsa_msgsize)) { + printf("rsa_decrypt_key mismatch len %lu", len2); + return 1; + } } /* sign a message (unsalted, lower cholestorol and Atkins approved) now */ diff --git a/des.c b/des.c index a4b4e04..e609014 100644 --- a/des.c +++ b/des.c @@ -1395,7 +1395,7 @@ static void _desfunc(ulong32 *block, const ulong32 *keys) #endif { ulong32 work, right, leftt; - int round; + int cur_round; leftt = block[0]; right = block[1]; @@ -1439,7 +1439,7 @@ static void _desfunc(ulong32 *block, const ulong32 *keys) } #endif - for (round = 0; round < 8; round++) { + for (cur_round = 0; cur_round < 8; cur_round++) { work = ROR(right, 4) ^ *keys++; leftt ^= SP7[work & 0x3fL] ^ SP5[(work >> 8) & 0x3fL] @@ -1534,7 +1534,7 @@ int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_k _ARGCHK(key != NULL); _ARGCHK(skey != NULL); - if( num_rounds != 0 && num_rounds != 16) { + if(num_rounds != 0 && num_rounds != 16) { return CRYPT_INVALID_ROUNDS; } diff --git a/doc/crypt.pdf b/doc/crypt.pdf index 5425a60..c8f5a95 100644 Binary files a/doc/crypt.pdf and b/doc/crypt.pdf differ diff --git a/ltc_tommath.h b/ltc_tommath.h index 6f855ce..a53c973 100644 --- a/ltc_tommath.h +++ b/ltc_tommath.h @@ -27,7 +27,7 @@ #define MAX(x,y) ((x)>(y)?(x):(y)) #ifdef __cplusplus - "C" { +extern "C" { /* C++ compilers don't like assigning void * to mp_digit * */ #define OPT_CAST(x) (x *) diff --git a/makefile b/makefile index 625cb4a..6b9a5da 100644 --- a/makefile +++ b/makefile @@ -4,7 +4,7 @@ # Modified by Clay Culver # The version -VERSION=0.97 +VERSION=0.97a # Compiler and Linker Names #CC=gcc diff --git a/mycrypt.h b/mycrypt.h index 9e3ff78..887bc43 100644 --- a/mycrypt.h +++ b/mycrypt.h @@ -12,12 +12,12 @@ #include #ifdef __cplusplus - "C" { +extern "C" { #endif /* version */ #define CRYPT 0x0097 -#define SCRYPT "0.97" +#define SCRYPT "0.97a" /* max size of either a cipher/hash block or symmetric key [largest of the two] */ #define MAXBLOCKSIZE 64 diff --git a/mycrypt_hash.h b/mycrypt_hash.h index 498e1da..dc828a4 100644 --- a/mycrypt_hash.h +++ b/mycrypt_hash.h @@ -149,7 +149,7 @@ extern struct _hash_descriptor { #define sha384_process sha512_process int sha384_done(hash_state * md, unsigned char *hash); int sha384_test(void); - const struct _hash_descriptor sha384_desc; + extern const struct _hash_descriptor sha384_desc; #endif #ifdef SHA256 diff --git a/mycrypt_macros.h b/mycrypt_macros.h index 9fa6899..cd69cd3 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)[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); } + { (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))); } + { 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))); } + { 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 */ diff --git a/pkcs_1_oaep_decode.c b/pkcs_1_oaep_decode.c index 66c9b47..2275bb3 100644 --- a/pkcs_1_oaep_decode.c +++ b/pkcs_1_oaep_decode.c @@ -140,7 +140,7 @@ int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, } /* rest is the message (and skip 0x01) */ - if (msglen - ++x > *outlen) { + if ((modulus_len - hLen - 1) - ++x > *outlen) { err = CRYPT_BUFFER_OVERFLOW; goto __ERR; } diff --git a/pkcs_1_oaep_encode.c b/pkcs_1_oaep_encode.c index 2ddc0a3..56816e6 100644 --- a/pkcs_1_oaep_encode.c +++ b/pkcs_1_oaep_encode.c @@ -58,7 +58,6 @@ int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, return CRYPT_MEM; } - /* test message size */ if (msglen > (modulus_len - 2*hLen - 2)) { err = CRYPT_PK_INVALID_SIZE; @@ -66,7 +65,7 @@ int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, } /* get lhash */ -// DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes + /* DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes */ x = modulus_len; if (lparam != NULL) { if ((err = hash_memory(hash_idx, lparam, lparamlen, DB, &x)) != CRYPT_OK) { diff --git a/pkcs_1_pss_decode.c b/pkcs_1_pss_decode.c index 64854c4..ff01b76 100644 --- a/pkcs_1_pss_decode.c +++ b/pkcs_1_pss_decode.c @@ -111,6 +111,7 @@ int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, } } + /* check for the 0x01 */ if (DB[x++] != 0x01) { err = CRYPT_OK; goto __ERR; diff --git a/rsa_decrypt_key.c b/rsa_decrypt_key.c index f8ac656..d6b6553 100644 --- a/rsa_decrypt_key.c +++ b/rsa_decrypt_key.c @@ -29,7 +29,7 @@ int rsa_decrypt_key(const unsigned char *in, unsigned long inlen, _ARGCHK(keylen != NULL); _ARGCHK(key != NULL); _ARGCHK(res != NULL); - + /* valid hash ? */ if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { return err; diff --git a/tiger.c b/tiger.c index 09ba9b3..06eb384 100644 --- a/tiger.c +++ b/tiger.c @@ -558,7 +558,7 @@ static const ulong64 table[4*256] = { #endif /* one round of the hash function */ -INLINE static void round(ulong64 *a, ulong64 *b, ulong64 *c, ulong64 x, int mul) +INLINE static void tiger_round(ulong64 *a, ulong64 *b, ulong64 *c, ulong64 x, int mul) { ulong64 tmp; tmp = (*c ^= x); @@ -574,14 +574,14 @@ INLINE static void round(ulong64 *a, ulong64 *b, ulong64 *c, ulong64 x, int mul) /* 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); + tiger_round(a,b,c,x[0],mul); + tiger_round(b,c,a,x[1],mul); + tiger_round(c,a,b,x[2],mul); + tiger_round(a,b,c,x[3],mul); + tiger_round(b,c,a,x[4],mul); + tiger_round(c,a,b,x[5],mul); + tiger_round(a,b,c,x[6],mul); + tiger_round(b,c,a,x[7],mul); } /* The key mixing schedule */