diff options
Diffstat (limited to 'src/Common/Pkcs5.c')
-rw-r--r-- | src/Common/Pkcs5.c | 1918 |
1 files changed, 959 insertions, 959 deletions
diff --git a/src/Common/Pkcs5.c b/src/Common/Pkcs5.c index 1dadb1e9..8bc828ef 100644 --- a/src/Common/Pkcs5.c +++ b/src/Common/Pkcs5.c @@ -1,960 +1,960 @@ -/*
- 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
- 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 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"
-
-#include <memory.h>
-#include <stdlib.h>
-#include "Rmd160.h"
-#ifndef TC_WINDOWS_BOOT
-#include "Sha2.h"
-#include "Whirlpool.h"
-#include "misc.h"
-#else
-#pragma optimize ("t", on)
-#include <string.h>
-#if defined( _MSC_VER )
-# ifndef DEBUG
-# pragma intrinsic( memcpy )
-# pragma intrinsic( memset )
-# endif
-#endif
-#include "Sha2Small.h"
-#endif
-#include "Pkcs5.h"
-#include "Crypto.h"
-
-void hmac_truncate
- (
- char *d1, /* data to be truncated */
- char *d2, /* truncated data */
- int len /* length in bytes to keep */
-)
-{
- int i;
- for (i = 0; i < len; i++)
- d2[i] = d1[i];
-}
-
-#if !defined(TC_WINDOWS_BOOT) || defined(TC_WINDOWS_BOOT_SHA2)
-
-typedef struct hmac_sha256_ctx_struct
-{
- sha256_ctx ctx;
- sha256_ctx inner_digest_ctx; /*pre-computed inner digest context */
- sha256_ctx outer_digest_ctx; /*pre-computed outer digest context */
- 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. It's ensured to be always <= 32 bytes */
- 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 input data in bytes */
- hmac_sha256_ctx* hmac /* HMAC-SHA256 context which holds temporary variables */
-)
-{
- sha256_ctx* ctx = &(hmac->ctx);
-
- /**** Restore Precomputed Inner Digest Context ****/
-
- memcpy (ctx, &(hmac->inner_digest_ctx), sizeof (sha256_ctx));
-
- sha256_hash ((unsigned char *) d, ld, ctx);
-
- sha256_end ((unsigned char *) d, ctx); /* d = inner digest */
-
- /**** Restore Precomputed Outer Digest Context ****/
-
- memcpy (ctx, &(hmac->outer_digest_ctx), sizeof (sha256_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;
- sha256_ctx* ctx;
- char* buf = hmac.k;
- int b;
- 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_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
- }
-
- /**** Precompute HMAC Inner Digest ****/
-
- ctx = &(hmac.inner_digest_ctx);
- sha256_begin (ctx);
-
- /* Pad the key for inner digest */
- for (b = 0; b < lk; ++b)
- buf[b] = (char) (k[b] ^ 0x36);
- memset (&buf[lk], 0x36, SHA256_BLOCKSIZE - lk);
-
- sha256_hash ((unsigned char *) buf, SHA256_BLOCKSIZE, ctx);
-
- /**** Precompute HMAC Outer Digest ****/
-
- ctx = &(hmac.outer_digest_ctx);
- sha256_begin (ctx);
-
- for (b = 0; b < lk; ++b)
- buf[b] = (char) (k[b] ^ 0x5C);
- memset (&buf[lk], 0x5C, SHA256_BLOCKSIZE - lk);
-
- sha256_hash ((unsigned char *) buf, SHA256_BLOCKSIZE, ctx);
-
- hmac_sha256_internal(k, lk, d, ld, &hmac);
- /* Prevent leaks */
- burn(&hmac, sizeof(hmac));
- burn(key, sizeof(key));
-}
-#endif
-
-static void derive_u_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, int b, hmac_sha256_ctx* hmac)
-{
- char* k = hmac->k;
- char* u = hmac->u;
- uint32 c;
- int i;
-
-#ifdef TC_WINDOWS_BOOT
- /* In bootloader mode, least significant bit of iterations is a boolean (TRUE for boot derivation mode, FALSE otherwise)
- * and the most significant 16 bits hold the pim value
- * This enables us to save code space needed for implementing other features.
- */
- c = iterations >> 16;
- i = ((int) iterations) & 0x01;
- if (i)
- c = (c == 0)? 200000 : c << 11;
- else
- c = (c == 0)? 500000 : 15000 + c * 1000;
-#else
- c = iterations;
-#endif
-
- /* 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_sha256_internal (pwd, pwd_len, k, salt_len + 4, hmac);
- memcpy (u, k, SHA256_DIGESTSIZE);
-
- /* remaining iterations */
- while (c > 1)
- {
- hmac_sha256_internal (pwd, pwd_len, k, SHA256_DIGESTSIZE, hmac);
- for (i = 0; i < SHA256_DIGESTSIZE; i++)
- {
- u[i] ^= k[i];
- }
- c--;
- }
-}
-
-
-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;
- 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)
- {
- l = 1 + dklen / SHA256_DIGESTSIZE;
- }
- else
- {
- l = dklen / SHA256_DIGESTSIZE;
- }
-
- r = dklen - (l - 1) * SHA256_DIGESTSIZE;
-
- /**** Precompute HMAC Inner Digest ****/
-
- ctx = &(hmac.inner_digest_ctx);
- sha256_begin (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, SHA256_BLOCKSIZE - pwd_len);
-
- sha256_hash ((unsigned char *) buf, SHA256_BLOCKSIZE, ctx);
-
- /**** Precompute HMAC Outer Digest ****/
-
- ctx = &(hmac.outer_digest_ctx);
- sha256_begin (ctx);
-
- for (b = 0; b < pwd_len; ++b)
- buf[b] = (char) (pwd[b] ^ 0x5C);
- memset (&buf[pwd_len], 0x5C, SHA256_BLOCKSIZE - pwd_len);
-
- sha256_hash ((unsigned char *) buf, SHA256_BLOCKSIZE, ctx);
-
- /* first l - 1 blocks */
- for (b = 1; b < l; b++)
- {
- 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, b, &hmac);
- memcpy (dk, hmac.u, r);
-
-
- /* Prevent possible leaks. */
- burn (&hmac, sizeof(hmac));
-#ifndef TC_WINDOWS_BOOT
- burn (key, sizeof(key));
-#endif
-}
-
-#endif
-
-#ifndef TC_WINDOWS_BOOT
-
-typedef struct hmac_sha512_ctx_struct
-{
- sha512_ctx ctx;
- sha512_ctx inner_digest_ctx; /*pre-computed inner digest context */
- sha512_ctx outer_digest_ctx; /*pre-computed outer digest context */
- 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 and also output buffer of at least 64 bytes */
- int ld, /* length of data in bytes */
- hmac_sha512_ctx* hmac
-)
-{
- sha512_ctx* ctx = &(hmac->ctx);
-
- /**** Restore Precomputed Inner Digest Context ****/
-
- memcpy (ctx, &(hmac->inner_digest_ctx), sizeof (sha512_ctx));
-
- sha512_hash ((unsigned char *) d, ld, ctx);
-
- sha512_end ((unsigned char *) d, ctx);
-
- /**** Restore Precomputed Outer Digest Context ****/
-
- memcpy (ctx, &(hmac->outer_digest_ctx), sizeof (sha512_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;
- sha512_ctx* ctx;
- char* buf = hmac.k; /* there is enough space to hold SHA512_BLOCKSIZE (128) bytes
- * because k is followed by u in hmac_sha512_ctx
- */
- int b;
- 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_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
- }
-
- /**** Precompute HMAC Inner Digest ****/
-
- ctx = &(hmac.inner_digest_ctx);
- sha512_begin (ctx);
-
- /* Pad the key for inner digest */
- for (b = 0; b < lk; ++b)
- buf[b] = (char) (k[b] ^ 0x36);
- memset (&buf[lk], 0x36, SHA512_BLOCKSIZE - lk);
-
- sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, ctx);
-
- /**** Precompute HMAC Outer Digest ****/
-
- ctx = &(hmac.outer_digest_ctx);
- sha512_begin (ctx);
-
- for (b = 0; b < lk; ++b)
- buf[b] = (char) (k[b] ^ 0x5C);
- memset (&buf[lk], 0x5C, SHA512_BLOCKSIZE - lk);
-
- sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, ctx);
-
- hmac_sha512_internal (k, lk, d, ld, &hmac);
-
- /* Prevent leaks */
- burn (&hmac, sizeof(hmac));
- burn (key, sizeof(key));
-}
-
-static void derive_u_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, int b, hmac_sha512_ctx* hmac)
-{
- char* k = hmac->k;
- char* u = hmac->u;
- 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_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_internal (pwd, pwd_len, k, SHA512_DIGESTSIZE, hmac);
- for (i = 0; i < SHA512_DIGESTSIZE; i++)
- {
- u[i] ^= k[i];
- }
- }
-}
-
-
-void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, char *dk, int dklen)
-{
- hmac_sha512_ctx hmac;
- sha512_ctx* ctx;
- char* buf = hmac.k; /* there is enough space to hold SHA512_BLOCKSIZE (128) bytes
- * because k is followed by u in hmac_sha512_ctx
- */
- 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)
- {
- l = 1 + dklen / SHA512_DIGESTSIZE;
- }
- else
- {
- l = dklen / SHA512_DIGESTSIZE;
- }
-
- r = dklen - (l - 1) * SHA512_DIGESTSIZE;
-
- /**** Precompute HMAC Inner Digest ****/
-
- ctx = &(hmac.inner_digest_ctx);
- sha512_begin (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, SHA512_BLOCKSIZE - pwd_len);
-
- sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, ctx);
-
- /**** Precompute HMAC Outer Digest ****/
-
- ctx = &(hmac.outer_digest_ctx);
- sha512_begin (ctx);
-
- for (b = 0; b < pwd_len; ++b)
- buf[b] = (char) (pwd[b] ^ 0x5C);
- memset (&buf[pwd_len], 0x5C, SHA512_BLOCKSIZE - pwd_len);
-
- sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, ctx);
-
- /* first l - 1 blocks */
- for (b = 1; b < l; b++)
- {
- 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, b, &hmac);
- memcpy (dk, hmac.u, r);
-
-
- /* Prevent possible leaks. */
- burn (&hmac, sizeof(hmac));
- burn (key, sizeof(key));
-}
-
-#endif // TC_WINDOWS_BOOT
-
-#if !defined(TC_WINDOWS_BOOT) || defined(TC_WINDOWS_BOOT_RIPEMD160)
-
-typedef struct hmac_ripemd160_ctx_struct
-{
- RMD160_CTX context;
- RMD160_CTX inner_digest_ctx; /*pre-computed inner digest context */
- RMD160_CTX outer_digest_ctx; /*pre-computed outer digest context */
- 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;
-
-void hmac_ripemd160_internal (char *key, int keylen, char *input_digest, int len, hmac_ripemd160_ctx* hmac)
-{
- RMD160_CTX* context = &(hmac->context);
-
- /**** Restore Precomputed Inner Digest Context ****/
-
- memcpy (context, &(hmac->inner_digest_ctx), sizeof (RMD160_CTX));
-
- RMD160Update(context, (const unsigned char *) input_digest, len); /* then text of datagram */
- RMD160Final((unsigned char *) input_digest, context); /* finish up 1st pass */
-
- /**** Restore Precomputed Outer Digest Context ****/
-
- memcpy (context, &(hmac->outer_digest_ctx), sizeof (RMD160_CTX));
-
- /* results of 1st hash */
- RMD160Update(context, (const unsigned char *) input_digest, RIPEMD160_DIGESTSIZE);
- RMD160Final((unsigned char *) input_digest, context); /* finish up 2nd pass */
-}
-
-#ifndef TC_WINDOWS_BOOT
-void hmac_ripemd160 (char *key, int keylen, char *input_digest, int len)
-{
- hmac_ripemd160_ctx hmac;
- RMD160_CTX* ctx;
- unsigned char* k_pad = (unsigned char*) hmac.k; /* inner/outer padding - key XORd with ipad */
- unsigned char tk[RIPEMD160_DIGESTSIZE];
- int i;
-
- /* 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);
-
- key = (char *) tk;
- 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++)
- {
- k_pad[i] ^= key[i];
- }
-
- RMD160Init(ctx); /* init context for 1st pass */
- RMD160Update(ctx, k_pad, RIPEMD160_BLOCKSIZE); /* start with inner pad */
-
- /* perform outer RIPEMD-160 */
- ctx = &(hmac.outer_digest_ctx);
- memset(k_pad, 0x5c, 64);
- for (i=0; i<keylen; i++)
- {
- k_pad[i] ^= key[i];
- }
-
- RMD160Init(ctx); /* init context for 2nd pass */
- RMD160Update(ctx, k_pad, RIPEMD160_BLOCKSIZE); /* start with outer pad */
-
- hmac_ripemd160_internal (key, keylen, input_digest, len, &hmac);
-
- burn (&hmac, sizeof(hmac));
- burn (tk, sizeof(tk));
-}
-#endif
-
-
-static void derive_u_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, int b, hmac_ripemd160_ctx* hmac)
-{
- char* k = hmac->k;
- char* u = hmac->u;
- uint32 c;
- int i;
-
-#ifdef TC_WINDOWS_BOOT
- /* In bootloader mode, least significant bit of iterations is a boolean (TRUE for boot derivation mode, FALSE otherwise)
- * and the most significant 16 bits hold the pim value
- * This enables us to save code space needed for implementing other features.
- */
- c = iterations >> 16;
- i = ((int) iterations) & 0x01;
- if (i)
- c = (c == 0)? 327661 : c << 11;
- else
- c = (c == 0)? 655331 : 15000 + c * 1000;
-#else
- c = iterations;
-#endif
-
- /* 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_ripemd160_internal (pwd, pwd_len, k, salt_len + 4, hmac);
- memcpy (u, k, RIPEMD160_DIGESTSIZE);
-
- /* remaining iterations */
- while ( c > 1)
- {
- hmac_ripemd160_internal (pwd, pwd_len, k, RIPEMD160_DIGESTSIZE, hmac);
- for (i = 0; i < RIPEMD160_DIGESTSIZE; i++)
- {
- u[i] ^= k[i];
- }
- c--;
- }
-}
-
-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;
- unsigned char* k_pad = (unsigned char*) hmac.k;
-#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)
- {
- l = 1 + dklen / RIPEMD160_DIGESTSIZE;
- }
- else
- {
- l = dklen / RIPEMD160_DIGESTSIZE;
- }
-
- r = dklen - (l - 1) * RIPEMD160_DIGESTSIZE;
-
- /* 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 (b=0; b<pwd_len; b++)
- {
- k_pad[b] ^= pwd[b];
- }
-
- RMD160Init(ctx); /* init context for 1st pass */
- RMD160Update(ctx, k_pad, RIPEMD160_BLOCKSIZE); /* start with inner pad */
-
- /* perform outer RIPEMD-160 */
- ctx = &(hmac.outer_digest_ctx);
- memset(k_pad, 0x5c, 64);
- for (b=0; b<pwd_len; b++)
- {
- k_pad[b] ^= pwd[b];
- }
-
- RMD160Init(ctx); /* init context for 2nd pass */
- RMD160Update(ctx, k_pad, RIPEMD160_BLOCKSIZE); /* start with outer pad */
-
- /* first l - 1 blocks */
- for (b = 1; b < l; b++)
- {
- 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, b, &hmac);
- memcpy (dk, hmac.u, r);
-
-
- /* Prevent possible leaks. */
- burn (&hmac, sizeof(hmac));
-#ifndef TC_WINDOWS_BOOT
- burn (tk, sizeof(tk));
-#endif
-}
-#endif // TC_WINDOWS_BOOT
-
-#ifndef TC_WINDOWS_BOOT
-
-typedef struct hmac_whirlpool_ctx_struct
-{
- WHIRLPOOL_CTX ctx;
- WHIRLPOOL_CTX inner_digest_ctx; /*pre-computed inner digest context */
- WHIRLPOOL_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 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, /* 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* ctx = &(hmac->ctx);
-
- /**** Restore Precomputed Inner Digest Context ****/
-
- memcpy (ctx, &(hmac->inner_digest_ctx), sizeof (WHIRLPOOL_CTX));
-
- WHIRLPOOL_add ((unsigned char *) d, ld * 8, ctx);
-
- WHIRLPOOL_finalize (ctx, (unsigned char *) d);
-
- /**** Restore Precomputed Outer Digest Context ****/
-
- memcpy (ctx, &(hmac->outer_digest_ctx), sizeof (WHIRLPOOL_CTX));
-
- WHIRLPOOL_add ((unsigned char *) d, WHIRLPOOL_DIGESTSIZE * 8, ctx);
-
- WHIRLPOOL_finalize (ctx, (unsigned char *) d);
-}
-
-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;
- WHIRLPOOL_CTX* ctx;
- char* buf = hmac.k;
- int b;
- 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;
-
- 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
- }
-
- /**** Precompute HMAC Inner Digest ****/
-
- ctx = &(hmac.inner_digest_ctx);
- WHIRLPOOL_init (ctx);
-
- /* Pad the key for inner digest */
- for (b = 0; b < lk; ++b)
- buf[b] = (char) (k[b] ^ 0x36);
- memset (&buf[lk], 0x36, WHIRLPOOL_BLOCKSIZE - lk);
-
- WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, ctx);
-
- /**** Precompute HMAC Outer Digest ****/
-
- ctx = &(hmac.outer_digest_ctx);
- WHIRLPOOL_init (ctx);
-
- for (b = 0; b < lk; ++b)
- buf[b] = (char) (k[b] ^ 0x5C);
- memset (&buf[lk], 0x5C, WHIRLPOOL_BLOCKSIZE - lk);
-
- WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, ctx);
-
- hmac_whirlpool_internal(k, lk, d, ld, &hmac);
- /* Prevent leaks */
- burn(&hmac, sizeof(hmac));
-}
-
-static void derive_u_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, int b, hmac_whirlpool_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_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_internal (pwd, pwd_len, k, WHIRLPOOL_DIGESTSIZE, hmac);
- for (i = 0; i < WHIRLPOOL_DIGESTSIZE; i++)
- {
- u[i] ^= k[i];
- }
- }
-}
-
-void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, char *dk, int dklen)
-{
- hmac_whirlpool_ctx hmac;
- WHIRLPOOL_CTX* ctx;
- char* buf = hmac.k;
- 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)
- {
- l = 1 + dklen / WHIRLPOOL_DIGESTSIZE;
- }
- else
- {
- l = dklen / WHIRLPOOL_DIGESTSIZE;
- }
-
- r = dklen - (l - 1) * WHIRLPOOL_DIGESTSIZE;
-
- /**** Precompute HMAC Inner Digest ****/
-
- ctx = &(hmac.inner_digest_ctx);
- WHIRLPOOL_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, WHIRLPOOL_BLOCKSIZE - pwd_len);
-
- WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, ctx);
-
- /**** Precompute HMAC Outer Digest ****/
-
- ctx = &(hmac.outer_digest_ctx);
- WHIRLPOOL_init (ctx);
-
- for (b = 0; b < pwd_len; ++b)
- buf[b] = (char) (pwd[b] ^ 0x5C);
- memset (&buf[pwd_len], 0x5C, WHIRLPOOL_BLOCKSIZE - pwd_len);
-
- WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, ctx);
-
- /* first l - 1 blocks */
- for (b = 1; b < l; b++)
- {
- 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, b, &hmac);
- memcpy (dk, hmac.u, r);
-
-
- /* 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:
- return L"HMAC-SHA-512";
-
- case SHA256:
- return L"HMAC-SHA-256";
-
- case RIPEMD160:
- return L"HMAC-RIPEMD-160";
-
- case WHIRLPOOL:
- return L"HMAC-Whirlpool";
-
- default:
- return L"(Unknown)";
- }
-}
-
-
-
-int get_pkcs5_iteration_count (int pkcs5_prf_id, int pim, BOOL truecryptMode, BOOL bBoot)
-{
- if ( (pim < 0)
- || (truecryptMode && pim > 0) /* No PIM for TrueCrypt mode */
- )
- {
- return 0;
- }
-
- switch (pkcs5_prf_id)
- {
-
- case RIPEMD160:
- if (truecryptMode)
- return bBoot ? 1000 : 2000;
- else if (pim == 0)
- return bBoot? 327661 : 655331;
- else
- {
- return bBoot? pim * 2048 : 15000 + pim * 1000;
- }
-
- case SHA512:
- return truecryptMode? 1000 : ((pim == 0)? 500000 : 15000 + pim * 1000);
-
- case WHIRLPOOL:
- return truecryptMode? 1000 : ((pim == 0)? 500000 : 15000 + pim * 1000);
-
- case SHA256:
- if (truecryptMode)
- return 0; // SHA-256 not supported by TrueCrypt
- 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;
-}
-
+/* + 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 + 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 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" + +#include <memory.h> +#include <stdlib.h> +#include "Rmd160.h" +#ifndef TC_WINDOWS_BOOT +#include "Sha2.h" +#include "Whirlpool.h" +#include "misc.h" +#else +#pragma optimize ("t", on) +#include <string.h> +#if defined( _MSC_VER ) +# ifndef DEBUG +# pragma intrinsic( memcpy ) +# pragma intrinsic( memset ) +# endif +#endif +#include "Sha2Small.h" +#endif +#include "Pkcs5.h" +#include "Crypto.h" + +void hmac_truncate + ( + char *d1, /* data to be truncated */ + char *d2, /* truncated data */ + int len /* length in bytes to keep */ +) +{ + int i; + for (i = 0; i < len; i++) + d2[i] = d1[i]; +} + +#if !defined(TC_WINDOWS_BOOT) || defined(TC_WINDOWS_BOOT_SHA2) + +typedef struct hmac_sha256_ctx_struct +{ + sha256_ctx ctx; + sha256_ctx inner_digest_ctx; /*pre-computed inner digest context */ + sha256_ctx outer_digest_ctx; /*pre-computed outer digest context */ + 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. It's ensured to be always <= 32 bytes */ + 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 input data in bytes */ + hmac_sha256_ctx* hmac /* HMAC-SHA256 context which holds temporary variables */ +) +{ + sha256_ctx* ctx = &(hmac->ctx); + + /**** Restore Precomputed Inner Digest Context ****/ + + memcpy (ctx, &(hmac->inner_digest_ctx), sizeof (sha256_ctx)); + + sha256_hash ((unsigned char *) d, ld, ctx); + + sha256_end ((unsigned char *) d, ctx); /* d = inner digest */ + + /**** Restore Precomputed Outer Digest Context ****/ + + memcpy (ctx, &(hmac->outer_digest_ctx), sizeof (sha256_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; + sha256_ctx* ctx; + char* buf = hmac.k; + int b; + 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_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 + } + + /**** Precompute HMAC Inner Digest ****/ + + ctx = &(hmac.inner_digest_ctx); + sha256_begin (ctx); + + /* Pad the key for inner digest */ + for (b = 0; b < lk; ++b) + buf[b] = (char) (k[b] ^ 0x36); + memset (&buf[lk], 0x36, SHA256_BLOCKSIZE - lk); + + sha256_hash ((unsigned char *) buf, SHA256_BLOCKSIZE, ctx); + + /**** Precompute HMAC Outer Digest ****/ + + ctx = &(hmac.outer_digest_ctx); + sha256_begin (ctx); + + for (b = 0; b < lk; ++b) + buf[b] = (char) (k[b] ^ 0x5C); + memset (&buf[lk], 0x5C, SHA256_BLOCKSIZE - lk); + + sha256_hash ((unsigned char *) buf, SHA256_BLOCKSIZE, ctx); + + hmac_sha256_internal(k, lk, d, ld, &hmac); + /* Prevent leaks */ + burn(&hmac, sizeof(hmac)); + burn(key, sizeof(key)); +} +#endif + +static void derive_u_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, int b, hmac_sha256_ctx* hmac) +{ + char* k = hmac->k; + char* u = hmac->u; + uint32 c; + int i; + +#ifdef TC_WINDOWS_BOOT + /* In bootloader mode, least significant bit of iterations is a boolean (TRUE for boot derivation mode, FALSE otherwise) + * and the most significant 16 bits hold the pim value + * This enables us to save code space needed for implementing other features. + */ + c = iterations >> 16; + i = ((int) iterations) & 0x01; + if (i) + c = (c == 0)? 200000 : c << 11; + else + c = (c == 0)? 500000 : 15000 + c * 1000; +#else + c = iterations; +#endif + + /* 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_sha256_internal (pwd, pwd_len, k, salt_len + 4, hmac); + memcpy (u, k, SHA256_DIGESTSIZE); + + /* remaining iterations */ + while (c > 1) + { + hmac_sha256_internal (pwd, pwd_len, k, SHA256_DIGESTSIZE, hmac); + for (i = 0; i < SHA256_DIGESTSIZE; i++) + { + u[i] ^= k[i]; + } + c--; + } +} + + +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; + 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) + { + l = 1 + dklen / SHA256_DIGESTSIZE; + } + else + { + l = dklen / SHA256_DIGESTSIZE; + } + + r = dklen - (l - 1) * SHA256_DIGESTSIZE; + + /**** Precompute HMAC Inner Digest ****/ + + ctx = &(hmac.inner_digest_ctx); + sha256_begin (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, SHA256_BLOCKSIZE - pwd_len); + + sha256_hash ((unsigned char *) buf, SHA256_BLOCKSIZE, ctx); + + /**** Precompute HMAC Outer Digest ****/ + + ctx = &(hmac.outer_digest_ctx); + sha256_begin (ctx); + + for (b = 0; b < pwd_len; ++b) + buf[b] = (char) (pwd[b] ^ 0x5C); + memset (&buf[pwd_len], 0x5C, SHA256_BLOCKSIZE - pwd_len); + + sha256_hash ((unsigned char *) buf, SHA256_BLOCKSIZE, ctx); + + /* first l - 1 blocks */ + for (b = 1; b < l; b++) + { + 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, b, &hmac); + memcpy (dk, hmac.u, r); + + + /* Prevent possible leaks. */ + burn (&hmac, sizeof(hmac)); +#ifndef TC_WINDOWS_BOOT + burn (key, sizeof(key)); +#endif +} + +#endif + +#ifndef TC_WINDOWS_BOOT + +typedef struct hmac_sha512_ctx_struct +{ + sha512_ctx ctx; + sha512_ctx inner_digest_ctx; /*pre-computed inner digest context */ + sha512_ctx outer_digest_ctx; /*pre-computed outer digest context */ + 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 and also output buffer of at least 64 bytes */ + int ld, /* length of data in bytes */ + hmac_sha512_ctx* hmac +) +{ + sha512_ctx* ctx = &(hmac->ctx); + + /**** Restore Precomputed Inner Digest Context ****/ + + memcpy (ctx, &(hmac->inner_digest_ctx), sizeof (sha512_ctx)); + + sha512_hash ((unsigned char *) d, ld, ctx); + + sha512_end ((unsigned char *) d, ctx); + + /**** Restore Precomputed Outer Digest Context ****/ + + memcpy (ctx, &(hmac->outer_digest_ctx), sizeof (sha512_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; + sha512_ctx* ctx; + char* buf = hmac.k; /* there is enough space to hold SHA512_BLOCKSIZE (128) bytes + * because k is followed by u in hmac_sha512_ctx + */ + int b; + 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_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 + } + + /**** Precompute HMAC Inner Digest ****/ + + ctx = &(hmac.inner_digest_ctx); + sha512_begin (ctx); + + /* Pad the key for inner digest */ + for (b = 0; b < lk; ++b) + buf[b] = (char) (k[b] ^ 0x36); + memset (&buf[lk], 0x36, SHA512_BLOCKSIZE - lk); + + sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, ctx); + + /**** Precompute HMAC Outer Digest ****/ + + ctx = &(hmac.outer_digest_ctx); + sha512_begin (ctx); + + for (b = 0; b < lk; ++b) + buf[b] = (char) (k[b] ^ 0x5C); + memset (&buf[lk], 0x5C, SHA512_BLOCKSIZE - lk); + + sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, ctx); + + hmac_sha512_internal (k, lk, d, ld, &hmac); + + /* Prevent leaks */ + burn (&hmac, sizeof(hmac)); + burn (key, sizeof(key)); +} + +static void derive_u_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, int b, hmac_sha512_ctx* hmac) +{ + char* k = hmac->k; + char* u = hmac->u; + 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_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_internal (pwd, pwd_len, k, SHA512_DIGESTSIZE, hmac); + for (i = 0; i < SHA512_DIGESTSIZE; i++) + { + u[i] ^= k[i]; + } + } +} + + +void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, char *dk, int dklen) +{ + hmac_sha512_ctx hmac; + sha512_ctx* ctx; + char* buf = hmac.k; /* there is enough space to hold SHA512_BLOCKSIZE (128) bytes + * because k is followed by u in hmac_sha512_ctx + */ + 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) + { + l = 1 + dklen / SHA512_DIGESTSIZE; + } + else + { + l = dklen / SHA512_DIGESTSIZE; + } + + r = dklen - (l - 1) * SHA512_DIGESTSIZE; + + /**** Precompute HMAC Inner Digest ****/ + + ctx = &(hmac.inner_digest_ctx); + sha512_begin (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, SHA512_BLOCKSIZE - pwd_len); + + sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, ctx); + + /**** Precompute HMAC Outer Digest ****/ + + ctx = &(hmac.outer_digest_ctx); + sha512_begin (ctx); + + for (b = 0; b < pwd_len; ++b) + buf[b] = (char) (pwd[b] ^ 0x5C); + memset (&buf[pwd_len], 0x5C, SHA512_BLOCKSIZE - pwd_len); + + sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, ctx); + + /* first l - 1 blocks */ + for (b = 1; b < l; b++) + { + 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, b, &hmac); + memcpy (dk, hmac.u, r); + + + /* Prevent possible leaks. */ + burn (&hmac, sizeof(hmac)); + burn (key, sizeof(key)); +} + +#endif // TC_WINDOWS_BOOT + +#if !defined(TC_WINDOWS_BOOT) || defined(TC_WINDOWS_BOOT_RIPEMD160) + +typedef struct hmac_ripemd160_ctx_struct +{ + RMD160_CTX context; + RMD160_CTX inner_digest_ctx; /*pre-computed inner digest context */ + RMD160_CTX outer_digest_ctx; /*pre-computed outer digest context */ + 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; + +void hmac_ripemd160_internal (char *key, int keylen, char *input_digest, int len, hmac_ripemd160_ctx* hmac) +{ + RMD160_CTX* context = &(hmac->context); + + /**** Restore Precomputed Inner Digest Context ****/ + + memcpy (context, &(hmac->inner_digest_ctx), sizeof (RMD160_CTX)); + + RMD160Update(context, (const unsigned char *) input_digest, len); /* then text of datagram */ + RMD160Final((unsigned char *) input_digest, context); /* finish up 1st pass */ + + /**** Restore Precomputed Outer Digest Context ****/ + + memcpy (context, &(hmac->outer_digest_ctx), sizeof (RMD160_CTX)); + + /* results of 1st hash */ + RMD160Update(context, (const unsigned char *) input_digest, RIPEMD160_DIGESTSIZE); + RMD160Final((unsigned char *) input_digest, context); /* finish up 2nd pass */ +} + +#ifndef TC_WINDOWS_BOOT +void hmac_ripemd160 (char *key, int keylen, char *input_digest, int len) +{ + hmac_ripemd160_ctx hmac; + RMD160_CTX* ctx; + unsigned char* k_pad = (unsigned char*) hmac.k; /* inner/outer padding - key XORd with ipad */ + unsigned char tk[RIPEMD160_DIGESTSIZE]; + int i; + + /* 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); + + key = (char *) tk; + 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++) + { + k_pad[i] ^= key[i]; + } + + RMD160Init(ctx); /* init context for 1st pass */ + RMD160Update(ctx, k_pad, RIPEMD160_BLOCKSIZE); /* start with inner pad */ + + /* perform outer RIPEMD-160 */ + ctx = &(hmac.outer_digest_ctx); + memset(k_pad, 0x5c, 64); + for (i=0; i<keylen; i++) + { + k_pad[i] ^= key[i]; + } + + RMD160Init(ctx); /* init context for 2nd pass */ + RMD160Update(ctx, k_pad, RIPEMD160_BLOCKSIZE); /* start with outer pad */ + + hmac_ripemd160_internal (key, keylen, input_digest, len, &hmac); + + burn (&hmac, sizeof(hmac)); + burn (tk, sizeof(tk)); +} +#endif + + +static void derive_u_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, int b, hmac_ripemd160_ctx* hmac) +{ + char* k = hmac->k; + char* u = hmac->u; + uint32 c; + int i; + +#ifdef TC_WINDOWS_BOOT + /* In bootloader mode, least significant bit of iterations is a boolean (TRUE for boot derivation mode, FALSE otherwise) + * and the most significant 16 bits hold the pim value + * This enables us to save code space needed for implementing other features. + */ + c = iterations >> 16; + i = ((int) iterations) & 0x01; + if (i) + c = (c == 0)? 327661 : c << 11; + else + c = (c == 0)? 655331 : 15000 + c * 1000; +#else + c = iterations; +#endif + + /* 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_ripemd160_internal (pwd, pwd_len, k, salt_len + 4, hmac); + memcpy (u, k, RIPEMD160_DIGESTSIZE); + + /* remaining iterations */ + while ( c > 1) + { + hmac_ripemd160_internal (pwd, pwd_len, k, RIPEMD160_DIGESTSIZE, hmac); + for (i = 0; i < RIPEMD160_DIGESTSIZE; i++) + { + u[i] ^= k[i]; + } + c--; + } +} + +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; + unsigned char* k_pad = (unsigned char*) hmac.k; +#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) + { + l = 1 + dklen / RIPEMD160_DIGESTSIZE; + } + else + { + l = dklen / RIPEMD160_DIGESTSIZE; + } + + r = dklen - (l - 1) * RIPEMD160_DIGESTSIZE; + + /* 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 (b=0; b<pwd_len; b++) + { + k_pad[b] ^= pwd[b]; + } + + RMD160Init(ctx); /* init context for 1st pass */ + RMD160Update(ctx, k_pad, RIPEMD160_BLOCKSIZE); /* start with inner pad */ + + /* perform outer RIPEMD-160 */ + ctx = &(hmac.outer_digest_ctx); + memset(k_pad, 0x5c, 64); + for (b=0; b<pwd_len; b++) + { + k_pad[b] ^= pwd[b]; + } + + RMD160Init(ctx); /* init context for 2nd pass */ + RMD160Update(ctx, k_pad, RIPEMD160_BLOCKSIZE); /* start with outer pad */ + + /* first l - 1 blocks */ + for (b = 1; b < l; b++) + { + 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, b, &hmac); + memcpy (dk, hmac.u, r); + + + /* Prevent possible leaks. */ + burn (&hmac, sizeof(hmac)); +#ifndef TC_WINDOWS_BOOT + burn (tk, sizeof(tk)); +#endif +} +#endif // TC_WINDOWS_BOOT + +#ifndef TC_WINDOWS_BOOT + +typedef struct hmac_whirlpool_ctx_struct +{ + WHIRLPOOL_CTX ctx; + WHIRLPOOL_CTX inner_digest_ctx; /*pre-computed inner digest context */ + WHIRLPOOL_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 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, /* 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* ctx = &(hmac->ctx); + + /**** Restore Precomputed Inner Digest Context ****/ + + memcpy (ctx, &(hmac->inner_digest_ctx), sizeof (WHIRLPOOL_CTX)); + + WHIRLPOOL_add ((unsigned char *) d, ld * 8, ctx); + + WHIRLPOOL_finalize (ctx, (unsigned char *) d); + + /**** Restore Precomputed Outer Digest Context ****/ + + memcpy (ctx, &(hmac->outer_digest_ctx), sizeof (WHIRLPOOL_CTX)); + + WHIRLPOOL_add ((unsigned char *) d, WHIRLPOOL_DIGESTSIZE * 8, ctx); + + WHIRLPOOL_finalize (ctx, (unsigned char *) d); +} + +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; + WHIRLPOOL_CTX* ctx; + char* buf = hmac.k; + int b; + 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; + + 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 + } + + /**** Precompute HMAC Inner Digest ****/ + + ctx = &(hmac.inner_digest_ctx); + WHIRLPOOL_init (ctx); + + /* Pad the key for inner digest */ + for (b = 0; b < lk; ++b) + buf[b] = (char) (k[b] ^ 0x36); + memset (&buf[lk], 0x36, WHIRLPOOL_BLOCKSIZE - lk); + + WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, ctx); + + /**** Precompute HMAC Outer Digest ****/ + + ctx = &(hmac.outer_digest_ctx); + WHIRLPOOL_init (ctx); + + for (b = 0; b < lk; ++b) + buf[b] = (char) (k[b] ^ 0x5C); + memset (&buf[lk], 0x5C, WHIRLPOOL_BLOCKSIZE - lk); + + WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, ctx); + + hmac_whirlpool_internal(k, lk, d, ld, &hmac); + /* Prevent leaks */ + burn(&hmac, sizeof(hmac)); +} + +static void derive_u_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, int b, hmac_whirlpool_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_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_internal (pwd, pwd_len, k, WHIRLPOOL_DIGESTSIZE, hmac); + for (i = 0; i < WHIRLPOOL_DIGESTSIZE; i++) + { + u[i] ^= k[i]; + } + } +} + +void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, char *dk, int dklen) +{ + hmac_whirlpool_ctx hmac; + WHIRLPOOL_CTX* ctx; + char* buf = hmac.k; + 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) + { + l = 1 + dklen / WHIRLPOOL_DIGESTSIZE; + } + else + { + l = dklen / WHIRLPOOL_DIGESTSIZE; + } + + r = dklen - (l - 1) * WHIRLPOOL_DIGESTSIZE; + + /**** Precompute HMAC Inner Digest ****/ + + ctx = &(hmac.inner_digest_ctx); + WHIRLPOOL_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, WHIRLPOOL_BLOCKSIZE - pwd_len); + + WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, ctx); + + /**** Precompute HMAC Outer Digest ****/ + + ctx = &(hmac.outer_digest_ctx); + WHIRLPOOL_init (ctx); + + for (b = 0; b < pwd_len; ++b) + buf[b] = (char) (pwd[b] ^ 0x5C); + memset (&buf[pwd_len], 0x5C, WHIRLPOOL_BLOCKSIZE - pwd_len); + + WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, ctx); + + /* first l - 1 blocks */ + for (b = 1; b < l; b++) + { + 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, b, &hmac); + memcpy (dk, hmac.u, r); + + + /* 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: + return L"HMAC-SHA-512"; + + case SHA256: + return L"HMAC-SHA-256"; + + case RIPEMD160: + return L"HMAC-RIPEMD-160"; + + case WHIRLPOOL: + return L"HMAC-Whirlpool"; + + default: + return L"(Unknown)"; + } +} + + + +int get_pkcs5_iteration_count (int pkcs5_prf_id, int pim, BOOL truecryptMode, BOOL bBoot) +{ + if ( (pim < 0) + || (truecryptMode && pim > 0) /* No PIM for TrueCrypt mode */ + ) + { + return 0; + } + + switch (pkcs5_prf_id) + { + + case RIPEMD160: + if (truecryptMode) + return bBoot ? 1000 : 2000; + else if (pim == 0) + return bBoot? 327661 : 655331; + else + { + return bBoot? pim * 2048 : 15000 + pim * 1000; + } + + case SHA512: + return truecryptMode? 1000 : ((pim == 0)? 500000 : 15000 + pim * 1000); + + case WHIRLPOOL: + return truecryptMode? 1000 : ((pim == 0)? 500000 : 15000 + pim * 1000); + + case SHA256: + if (truecryptMode) + return 0; // SHA-256 not supported by TrueCrypt + 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; +} + #endif //!TC_WINDOWS_BOOT |