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/Common/Pkcs5.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 161 insertions(+), 1 deletion(-) (limited to 'src/Common/Pkcs5.c') 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 } -- cgit v1.2.3