1
0
mirror of https://github.com/veracrypt/VeraCrypt.git synced 2025-11-12 19:38:26 -06:00

Windows: Add support for Streebog (hash) and kuznyechik (encryption)

This commit is contained in:
Mounir IDRASSI
2016-08-09 14:25:52 +02:00
parent 0b2c8b09c6
commit e90e24b30b
28 changed files with 5597 additions and 14 deletions

View File

@@ -912,6 +912,222 @@ 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)
@@ -928,6 +1144,9 @@ wchar_t *get_pkcs5_prf_name (int pkcs5_prf_id)
case WHIRLPOOL:
return L"HMAC-Whirlpool";
case STREEBOG:
return L"HMAC-STREEBOG";
default:
return L"(Unknown)";
}
@@ -973,6 +1192,16 @@ int get_pkcs5_iteration_count (int pkcs5_prf_id, int pim, BOOL truecryptMode, BO
return bBoot? pim * 2048 : 15000 + pim * 1000;
}
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
}