From f38cf0b6943da24c802424f53588b54aada48fd8 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Tue, 14 Oct 2014 17:09:18 +0200 Subject: Add support for SHA-256 in key derivation for bootloader encryption. Create separate bootloader images for SHA-256 and RIPEMD-160. Set SHA-256 as the default PRF for boot encryption and SHA-512 as default PRF for all other cases. Depricate RIPEMD-160. --- src/Boot/Windows/Boot.vcproj | 10 ++- src/Boot/Windows/Makefile | 11 +++ src/Common/Crypto.c | 47 ++++++++----- src/Common/Crypto.h | 23 +++--- src/Common/Pkcs5.c | 162 ++++++++++++++++++++++++++++++++++++++++++- src/Common/Pkcs5.h | 3 + src/Common/Volumes.c | 24 +++++++ 7 files changed, 252 insertions(+), 28 deletions(-) diff --git a/src/Boot/Windows/Boot.vcproj b/src/Boot/Windows/Boot.vcproj index 862f1e33..d0b40f1a 100644 --- a/src/Boot/Windows/Boot.vcproj +++ b/src/Boot/Windows/Boot.vcproj @@ -24,9 +24,9 @@ > + + diff --git a/src/Boot/Windows/Makefile b/src/Boot/Windows/Makefile index 737fbe5f..9ef70d41 100644 --- a/src/Boot/Windows/Makefile +++ b/src/Boot/Windows/Makefile @@ -39,6 +39,13 @@ OBJDIR = $(OBJDIR)_$(SINGLE_CIPHER) CFLAGS = $(CFLAGS) /D TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE /D TC_WINDOWS_BOOT_$(SINGLE_CIPHER) !endif +!ifdef SINGLE_PRF +OBJDIR = $(OBJDIR)_$(SINGLE_PRF) +CFLAGS = $(CFLAGS) /D TC_WINDOWS_BOOT_$(SINGLE_PRF) +!else +CFLAGS = $(CFLAGS) /D TC_WINDOWS_BOOT_RIPEMD160 +!endif + OUTDIR = $(OBJDIR) TARGETEXT = com TARGETS = $(OUTDIR)\BootDefs.i $(OUTDIR)\BootSector.bin $(OUTDIR)\Decompressor.com @@ -72,7 +79,11 @@ OBJS = $(OBJS) $(OUTDIR)\Pkcs5.obj OBJS = $(OBJS) $(OUTDIR)\Volumes.obj OBJS = $(OBJS) $(OUTDIR)\Xts.obj +!if "$(SINGLE_PRF)" == "SHA2" +OBJS = $(OBJS) $(OUTDIR)\Sha2Small.obj +!else OBJS = $(OBJS) $(OUTDIR)\Rmd160.obj +!endif !if !DEFINED (SINGLE_CIPHER) OBJS = $(OBJS) $(OUTDIR)\AesSmall.obj diff --git a/src/Common/Crypto.c b/src/Common/Crypto.c index a63bc954..9fc69022 100644 --- a/src/Common/Crypto.c +++ b/src/Common/Crypto.c @@ -90,11 +90,12 @@ static EncryptionAlgorithm EncryptionAlgorithms[] = // Hash algorithms static Hash Hashes[] = { // ID Name Deprecated System Encryption - { RIPEMD160, "RIPEMD-160", FALSE, TRUE }, #ifndef TC_WINDOWS_BOOT { SHA512, "SHA-512", FALSE, FALSE }, { WHIRLPOOL, "Whirlpool", FALSE, FALSE }, #endif + { SHA256, "SHA-256", FALSE, TRUE }, + { RIPEMD160, "RIPEMD-160", TRUE, TRUE }, { 0, 0, 0 } }; @@ -651,17 +652,42 @@ char *HashGetName (int hashId) #endif } +#ifndef TC_WINDOWS_BOOT +void HashGetName2 (char *buf, int hashId) +{ + Hash* pHash = HashGet(hashId); + if (pHash) + strcpy(buf, pHash -> Name); + else + buf[0] = '\0'; +} BOOL HashIsDeprecated (int hashId) { -#ifdef TC_WINDOWS_BOOT - return HashGet(hashId) -> Deprecated; -#else Hash* pHash = HashGet(hashId); return pHash? pHash -> Deprecated : FALSE; -#endif + } +BOOL HashForSystemEncryption (int hashId) +{ + Hash* pHash = HashGet(hashId); + return pHash? pHash -> SystemEncryption : FALSE; + +} + +// Returns the maximum number of bytes necessary to be generated by the PBKDF2 (PKCS #5) +int GetMaxPkcs5OutSize (void) +{ + int size = 32; + + size = max (size, EAGetLargestKeyForMode (XTS) * 2); // Sizes of primary + secondary keys + + return size; +} + +#endif + #endif // TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE @@ -904,17 +930,6 @@ void DecryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *s } -// Returns the maximum number of bytes necessary to be generated by the PBKDF2 (PKCS #5) -int GetMaxPkcs5OutSize (void) -{ - int size = 32; - - size = max (size, EAGetLargestKeyForMode (XTS) * 2); // Sizes of primary + secondary keys - - return size; -} - - #else // TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE diff --git a/src/Common/Crypto.h b/src/Common/Crypto.h index 651da737..7875e1a5 100644 --- a/src/Common/Crypto.h +++ b/src/Common/Crypto.h @@ -48,11 +48,10 @@ extern "C" { // Hash algorithms (pseudorandom functions). enum { - RIPEMD160 = FIRST_PRF_ID, -#ifndef TC_WINDOWS_BOOT - SHA512, + SHA512 = FIRST_PRF_ID, WHIRLPOOL, -#endif + SHA256, + RIPEMD160, HASH_ENUM_END_ID }; @@ -62,6 +61,9 @@ enum #define RIPEMD160_BLOCKSIZE 64 #define RIPEMD160_DIGESTSIZE 20 +#define SHA256_BLOCKSIZE 64 +#define SHA256_DIGESTSIZE 32 + #define SHA512_BLOCKSIZE 128 #define SHA512_DIGESTSIZE 64 @@ -71,7 +73,7 @@ enum #define MAX_DIGESTSIZE WHIRLPOOL_DIGESTSIZE #define DEFAULT_HASH_ALGORITHM FIRST_PRF_ID -#define DEFAULT_HASH_ALGORITHM_BOOT RIPEMD160 +#define DEFAULT_HASH_ALGORITHM_BOOT SHA256 // The mode of operation used for newly created volumes and first to try when mounting #define FIRST_MODE_OF_OPERATION_ID 1 @@ -207,8 +209,7 @@ typedef struct CRYPTO_INFO_t 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. */ unsigned __int8 salt[PKCS5_SALT_SIZE]; - int noIterations; - int pkcs5; + int noIterations; uint64 volume_creation_time; // Legacy uint64 header_creation_time; // Legacy @@ -239,6 +240,7 @@ typedef struct CRYPTO_INFO_t UINT64_STRUCT EncryptedAreaLength; uint32 HeaderFlags; + int pkcs5; } CRYPTO_INFO, *PCRYPTO_INFO; @@ -292,9 +294,14 @@ BOOL EAIsModeSupported (int ea, int testedMode); const #endif char *HashGetName (int hash_algo_id); -BOOL HashIsDeprecated (int hashId); +#ifndef TC_WINDOWS_BOOT +void HashGetName2 (char *buf, int hashId); +BOOL HashIsDeprecated (int hashId); +BOOL HashForSystemEncryption (int hashId); int GetMaxPkcs5OutSize (void); +#endif + void EncryptDataUnits (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, uint32 nbrUnits, PCRYPTO_INFO ci); void EncryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci); diff --git a/src/Common/Pkcs5.c b/src/Common/Pkcs5.c index c1222a03..2901d6a1 100644 --- a/src/Common/Pkcs5.c +++ b/src/Common/Pkcs5.c @@ -16,6 +16,8 @@ #ifndef TC_WINDOWS_BOOT #include "Sha2.h" #include "Whirlpool.h" +#else +#include "Sha2Small.h" #endif #include "Pkcs5.h" #include "Crypto.h" @@ -32,6 +34,155 @@ void hmac_truncate d2[i] = d1[i]; } +#if !defined(TC_WINDOWS_BOOT) || defined(TC_WINDOWS_BOOT_SHA2) + +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 */ + char *out /* output buffer, at least "t" bytes */ +) +{ + sha256_ctx ictx, octx; + char isha[SHA256_DIGESTSIZE], osha[SHA256_DIGESTSIZE]; + char key[SHA256_DIGESTSIZE]; + char buf[SHA256_BLOCKSIZE]; + int i; + + /* 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 + } + + /**** Inner Digest ****/ + + sha256_begin (&ictx); + + /* 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_end ((unsigned char *) isha, &ictx); + + /**** Outer Digest ****/ + + sha256_begin (&octx); + + 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_end ((unsigned char *) osha, &octx); + + /* truncate and print the results */ + hmac_truncate (osha, out, SHA256_DIGESTSIZE); + + /* Prevent leaks */ + burn (&ictx, sizeof(ictx)); + burn (&octx, sizeof(octx)); + burn (isha, sizeof(isha)); + burn (osha, sizeof(osha)); + burn (buf, sizeof(buf)); + burn (key, sizeof(key)); +} + + +void derive_u_sha256 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b) +{ + char j[SHA256_DIGESTSIZE], k[SHA256_DIGESTSIZE]; + char init[128]; + char counter[4]; + uint32 c; + int i; + + if (iterations == 2000) + c = 200000; + else + c = 500000; + + /* 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); + + /* remaining iterations */ + while (c > 1) + { + hmac_sha256 (pwd, pwd_len, j, SHA256_DIGESTSIZE, k); + 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]; + int b, l, r; + + if (dklen % SHA256_DIGESTSIZE) + { + l = 1 + dklen / SHA256_DIGESTSIZE; + } + else + { + l = dklen / SHA256_DIGESTSIZE; + } + + 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); + dk += SHA256_DIGESTSIZE; + } + + /* last block */ + derive_u_sha256 (pwd, pwd_len, salt, salt_len, iterations, u, b); + memcpy (dk, u, r); + + + /* Prevent possible leaks. */ + burn (u, sizeof(u)); +} + +#endif + #ifndef TC_WINDOWS_BOOT void hmac_sha512 @@ -176,6 +327,8 @@ void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int it #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) { RMD160_CTX context; @@ -319,6 +472,7 @@ void derive_key_ripemd160 (BOOL bNotTest, char *pwd, int pwd_len, char *salt, in /* Prevent possible leaks. */ burn (u, sizeof(u)); } +#endif // TC_WINDOWS_BOOT #ifndef TC_WINDOWS_BOOT @@ -468,6 +622,9 @@ char *get_pkcs5_prf_name (int pkcs5_prf_id) case SHA512: return "HMAC-SHA-512"; + case SHA256: + return "HMAC-SHA-256"; + case RIPEMD160: return "HMAC-RIPEMD-160"; @@ -488,7 +645,7 @@ int get_pkcs5_iteration_count (int pkcs5_prf_id, BOOL bBoot) { case RIPEMD160: - return bBoot? 16384 : 32767; /* we multiply this number by 10 inside derive_u_ripemd160 */ + return bBoot? 16384 : 32767; /* it will be changed to 327661 and 655331 respectively inside derive_u_ripemd160 */ #ifndef TC_WINDOWS_BOOT @@ -499,6 +656,9 @@ int get_pkcs5_iteration_count (int pkcs5_prf_id, BOOL bBoot) return 500000; #endif + case SHA256: + return bBoot? 2000 : 5000; /* it will be changed to 200000 and 500000 respectively inside derive_u_sha256 */ + default: TC_THROW_FATAL_EXCEPTION; // Unknown/wrong ID } diff --git a/src/Common/Pkcs5.h b/src/Common/Pkcs5.h index 148a3e2d..aff36cc4 100644 --- a/src/Common/Pkcs5.h +++ b/src/Common/Pkcs5.h @@ -18,6 +18,9 @@ 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); +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); diff --git a/src/Common/Volumes.c b/src/Common/Volumes.c index 9a0d3efc..2b7b01ab 100644 --- a/src/Common/Volumes.c +++ b/src/Common/Volumes.c @@ -316,6 +316,11 @@ KeyReady: ; PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); break; + case SHA256: + derive_key_sha256 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + default: // Unknown/wrong ID TC_THROW_FATAL_EXCEPTION; @@ -561,8 +566,13 @@ int ReadVolumeHeader (BOOL bBoot, char *header, Password *password, PCRYPTO_INFO cryptoInfo = *retInfo = crypto_open (); // PKCS5 PRF +#ifdef TC_WINDOWS_BOOT_SHA2 + derive_key_sha256 (password->Text, (int) password->Length, header + HEADER_SALT_OFFSET, + PKCS5_SALT_SIZE, bBoot ? 2000 : 5000, dk, sizeof (dk)); +#else derive_key_ripemd160 (TRUE, password->Text, (int) password->Length, header + HEADER_SALT_OFFSET, PKCS5_SALT_SIZE, bBoot ? 16384 : 32767, dk, sizeof (dk)); +#endif // Mode of operation cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID; @@ -606,6 +616,12 @@ int ReadVolumeHeader (BOOL bBoot, char *header, Password *password, PCRYPTO_INFO // Flags cryptoInfo->HeaderFlags = GetHeaderField32 (header, TC_HEADER_OFFSET_FLAGS); +#ifdef TC_WINDOWS_BOOT_SHA2 + cryptoInfo->pkcs5 = SHA256; +#else + cryptoInfo->pkcs5 = RIPEMD160; +#endif + memcpy (masterKey, header + HEADER_MASTER_KEYDATA_OFFSET, sizeof (masterKey)); EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); @@ -703,6 +719,9 @@ int CreateVolumeHeaderInMemory (BOOL bBoot, char *header, int ea, int mode, Pass // User selected encryption algorithm cryptoInfo->ea = ea; + // User selected PRF + cryptoInfo->pkcs5 = pkcs5_prf; + // Mode of operation cryptoInfo->mode = mode; @@ -718,6 +737,11 @@ int CreateVolumeHeaderInMemory (BOOL bBoot, char *header, int ea, int mode, Pass PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); break; + case SHA256: + derive_key_sha256 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + case RIPEMD160: derive_key_ripemd160 (TRUE, keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); -- cgit v1.2.3