VeraCrypt
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Common/Pkcs5.c634
-rw-r--r--src/Common/Pkcs5.h19
-rw-r--r--src/Common/Tests.c20
3 files changed, 383 insertions, 290 deletions
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
@@ -33,97 +33,102 @@ void hmac_truncate
for (i = 0; i < len; i++)
d2[i] = d1[i];
}
#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)
buf[i] = (char) (k[i] ^ 0x36);
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
* This enables us to save code space needed for implementing other features.
*/
if (iterations)
@@ -132,41 +137,56 @@ void derive_u_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, int iter
c = 500000;
#else
c = iterations;
#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)
{
l = 1 + dklen / SHA256_DIGESTSIZE;
}
else
@@ -176,146 +196,166 @@ void derive_key_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, int it
r = dklen - (l - 1) * SHA256_DIGESTSIZE;
/* 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)
buf[i] = (char) (k[i] ^ 0x36);
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)
{
l = 1 + dklen / SHA512_DIGESTSIZE;
}
else
@@ -325,106 +365,119 @@ void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int it
r = dklen - (l - 1) * SHA512_DIGESTSIZE;
/* 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))
where K is an n byte key
ipad is the byte 0x36 repeated RIPEMD160_BLOCKSIZE times
opad is the byte 0x5c repeated RIPEMD160_BLOCKSIZE times
and text is the data being protected */
/* 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<keylen; i++)
{
- k_ipad[i] ^= key[i];
- k_opad[i] ^= key[i];
+ k_pad[i] ^= key[i];
}
/* perform inner RIPEMD-160 */
- RMD160Init(&context); /* init context for 1st pass */
- RMD160Update(&context, k_ipad, RIPEMD160_BLOCKSIZE); /* start with inner pad */
- RMD160Update(&context, (const unsigned char *) input, len); /* then text of datagram */
- RMD160Final((unsigned char *) digest, &context); /* finish up 1st pass */
+ RMD160Init(context); /* init context for 1st pass */
+ RMD160Update(context, k_pad, RIPEMD160_BLOCKSIZE); /* start with inner pad */
+ RMD160Update(context, (const unsigned char *) input_digest, len); /* then text of datagram */
+ RMD160Final((unsigned char *) input_digest, context); /* finish up 1st pass */
/* perform outer RIPEMD-160 */
- RMD160Init(&context); /* init context for 2nd pass */
- RMD160Update(&context, k_opad, RIPEMD160_BLOCKSIZE); /* start with outer pad */
+ memset(k_pad, 0x5c, 65);
+ for (i=0; i<keylen; i++)
+ {
+ k_pad[i] ^= key[i];
+ }
+
+ RMD160Init(context); /* init context for 2nd pass */
+ RMD160Update(context, k_pad, RIPEMD160_BLOCKSIZE); /* start with outer pad */
/* results of 1st hash */
- RMD160Update(&context, (const unsigned char *) digest, RIPEMD160_DIGESTSIZE);
- RMD160Final((unsigned char *) digest, &context); /* finish up 2nd pass */
+ RMD160Update(context, (const unsigned char *) input_digest, RIPEMD160_DIGESTSIZE);
+ RMD160Final((unsigned char *) input_digest, context); /* finish up 2nd pass */
+}
- /* Prevent possible leaks. */
- burn (k_ipad, sizeof(k_ipad));
- burn (k_opad, sizeof(k_opad));
#ifndef TC_WINDOWS_BOOT
+void hmac_ripemd160 (char *key, int keylen, char *input_digest, int len)
+{
+ hmac_ripemd160_ctx hmac;
+ unsigned char tk[RIPEMD160_DIGESTSIZE];
+
+ /* 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
+ }
+
+ 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;
#ifdef TC_WINDOWS_BOOT
/* In bootloader, iterations is a boolean : TRUE for boot derivation mode, FALSE otherwise
* This enables us to save code space needed for implementing other features.
@@ -435,40 +488,55 @@ void derive_u_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int i
c = 655331;
#else
c = iterations;
#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)
{
l = 1 + dklen / RIPEMD160_DIGESTSIZE;
}
else
@@ -478,143 +546,160 @@ void derive_key_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int
r = dklen - (l - 1) * RIPEMD160_DIGESTSIZE;
/* 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)
buf[i] = (char) (k[i] ^ 0x36);
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)
{
l = 1 + dklen / WHIRLPOOL_DIGESTSIZE;
}
else
@@ -624,24 +709,25 @@ void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int
r = dklen - (l - 1) * WHIRLPOOL_DIGESTSIZE;
/* 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));
}
char *get_pkcs5_prf_name (int pkcs5_prf_id)
{
switch (pkcs5_prf_id)
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
@@ -15,25 +15,28 @@
#include "Tcdefs.h"
#if defined(__cplusplus)
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);
#if defined(__cplusplus)
}
#endif
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
@@ -1013,14 +1013,15 @@ BOOL test_hmac_sha256 ()
{
unsigned int i;
int nTestsPerformed = 0;
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
nTestsPerformed++;
}
@@ -1031,14 +1032,15 @@ BOOL test_hmac_sha512 ()
{
unsigned int i;
int nTestsPerformed = 0;
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
nTestsPerformed++;
}
@@ -1049,28 +1051,30 @@ BOOL test_hmac_ripemd160 ()
{
int nTestsPerformed = 0;
unsigned int i;
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
nTestsPerformed++;
}
return (nTestsPerformed == 2);
}
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;
return TRUE;
}