VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Common/Pkcs5.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Common/Pkcs5.c')
-rw-r--r--src/Common/Pkcs5.c324
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;