From cb9859fa0e061fa3b068447c3860588cf3522f4e Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Sun, 22 Feb 2015 00:23:19 +0100 Subject: Speed and memory usage optimization for key derivation based on patches by Nils Maier. 20% improvement on 64-bit CPU for SHA512 and SHA256, 11% for Whirlpool and 13% for RIPEMD-160. --- src/Common/Pkcs5.c | 634 ++++++++++++++++++++++++++++++----------------------- src/Common/Pkcs5.h | 19 +- src/Common/Tests.c | 20 +- 3 files changed, 383 insertions(+), 290 deletions(-) (limited to 'src/Common') diff --git a/src/Common/Pkcs5.c b/src/Common/Pkcs5.c index 396e3625..6585704c 100644 --- a/src/Common/Pkcs5.c +++ b/src/Common/Pkcs5.c @@ -36,43 +36,30 @@ void hmac_truncate #if !defined(TC_WINDOWS_BOOT) || defined(TC_WINDOWS_BOOT_SHA2) -void hmac_sha256 +typedef struct hmac_sha256_ctx_struct +{ + sha256_ctx ctx; + char buf[SHA256_BLOCKSIZE]; + char k[PKCS5_SALT_SIZE + 4]; /* enough to hold (salt_len + 4) and also the SHA256 hash */ + char u[SHA256_DIGESTSIZE]; +} hmac_sha256_ctx; + +void hmac_sha256_internal ( - char *k, /* secret key */ + char *k, /* secret key. It's ensured to be always <= 32 bytes */ int lk, /* length of the key in bytes */ - char *d, /* data */ - int ld, /* length of data in bytes */ - char *out /* output buffer, at least "t" bytes */ + char *d, /* input data. d pointer is guaranteed to be at least 32-bytes long */ + int ld, /* length of input data in bytes */ + hmac_sha256_ctx* hmac /* HMAC-SHA256 context which holds temporary variables */ ) { - sha256_ctx ictx, octx; - char isha[SHA256_DIGESTSIZE], osha[SHA256_DIGESTSIZE]; -#ifndef TC_WINDOWS_BOOT - char key[SHA256_DIGESTSIZE]; -#endif - char buf[SHA256_BLOCKSIZE]; int i; + sha256_ctx* ctx = &(hmac->ctx); + char* buf = hmac->buf; -#ifndef TC_WINDOWS_BOOT - /* If the key is longer than the hash algorithm block size, - let key = sha256(key), as per HMAC specifications. */ - if (lk > SHA256_BLOCKSIZE) - { - sha256_ctx tctx; - - sha256_begin (&tctx); - sha256_hash ((unsigned char *) k, lk, &tctx); - sha256_end ((unsigned char *) key, &tctx); - - k = key; - lk = SHA256_DIGESTSIZE; - - burn (&tctx, sizeof(tctx)); // Prevent leaks - } -#endif /**** Inner Digest ****/ - sha256_begin (&ictx); + sha256_begin (ctx); /* Pad the key for inner digest */ for (i = 0; i < lk; ++i) @@ -80,47 +67,65 @@ void hmac_sha256 for (i = lk; i < SHA256_BLOCKSIZE; ++i) buf[i] = 0x36; - sha256_hash ((unsigned char *) buf, SHA256_BLOCKSIZE, &ictx); - sha256_hash ((unsigned char *) d, ld, &ictx); + sha256_hash ((unsigned char *) buf, SHA256_BLOCKSIZE, ctx); + sha256_hash ((unsigned char *) d, ld, ctx); - sha256_end ((unsigned char *) isha, &ictx); + sha256_end ((unsigned char *) d, ctx); /* d = inner digest */ /**** Outer Digest ****/ - sha256_begin (&octx); + sha256_begin (ctx); for (i = 0; i < lk; ++i) buf[i] = (char) (k[i] ^ 0x5C); for (i = lk; i < SHA256_BLOCKSIZE; ++i) buf[i] = 0x5C; - sha256_hash ((unsigned char *) buf, SHA256_BLOCKSIZE, &octx); - sha256_hash ((unsigned char *) isha, SHA256_DIGESTSIZE, &octx); + sha256_hash ((unsigned char *) buf, SHA256_BLOCKSIZE, ctx); + sha256_hash ((unsigned char *) d, SHA256_DIGESTSIZE, ctx); + + sha256_end ((unsigned char *) d, ctx); /* d = outer digest */ +} + +#ifndef TC_WINDOWS_BOOT +void hmac_sha256 +( + char *k, /* secret key */ + int lk, /* length of the key in bytes */ + char *d, /* data */ + int ld /* length of data in bytes */ +) +{ + hmac_sha256_ctx hmac; + char key[SHA256_DIGESTSIZE]; + /* If the key is longer than the hash algorithm block size, + let key = sha256(key), as per HMAC specifications. */ + if (lk > SHA256_BLOCKSIZE) + { + sha256_ctx tctx; - sha256_end ((unsigned char *) osha, &octx); + sha256_begin (&tctx); + sha256_hash ((unsigned char *) k, lk, &tctx); + sha256_end ((unsigned char *) key, &tctx); - /* truncate and print the results */ - hmac_truncate (osha, out, SHA256_DIGESTSIZE); + k = key; + lk = SHA256_DIGESTSIZE; + burn (&tctx, sizeof(tctx)); // Prevent leaks + } + hmac_sha256_internal(k, lk, d, ld, &hmac); /* Prevent leaks */ - burn (&ictx, sizeof(ictx)); - burn (&octx, sizeof(octx)); - burn (isha, sizeof(isha)); - burn (osha, sizeof(osha)); - burn (buf, sizeof(buf)); -#ifndef TC_WINDOWS_BOOT - burn (key, sizeof(key)); -#endif + burn(&hmac, sizeof(hmac)); + burn(key, sizeof(key)); } +#endif - -void derive_u_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b) +static void derive_u_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, int b, hmac_sha256_ctx* hmac) { - char j[SHA256_DIGESTSIZE], k[SHA256_DIGESTSIZE]; - char init[128]; - char counter[4]; + char* k = hmac->k; + char* u = hmac->u; uint32 c; - int i; + int i; #ifdef TC_WINDOWS_BOOT /* In bootloader, iterations is a boolean : TRUE for boot derivation mode, FALSE otherwise @@ -135,35 +140,50 @@ void derive_u_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, int iter #endif /* iteration 1 */ - memset (counter, 0, 4); - counter[3] = (char) b; - memcpy (init, salt, salt_len); /* salt */ - memcpy (&init[salt_len], counter, 4); /* big-endian block number */ - hmac_sha256 (pwd, pwd_len, init, salt_len + 4, j); - memcpy (u, j, SHA256_DIGESTSIZE); + memcpy (k, salt, salt_len); /* salt */ + + /* big-endian block number */ + memset (&k[salt_len], 0, 3); + k[salt_len + 3] = (char) b; + + hmac_sha256_internal (pwd, pwd_len, k, salt_len + 4, hmac); + memcpy (u, k, SHA256_DIGESTSIZE); /* remaining iterations */ while (c > 1) { - hmac_sha256 (pwd, pwd_len, j, SHA256_DIGESTSIZE, k); + hmac_sha256_internal (pwd, pwd_len, k, SHA256_DIGESTSIZE, hmac); for (i = 0; i < SHA256_DIGESTSIZE; i++) { u[i] ^= k[i]; - j[i] = k[i]; } c--; } - - /* Prevent possible leaks. */ - burn (j, sizeof(j)); - burn (k, sizeof(k)); } void derive_key_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen) -{ - char u[SHA256_DIGESTSIZE]; +{ + hmac_sha256_ctx hmac; int b, l, r; +#ifndef TC_WINDOWS_BOOT + char key[SHA256_DIGESTSIZE]; + /* If the password is longer than the hash algorithm block size, + let pwd = sha256(pwd), as per HMAC specifications. */ + if (pwd_len > SHA256_BLOCKSIZE) + { + sha256_ctx tctx; + + sha256_begin (&tctx); + sha256_hash ((unsigned char *) pwd, pwd_len, &tctx); + sha256_end ((unsigned char *) key, &tctx); + + pwd = key; + pwd_len = SHA256_DIGESTSIZE; + + burn (&tctx, sizeof(tctx)); // Prevent leaks + } +#endif if (dklen % SHA256_DIGESTSIZE) { @@ -179,62 +199,51 @@ void derive_key_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, int it /* first l - 1 blocks */ for (b = 1; b < l; b++) { - derive_u_sha256 (pwd, pwd_len, salt, salt_len, iterations, u, b); - memcpy (dk, u, SHA256_DIGESTSIZE); + derive_u_sha256 (pwd, pwd_len, salt, salt_len, iterations, b, &hmac); + memcpy (dk, hmac.u, SHA256_DIGESTSIZE); dk += SHA256_DIGESTSIZE; } /* last block */ - derive_u_sha256 (pwd, pwd_len, salt, salt_len, iterations, u, b); - memcpy (dk, u, r); + derive_u_sha256 (pwd, pwd_len, salt, salt_len, iterations, b, &hmac); + memcpy (dk, hmac.u, r); /* Prevent possible leaks. */ - burn (u, sizeof(u)); + burn (&hmac, sizeof(hmac)); +#ifndef TC_WINDOWS_BOOT + burn (key, sizeof(key)); +#endif } #endif #ifndef TC_WINDOWS_BOOT -void hmac_sha512 +typedef struct hmac_sha512_ctx_struct +{ + sha512_ctx ctx; + char buf[SHA512_BLOCKSIZE]; + char k[PKCS5_SALT_SIZE + 4]; /* enough to hold (salt_len + 4) and also the SHA512 hash */ + char u[SHA512_DIGESTSIZE]; +} hmac_sha512_ctx; + +void hmac_sha512_internal ( char *k, /* secret key */ int lk, /* length of the key in bytes */ - char *d, /* data */ - int ld, /* length of data in bytes */ - char *out, /* output buffer, at least "t" bytes */ - int t + char *d, /* data and also output buffer of at least 64 bytes */ + int ld, /* length of data in bytes */ + hmac_sha512_ctx* hmac ) { - sha512_ctx ictx, octx; - char isha[SHA512_DIGESTSIZE], osha[SHA512_DIGESTSIZE]; -#ifndef TC_WINDOWS_BOOT - char key[SHA512_DIGESTSIZE]; -#endif - char buf[SHA512_BLOCKSIZE]; + sha512_ctx* ctx = &(hmac->ctx); + char* buf = hmac->buf; int i; -#ifndef TC_WINDOWS_BOOT - /* If the key is longer than the hash algorithm block size, - let key = sha512(key), as per HMAC specifications. */ - if (lk > SHA512_BLOCKSIZE) - { - sha512_ctx tctx; - - sha512_begin (&tctx); - sha512_hash ((unsigned char *) k, lk, &tctx); - sha512_end ((unsigned char *) key, &tctx); - - k = key; - lk = SHA512_DIGESTSIZE; - - burn (&tctx, sizeof(tctx)); // Prevent leaks - } -#endif /**** Inner Digest ****/ - sha512_begin (&ictx); + sha512_begin (ctx); /* Pad the key for inner digest */ for (i = 0; i < lk; ++i) @@ -242,77 +251,108 @@ void hmac_sha512 for (i = lk; i < SHA512_BLOCKSIZE; ++i) buf[i] = 0x36; - sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, &ictx); - sha512_hash ((unsigned char *) d, ld, &ictx); + sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, ctx); + sha512_hash ((unsigned char *) d, ld, ctx); - sha512_end ((unsigned char *) isha, &ictx); + sha512_end ((unsigned char *) d, ctx); /**** Outer Digest ****/ - sha512_begin (&octx); + sha512_begin (ctx); for (i = 0; i < lk; ++i) buf[i] = (char) (k[i] ^ 0x5C); for (i = lk; i < SHA512_BLOCKSIZE; ++i) buf[i] = 0x5C; - sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, &octx); - sha512_hash ((unsigned char *) isha, SHA512_DIGESTSIZE, &octx); + sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, ctx); + sha512_hash ((unsigned char *) d, SHA512_DIGESTSIZE, ctx); + + sha512_end ((unsigned char *) d, ctx); +} + +void hmac_sha512 +( + char *k, /* secret key */ + int lk, /* length of the key in bytes */ + char *d, /* data and also output buffer of at least 64 bytes */ + int ld /* length of data in bytes */ +) +{ + hmac_sha512_ctx hmac; + char key[SHA512_DIGESTSIZE]; + + /* If the key is longer than the hash algorithm block size, + let key = sha512(key), as per HMAC specifications. */ + if (lk > SHA512_BLOCKSIZE) + { + sha512_ctx tctx; - sha512_end ((unsigned char *) osha, &octx); + sha512_begin (&tctx); + sha512_hash ((unsigned char *) k, lk, &tctx); + sha512_end ((unsigned char *) key, &tctx); - /* truncate and print the results */ - t = t > SHA512_DIGESTSIZE ? SHA512_DIGESTSIZE : t; - hmac_truncate (osha, out, t); + k = key; + lk = SHA512_DIGESTSIZE; + + burn (&tctx, sizeof(tctx)); // Prevent leaks + } + + hmac_sha512_internal (k, lk, d, ld, &hmac); /* Prevent leaks */ - burn (&ictx, sizeof(ictx)); - burn (&octx, sizeof(octx)); - burn (isha, sizeof(isha)); - burn (osha, sizeof(osha)); - burn (buf, sizeof(buf)); -#ifndef TC_WINDOWS_BOOT + burn (&hmac, sizeof(hmac)); burn (key, sizeof(key)); -#endif } - -void derive_u_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b) +static void derive_u_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, int b, hmac_sha512_ctx* hmac) { - char j[SHA512_DIGESTSIZE], k[SHA512_DIGESTSIZE]; - char init[128]; - char counter[4]; + char* k = hmac->k; + char* u = hmac->u; int c, i; /* iteration 1 */ - memset (counter, 0, 4); - counter[3] = (char) b; - memcpy (init, salt, salt_len); /* salt */ - memcpy (&init[salt_len], counter, 4); /* big-endian block number */ - hmac_sha512 (pwd, pwd_len, init, salt_len + 4, j, SHA512_DIGESTSIZE); - memcpy (u, j, SHA512_DIGESTSIZE); + memcpy (k, salt, salt_len); /* salt */ + /* big-endian block number */ + memset (&k[salt_len], 0, 3); + k[salt_len + 3] = (char) b; + + hmac_sha512_internal (pwd, pwd_len, k, salt_len + 4, hmac); + memcpy (u, k, SHA512_DIGESTSIZE); /* remaining iterations */ for (c = 1; c < iterations; c++) { - hmac_sha512 (pwd, pwd_len, j, SHA512_DIGESTSIZE, k, SHA512_DIGESTSIZE); + hmac_sha512_internal (pwd, pwd_len, k, SHA512_DIGESTSIZE, hmac); for (i = 0; i < SHA512_DIGESTSIZE; i++) { u[i] ^= k[i]; - j[i] = k[i]; } } - - /* Prevent possible leaks. */ - burn (j, sizeof(j)); - burn (k, sizeof(k)); } void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen) { - char u[SHA512_DIGESTSIZE]; + hmac_sha512_ctx hmac; int b, l, r; + char key[SHA512_DIGESTSIZE]; + + /* If the password is longer than the hash algorithm block size, + let pwd = sha512(pwd), as per HMAC specifications. */ + if (pwd_len > SHA512_BLOCKSIZE) + { + sha512_ctx tctx; + + sha512_begin (&tctx); + sha512_hash ((unsigned char *) pwd, pwd_len, &tctx); + sha512_end ((unsigned char *) key, &tctx); + + pwd = key; + pwd_len = SHA512_DIGESTSIZE; + + burn (&tctx, sizeof(tctx)); // Prevent leaks + } if (dklen % SHA512_DIGESTSIZE) { @@ -328,51 +368,39 @@ void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int it /* first l - 1 blocks */ for (b = 1; b < l; b++) { - derive_u_sha512 (pwd, pwd_len, salt, salt_len, iterations, u, b); - memcpy (dk, u, SHA512_DIGESTSIZE); + derive_u_sha512 (pwd, pwd_len, salt, salt_len, iterations, b, &hmac); + memcpy (dk, hmac.u, SHA512_DIGESTSIZE); dk += SHA512_DIGESTSIZE; } /* last block */ - derive_u_sha512 (pwd, pwd_len, salt, salt_len, iterations, u, b); - memcpy (dk, u, r); + derive_u_sha512 (pwd, pwd_len, salt, salt_len, iterations, b, &hmac); + memcpy (dk, hmac.u, r); /* Prevent possible leaks. */ - burn (u, sizeof(u)); + burn (&hmac, sizeof(hmac)); + burn (key, sizeof(key)); } #endif // TC_WINDOWS_BOOT #if !defined(TC_WINDOWS_BOOT) || defined(TC_WINDOWS_BOOT_RIPEMD160) -void hmac_ripemd160 (char *key, int keylen, char *input, int len, char *digest) +typedef struct hmac_ripemd160_ctx_struct { - RMD160_CTX context; - unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */ - unsigned char k_opad[65]; /* outer padding - key XORd with opad */ -#ifndef TC_WINDOWS_BOOT - unsigned char tk[RIPEMD160_DIGESTSIZE]; -#endif - int i; - -#ifndef TC_WINDOWS_BOOT - /* If the key is longer than the hash algorithm block size, - let key = ripemd160(key), as per HMAC specifications. */ - if (keylen > RIPEMD160_BLOCKSIZE) - { - RMD160_CTX tctx; - - RMD160Init(&tctx); - RMD160Update(&tctx, (const unsigned char *) key, keylen); - RMD160Final(tk, &tctx); + RMD160_CTX context; + char k_pad[65]; + char k[PKCS5_SALT_SIZE + 4]; /* enough to hold (salt_len + 4) and also the RIPEMD-160 hash */ + char u[RIPEMD160_DIGESTSIZE]; +} hmac_ripemd160_ctx; - key = (char *) tk; - keylen = RIPEMD160_DIGESTSIZE; +void hmac_ripemd160_internal (char *key, int keylen, char *input_digest, int len, hmac_ripemd160_ctx* hmac) +{ + RMD160_CTX* context = &(hmac->context); + unsigned char* k_pad = hmac->k_pad; /* inner/outer padding - key XORd with ipad */ + int i; - burn (&tctx, sizeof(tctx)); // Prevent leaks - } -#endif /* RMD160(K XOR opad, RMD160(K XOR ipad, text)) @@ -384,44 +412,69 @@ void hmac_ripemd160 (char *key, int keylen, char *input, int len, char *digest) /* start out by storing key in pads */ - memset(k_ipad, 0x36, sizeof(k_ipad)); - memset(k_opad, 0x5c, sizeof(k_opad)); + memset(k_pad, 0x36, 65); /* XOR key with ipad and opad values */ for (i=0; i RIPEMD160_BLOCKSIZE) + { + RMD160_CTX tctx; + + RMD160Init(&tctx); + RMD160Update(&tctx, (const unsigned char *) key, keylen); + RMD160Final(tk, &tctx); + + key = (char *) tk; + keylen = RIPEMD160_DIGESTSIZE; + + burn (&tctx, sizeof(tctx)); // Prevent leaks + } + + hmac_ripemd160_internal (key, keylen, input_digest, len, &hmac); + + burn (&hmac, sizeof(hmac)); burn (tk, sizeof(tk)); -#endif - burn (&context, sizeof(context)); } +#endif + -void derive_u_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b) +static void derive_u_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, int b, hmac_ripemd160_ctx* hmac) { - char j[RIPEMD160_DIGESTSIZE], k[RIPEMD160_DIGESTSIZE]; - char init[128]; - char counter[4]; + char* k = hmac->k; + char* u = hmac->u; uint32 c; int i; @@ -438,34 +491,49 @@ void derive_u_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int i #endif /* iteration 1 */ - memset (counter, 0, 4); - counter[3] = (char) b; - memcpy (init, salt, salt_len); /* salt */ - memcpy (&init[salt_len], counter, 4); /* big-endian block number */ - hmac_ripemd160 (pwd, pwd_len, init, salt_len + 4, j); - memcpy (u, j, RIPEMD160_DIGESTSIZE); + memcpy (k, salt, salt_len); /* salt */ + + /* big-endian block number */ + memset (&k[salt_len], 0, 3); + k[salt_len + 3] = (char) b; + + hmac_ripemd160_internal (pwd, pwd_len, k, salt_len + 4, hmac); + memcpy (u, k, RIPEMD160_DIGESTSIZE); /* remaining iterations */ while ( c > 1) { - hmac_ripemd160 (pwd, pwd_len, j, RIPEMD160_DIGESTSIZE, k); + hmac_ripemd160_internal (pwd, pwd_len, k, RIPEMD160_DIGESTSIZE, hmac); for (i = 0; i < RIPEMD160_DIGESTSIZE; i++) { u[i] ^= k[i]; - j[i] = k[i]; } c--; } - - /* Prevent possible leaks. */ - burn (j, sizeof(j)); - burn (k, sizeof(k)); } void derive_key_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen) -{ - char u[RIPEMD160_DIGESTSIZE]; +{ int b, l, r; + hmac_ripemd160_ctx hmac; +#ifndef TC_WINDOWS_BOOT + unsigned char tk[RIPEMD160_DIGESTSIZE]; + /* If the password is longer than the hash algorithm block size, + let password = ripemd160(password), as per HMAC specifications. */ + if (pwd_len > RIPEMD160_BLOCKSIZE) + { + RMD160_CTX tctx; + + RMD160Init(&tctx); + RMD160Update(&tctx, (const unsigned char *) pwd, pwd_len); + RMD160Final(tk, &tctx); + + pwd = (char *) tk; + pwd_len = RIPEMD160_DIGESTSIZE; + + burn (&tctx, sizeof(tctx)); // Prevent leaks + } +#endif if (dklen % RIPEMD160_DIGESTSIZE) { @@ -481,61 +549,50 @@ void derive_key_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int /* first l - 1 blocks */ for (b = 1; b < l; b++) { - derive_u_ripemd160 (pwd, pwd_len, salt, salt_len, iterations, u, b); - memcpy (dk, u, RIPEMD160_DIGESTSIZE); + derive_u_ripemd160 (pwd, pwd_len, salt, salt_len, iterations, b, &hmac); + memcpy (dk, hmac.u, RIPEMD160_DIGESTSIZE); dk += RIPEMD160_DIGESTSIZE; } /* last block */ - derive_u_ripemd160 (pwd, pwd_len, salt, salt_len, iterations, u, b); - memcpy (dk, u, r); + derive_u_ripemd160 (pwd, pwd_len, salt, salt_len, iterations, b, &hmac); + memcpy (dk, hmac.u, r); /* Prevent possible leaks. */ - burn (u, sizeof(u)); + burn (&hmac, sizeof(hmac)); +#ifndef TC_WINDOWS_BOOT + burn (tk, sizeof(tk)); +#endif } #endif // TC_WINDOWS_BOOT #ifndef TC_WINDOWS_BOOT -void hmac_whirlpool +typedef struct hmac_whirlpool_ctx_struct +{ + WHIRLPOOL_CTX ctx; + char buf[WHIRLPOOL_BLOCKSIZE]; + char k[PKCS5_SALT_SIZE + 4]; /* enough to hold (salt_len + 4) and also the Whirlpool hash */ + char u[WHIRLPOOL_DIGESTSIZE]; +} hmac_whirlpool_ctx; + +void hmac_whirlpool_internal ( char *k, /* secret key */ int lk, /* length of the key in bytes */ - char *d, /* data */ - int ld, /* length of data in bytes */ - char *out, /* output buffer, at least "t" bytes */ - int t + char *d, /* input/output data. d pointer is guaranteed to be at least 64-bytes long */ + int ld, /* length of input data in bytes */ + hmac_whirlpool_ctx* hmac /* HMAC-Whirlpool context which holds temporary variables */ ) { - WHIRLPOOL_CTX ictx, octx; - char iwhi[WHIRLPOOL_DIGESTSIZE], owhi[WHIRLPOOL_DIGESTSIZE]; -#ifndef TC_WINDOWS_BOOT - char key[WHIRLPOOL_DIGESTSIZE]; -#endif - char buf[WHIRLPOOL_BLOCKSIZE]; + WHIRLPOOL_CTX* ctx = &(hmac->ctx); + char* buf = hmac->buf; int i; -#ifndef TC_WINDOWS_BOOT - /* If the key is longer than the hash algorithm block size, - let key = whirlpool(key), as per HMAC specifications. */ - if (lk > WHIRLPOOL_BLOCKSIZE) - { - WHIRLPOOL_CTX tctx; - - WHIRLPOOL_init (&tctx); - WHIRLPOOL_add ((unsigned char *) k, lk * 8, &tctx); - WHIRLPOOL_finalize (&tctx, (unsigned char *) key); - - k = key; - lk = WHIRLPOOL_DIGESTSIZE; - - burn (&tctx, sizeof(tctx)); // Prevent leaks - } -#endif /**** Inner Digest ****/ - WHIRLPOOL_init (&ictx); + WHIRLPOOL_init (ctx); /* Pad the key for inner digest */ for (i = 0; i < lk; ++i) @@ -543,75 +600,103 @@ void hmac_whirlpool for (i = lk; i < WHIRLPOOL_BLOCKSIZE; ++i) buf[i] = 0x36; - WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, &ictx); - WHIRLPOOL_add ((unsigned char *) d, ld * 8, &ictx); + WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, ctx); + WHIRLPOOL_add ((unsigned char *) d, ld * 8, ctx); - WHIRLPOOL_finalize (&ictx, (unsigned char *) iwhi); + WHIRLPOOL_finalize (ctx, (unsigned char *) d); /**** Outer Digest ****/ - WHIRLPOOL_init (&octx); + WHIRLPOOL_init (ctx); for (i = 0; i < lk; ++i) buf[i] = (char) (k[i] ^ 0x5C); for (i = lk; i < WHIRLPOOL_BLOCKSIZE; ++i) buf[i] = 0x5C; - WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, &octx); - WHIRLPOOL_add ((unsigned char *) iwhi, WHIRLPOOL_DIGESTSIZE * 8, &octx); + WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, ctx); + WHIRLPOOL_add ((unsigned char *) d, WHIRLPOOL_DIGESTSIZE * 8, ctx); - WHIRLPOOL_finalize (&octx, (unsigned char *) owhi); + WHIRLPOOL_finalize (ctx, (unsigned char *) d); +} - /* truncate and print the results */ - t = t > WHIRLPOOL_DIGESTSIZE ? WHIRLPOOL_DIGESTSIZE : t; - hmac_truncate (owhi, out, t); +void hmac_whirlpool +( + char *k, /* secret key */ + int lk, /* length of the key in bytes */ + char *d, /* input data. d pointer is guaranteed to be at least 32-bytes long */ + int ld /* length of data in bytes */ +) +{ + hmac_whirlpool_ctx hmac; + char key[WHIRLPOOL_DIGESTSIZE]; + /* If the key is longer than the hash algorithm block size, + let key = whirlpool(key), as per HMAC specifications. */ + if (lk > WHIRLPOOL_BLOCKSIZE) + { + WHIRLPOOL_CTX tctx; - /* Prevent possible leaks. */ - burn (&ictx, sizeof(ictx)); - burn (&octx, sizeof(octx)); - burn (owhi, sizeof(owhi)); - burn (iwhi, sizeof(iwhi)); - burn (buf, sizeof(buf)); -#ifndef TC_WINDOWS_BOOT - burn (key, sizeof(key)); -#endif + WHIRLPOOL_init (&tctx); + WHIRLPOOL_add ((unsigned char *) k, lk * 8, &tctx); + WHIRLPOOL_finalize (&tctx, (unsigned char *) key); + + k = key; + lk = WHIRLPOOL_DIGESTSIZE; + + burn (&tctx, sizeof(tctx)); // Prevent leaks + } + + hmac_whirlpool_internal(k, lk, d, ld, &hmac); + /* Prevent leaks */ + burn(&hmac, sizeof(hmac)); } -void derive_u_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b) +static void derive_u_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, int b, hmac_whirlpool_ctx* hmac) { - char j[WHIRLPOOL_DIGESTSIZE], k[WHIRLPOOL_DIGESTSIZE]; - char init[128]; - char counter[4]; + char* u = hmac->u; + char* k = hmac->k; int c, i; /* iteration 1 */ - memset (counter, 0, 4); - counter[3] = (char) b; - memcpy (init, salt, salt_len); /* salt */ - memcpy (&init[salt_len], counter, 4); /* big-endian block number */ - hmac_whirlpool (pwd, pwd_len, init, salt_len + 4, j, WHIRLPOOL_DIGESTSIZE); - memcpy (u, j, WHIRLPOOL_DIGESTSIZE); + memcpy (k, salt, salt_len); /* salt */ + /* big-endian block number */ + memset (&k[salt_len], 0, 3); + k[salt_len + 3] = (char) b; + + hmac_whirlpool_internal (pwd, pwd_len, k, salt_len + 4, hmac); + memcpy (u, k, WHIRLPOOL_DIGESTSIZE); /* remaining iterations */ for (c = 1; c < iterations; c++) { - hmac_whirlpool (pwd, pwd_len, j, WHIRLPOOL_DIGESTSIZE, k, WHIRLPOOL_DIGESTSIZE); + hmac_whirlpool_internal (pwd, pwd_len, k, WHIRLPOOL_DIGESTSIZE, hmac); for (i = 0; i < WHIRLPOOL_DIGESTSIZE; i++) { u[i] ^= k[i]; - j[i] = k[i]; } } - - /* Prevent possible leaks. */ - burn (j, sizeof(j)); - burn (k, sizeof(k)); } void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen) { - char u[WHIRLPOOL_DIGESTSIZE]; + hmac_whirlpool_ctx hmac; + char key[WHIRLPOOL_DIGESTSIZE]; int b, l, r; + /* If the password is longer than the hash algorithm block size, + let pwd = whirlpool(pwd), as per HMAC specifications. */ + if (pwd_len > WHIRLPOOL_BLOCKSIZE) + { + WHIRLPOOL_CTX tctx; + + WHIRLPOOL_init (&tctx); + WHIRLPOOL_add ((unsigned char *) pwd, pwd_len * 8, &tctx); + WHIRLPOOL_finalize (&tctx, (unsigned char *) key); + + pwd = key; + pwd_len = WHIRLPOOL_DIGESTSIZE; + + burn (&tctx, sizeof(tctx)); // Prevent leaks + } if (dklen % WHIRLPOOL_DIGESTSIZE) { @@ -627,18 +712,19 @@ void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int /* first l - 1 blocks */ for (b = 1; b < l; b++) { - derive_u_whirlpool (pwd, pwd_len, salt, salt_len, iterations, u, b); - memcpy (dk, u, WHIRLPOOL_DIGESTSIZE); + derive_u_whirlpool (pwd, pwd_len, salt, salt_len, iterations, b, &hmac); + memcpy (dk, hmac.u, WHIRLPOOL_DIGESTSIZE); dk += WHIRLPOOL_DIGESTSIZE; } /* last block */ - derive_u_whirlpool (pwd, pwd_len, salt, salt_len, iterations, u, b); - memcpy (dk, u, r); + derive_u_whirlpool (pwd, pwd_len, salt, salt_len, iterations, b, &hmac); + memcpy (dk, hmac.u, r); /* Prevent possible leaks. */ - burn (u, sizeof(u)); + burn (&hmac, sizeof(hmac)); + burn (key, sizeof(key)); } diff --git a/src/Common/Pkcs5.h b/src/Common/Pkcs5.h index d7ab90db..ef931397 100644 --- a/src/Common/Pkcs5.h +++ b/src/Common/Pkcs5.h @@ -18,19 +18,22 @@ extern "C" { #endif -void hmac_sha256 (char *k, int lk, char *d, int ld, char *out); -void derive_u_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b); +/* output written to d which must be at lease 32 bytes long */ +void hmac_sha256 (char *k, int lk, char *d, int ld); void derive_key_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen); -void hmac_sha512 (char *k, int lk, char *d, int ld, char *out, int t); -void derive_u_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b); +/* output written to d which must be at lease 64 bytes long */ +void hmac_sha512 (char *k, int lk, char *d, int ld); void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen); -void hmac_ripemd160 (char *key, int keylen, char *input, int len, char *digest); -void derive_u_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b); + +/* output written to input_digest which must be at lease 20 bytes long */ +void hmac_ripemd160 (char *key, int keylen, char *input_digest, int len); void derive_key_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen); -void hmac_whirlpool (char *k, int lk, char *d, int ld, char *out, int t); -void derive_u_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b); + +/* output written to d which must be at lease 64 bytes long */ +void hmac_whirlpool (char *k, int lk, char *d, int ld); void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen); + int get_pkcs5_iteration_count (int pkcs5_prf_id, BOOL truecryptMode, BOOL bBoot); char *get_pkcs5_prf_name (int pkcs5_prf_id); diff --git a/src/Common/Tests.c b/src/Common/Tests.c index c5aea91d..6e2b0d95 100644 --- a/src/Common/Tests.c +++ b/src/Common/Tests.c @@ -1016,8 +1016,9 @@ BOOL test_hmac_sha256 () for (i = 0; i < sizeof (hmac_sha256_test_data) / sizeof(char *); i++) { - char digest[SHA256_DIGESTSIZE]; - hmac_sha256 (hmac_sha256_test_keys[i], (int) strlen (hmac_sha256_test_keys[i]), hmac_sha256_test_data[i], (int) strlen (hmac_sha256_test_data[i]), digest); + char digest[1024]; /* large enough to hold digets and test vector inputs */ + memcpy (digest, hmac_sha256_test_data[i], strlen (hmac_sha256_test_data[i])); + hmac_sha256 (hmac_sha256_test_keys[i], (int) strlen (hmac_sha256_test_keys[i]), digest, (int) strlen (hmac_sha256_test_data[i])); if (memcmp (digest, hmac_sha256_test_vectors[i], SHA256_DIGESTSIZE) != 0) return FALSE; else @@ -1034,8 +1035,9 @@ BOOL test_hmac_sha512 () for (i = 0; i < sizeof (hmac_sha512_test_data) / sizeof(char *); i++) { - char digest[SHA512_DIGESTSIZE]; - hmac_sha512 (hmac_sha512_test_keys[i], (int) strlen (hmac_sha512_test_keys[i]), hmac_sha512_test_data[i], (int) strlen (hmac_sha512_test_data[i]), digest, SHA512_DIGESTSIZE); + char digest[1024]; /* large enough to hold digets and test vector inputs */ + memcpy (digest, hmac_sha512_test_data[i], (int) strlen (hmac_sha512_test_data[i])); + hmac_sha512 (hmac_sha512_test_keys[i], (int) strlen (hmac_sha512_test_keys[i]), digest, (int) strlen (hmac_sha512_test_data[i])); if (memcmp (digest, hmac_sha512_test_vectors[i], SHA512_DIGESTSIZE) != 0) return FALSE; else @@ -1052,8 +1054,9 @@ BOOL test_hmac_ripemd160 () for (i = 0; i < sizeof (hmac_ripemd160_test_data) / sizeof(char *); i++) { - char digest[RIPEMD160_DIGESTSIZE]; - hmac_ripemd160 (hmac_ripemd160_test_keys[i], RIPEMD160_DIGESTSIZE, hmac_ripemd160_test_data[i], (int) strlen (hmac_ripemd160_test_data[i]), digest); + char digest[1024]; /* large enough to hold digets and test vector inputs */ + memcpy (digest, hmac_ripemd160_test_data[i], strlen (hmac_ripemd160_test_data[i])); + hmac_ripemd160 (hmac_ripemd160_test_keys[i], RIPEMD160_DIGESTSIZE, digest, (int) strlen (hmac_ripemd160_test_data[i])); if (memcmp (digest, hmac_ripemd160_test_vectors[i], RIPEMD160_DIGESTSIZE) != 0) return FALSE; else @@ -1065,9 +1068,10 @@ BOOL test_hmac_ripemd160 () BOOL test_hmac_whirlpool () { - unsigned char digest[WHIRLPOOL_DIGESTSIZE]; + unsigned char digest[1024]; /* large enough to hold digets and test vector inputs */ - hmac_whirlpool (hmac_whirlpool_test_key, 64, hmac_whirlpool_test_data, (int) strlen (hmac_whirlpool_test_data), digest, WHIRLPOOL_DIGESTSIZE); + memcpy (digest, hmac_whirlpool_test_data, strlen (hmac_whirlpool_test_data)); + hmac_whirlpool (hmac_whirlpool_test_key, 64, digest, (int) strlen (hmac_whirlpool_test_data)); if (memcmp (digest, hmac_whirlpool_test_vectors, WHIRLPOOL_DIGESTSIZE) != 0) return FALSE; -- cgit v1.2.3