From 067c5e2f8fbf28170f2ba80a6a694a20fdf7615b Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Sat, 11 Mar 2023 15:57:09 +0100 Subject: [PATCH] add possibility to use different hash algorithms in RSAES-OAEP The hash algorithms used in the MGF and to create the hash of the Label must not forcibly be the same. This change allows to use different algorithms. Unfortunately this breaks API if you use `rsa_decrypt_key_ex()`. The `rsa_decrypt_key()` macro is still the same. Signed-off-by: Steffen Jaeckel --- src/headers/tomcrypt_pk.h | 5 +++-- src/headers/tomcrypt_pkcs.h | 3 ++- src/pk/pkcs1/pkcs_1_oaep_decode.c | 28 +++++++++++++++++++--------- src/pk/rsa/rsa_decrypt_key.c | 12 +++++++----- tests/pkcs_1_eme_test.c | 2 +- tests/pkcs_1_test.c | 2 +- tests/rsa_test.c | 2 +- 7 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index 132fc74c3..215f9fe68 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -60,7 +60,7 @@ void rsa_free(rsa_key *key); rsa_encrypt_key_ex(in, inlen, out, outlen, lparam, lparamlen, prng, prng_idx, hash_idx, LTC_PKCS_1_OAEP, key) #define rsa_decrypt_key(in, inlen, out, outlen, lparam, lparamlen, hash_idx, stat, key) \ - rsa_decrypt_key_ex(in, inlen, out, outlen, lparam, lparamlen, hash_idx, LTC_PKCS_1_OAEP, stat, key) + rsa_decrypt_key_ex(in, inlen, out, outlen, lparam, lparamlen, hash_idx, -1, LTC_PKCS_1_OAEP, stat, key) #define rsa_sign_hash(in, inlen, out, outlen, prng, prng_idx, hash_idx, saltlen, key) \ rsa_sign_hash_ex(in, inlen, out, outlen, LTC_PKCS_1_PSS, prng, prng_idx, hash_idx, saltlen, key) @@ -82,7 +82,8 @@ int rsa_encrypt_key_ex(const unsigned char *in, unsigned long inlen, int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, const unsigned char *lparam, unsigned long lparamlen, - int hash_idx, int padding, + int mgf_hash, int lparam_hash, + int padding, int *stat, const rsa_key *key); int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, diff --git a/src/headers/tomcrypt_pkcs.h b/src/headers/tomcrypt_pkcs.h index a0aa89204..8691583ea 100644 --- a/src/headers/tomcrypt_pkcs.h +++ b/src/headers/tomcrypt_pkcs.h @@ -54,7 +54,8 @@ int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, const unsigned char *lparam, unsigned long lparamlen, - unsigned long modulus_bitlen, int hash_idx, + unsigned long modulus_bitlen, + int mgf_hash, int lparam_hash, unsigned char *out, unsigned long *outlen, int *res); diff --git a/src/pk/pkcs1/pkcs_1_oaep_decode.c b/src/pk/pkcs1/pkcs_1_oaep_decode.c index a5d5a9567..f154ad5f6 100644 --- a/src/pk/pkcs1/pkcs_1_oaep_decode.c +++ b/src/pk/pkcs1/pkcs_1_oaep_decode.c @@ -16,7 +16,8 @@ @param lparam The session or system data (can be NULL) @param lparamlen The length of the lparam @param modulus_bitlen The bit length of the RSA modulus - @param hash_idx The index of the hash desired + @param mgf_hash The hash algorithm used for the MGF + @param lparam_hash The hash algorithm used when hashing the lparam (can be -1) @param out [out] Destination of decoding @param outlen [in/out] The max size and resulting size of the decoding @param res [out] Result of decoding, 1==valid, 0==invalid @@ -24,13 +25,14 @@ */ int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, const unsigned char *lparam, unsigned long lparamlen, - unsigned long modulus_bitlen, int hash_idx, + unsigned long modulus_bitlen, + int mgf_hash, int lparam_hash, unsigned char *out, unsigned long *outlen, int *res) { unsigned char *DB, *seed, *mask; unsigned long hLen, x, y, modulus_len; - int err, ret; + int err, ret, lparam_hash_; LTC_ARGCHK(msg != NULL); LTC_ARGCHK(out != NULL); @@ -41,10 +43,18 @@ int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, *res = 0; /* test valid hash */ - if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { + if ((err = hash_is_valid(mgf_hash)) != CRYPT_OK) { return err; } - hLen = hash_descriptor[hash_idx].hashsize; + if (lparam_hash != -1) { + if ((err = hash_is_valid(lparam_hash)) != CRYPT_OK) { + return err; + } + lparam_hash_ = lparam_hash; + } else { + lparam_hash_ = mgf_hash; + } + hLen = hash_descriptor[mgf_hash].hashsize; modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0); /* test hash/message size */ @@ -94,7 +104,7 @@ int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, x += modulus_len - hLen - 1; /* compute MGF1 of maskedDB (hLen) */ - if ((err = pkcs_1_mgf1(hash_idx, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) { + if ((err = pkcs_1_mgf1(mgf_hash, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) { goto LBL_ERR; } @@ -104,7 +114,7 @@ int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, } /* compute MGF1 of seed (k - hlen - 1) */ - if ((err = pkcs_1_mgf1(hash_idx, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { + if ((err = pkcs_1_mgf1(mgf_hash, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { goto LBL_ERR; } @@ -118,12 +128,12 @@ int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, /* compute lhash and store it in seed [reuse temps!] */ x = modulus_len; if (lparam != NULL) { - if ((err = hash_memory(hash_idx, lparam, lparamlen, seed, &x)) != CRYPT_OK) { + if ((err = hash_memory(lparam_hash_, lparam, lparamlen, seed, &x)) != CRYPT_OK) { goto LBL_ERR; } } else { /* can't pass hash_memory a NULL so use DB with zero length */ - if ((err = hash_memory(hash_idx, DB, 0, seed, &x)) != CRYPT_OK) { + if ((err = hash_memory(lparam_hash_, DB, 0, seed, &x)) != CRYPT_OK) { goto LBL_ERR; } } diff --git a/src/pk/rsa/rsa_decrypt_key.c b/src/pk/rsa/rsa_decrypt_key.c index 34a11f918..12ec47aeb 100644 --- a/src/pk/rsa/rsa_decrypt_key.c +++ b/src/pk/rsa/rsa_decrypt_key.c @@ -17,7 +17,8 @@ @param outlen [in/out] The max size and resulting size of the plaintext (octets) @param lparam The system "lparam" value @param lparamlen The length of the lparam value (octets) - @param hash_idx The index of the hash desired + @param mgf_hash The hash algorithm used for the MGF + @param lparam_hash The hash algorithm used when hashing the lparam (can be -1) @param padding Type of padding (LTC_PKCS_1_OAEP or LTC_PKCS_1_V1_5) @param stat [out] Result of the decryption, 1==valid, 0==invalid @param key The corresponding private RSA key @@ -26,7 +27,8 @@ int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, const unsigned char *lparam, unsigned long lparamlen, - int hash_idx, int padding, + int mgf_hash, int lparam_hash, + int padding, int *stat, const rsa_key *key) { unsigned long modulus_bitlen, modulus_bytelen, x; @@ -50,7 +52,7 @@ int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen if (padding == LTC_PKCS_1_OAEP) { /* valid hash ? */ - if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { + if ((err = hash_is_valid(mgf_hash)) != CRYPT_OK) { return err; } } @@ -79,8 +81,8 @@ int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen if (padding == LTC_PKCS_1_OAEP) { /* now OAEP decode the packet */ - err = pkcs_1_oaep_decode(tmp, x, lparam, lparamlen, modulus_bitlen, hash_idx, - out, outlen, stat); + err = pkcs_1_oaep_decode(tmp, x, lparam, lparamlen, modulus_bitlen, mgf_hash, + lparam_hash, out, outlen, stat); } else { /* now PKCS #1 v1.5 depad the packet */ err = pkcs_1_v1_5_decode(tmp, x, LTC_PKCS_1_EME, modulus_bitlen, out, outlen, stat); diff --git a/tests/pkcs_1_eme_test.c b/tests/pkcs_1_eme_test.c index 217930d5f..37be79287 100644 --- a/tests/pkcs_1_eme_test.c +++ b/tests/pkcs_1_eme_test.c @@ -45,7 +45,7 @@ int pkcs_1_eme_test(void) prng_descriptor[prng_idx].add_entropy(s->o2, s->o2_l, (void*)no_prng_desc); DOX(rsa_encrypt_key_ex(s->o1, s->o1_l, obuf, &obuflen, NULL, 0, (void*)no_prng_desc, prng_idx, -1, LTC_PKCS_1_V1_5, key), s->name); COMPARE_TESTVECTOR(obuf, obuflen, s->o3, s->o3_l,s->name, j); - DOX(rsa_decrypt_key_ex(obuf, obuflen, buf, &buflen, NULL, 0, -1, LTC_PKCS_1_V1_5, &stat, key), s->name); + DOX(rsa_decrypt_key_ex(obuf, obuflen, buf, &buflen, NULL, 0, -1, -1, LTC_PKCS_1_V1_5, &stat, key), s->name); DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, s->name); } /* for */ diff --git a/tests/pkcs_1_test.c b/tests/pkcs_1_test.c index 9bc9a2777..0d1251c8e 100644 --- a/tests/pkcs_1_test.c +++ b/tests/pkcs_1_test.c @@ -50,7 +50,7 @@ int pkcs_1_test(void) /* decode it */ l2 = sizeof(buf[2]); - DO(pkcs_1_oaep_decode(buf[1], l1, lparam, lparamlen, modlen, hash_idx, buf[2], &l2, &res1)); + DO(pkcs_1_oaep_decode(buf[1], l1, lparam, lparamlen, modlen, hash_idx, -1, buf[2], &l2, &res1)); if (res1 != 1 || l2 != l3 || memcmp(buf[2], buf[0], l3) != 0) { fprintf(stderr, "Outsize == %lu, should have been %lu, res1 = %d, lparamlen = %lu, msg contents follow.\n", l2, l3, res1, lparamlen); diff --git a/tests/rsa_test.c b/tests/rsa_test.c index 0bffaa2f1..977f33a01 100644 --- a/tests/rsa_test.c +++ b/tests/rsa_test.c @@ -550,7 +550,7 @@ print_hex("q", tmp, len); DO(rsa_encrypt_key_ex(in, rsa_msgsize, out, &len, NULL, 0, &yarrow_prng, prng_idx, 0, LTC_PKCS_1_V1_5, &key)); len2 = rsa_msgsize; - DO(rsa_decrypt_key_ex(out, len, tmp, &len2, NULL, 0, 0, LTC_PKCS_1_V1_5, &stat, &key)); + DO(rsa_decrypt_key_ex(out, len, tmp, &len2, NULL, 0, 0, -1, LTC_PKCS_1_V1_5, &stat, &key)); ENSURE(stat == 1); DO(do_compare_testvector(tmp, len2, in, rsa_msgsize, "rsa_decrypt_key_ex", rsa_msgsize)); }