diff options
Diffstat (limited to 'src/Common/Pkcs5.c')
-rw-r--r-- | src/Common/Pkcs5.c | 324 |
1 files changed, 288 insertions, 36 deletions
diff --git a/src/Common/Pkcs5.c b/src/Common/Pkcs5.c index 8bc828ef..3dbfd322 100644 --- a/src/Common/Pkcs5.c +++ b/src/Common/Pkcs5.c @@ -1,24 +1,26 @@ /* Legal Notice: Some portions of the source code contained in this file were - derived from the source code of TrueCrypt 7.1a, which is - Copyright (c) 2003-2012 TrueCrypt Developers Association and which is + derived from the source code of TrueCrypt 7.1a, which is + Copyright (c) 2003-2012 TrueCrypt Developers Association and which is governed by the TrueCrypt License 3.0, also from the source code of Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux - and which is governed by the 'License Agreement for Encryption for the Masses' - Modifications and additions to the original source code (contained in this file) + and which is governed by the 'License Agreement for Encryption for the Masses' + Modifications and additions to the original source code (contained in this file) and all other portions of this file are Copyright (c) 2013-2016 IDRIX and are governed by the Apache License 2.0 the full text of which is contained in the file License.txt included in VeraCrypt binary and source code distribution packages. */ #include "Tcdefs.h" - +#if !defined(_UEFI) #include <memory.h> #include <stdlib.h> +#endif #include "Rmd160.h" #ifndef TC_WINDOWS_BOOT #include "Sha2.h" #include "Whirlpool.h" +#include "cpu.h" #include "misc.h" #else #pragma optimize ("t", on) @@ -150,7 +152,7 @@ static void derive_u_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, u char* k = hmac->k; char* u = hmac->u; uint32 c; - int i; + int i; #ifdef TC_WINDOWS_BOOT /* In bootloader mode, least significant bit of iterations is a boolean (TRUE for boot derivation mode, FALSE otherwise) @@ -169,7 +171,7 @@ static void derive_u_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, u /* iteration 1 */ memcpy (k, salt, salt_len); /* salt */ - + /* big-endian block number */ memset (&k[salt_len], 0, 3); k[salt_len + 3] = (char) b; @@ -191,7 +193,7 @@ static void derive_u_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, u void derive_key_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, char *dk, int dklen) -{ +{ hmac_sha256_ctx hmac; sha256_ctx* ctx; char* buf = hmac.k; @@ -315,7 +317,7 @@ 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 */ + int ld /* length of data in bytes */ ) { hmac_sha512_ctx hmac; @@ -521,7 +523,7 @@ void hmac_ripemd160 (char *key, int keylen, char *input_digest, int len) /* If the key is longer than the hash algorithm block size, let key = ripemd160(key), as per HMAC specifications. */ - if (keylen > RIPEMD160_BLOCKSIZE) + if (keylen > RIPEMD160_BLOCKSIZE) { RMD160_CTX tctx; @@ -533,14 +535,14 @@ void hmac_ripemd160 (char *key, int keylen, char *input_digest, int len) keylen = RIPEMD160_DIGESTSIZE; burn (&tctx, sizeof(tctx)); // Prevent leaks - } + } /* perform inner RIPEMD-160 */ ctx = &(hmac.inner_digest_ctx); /* start out by storing key in pads */ memset(k_pad, 0x36, 64); /* XOR key with ipad and opad values */ - for (i=0; i<keylen; i++) + for (i=0; i<keylen; i++) { k_pad[i] ^= key[i]; } @@ -551,7 +553,7 @@ void hmac_ripemd160 (char *key, int keylen, char *input_digest, int len) /* perform outer RIPEMD-160 */ ctx = &(hmac.outer_digest_ctx); memset(k_pad, 0x5c, 64); - for (i=0; i<keylen; i++) + for (i=0; i<keylen; i++) { k_pad[i] ^= key[i]; } @@ -591,7 +593,7 @@ static void derive_u_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len /* iteration 1 */ memcpy (k, salt, salt_len); /* salt */ - + /* big-endian block number */ memset (&k[salt_len], 0, 3); k[salt_len + 3] = (char) b; @@ -612,7 +614,7 @@ static void derive_u_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len } void derive_key_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, char *dk, int dklen) -{ +{ int b, l, r; hmac_ripemd160_ctx hmac; RMD160_CTX* ctx; @@ -621,7 +623,7 @@ void derive_key_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, uin 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) + if (pwd_len > RIPEMD160_BLOCKSIZE) { RMD160_CTX tctx; @@ -652,7 +654,7 @@ void derive_key_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, uin /* start out by storing key in pads */ memset(k_pad, 0x36, 64); /* XOR key with ipad and opad values */ - for (b=0; b<pwd_len; b++) + for (b=0; b<pwd_len; b++) { k_pad[b] ^= pwd[b]; } @@ -663,7 +665,7 @@ void derive_key_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, uin /* perform outer RIPEMD-160 */ ctx = &(hmac.outer_digest_ctx); memset(k_pad, 0x5c, 64); - for (b=0; b<pwd_len; b++) + for (b=0; b<pwd_len; b++) { k_pad[b] ^= pwd[b]; } @@ -718,7 +720,7 @@ void hmac_whirlpool_internal memcpy (ctx, &(hmac->inner_digest_ctx), sizeof (WHIRLPOOL_CTX)); - WHIRLPOOL_add ((unsigned char *) d, ld * 8, ctx); + WHIRLPOOL_add ((unsigned char *) d, ld, ctx); WHIRLPOOL_finalize (ctx, (unsigned char *) d); @@ -726,7 +728,7 @@ void hmac_whirlpool_internal memcpy (ctx, &(hmac->outer_digest_ctx), sizeof (WHIRLPOOL_CTX)); - WHIRLPOOL_add ((unsigned char *) d, WHIRLPOOL_DIGESTSIZE * 8, ctx); + WHIRLPOOL_add ((unsigned char *) d, WHIRLPOOL_DIGESTSIZE, ctx); WHIRLPOOL_finalize (ctx, (unsigned char *) d); } @@ -744,6 +746,12 @@ void hmac_whirlpool char* buf = hmac.k; int b; char key[WHIRLPOOL_DIGESTSIZE]; +#if defined (DEVICE_DRIVER) && !defined (_WIN64) + KFLOATING_SAVE floatingPointState; + NTSTATUS saveStatus = STATUS_SUCCESS; + if (HasISSE()) + saveStatus = KeSaveFloatingPointState (&floatingPointState); +#endif /* If the key is longer than the hash algorithm block size, let key = whirlpool(key), as per HMAC specifications. */ if (lk > WHIRLPOOL_BLOCKSIZE) @@ -751,7 +759,7 @@ void hmac_whirlpool WHIRLPOOL_CTX tctx; WHIRLPOOL_init (&tctx); - WHIRLPOOL_add ((unsigned char *) k, lk * 8, &tctx); + WHIRLPOOL_add ((unsigned char *) k, lk, &tctx); WHIRLPOOL_finalize (&tctx, (unsigned char *) key); k = key; @@ -770,7 +778,7 @@ void hmac_whirlpool buf[b] = (char) (k[b] ^ 0x36); memset (&buf[lk], 0x36, WHIRLPOOL_BLOCKSIZE - lk); - WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, ctx); + WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE, ctx); /**** Precompute HMAC Outer Digest ****/ @@ -781,9 +789,14 @@ void hmac_whirlpool buf[b] = (char) (k[b] ^ 0x5C); memset (&buf[lk], 0x5C, WHIRLPOOL_BLOCKSIZE - lk); - WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, ctx); + WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE, ctx); hmac_whirlpool_internal(k, lk, d, ld, &hmac); + +#if defined (DEVICE_DRIVER) && !defined (_WIN64) + if (NT_SUCCESS (saveStatus) && HasISSE()) + KeRestoreFloatingPointState (&floatingPointState); +#endif /* Prevent leaks */ burn(&hmac, sizeof(hmac)); } @@ -797,7 +810,7 @@ static void derive_u_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len /* iteration 1 */ memcpy (k, salt, salt_len); /* salt */ /* big-endian block number */ - memset (&k[salt_len], 0, 3); + memset (&k[salt_len], 0, 3); k[salt_len + 3] = (char) b; hmac_whirlpool_internal (pwd, pwd_len, k, salt_len + 4, hmac); @@ -821,6 +834,12 @@ void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, uin char* buf = hmac.k; char key[WHIRLPOOL_DIGESTSIZE]; int b, l, r; +#if defined (DEVICE_DRIVER) && !defined (_WIN64) + KFLOATING_SAVE floatingPointState; + NTSTATUS saveStatus = STATUS_SUCCESS; + if (HasISSE()) + saveStatus = KeSaveFloatingPointState (&floatingPointState); +#endif /* If the password is longer than the hash algorithm block size, let pwd = whirlpool(pwd), as per HMAC specifications. */ if (pwd_len > WHIRLPOOL_BLOCKSIZE) @@ -828,7 +847,7 @@ void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, uin WHIRLPOOL_CTX tctx; WHIRLPOOL_init (&tctx); - WHIRLPOOL_add ((unsigned char *) pwd, pwd_len * 8, &tctx); + WHIRLPOOL_add ((unsigned char *) pwd, pwd_len, &tctx); WHIRLPOOL_finalize (&tctx, (unsigned char *) key); pwd = key; @@ -858,7 +877,7 @@ void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, uin buf[b] = (char) (pwd[b] ^ 0x36); memset (&buf[pwd_len], 0x36, WHIRLPOOL_BLOCKSIZE - pwd_len); - WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, ctx); + WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE, ctx); /**** Precompute HMAC Outer Digest ****/ @@ -869,7 +888,7 @@ void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, uin buf[b] = (char) (pwd[b] ^ 0x5C); memset (&buf[pwd_len], 0x5C, WHIRLPOOL_BLOCKSIZE - pwd_len); - WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, ctx); + WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE, ctx); /* first l - 1 blocks */ for (b = 1; b < l; b++) @@ -883,6 +902,10 @@ void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, uin derive_u_whirlpool (pwd, pwd_len, salt, salt_len, iterations, b, &hmac); memcpy (dk, hmac.u, r); +#if defined (DEVICE_DRIVER) && !defined (_WIN64) + if (NT_SUCCESS (saveStatus) && HasISSE()) + KeRestoreFloatingPointState (&floatingPointState); +#endif /* Prevent possible leaks. */ burn (&hmac, sizeof(hmac)); @@ -890,23 +913,242 @@ void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, uin } +typedef struct hmac_streebog_ctx_struct +{ + STREEBOG_CTX ctx; + STREEBOG_CTX inner_digest_ctx; /*pre-computed inner digest context */ + STREEBOG_CTX outer_digest_ctx; /*pre-computed outer digest context */ + CRYPTOPP_ALIGN_DATA(16) char k[PKCS5_SALT_SIZE + 4]; /* enough to hold (salt_len + 4) and also the Streebog hash */ + char u[STREEBOG_DIGESTSIZE]; +} hmac_streebog_ctx; + +void hmac_streebog_internal +( + char *k, /* secret key */ + int lk, /* length of the key in bytes */ + 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_streebog_ctx* hmac /* HMAC-Whirlpool context which holds temporary variables */ +) +{ + STREEBOG_CTX* ctx = &(hmac->ctx); + + /**** Restore Precomputed Inner Digest Context ****/ + + memcpy (ctx, &(hmac->inner_digest_ctx), sizeof (STREEBOG_CTX)); + + STREEBOG_add (ctx, (unsigned char *) d, ld); + + STREEBOG_finalize (ctx, (unsigned char *) d); + + /**** Restore Precomputed Outer Digest Context ****/ + + memcpy (ctx, &(hmac->outer_digest_ctx), sizeof (STREEBOG_CTX)); + + STREEBOG_add (ctx, (unsigned char *) d, STREEBOG_DIGESTSIZE); + + STREEBOG_finalize (ctx, (unsigned char *) d); +} + +void hmac_streebog +( + 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_streebog_ctx hmac; + STREEBOG_CTX* ctx; + char* buf = hmac.k; + int b; + CRYPTOPP_ALIGN_DATA(16) char key[STREEBOG_DIGESTSIZE]; +#if defined (DEVICE_DRIVER) && !defined (_WIN64) + KFLOATING_SAVE floatingPointState; + NTSTATUS saveStatus = STATUS_SUCCESS; + if (HasSSE2() || HasSSE41()) + saveStatus = KeSaveFloatingPointState (&floatingPointState); +#endif + /* If the key is longer than the hash algorithm block size, + let key = streebog(key), as per HMAC specifications. */ + if (lk > STREEBOG_BLOCKSIZE) + { + STREEBOG_CTX tctx; + + STREEBOG_init (&tctx); + STREEBOG_add (&tctx, (unsigned char *) k, lk); + STREEBOG_finalize (&tctx, (unsigned char *) key); + + k = key; + lk = STREEBOG_DIGESTSIZE; + + burn (&tctx, sizeof(tctx)); // Prevent leaks + } + + /**** Precompute HMAC Inner Digest ****/ + + ctx = &(hmac.inner_digest_ctx); + STREEBOG_init (ctx); + + /* Pad the key for inner digest */ + for (b = 0; b < lk; ++b) + buf[b] = (char) (k[b] ^ 0x36); + memset (&buf[lk], 0x36, STREEBOG_BLOCKSIZE - lk); + + STREEBOG_add (ctx, (unsigned char *) buf, STREEBOG_BLOCKSIZE); + + /**** Precompute HMAC Outer Digest ****/ + + ctx = &(hmac.outer_digest_ctx); + STREEBOG_init (ctx); + + for (b = 0; b < lk; ++b) + buf[b] = (char) (k[b] ^ 0x5C); + memset (&buf[lk], 0x5C, STREEBOG_BLOCKSIZE - lk); + + STREEBOG_add (ctx, (unsigned char *) buf, STREEBOG_BLOCKSIZE); + + hmac_streebog_internal(k, lk, d, ld, &hmac); + +#if defined (DEVICE_DRIVER) && !defined (_WIN64) + if (NT_SUCCESS (saveStatus) && (HasSSE2() || HasSSE41())) + KeRestoreFloatingPointState (&floatingPointState); +#endif + /* Prevent leaks */ + burn(&hmac, sizeof(hmac)); +} + +static void derive_u_streebog (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, int b, hmac_streebog_ctx* hmac) +{ + char* u = hmac->u; + char* k = hmac->k; + uint32 c, i; + + /* iteration 1 */ + memcpy (k, salt, salt_len); /* salt */ + /* big-endian block number */ + memset (&k[salt_len], 0, 3); + k[salt_len + 3] = (char) b; + + hmac_streebog_internal (pwd, pwd_len, k, salt_len + 4, hmac); + memcpy (u, k, STREEBOG_DIGESTSIZE); + + /* remaining iterations */ + for (c = 1; c < iterations; c++) + { + hmac_streebog_internal (pwd, pwd_len, k, STREEBOG_DIGESTSIZE, hmac); + for (i = 0; i < STREEBOG_DIGESTSIZE; i++) + { + u[i] ^= k[i]; + } + } +} + +void derive_key_streebog (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, char *dk, int dklen) +{ + hmac_streebog_ctx hmac; + STREEBOG_CTX* ctx; + char* buf = hmac.k; + char key[STREEBOG_DIGESTSIZE]; + int b, l, r; +#if defined (DEVICE_DRIVER) && !defined (_WIN64) + KFLOATING_SAVE floatingPointState; + NTSTATUS saveStatus = STATUS_SUCCESS; + if (HasSSE2() || HasSSE41()) + saveStatus = KeSaveFloatingPointState (&floatingPointState); +#endif + /* If the password is longer than the hash algorithm block size, + let pwd = streebog(pwd), as per HMAC specifications. */ + if (pwd_len > STREEBOG_BLOCKSIZE) + { + STREEBOG_CTX tctx; + + STREEBOG_init (&tctx); + STREEBOG_add (&tctx, (unsigned char *) pwd, pwd_len); + STREEBOG_finalize (&tctx, (unsigned char *) key); + + pwd = key; + pwd_len = STREEBOG_DIGESTSIZE; + + burn (&tctx, sizeof(tctx)); // Prevent leaks + } + + if (dklen % STREEBOG_DIGESTSIZE) + { + l = 1 + dklen / STREEBOG_DIGESTSIZE; + } + else + { + l = dklen / STREEBOG_DIGESTSIZE; + } + + r = dklen - (l - 1) * STREEBOG_DIGESTSIZE; + + /**** Precompute HMAC Inner Digest ****/ + + ctx = &(hmac.inner_digest_ctx); + STREEBOG_init (ctx); + + /* Pad the key for inner digest */ + for (b = 0; b < pwd_len; ++b) + buf[b] = (char) (pwd[b] ^ 0x36); + memset (&buf[pwd_len], 0x36, STREEBOG_BLOCKSIZE - pwd_len); + + STREEBOG_add (ctx, (unsigned char *) buf, STREEBOG_BLOCKSIZE); + + /**** Precompute HMAC Outer Digest ****/ + + ctx = &(hmac.outer_digest_ctx); + STREEBOG_init (ctx); + + for (b = 0; b < pwd_len; ++b) + buf[b] = (char) (pwd[b] ^ 0x5C); + memset (&buf[pwd_len], 0x5C, STREEBOG_BLOCKSIZE - pwd_len); + + STREEBOG_add (ctx, (unsigned char *) buf, STREEBOG_BLOCKSIZE); + + /* first l - 1 blocks */ + for (b = 1; b < l; b++) + { + derive_u_streebog (pwd, pwd_len, salt, salt_len, iterations, b, &hmac); + memcpy (dk, hmac.u, STREEBOG_DIGESTSIZE); + dk += STREEBOG_DIGESTSIZE; + } + + /* last block */ + derive_u_streebog (pwd, pwd_len, salt, salt_len, iterations, b, &hmac); + memcpy (dk, hmac.u, r); + +#if defined (DEVICE_DRIVER) && !defined (_WIN64) + if (NT_SUCCESS (saveStatus) && (HasSSE2() || HasSSE41())) + KeRestoreFloatingPointState (&floatingPointState); +#endif + + /* Prevent possible leaks. */ + burn (&hmac, sizeof(hmac)); + burn (key, sizeof(key)); +} + wchar_t *get_pkcs5_prf_name (int pkcs5_prf_id) { switch (pkcs5_prf_id) { - case SHA512: + case SHA512: return L"HMAC-SHA-512"; - case SHA256: + case SHA256: return L"HMAC-SHA-256"; - case RIPEMD160: + case RIPEMD160: return L"HMAC-RIPEMD-160"; - case WHIRLPOOL: + case WHIRLPOOL: return L"HMAC-Whirlpool"; - default: + case STREEBOG: + return L"HMAC-STREEBOG"; + + default: return L"(Unknown)"; } } @@ -925,7 +1167,7 @@ int get_pkcs5_iteration_count (int pkcs5_prf_id, int pim, BOOL truecryptMode, BO switch (pkcs5_prf_id) { - case RIPEMD160: + case RIPEMD160: if (truecryptMode) return bBoot ? 1000 : 2000; else if (pim == 0) @@ -935,10 +1177,10 @@ int get_pkcs5_iteration_count (int pkcs5_prf_id, int pim, BOOL truecryptMode, BO return bBoot? pim * 2048 : 15000 + pim * 1000; } - case SHA512: + case SHA512: return truecryptMode? 1000 : ((pim == 0)? 500000 : 15000 + pim * 1000); - case WHIRLPOOL: + case WHIRLPOOL: return truecryptMode? 1000 : ((pim == 0)? 500000 : 15000 + pim * 1000); case SHA256: @@ -951,7 +1193,17 @@ int get_pkcs5_iteration_count (int pkcs5_prf_id, int pim, BOOL truecryptMode, BO return bBoot? pim * 2048 : 15000 + pim * 1000; } - default: + case STREEBOG: + if (truecryptMode) + return 1000; + else if (pim == 0) + return bBoot? 200000 : 500000; + else + { + return bBoot? pim * 2048 : 15000 + pim * 1000; + } + + default: TC_THROW_FATAL_EXCEPTION; // Unknown/wrong ID } return 0; |