VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Common
diff options
context:
space:
mode:
Diffstat (limited to 'src/Common')
-rw-r--r--src/Common/BootEncryption.cpp15
-rw-r--r--src/Common/Crypto.c8
-rw-r--r--src/Common/Crypto.h23
-rw-r--r--src/Common/Dlgcode.c28
-rw-r--r--src/Common/EncryptionThreadPool.c5
-rw-r--r--src/Common/Pkcs5.c229
-rw-r--r--src/Common/Pkcs5.h3
-rw-r--r--src/Common/Random.c15
-rw-r--r--src/Common/Tests.c163
-rw-r--r--src/Common/Volumes.c10
10 files changed, 486 insertions, 13 deletions
diff --git a/src/Common/BootEncryption.cpp b/src/Common/BootEncryption.cpp
index bf65fd6a..b18d1ce1 100644
--- a/src/Common/BootEncryption.cpp
+++ b/src/Common/BootEncryption.cpp
@@ -1082,11 +1082,23 @@ namespace VeraCrypt
ea = SERPENT;
else if (_stricmp (request.BootEncryptionAlgorithmName, "Twofish") == 0)
ea = TWOFISH;
+ else if (_stricmp (request.BootEncryptionAlgorithmName, "Camellia") == 0)
+ ea = CAMELLIA;
+#if defined(CIPHER_GOST89)
+ else if (_stricmp (request.BootEncryptionAlgorithmName, "GOST89") == 0)
+ ea = GOST89;
+#endif
if (_stricmp(request.BootPrfAlgorithmName, "SHA-256") == 0)
pkcs5_prf = SHA256;
else if (_stricmp(request.BootPrfAlgorithmName, "RIPEMD-160") == 0)
pkcs5_prf = RIPEMD160;
+ else if (_stricmp(request.BootPrfAlgorithmName, "SHA-512") == 0)
+ pkcs5_prf = SHA512;
+ else if (_stricmp(request.BootPrfAlgorithmName, "Whirlpool") == 0)
+ pkcs5_prf = WHIRLPOOL;
+ else if (_stricmp(request.BootPrfAlgorithmName, "Streebog") == 0)
+ pkcs5_prf = STREEBOG;
else if (strlen(request.BootPrfAlgorithmName) == 0) // case of version < 1.0f
pkcs5_prf = RIPEMD160;
}
@@ -1101,6 +1113,9 @@ namespace VeraCrypt
}
catch (...) { }
}
+
+ if (pkcs5_prf == 0)
+ throw ParameterIncorrect (SRC_POS);
}
else
{
diff --git a/src/Common/Crypto.c b/src/Common/Crypto.c
index 16115bf6..69d5b5dc 100644
--- a/src/Common/Crypto.c
+++ b/src/Common/Crypto.c
@@ -58,6 +58,7 @@ static Cipher Ciphers[] =
#if defined(CIPHER_GOST89)
{ GOST89, L"GOST89", 16, 32, GOST_KS },
#endif // defined(CIPHER_GOST89)
+ { KUZNYECHIK, L"Kuznyechik",16, 32, KUZNYECHIK_KS },
#endif
{ 0, 0, 0, 0, 0 }
};
@@ -78,6 +79,7 @@ static EncryptionAlgorithm EncryptionAlgorithms[] =
#if defined(CIPHER_GOST89)
{ { GOST89, 0 }, { XTS, 0 }, 1 },
#endif // defined(CIPHER_GOST89)
+ { { KUZNYECHIK, 0 }, { XTS, 0 }, 1 },
{ { TWOFISH, AES, 0 }, { XTS, 0 }, 1 },
{ { SERPENT, TWOFISH, AES, 0 }, { XTS, 0 }, 1 },
{ { AES, SERPENT, 0 }, { XTS, 0 }, 1 },
@@ -112,6 +114,7 @@ static Hash Hashes[] =
{ WHIRLPOOL, L"Whirlpool", FALSE, FALSE },
{ SHA256, L"SHA-256", FALSE, TRUE },
{ RIPEMD160, L"RIPEMD-160", TRUE, TRUE },
+ { STREEBOG, L"Streebog", FALSE, FALSE },
{ 0, 0, 0 }
};
#endif
@@ -156,6 +159,9 @@ int CipherInit (int cipher, unsigned char *key, unsigned __int8 *ks)
gost_set_key(key, (gost_kds*)ks);
break;
#endif // && defined(CIPHER_GOST89)
+ case KUZNYECHIK:
+ kuznyechik_set_key(key, (kuznyechik_kds*)ks);
+ break;
#endif // !defined(TC_WINDOWS_BOOT)
default:
@@ -189,6 +195,7 @@ void EncipherBlock(int cipher, void *data, void *ks)
#if defined(CIPHER_GOST89)
case GOST89: gost_encrypt(data, data, ks, 1); break;
#endif // defined(CIPHER_GOST89)
+ case KUZNYECHIK: kuznyechik_encrypt_block(data, data, ks); break;
#endif // !defined(TC_WINDOWS_BOOT)
default: TC_THROW_FATAL_EXCEPTION; // Unknown/wrong ID
}
@@ -252,6 +259,7 @@ void DecipherBlock(int cipher, void *data, void *ks)
#if defined(CIPHER_GOST89)
case GOST89: gost_decrypt(data, data, ks, 1); break;
#endif // defined(CIPHER_GOST89)
+ case KUZNYECHIK: kuznyechik_decrypt_block(data, data, ks); break;
#endif // !defined(TC_WINDOWS_BOOT)
diff --git a/src/Common/Crypto.h b/src/Common/Crypto.h
index 9b5fbace..abcdfa5b 100644
--- a/src/Common/Crypto.h
+++ b/src/Common/Crypto.h
@@ -54,6 +54,7 @@ enum
WHIRLPOOL,
SHA256,
RIPEMD160,
+ STREEBOG,
HASH_ENUM_END_ID
};
@@ -72,6 +73,9 @@ enum
#define WHIRLPOOL_BLOCKSIZE 64
#define WHIRLPOOL_DIGESTSIZE 64
+#define STREEBOG_BLOCKSIZE 64
+#define STREEBOG_DIGESTSIZE 64
+
#define MAX_DIGESTSIZE WHIRLPOOL_DIGESTSIZE
#define DEFAULT_HASH_ALGORITHM FIRST_PRF_ID
@@ -108,7 +112,8 @@ enum
SERPENT,
TWOFISH,
CAMELLIA,
- GOST89
+ GOST89,
+ KUZNYECHIK
};
typedef struct
@@ -162,9 +167,11 @@ typedef struct
# endif
#else
-
-#define MAX_EXPANDED_KEY (AES_KS + SERPENT_KS + TWOFISH_KS)
-
+#ifdef TC_WINDOWS_BOOT
+#define MAX_EXPANDED_KEY max((AES_KS + SERPENT_KS + TWOFISH_KS), CAMELLIA_KS)
+#else
+#define MAX_EXPANDED_KEY max(max(max((AES_KS + SERPENT_KS + TWOFISH_KS), GOST_KS), CAMELLIA_KS), KUZNYECHIK_KS)
+#endif
#endif
#ifdef DEBUG
@@ -190,7 +197,9 @@ typedef struct
#ifndef TC_WINDOWS_BOOT
# include "Sha2.h"
# include "Whirlpool.h"
+# include "Streebog.h"
# include "GostCipher.h"
+# include "kuznyechik.h"
# include "Camellia.h"
#else
# include "CamelliaSmall.h"
@@ -209,7 +218,7 @@ typedef struct keyInfo_t
int keyLength; /* Length of the key */
uint64 dummy; /* Dummy field to ensure 16-byte alignment of this structure */
__int8 salt[PKCS5_SALT_SIZE]; /* PKCS-5 salt */
- __int8 master_keydata[MASTER_KEYDATA_SIZE]; /* Concatenated master primary and secondary key(s) (XTS mode). For LRW (deprecated/legacy), it contains the tweak key before the master key(s). For CBC (deprecated/legacy), it contains the IV seed before the master key(s). */
+ CRYPTOPP_ALIGN_DATA(16) __int8 master_keydata[MASTER_KEYDATA_SIZE]; /* Concatenated master primary and secondary key(s) (XTS mode). For LRW (deprecated/legacy), it contains the tweak key before the master key(s). For CBC (deprecated/legacy), it contains the IV seed before the master key(s). */
CRYPTOPP_ALIGN_DATA(16) __int8 userKey[MAX_PASSWORD]; /* Password (to which keyfiles may have been applied). WITHOUT +1 for the null terminator. */
} KEY_INFO, *PKEY_INFO;
@@ -231,8 +240,8 @@ typedef struct CRYPTO_INFO_t
GfCtx gf_ctx;
- unsigned __int8 master_keydata[MASTER_KEYDATA_SIZE]; /* This holds the volume header area containing concatenated master key(s) and secondary key(s) (XTS mode). For LRW (deprecated/legacy), it contains the tweak key before the master key(s). For CBC (deprecated/legacy), it contains the IV seed before the master key(s). */
- unsigned __int8 k2[MASTER_KEYDATA_SIZE]; /* For XTS, this contains the secondary key (if cascade, multiple concatenated). For LRW (deprecated/legacy), it contains the tweak key. For CBC (deprecated/legacy), it contains the IV seed. */
+ CRYPTOPP_ALIGN_DATA(16) unsigned __int8 master_keydata[MASTER_KEYDATA_SIZE]; /* This holds the volume header area containing concatenated master key(s) and secondary key(s) (XTS mode). For LRW (deprecated/legacy), it contains the tweak key before the master key(s). For CBC (deprecated/legacy), it contains the IV seed before the master key(s). */
+ CRYPTOPP_ALIGN_DATA(16) unsigned __int8 k2[MASTER_KEYDATA_SIZE]; /* For XTS, this contains the secondary key (if cascade, multiple concatenated). For LRW (deprecated/legacy), it contains the tweak key. For CBC (deprecated/legacy), it contains the IV seed. */
unsigned __int8 salt[PKCS5_SALT_SIZE];
int noIterations;
BOOL bTrueCryptMode;
diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c
index 1ecc3c0a..31be6b90 100644
--- a/src/Common/Dlgcode.c
+++ b/src/Common/Dlgcode.c
@@ -5154,6 +5154,7 @@ static BOOL PerformBenchmark(HWND hBenchDlg, HWND hwndDlg)
RMD160_CTX rctx;
sha512_ctx s2ctx;
sha256_ctx s256ctx;
+ STREEBOG_CTX stctx;
int hid, i;
@@ -5190,6 +5191,13 @@ static BOOL PerformBenchmark(HWND hBenchDlg, HWND hwndDlg)
WHIRLPOOL_add (lpTestBuffer, benchmarkBufferSize, &wctx);
WHIRLPOOL_finalize (&wctx, (unsigned char *) digest);
break;
+
+ case STREEBOG:
+ STREEBOG_init(&stctx);
+ STREEBOG_add(&stctx, lpTestBuffer, benchmarkBufferSize);
+ STREEBOG_finalize(&stctx, (unsigned char *)digest);
+ break;
+
}
}
@@ -5249,6 +5257,11 @@ static BOOL PerformBenchmark(HWND hBenchDlg, HWND hwndDlg)
/* PKCS-5 test with HMAC-Whirlpool used as the PRF */
derive_key_whirlpool ("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, benchmarkPim, FALSE, benchmarkPreBoot), dk, MASTER_KEYDATA_SIZE);
break;
+
+ case STREEBOG:
+ /* PKCS-5 test with HMAC-STREEBOG used as the PRF */
+ derive_key_streebog("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, benchmarkPim, FALSE, benchmarkPreBoot), dk, MASTER_KEYDATA_SIZE);
+ break;
}
}
@@ -6612,7 +6625,12 @@ ResetCipherTest(HWND hwndDlg, int idTestCipher)
SetWindowText(GetDlgItem(hwndDlg, IDC_PLAINTEXT), L"0000000000000000");
SetWindowText(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), L"0000000000000000");
- if (idTestCipher == AES || idTestCipher == SERPENT || idTestCipher == TWOFISH || idTestCipher == CAMELLIA)
+ if (idTestCipher == AES || idTestCipher == SERPENT || idTestCipher == TWOFISH || idTestCipher == CAMELLIA
+#if defined(CIPHER_GOST89)
+ || idTestCipher == GOST89
+#endif
+ || idTestCipher == KUZNYECHIK
+ )
{
ndx = (int) SendMessage (GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_ADDSTRING, 0,(LPARAM) L"256");
SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETITEMDATA, ndx,(LPARAM) 32);
@@ -10186,6 +10204,14 @@ void Applink (char *dest, BOOL bSendOS, char *extraOutput)
{
StringCbCopyA (url, sizeof (url),"https://veracrypt.codeplex.com/wikipage?title=Twofish");
}
+ else if (strcmp(dest, "gost89") == 0)
+ {
+ StringCbCopyA (url, sizeof (url),"https://veracrypt.codeplex.com/wikipage?title=GOST89");
+ }
+ else if (strcmp(dest, "kuznyechik") == 0)
+ {
+ StringCbCopyA (url, sizeof (url),"https://veracrypt.codeplex.com/wikipage?title=Kuznyechik");
+ }
else if (strcmp(dest, "camellia") == 0)
{
StringCbCopyA (url, sizeof (url),"https://veracrypt.codeplex.com/wikipage?title=Camellia");
diff --git a/src/Common/EncryptionThreadPool.c b/src/Common/EncryptionThreadPool.c
index d99512a9..f1207113 100644
--- a/src/Common/EncryptionThreadPool.c
+++ b/src/Common/EncryptionThreadPool.c
@@ -182,6 +182,11 @@ static TC_THREAD_PROC EncryptionThreadProc (void *threadArg)
workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize());
break;
+ case STREEBOG:
+ derive_key_streebog(workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE,
+ workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize());
+ break;
+
default:
TC_THROW_FATAL_EXCEPTION;
}
diff --git a/src/Common/Pkcs5.c b/src/Common/Pkcs5.c
index eb1a66ad..2ce475ef 100644
--- a/src/Common/Pkcs5.c
+++ b/src/Common/Pkcs5.c
@@ -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
}
diff --git a/src/Common/Pkcs5.h b/src/Common/Pkcs5.h
index 81d9de64..261df85d 100644
--- a/src/Common/Pkcs5.h
+++ b/src/Common/Pkcs5.h
@@ -37,6 +37,9 @@ void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, uint32
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, uint32 iterations, char *dk, int dklen);
+void hmac_streebog (char *k, int32 lk, char *d, int32 ld);
+void derive_key_streebog (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, char *dk, int dklen);
+
int get_pkcs5_iteration_count (int pkcs5_prf_id, int pim, BOOL truecryptMode, BOOL bBoot);
wchar_t *get_pkcs5_prf_name (int pkcs5_prf_id);
#endif
diff --git a/src/Common/Random.c b/src/Common/Random.c
index 2be230fd..edc6acca 100644
--- a/src/Common/Random.c
+++ b/src/Common/Random.c
@@ -247,6 +247,7 @@ BOOL Randmix ()
RMD160_CTX rctx;
sha512_ctx sctx;
sha256_ctx s256ctx;
+ STREEBOG_CTX stctx;
int poolIndex, digestIndex, digestSize;
switch (HashFunction)
@@ -267,6 +268,10 @@ BOOL Randmix ()
digestSize = WHIRLPOOL_DIGESTSIZE;
break;
+ case STREEBOG:
+ digestSize = STREEBOG_DIGESTSIZE;
+ break;
+
default:
TC_THROW_FATAL_EXCEPTION;
}
@@ -303,6 +308,12 @@ BOOL Randmix ()
WHIRLPOOL_finalize (&wctx, hashOutputBuffer);
break;
+ case STREEBOG:
+ STREEBOG_init (&stctx);
+ STREEBOG_add (&stctx, pRandPool, RNG_POOL_SIZE);
+ STREEBOG_finalize (&stctx, hashOutputBuffer);
+ break;
+
default:
// Unknown/wrong ID
TC_THROW_FATAL_EXCEPTION;
@@ -335,6 +346,10 @@ BOOL Randmix ()
burn (&wctx, sizeof(wctx));
break;
+ case STREEBOG:
+ burn (&stctx, sizeof(sctx));
+ break;
+
default:
// Unknown/wrong ID
TC_THROW_FATAL_EXCEPTION;
diff --git a/src/Common/Tests.c b/src/Common/Tests.c
index 02f893c7..c51b6338 100644
--- a/src/Common/Tests.c
+++ b/src/Common/Tests.c
@@ -19,10 +19,11 @@
#include "Xts.h"
#include <string.h>
#include "Pkcs5.h"
+#include "cpu.h"
typedef struct {
- unsigned __int8 key1[32];
- unsigned __int8 key2[32];
+ CRYPTOPP_ALIGN_DATA(16) unsigned __int8 key1[32];
+ CRYPTOPP_ALIGN_DATA(16) unsigned __int8 key2[32];
unsigned __int8 dataUnitNo[8];
unsigned int blockNo;
unsigned __int8 plaintext[ENCRYPTION_DATA_UNIT_SIZE];
@@ -475,6 +476,95 @@ char *hmac_whirlpool_test_vectors =
"\x6a\xbf\xa4\x02"
};
+typedef struct _HashTestVector
+{
+ const char* hexInput;
+ const char* hexOutput;
+
+} HashTestVector;
+
+typedef int (__cdecl HashFunction) (unsigned char* input, unsigned long inputLen, unsigned char* output);
+
+unsigned char HexCharToByte (char c)
+{
+ if (c >= ('0') && c <= ('9'))
+ return c - ('0');
+ else if (c >= ('A') && c <= ('F'))
+ return c - ('A') + 10;
+ else if (c >= ('a') && c <= ('f'))
+ return c - ('a') + 10;
+ else
+ return 0xFF;
+}
+
+unsigned long HexStringToByteArray(const char* hexStr, unsigned char* pbData)
+{
+ unsigned long count = 0;
+ while (*hexStr)
+ {
+ *pbData++ = (HexCharToByte(hexStr[0]) << 4) | HexCharToByte(hexStr[1]);
+ hexStr += 2;
+ count++;
+ }
+ return count;
+}
+
+BOOL RunHashTest (HashFunction fn, HashTestVector* vector, BOOL bUseSSE)
+{
+ ALIGN (16) unsigned char input[256];
+ unsigned char output[64];
+ unsigned char digest[64];
+ unsigned long i = 0, inputLen, outputLen, digestLen;
+ BOOL bRet = TRUE;
+#if defined (DEVICE_DRIVER) && !defined (_WIN64)
+ KFLOATING_SAVE floatingPointState;
+ NTSTATUS saveStatus = STATUS_SUCCESS;
+ if (bUseSSE && (HasSSE2() || HasSSE41()))
+ saveStatus = KeSaveFloatingPointState (&floatingPointState);
+#endif
+ while (vector[i].hexInput && vector[i].hexOutput)
+ {
+ inputLen = HexStringToByteArray (vector[i].hexInput, input);
+ outputLen = HexStringToByteArray (vector[i].hexOutput, output);
+ digestLen = fn (input, inputLen, digest);
+ if ((digestLen != outputLen) || (0 != memcmp (digest, output, digestLen)))
+ {
+ bRet = FALSE;
+ break;
+ }
+ i++;
+ }
+
+#if defined (DEVICE_DRIVER) && !defined (_WIN64)
+ if (NT_SUCCESS (saveStatus) && bUseSSE && (HasSSE2() || HasSSE41()))
+ KeRestoreFloatingPointState (&floatingPointState);
+#endif
+
+ return bRet;
+}
+
+
+/* https://www.streebog.net/src/trunk/examples/ */
+HashTestVector Streebog512TestVectors[] = {
+ /* M1 */
+ {"303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132",
+ "1b54d01a4af5b9d5cc3d86d68d285462b19abc2475222f35c085122be4ba1ffa00ad30f8767b3a82384c6574f024c311e2a481332b08ef7f41797891c1646f48"
+ },
+ /* M2 */
+ {"d1e520e2e5f2f0e82c20d1f2f0e8e1eee6e820e2edf3f6e82c20e2e5fef2fa20f120eceef0ff20f1f2f0e5ebe0ece820ede020f5f0e0e1f0fbff20efebfaeafb20c8e3eef0e5e2fb",
+ "1e88e62226bfca6f9994f1f2d51569e0daf8475a3b0fe61a5300eee46d961376035fe83549ada2b8620fcd7c496ce5b33f0cb9dddc2b6460143b03dabac9fb28"
+ },
+ /* M3 */
+ {"",
+ "8e945da209aa869f0455928529bcae4679e9873ab707b55315f56ceb98bef0a7362f715528356ee83cda5f2aac4c6ad2ba3a715c1bcd81cb8e9f90bf4c1c1a8a"
+ },
+ /* M4 */
+ {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "b0fd29ac1b0df441769ff3fdb8dc564df67721d6ac06fb28ceffb7bbaa7948c6c014ac999235b58cb26fb60fb112a145d7b4ade9ae566bf2611402c552d20db7"
+ },
+ {NULL, NULL}
+};
+
unsigned char ks_tmp[MAX_EXPANDED_KEY];
void CipherInit2(int cipher, void* key, void* ks, int key_len)
@@ -502,6 +592,9 @@ void CipherInit2(int cipher, void* key, void* ks, int key_len)
CipherInit(cipher,key,ks);
break;
#endif // defined(CIPHER_GOST89)
+ case KUZNYECHIK:
+ CipherInit(cipher, key, ks);
+ break;
default:
/* Unknown/wrong ID */
TC_THROW_FATAL_EXCEPTION;
@@ -521,7 +614,7 @@ BOOL TestSectorBufEncryption (PCRYPTO_INFO ci)
int testCase = 0;
int nTestsPerformed = 0;
- static unsigned char key1[] =
+ static CRYPTOPP_ALIGN_DATA(16) unsigned char key1[] =
{
0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45, 0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26, 0x62, 0x49, 0x77, 0x57, 0x24, 0x70, 0x93, 0x69, 0x99, 0x59, 0x57, 0x49, 0x66, 0x96, 0x76, 0x27,
0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93, 0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95, 0x02, 0x88, 0x41, 0x97, 0x16, 0x93, 0x99, 0x37, 0x51, 0x05, 0x82, 0x09, 0x74, 0x94, 0x45, 0x92,
@@ -939,7 +1032,7 @@ BOOL TestSectorBufEncryption (PCRYPTO_INFO ci)
static BOOL DoAutoTestAlgorithms (void)
{
PCRYPTO_INFO ci;
- char key[32];
+ CRYPTOPP_ALIGN_DATA(16) char key[32];
unsigned char tmp[16];
BOOL bFailed = FALSE;
int i;
@@ -1172,6 +1265,50 @@ BOOL test_hmac_whirlpool ()
return TRUE;
}
+/* http://www.tc26.ru/methods/recommendation/%D0%A2%D0%9A26%D0%90%D0%9B%D0%93.pdf */
+/* https://tools.ietf.org/html/draft-smyshlyaev-gost-usage-00 */
+/* https://datatracker.ietf.org/doc/rfc7836/?include_text=1 */
+static const unsigned char gost3411_2012_hmac_k1[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
+};
+static const unsigned char gost3411_2012_hmac_m1[] = {
+ 0x01, 0x26, 0xbd, 0xb8, 0x78, 0x00, 0xaf, 0x21,
+ 0x43, 0x41, 0x45, 0x65, 0x63, 0x78, 0x01, 0x00
+};
+static const unsigned char gost3411_2012_hmac_r1[] = {
+ 0xA5, 0x9B, 0xAB, 0x22, 0xEC, 0xAE, 0x19, 0xC6, 0x5F, 0xBD, 0xE6, 0xE5,
+ 0xF4, 0xE9, 0xF5, 0xD8, 0x54, 0x9D, 0x31, 0xF0, 0x37, 0xF9, 0xDF, 0x9B,
+ 0x90, 0x55, 0x00, 0xE1, 0x71, 0x92, 0x3A, 0x77, 0x3D, 0x5F, 0x15, 0x30,
+ 0xF2, 0xED, 0x7E, 0x96, 0x4C, 0xB2, 0xEE, 0xDC, 0x29, 0xE9, 0xAD, 0x2F,
+ 0x3A, 0xFE, 0x93, 0xB2, 0x81, 0x4F, 0x79, 0xF5, 0x00, 0x0F, 0xFC, 0x03,
+ 0x66, 0xC2, 0x51, 0xE6
+};
+
+
+BOOL test_hmac_streebog ()
+{
+ ALIGN(16) char digest[64]; /* large enough to hold digets and test vector inputs */
+
+ memcpy (digest, gost3411_2012_hmac_m1, sizeof (gost3411_2012_hmac_m1));
+ hmac_streebog ((char*) gost3411_2012_hmac_k1, sizeof(gost3411_2012_hmac_k1), digest, (int) sizeof (gost3411_2012_hmac_m1));
+ if (memcmp (digest, gost3411_2012_hmac_r1, STREEBOG_DIGESTSIZE) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+int __cdecl StreebogHash (unsigned char* input, unsigned long inputLen, unsigned char* output)
+{
+ STREEBOG_CTX ctx;
+ STREEBOG_init (&ctx);
+ STREEBOG_add (&ctx, input, inputLen);
+ STREEBOG_finalize (&ctx, output);
+ return STREEBOG_DIGESTSIZE;
+}
+
BOOL test_pkcs5 ()
{
char dk[144];
@@ -1192,6 +1329,14 @@ BOOL test_pkcs5 ()
if (test_hmac_whirlpool() == FALSE)
return FALSE;
+ /* HMAC-STREEBOG tests */
+ if (test_hmac_streebog() == FALSE)
+ return FALSE;
+
+ /* STREEBOG hash tests */
+ if (RunHashTest (StreebogHash, Streebog512TestVectors, TRUE) == FALSE)
+ return FALSE;
+
/* PKCS-5 test 1 with HMAC-SHA-256 used as the PRF (https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-00) */
derive_key_sha256 ("passwd", 6, "\x73\x61\x6C\x74", 4, 1, dk, 64);
if (memcmp (dk, "\x55\xac\x04\x6e\x56\xe3\x08\x9f\xec\x16\x91\xc2\x25\x44\xb6\x05\xf9\x41\x85\x21\x6d\xde\x04\x65\xe6\x8b\x9d\x57\xc2\x0d\xac\xbc\x49\xca\x9c\xcc\xf1\x79\xb6\x45\x99\x16\x64\xb3\x9d\x77\xef\x31\x7c\x71\xb8\x45\xb1\xe3\x0b\xd5\x09\x11\x20\x41\xd3\xa1\x97\x83", 64) != 0)
@@ -1243,5 +1388,15 @@ BOOL test_pkcs5 ()
if (memcmp (dk, "\x50\x7c\x36\x6f\xee\x10\x2e\x9a\xe2\x8a\xd5\x82\x72\x7d\x27\x0f\xe8\x4d\x7f\x68\x7a\xcf\xb5\xe7\x43\x67\xaa\x98\x93\x52\x2b\x09\x6e\x42\xdf\x2c\x59\x4a\x91\x6d\x7e\x10\xae\xb2\x1a\x89\x8f\xb9\x8f\xe6\x31\xa9\xd8\x9f\x98\x26\xf4\xda\xcd\x7d\x65\x65\xde\x10\x95\x91\xb4\x84\x26\xae\x43\xa1\x00\x5b\x1e\xb8\x38\x97\xa4\x1e\x4b\xd2\x65\x64\xbc\xfa\x1f\x35\x85\xdb\x4f\x97\x65\x6f\xbd\x24", 96) != 0)
return FALSE;
+ /* PKCS-5 test 1 with HMAC-STREEBOG used as the PRF */
+ derive_key_streebog ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 4);
+ if (memcmp (dk, "\xd0\x53\xa2\x30", 4) != 0)
+ return FALSE;
+
+ /* PKCS-5 test 2 with HMAC-STREEBOG used as the PRF (derives a key longer than the underlying hash) */
+ derive_key_streebog ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 96);
+ if (memcmp (dk, "\xd0\x53\xa2\x30\x6f\x45\x81\xeb\xbc\x06\x81\xc5\xe7\x53\xa8\x5d\xc7\xf1\x23\x33\x1e\xbe\x64\x2c\x3b\x0f\x26\xd7\x00\xe1\x95\xc9\x65\x26\xb1\x85\xbe\x1e\xe2\xf4\x9b\xfc\x6b\x14\x84\xda\x24\x61\xa0\x1b\x9e\x79\x5c\xee\x69\x6e\xf9\x25\xb1\x1d\xca\xa0\x31\xba\x02\x6f\x9e\x99\x0f\xdb\x25\x01\x5b\xf1\xc7\x10\x19\x53\x3b\x29\x3f\x18\x00\xd6\xfc\x85\x03\xdc\xf2\xe5\xe9\x5a\xb1\x1e\x61\xde", 96) != 0)
+ return FALSE;
+
return TRUE;
}
diff --git a/src/Common/Volumes.c b/src/Common/Volumes.c
index 8ad40ac1..21b34f6d 100644
--- a/src/Common/Volumes.c
+++ b/src/Common/Volumes.c
@@ -171,7 +171,7 @@ int ReadVolumeHeader (BOOL bBoot, char *encryptedHeader, Password *password, int
char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
CRYPTOPP_ALIGN_DATA(16) KEY_INFO keyInfo;
PCRYPTO_INFO cryptoInfo;
- char dk[MASTER_KEYDATA_SIZE];
+ CRYPTOPP_ALIGN_DATA(16) char dk[MASTER_KEYDATA_SIZE];
int enqPkcs5Prf, pkcs5_prf;
uint16 headerVersion;
int status = ERR_PARAMETER_INCORRECT;
@@ -345,6 +345,10 @@ KeyReady: ;
PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
break;
+ case STREEBOG:
+ derive_key_streebog(keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
+ PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
+ break;
default:
// Unknown/wrong ID
TC_THROW_FATAL_EXCEPTION;
@@ -912,6 +916,10 @@ int CreateVolumeHeaderInMemory (HWND hwndDlg, BOOL bBoot, char *header, int ea,
PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
break;
+ case STREEBOG:
+ derive_key_streebog(keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
+ PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
+ break;
default:
// Unknown/wrong ID