From e4d5e4933a7ce3776a0a034bb8e08b1ae8aadbef Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Tue, 26 Aug 2025 18:14:42 +0200 Subject: [PATCH 1/4] Add support for separate MGF1 hashes Update PKCS#1-PSS and RSA APIs that allow passing a separate hash index for the MGF1 hash. Signed-off-by: Steffen Jaeckel --- src/headers/tomcrypt_pk.h | 12 +++++---- src/headers/tomcrypt_private.h | 16 ++++++++++++ src/pk/pkcs1/pkcs_1_pss_decode.c | 38 +++++++++++++++++++++++---- src/pk/pkcs1/pkcs_1_pss_encode.c | 44 +++++++++++++++++++++++++++----- src/pk/rsa/rsa_sign_hash.c | 11 ++++---- src/pk/rsa/rsa_verify_hash.c | 7 ++--- tests/pkcs_1_emsa_test.c | 4 +-- tests/rsa_test.c | 20 +++++++-------- 8 files changed, 115 insertions(+), 37 deletions(-) diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index a6b893128..a4569c383 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -103,10 +103,10 @@ void rsa_free(rsa_key *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) + rsa_sign_hash_ex(in, inlen, out, outlen, LTC_PKCS_1_PSS, prng, prng_idx, hash_idx, hash_idx, saltlen, key) #define rsa_verify_hash(sig, siglen, hash, hashlen, hash_idx, saltlen, stat, key) \ - rsa_verify_hash_ex(sig, siglen, hash, hashlen, LTC_PKCS_1_PSS, hash_idx, saltlen, stat, key) + rsa_verify_hash_ex(sig, siglen, hash, hashlen, LTC_PKCS_1_PSS, hash_idx, hash_idx, saltlen, stat, key) #define rsa_sign_saltlen_get_max(hash_idx, key) \ rsa_sign_saltlen_get_max_ex(LTC_PKCS_1_PSS, hash_idx, key) @@ -130,14 +130,16 @@ int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, int padding, - prng_state *prng, int prng_idx, - int hash_idx, unsigned long saltlen, + prng_state *prng, int prng_idx, + int hash_idx, int mgf_hash_idx, + unsigned long saltlen, const rsa_key *key); int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen, const unsigned char *hash, unsigned long hashlen, int padding, - int hash_idx, unsigned long saltlen, + int hash_idx, int mgf_hash_idx, + unsigned long saltlen, int *stat, const rsa_key *key); int rsa_sign_saltlen_get_max_ex(int padding, int hash_idx, const rsa_key *key); diff --git a/src/headers/tomcrypt_private.h b/src/headers/tomcrypt_private.h index 16afb8b9e..89910baa4 100644 --- a/src/headers/tomcrypt_private.h +++ b/src/headers/tomcrypt_private.h @@ -750,6 +750,22 @@ int pk_oid_cmp_with_asn1(const char *o1, const ltc_asn1_list *o2); /* tomcrypt_pkcs.h */ +#ifdef LTC_PKCS_1 + +int pkcs_1_pss_encode_mgf1(const unsigned char *msghash, unsigned long msghashlen, + unsigned long saltlen, + prng_state *prng, int prng_idx, + int hash_idx, int mgf_hash_idx, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen); +int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashlen, + const unsigned char *sig, unsigned long siglen, + unsigned long saltlen, + int hash_idx, int mgf_hash_idx, + unsigned long modulus_bitlen, int *res); + +#endif /* LTC_PKCS_1 */ + #ifdef LTC_PKCS_8 /* Public-Key Cryptography Standards (PKCS) #8: diff --git a/src/pk/pkcs1/pkcs_1_pss_decode.c b/src/pk/pkcs1/pkcs_1_pss_decode.c index fad401d1b..fc258ea4f 100644 --- a/src/pk/pkcs1/pkcs_1_pss_decode.c +++ b/src/pk/pkcs1/pkcs_1_pss_decode.c @@ -17,14 +17,16 @@ @param siglen The length of the signature data (octets) @param saltlen The length of the salt used (octets) @param hash_idx The index of the hash desired + @param mgf_hash_idx The index of the hash desired for MGF1 @param modulus_bitlen The bit length of the RSA modulus @param res [out] The result of the comparison, 1==valid, 0==invalid @return CRYPT_OK if successful (even if the comparison failed) */ -int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, - const unsigned char *sig, unsigned long siglen, - unsigned long saltlen, int hash_idx, - unsigned long modulus_bitlen, int *res) +int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashlen, + const unsigned char *sig, unsigned long siglen, + unsigned long saltlen, + int hash_idx, int mgf_hash_idx, + unsigned long modulus_bitlen, int *res) { unsigned char *DB, *mask, *salt, *hash; unsigned long x, y, hLen, modulus_len; @@ -41,6 +43,11 @@ int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { return err; } + if (hash_idx != mgf_hash_idx) { + if ((err = hash_is_valid(mgf_hash_idx)) != CRYPT_OK) { + return err; + } + } hLen = hash_descriptor[hash_idx].hashsize; modulus_bitlen--; @@ -95,7 +102,7 @@ int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, } /* generate mask of length modulus_len - hLen - 1 from hash */ - if ((err = pkcs_1_mgf1(hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { + if ((err = pkcs_1_mgf1(mgf_hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { goto LBL_ERR; } @@ -163,4 +170,25 @@ int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, return err; } + +/** + PKCS #1 v2.00 PSS decode + @param msghash The hash to verify + @param msghashlen The length of the hash (octets) + @param sig The signature data (encoded data) + @param siglen The length of the signature data (octets) + @param saltlen The length of the salt used (octets) + @param hash_idx The index of the hash desired + @param modulus_bitlen The bit length of the RSA modulus + @param res [out] The result of the comparison, 1==valid, 0==invalid + @return CRYPT_OK if successful (even if the comparison failed) +*/ +int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, + const unsigned char *sig, unsigned long siglen, + unsigned long saltlen, int hash_idx, + unsigned long modulus_bitlen, int *res) +{ + return pkcs_1_pss_decode_mgf1(msghash, msghashlen, sig, siglen, saltlen, hash_idx, hash_idx, modulus_bitlen, res); +} + #endif /* LTC_PKCS_1 */ diff --git a/src/pk/pkcs1/pkcs_1_pss_encode.c b/src/pk/pkcs1/pkcs_1_pss_encode.c index 2a4e3728a..01d9636f9 100644 --- a/src/pk/pkcs1/pkcs_1_pss_encode.c +++ b/src/pk/pkcs1/pkcs_1_pss_encode.c @@ -17,16 +17,18 @@ @param prng An active PRNG context @param prng_idx The index of the PRNG desired @param hash_idx The index of the hash desired + @param mgf_hash_idx The index of the hash desired for MGF1 @param modulus_bitlen The bit length of the RSA modulus @param out [out] The destination of the encoding @param outlen [in/out] The max size and resulting size of the encoded data @return CRYPT_OK if successful */ -int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, - unsigned long saltlen, prng_state *prng, - int prng_idx, int hash_idx, - unsigned long modulus_bitlen, - unsigned char *out, unsigned long *outlen) +int pkcs_1_pss_encode_mgf1(const unsigned char *msghash, unsigned long msghashlen, + unsigned long saltlen, + prng_state *prng, int prng_idx, + int hash_idx, int mgf_hash_idx, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen) { unsigned char *DB, *mask, *salt, *hash; unsigned long x, y, hLen, modulus_len; @@ -37,10 +39,15 @@ int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); - /* ensure hash and PRNG are valid */ + /* ensure hashes and PRNG are valid */ if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { return err; } + if (hash_idx != mgf_hash_idx) { + if ((err = hash_is_valid(mgf_hash_idx)) != CRYPT_OK) { + return err; + } + } if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) { return err; } @@ -111,7 +118,7 @@ int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, /* x += saltlen; */ /* generate mask of length modulus_len - hLen - 1 from hash */ - if ((err = pkcs_1_mgf1(hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { + if ((err = pkcs_1_mgf1(mgf_hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { goto LBL_ERR; } @@ -161,4 +168,27 @@ int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, return err; } + +/** + PKCS #1 v2.00 Signature Encoding using MGF1 and both hashes are the same + @param msghash The hash to encode + @param msghashlen The length of the hash (octets) + @param saltlen The length of the salt desired (octets) + @param prng An active PRNG context + @param prng_idx The index of the PRNG desired + @param hash_idx The index of the hash desired + @param modulus_bitlen The bit length of the RSA modulus + @param out [out] The destination of the encoding + @param outlen [in/out] The max size and resulting size of the encoded data + @return CRYPT_OK if successful +*/ +int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, + unsigned long saltlen, prng_state *prng, + int prng_idx, int hash_idx, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen) +{ + return pkcs_1_pss_encode_mgf1(msghash, msghashlen, saltlen, prng, prng_idx, hash_idx, hash_idx, modulus_bitlen, out, outlen); +} + #endif /* LTC_PKCS_1 */ diff --git a/src/pk/rsa/rsa_sign_hash.c b/src/pk/rsa/rsa_sign_hash.c index bc5e0a89f..a7a18036d 100644 --- a/src/pk/rsa/rsa_sign_hash.c +++ b/src/pk/rsa/rsa_sign_hash.c @@ -26,9 +26,10 @@ int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, int padding, - prng_state *prng, int prng_idx, - int hash_idx, unsigned long saltlen, - const rsa_key *key) + prng_state *prng, int prng_idx, + int hash_idx, int mgf_hash_idx, + unsigned long saltlen, + const rsa_key *key) { unsigned long modulus_bitlen, modulus_bytelen, x, y; int err; @@ -72,8 +73,8 @@ int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, if (padding == LTC_PKCS_1_PSS) { /* PSS pad the key */ x = *outlen; - if ((err = pkcs_1_pss_encode(in, inlen, saltlen, prng, prng_idx, - hash_idx, modulus_bitlen, out, &x)) != CRYPT_OK) { + if ((err = pkcs_1_pss_encode_mgf1(in, inlen, saltlen, prng, prng_idx, + hash_idx, mgf_hash_idx, modulus_bitlen, out, &x)) != CRYPT_OK) { return err; } } else { diff --git a/src/pk/rsa/rsa_verify_hash.c b/src/pk/rsa/rsa_verify_hash.c index 9ca1641a6..7303a7b26 100644 --- a/src/pk/rsa/rsa_verify_hash.c +++ b/src/pk/rsa/rsa_verify_hash.c @@ -25,7 +25,8 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen, const unsigned char *hash, unsigned long hashlen, int padding, - int hash_idx, unsigned long saltlen, + int hash_idx, int mgf_hash_idx, + unsigned long saltlen, int *stat, const rsa_key *key) { unsigned long modulus_bitlen, modulus_bytelen, x; @@ -87,10 +88,10 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long sigle /* PSS decode and verify it */ if(modulus_bitlen%8 == 1){ - err = pkcs_1_pss_decode(hash, hashlen, tmpbuf+1, x-1, saltlen, hash_idx, modulus_bitlen, stat); + err = pkcs_1_pss_decode_mgf1(hash, hashlen, tmpbuf+1, x-1, saltlen, hash_idx, mgf_hash_idx, modulus_bitlen, stat); } else{ - err = pkcs_1_pss_decode(hash, hashlen, tmpbuf, x, saltlen, hash_idx, modulus_bitlen, stat); + err = pkcs_1_pss_decode_mgf1(hash, hashlen, tmpbuf, x, saltlen, hash_idx, mgf_hash_idx, modulus_bitlen, stat); } } else { diff --git a/tests/pkcs_1_emsa_test.c b/tests/pkcs_1_emsa_test.c index 43fb112ae..327f2b5df 100644 --- a/tests/pkcs_1_emsa_test.c +++ b/tests/pkcs_1_emsa_test.c @@ -39,9 +39,9 @@ int pkcs_1_emsa_test(void) unsigned long buflen = sizeof(buf), obuflen = sizeof(obuf); int stat; DOX(hash_memory(hash_idx, s->o1, s->o1_l, buf, &buflen), s->name); - DOX(rsa_sign_hash_ex(buf, buflen, obuf, &obuflen, LTC_PKCS_1_V1_5, NULL, -1, hash_idx, 0, key), s->name); + DOX(rsa_sign_hash_ex(buf, buflen, obuf, &obuflen, LTC_PKCS_1_V1_5, NULL, -1, hash_idx, -1, 0, key), s->name); COMPARE_TESTVECTOR(obuf, obuflen, s->o2, s->o2_l,s->name, j); - DOX(rsa_verify_hash_ex(obuf, obuflen, buf, buflen, LTC_PKCS_1_V1_5, hash_idx, 0, &stat, key), s->name); + DOX(rsa_verify_hash_ex(obuf, obuflen, buf, buflen, LTC_PKCS_1_V1_5, hash_idx, -1, 0, &stat, key), s->name); DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, s->name); } /* for */ diff --git a/tests/rsa_test.c b/tests/rsa_test.c index c1cfbb2b0..acc82d5b8 100644 --- a/tests/rsa_test.c +++ b/tests/rsa_test.c @@ -191,13 +191,13 @@ static int rsa_compat_test(void) /* sign-verify a message with PKCS #1 v1.5 no ASN.1 */ len = sizeof(buf); - DO(rsa_sign_hash_ex((unsigned char*)"test", 4, buf, &len, LTC_PKCS_1_V1_5_NA1, NULL, 0, 0, 0, &key)); + DO(rsa_sign_hash_ex((unsigned char*)"test", 4, buf, &len, LTC_PKCS_1_V1_5_NA1, NULL, 0, 0, 0, 0, &key)); if (len != sizeof(openssl_rsautl_pkcs) || memcmp(buf, openssl_rsautl_pkcs, len)) { fprintf(stderr, "RSA rsa_sign_hash_ex + LTC_PKCS_1_V1_5_NA1 failed\n"); return 1; } stat = 0; - DO(rsa_verify_hash_ex(openssl_rsautl_pkcs, sizeof(openssl_rsautl_pkcs), (unsigned char*)"test", 4, LTC_PKCS_1_V1_5_NA1, 0, 0, &stat, &pubkey)); + DO(rsa_verify_hash_ex(openssl_rsautl_pkcs, sizeof(openssl_rsautl_pkcs), (unsigned char*)"test", 4, LTC_PKCS_1_V1_5_NA1, 0, 0, 0, &stat, &pubkey)); if (stat != 1) { fprintf(stderr, "RSA rsa_verify_hash_ex + LTC_PKCS_1_V1_5_NA1 failed\n"); return 1; @@ -331,9 +331,9 @@ static int s_rsa_cryptx_issue_69(void) l1 = sizeof(buf1); DO(radix_to_bin(sig1, 16, buf0, &l0)); DO(radix_to_bin(hash, 16, buf1, &l1)); - SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, &stat, &key)); + SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, 0, &stat, &key)); DO(radix_to_bin(sig2, 16, buf0, &l0)); - SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, &stat, &key)); + SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, 0, &stat, &key)); rsa_free(&key); return CRYPT_OK; } @@ -684,11 +684,11 @@ print_hex("q", tmp, len); /* sign a message with PKCS #1 v1.5 */ len = sizeof(out); - DO(rsa_sign_hash_ex(in, 20, out, &len, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 8, &privKey)); - DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 8, &stat, &pubKey)); + DO(rsa_sign_hash_ex(in, 20, out, &len, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 0, 8, &privKey)); + DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 0, 8, &stat, &pubKey)); /* change a byte */ in[0] ^= 1; - DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 8, &stat2, &pubKey)); + DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 0, 8, &stat2, &pubKey)); if (!(stat == 1 && stat2 == 0)) { fprintf(stderr, "rsa_verify_hash_ex failed, %d, %d", stat, stat2); @@ -721,9 +721,9 @@ print_hex("q", tmp, len); len = sizeof(in); len2 = sizeof(out); /* (1) */ - DO(rsa_sign_hash_ex(p, 20, p2, &len2, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 8, &privKey)); + DO(rsa_sign_hash_ex(p, 20, p2, &len2, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 0, 8, &privKey)); /* (2) */ - DOX(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, &stat, &pubKey), "should succeed"); + DOX(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, 0, -1, &stat, &pubKey), "should succeed"); DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, "should succeed"); len3 = sizeof(tmp); /* (3) */ @@ -757,7 +757,7 @@ print_hex("q", tmp, len); len3 = sizeof(tmp); /* (6) */ - SHOULD_FAIL(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, &stat, &pubKey)); + SHOULD_FAIL(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, -1, &stat, &pubKey)); DOX(stat == 0?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, "should fail"); } rsa_free(&key); From e25a1438a8fd99c47c4f81b2d8ef91cd7addef25 Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Tue, 26 Aug 2025 18:40:23 +0200 Subject: [PATCH 2/4] Add support for RSA-PSS keys Signed-off-by: Steffen Jaeckel --- src/headers/tomcrypt_custom.h | 4 + src/headers/tomcrypt_pk.h | 16 +- src/headers/tomcrypt_private.h | 17 +- src/misc/crypt/crypt.c | 1 + src/pk/asn1/oid/pk_get.c | 46 +++-- .../x509_decode_public_key_from_certificate.c | 75 +++++--- src/pk/asn1/x509/x509_decode_spki.c | 62 ++++--- src/pk/asn1/x509/x509_get_pka.c | 4 +- src/pk/asn1/x509/x509_import_spki.c | 4 +- src/pk/pka_key.c | 1 + src/pk/rsa/rsa_decrypt_key.c | 12 +- src/pk/rsa/rsa_encrypt_key.c | 12 +- src/pk/rsa/rsa_import.c | 66 +++---- src/pk/rsa/rsa_import_x509.c | 161 +++++++++++++++++- src/pk/rsa/rsa_key.c | 85 +++++++++ src/pk/rsa/rsa_sign_hash.c | 13 +- src/pk/rsa/rsa_verify_hash.c | 14 +- 17 files changed, 441 insertions(+), 152 deletions(-) diff --git a/src/headers/tomcrypt_custom.h b/src/headers/tomcrypt_custom.h index 3fc51c750..0afd6884a 100644 --- a/src/headers/tomcrypt_custom.h +++ b/src/headers/tomcrypt_custom.h @@ -605,6 +605,10 @@ /* Maximum recursion limit when processing nested ASN.1 types. */ #define LTC_DER_MAX_RECURSION 30 #endif + #ifndef LTC_DER_OID_DEFAULT_NODES + /* Default number of nodes when decoding an OID. */ + #define LTC_DER_OID_DEFAULT_NODES 12 + #endif #endif #if defined(LTC_MECC) || defined(LTC_MRSA) || defined(LTC_MDSA) || defined(LTC_SSH) diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index a4569c383..d517b2fe4 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -40,6 +40,7 @@ enum ltc_pka_id { LTC_PKA_X25519, LTC_PKA_ED25519, LTC_PKA_DH, + LTC_PKA_RSA_PSS, LTC_PKA_NUM }; @@ -62,7 +63,18 @@ int rand_prime(void *N, long len, prng_state *prng, int wprng); /* ---- RSA ---- */ #ifdef LTC_MRSA -/** RSA PKCS style key */ +typedef struct ltc_rsa_parameters { + /** PSS/OAEP or PKCS #1 v1.5 style + * 0 -> PKCS #1 v1.5, 1 -> PSS/OAEP */ + int pss_oaep; + /** saltLength is only defined for PSS + * If saltLength == 0 -> OAEP, else -> PSS */ + unsigned long saltlen; + /** hash and MGF hash algorithms */ + const char *hash_alg, *mgf1_hash_alg; +} ltc_rsa_parameters; + +/** RSA key */ typedef struct Rsa_key { /** Type of key, PK_PRIVATE or PK_PUBLIC */ int type; @@ -82,6 +94,8 @@ typedef struct Rsa_key { void *dP; /** The d mod (q - 1) CRT param */ void *dQ; + /** Further parameters of the RSA key */ + ltc_rsa_parameters params; } rsa_key; int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key); diff --git a/src/headers/tomcrypt_private.h b/src/headers/tomcrypt_private.h index 89910baa4..7797af0e9 100644 --- a/src/headers/tomcrypt_private.h +++ b/src/headers/tomcrypt_private.h @@ -60,6 +60,9 @@ enum ltc_oid_id { LTC_OID_X25519, LTC_OID_ED25519, LTC_OID_DH, + LTC_OID_RSA_OAEP, + LTC_OID_RSA_MGF1, + LTC_OID_RSA_PSS, LTC_OID_NUM }; @@ -443,8 +446,14 @@ int pk_oid_cmp_with_ulong(const char *o1, const unsigned long *o2, unsigned long /* ---- DH Routines ---- */ #ifdef LTC_MRSA +typedef enum ltc_rsa_op { + LTC_RSA_CRYPT, + LTC_RSA_SIGN +} ltc_rsa_op; int rsa_init(rsa_key *key); void rsa_shrink_key(rsa_key *key); +int rsa_key_valid_op(const rsa_key *key, ltc_rsa_op op, int padding, int hash_idx); +int rsa_params_equal(const ltc_rsa_parameters *a, const ltc_rsa_parameters *b); int rsa_make_key_bn_e(prng_state *prng, int wprng, int size, void *e, rsa_key *key); /* used by op-tee */ int rsa_import_pkcs1(const unsigned char *in, unsigned long inlen, rsa_key *key); @@ -730,7 +739,11 @@ int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned lo enum ltc_oid_id algorithm, ltc_asn1_type param_type, ltc_asn1_list* parameters, unsigned long *parameters_len, public_key_decode_cb callback, void *ctx); -int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, ltc_asn1_list **spki); +int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, const ltc_asn1_list **spki); +int x509_process_public_key_from_spki(const unsigned char *in, unsigned long inlen, + enum ltc_oid_id algorithm, ltc_asn1_type param_type, + ltc_asn1_list* parameters, unsigned long *parameters_len, + public_key_decode_cb callback, void *ctx); /* SUBJECT PUBLIC KEY INFO */ int x509_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen, @@ -741,7 +754,7 @@ int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long i enum ltc_oid_id algorithm, void *public_key, unsigned long *public_key_len, ltc_asn1_type parameters_type, ltc_asn1_list* parameters, unsigned long *parameters_len); -int x509_get_pka(ltc_asn1_list *pub, enum ltc_pka_id *pka); +int x509_get_pka(const ltc_asn1_list *pub, enum ltc_pka_id *pka); int x509_import_spki(const unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, ltc_asn1_list **root); int pk_oid_cmp_with_asn1(const char *o1, const ltc_asn1_list *o2); diff --git a/src/misc/crypt/crypt.c b/src/misc/crypt/crypt.c index 97065a3fc..dba6479c3 100644 --- a/src/misc/crypt/crypt.c +++ b/src/misc/crypt/crypt.c @@ -458,6 +458,7 @@ const char *crypt_build_settings = #if defined(LTC_DER) " DER " " " NAME_VALUE(LTC_DER_MAX_RECURSION) " " + " " NAME_VALUE(LTC_DER_OID_DEFAULT_NODES) " " #endif #if defined(LTC_PKCS_1) " PKCS#1 " diff --git a/src/pk/asn1/oid/pk_get.c b/src/pk/asn1/oid/pk_get.c index 1fd5872e2..81a1b2f3e 100644 --- a/src/pk/asn1/oid/pk_get.c +++ b/src/pk/asn1/oid/pk_get.c @@ -7,18 +7,22 @@ typedef struct { enum ltc_oid_id id; enum ltc_pka_id pka; - const char* oid; + const char *hash; + const char *oid; } oid_table_entry; static const oid_table_entry pka_oids[] = { - { LTC_OID_UNDEF, LTC_PKA_UNDEF, NULL }, - { LTC_OID_RSA, LTC_PKA_RSA, "1.2.840.113549.1.1.1" }, - { LTC_OID_DSA, LTC_PKA_DSA, "1.2.840.10040.4.1" }, - { LTC_OID_EC, LTC_PKA_EC, "1.2.840.10045.2.1" }, - { LTC_OID_EC_PRIMEF, LTC_PKA_EC, "1.2.840.10045.1.1" }, - { LTC_OID_X25519, LTC_PKA_X25519, "1.3.101.110" }, - { LTC_OID_ED25519, LTC_PKA_ED25519, "1.3.101.112" }, - { LTC_OID_DH, LTC_PKA_DH, "1.2.840.113549.1.3.1" }, + { LTC_OID_UNDEF, LTC_PKA_UNDEF, NULL, NULL }, + { LTC_OID_RSA, LTC_PKA_RSA, NULL, "1.2.840.113549.1.1.1" }, + { LTC_OID_DSA, LTC_PKA_DSA, NULL, "1.2.840.10040.4.1" }, + { LTC_OID_EC, LTC_PKA_EC, NULL, "1.2.840.10045.2.1" }, + { LTC_OID_EC_PRIMEF, LTC_PKA_EC, NULL, "1.2.840.10045.1.1" }, + { LTC_OID_X25519, LTC_PKA_X25519, NULL, "1.3.101.110" }, + { LTC_OID_ED25519, LTC_PKA_ED25519, NULL, "1.3.101.112" }, + { LTC_OID_DH, LTC_PKA_DH, NULL, "1.2.840.113549.1.3.1" }, + { LTC_OID_RSA_OAEP, LTC_PKA_RSA, NULL, "1.2.840.113549.1.1.7" }, + { LTC_OID_RSA_MGF1, LTC_PKA_RSA, NULL, "1.2.840.113549.1.1.8" }, + { LTC_OID_RSA_PSS, LTC_PKA_RSA_PSS, NULL, "1.2.840.113549.1.1.10" }, }; static LTC_INLINE const oid_table_entry* s_get_entry(enum ltc_oid_id id) @@ -43,21 +47,35 @@ int pk_get_oid(enum ltc_oid_id id, const char **st) return CRYPT_INVALID_ARG; } -/* - Returns the PKA ID requested. - @return CRYPT_OK if valid -*/ -int pk_get_pka_id(enum ltc_oid_id id, enum ltc_pka_id *pka) +static LTC_INLINE int s_get_values(enum ltc_oid_id id, enum ltc_pka_id *pka, const char **hash) { const oid_table_entry* e = s_get_entry(id); LTC_ARGCHK(pka != NULL); if (e != NULL) { *pka = e->pka; + if (hash) { + *hash = e->hash; + } else if (e->hash) { + /* If we don't want the hash result, but the entry has a hash, we're most likely + * confused and we prefer to stop processing then, instead of continuing with a + * maybe wrong assumption. + */ + return CRYPT_INVALID_ARG; + } return CRYPT_OK; } return CRYPT_INVALID_ARG; } +/* + Returns the PKA ID requested. + @return CRYPT_OK if valid +*/ +int pk_get_pka_id(enum ltc_oid_id id, enum ltc_pka_id *pka) +{ + return s_get_values(id, pka, NULL); +} + /* Returns the OID ID requested. @return CRYPT_OK if valid diff --git a/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c b/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c index 45a1c6f60..65623a956 100644 --- a/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c +++ b/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c @@ -10,7 +10,7 @@ #ifdef LTC_DER /** - Try to decode the public key from a X.509 certificate + Process the public key from the SubjectPublicKeyInfo of a X.509 certificate @param in The input buffer @param inlen The length of the input buffer @param algorithm One out of the enum #public_key_algorithms @@ -19,53 +19,82 @@ @param parameters_len [in/out] The number of parameters to include @param callback The callback @param ctx The context passed to the callback - @return CRYPT_OK on success, - CRYPT_NOP if no SubjectPublicKeyInfo was found, - another error if decoding or memory allocation failed + @return CRYPT_OK on success */ -int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned long inlen, - enum ltc_oid_id algorithm, ltc_asn1_type param_type, - ltc_asn1_list* parameters, unsigned long *parameters_len, - public_key_decode_cb callback, void *ctx) +int x509_process_public_key_from_spki(const unsigned char *in, unsigned long inlen, + enum ltc_oid_id algorithm, ltc_asn1_type param_type, + ltc_asn1_list* parameters, unsigned long *parameters_len, + public_key_decode_cb callback, void *ctx) { int err; unsigned char *tmpbuf = NULL; unsigned long tmpbuf_len; - ltc_asn1_list *decoded_list = NULL, *spki; - - LTC_ARGCHK(in != NULL); - LTC_ARGCHK(inlen != 0); - LTC_ARGCHK(callback != NULL); - if ((err = x509_decode_spki(in, inlen, &decoded_list, &spki)) != CRYPT_OK) { - return err; - } + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(callback != NULL); if (algorithm == LTC_OID_EC) { - err = callback(spki->data, spki->size, ctx); + err = callback(in, inlen, ctx); } else { tmpbuf_len = inlen; tmpbuf = XCALLOC(1, tmpbuf_len); if (tmpbuf == NULL) { - err = CRYPT_MEM; - goto LBL_OUT; + return CRYPT_MEM; } - err = x509_decode_subject_public_key_info(spki->data, spki->size, + err = x509_decode_subject_public_key_info(in, inlen, algorithm, tmpbuf, &tmpbuf_len, param_type, parameters, parameters_len); if (err == CRYPT_OK) { err = callback(tmpbuf, tmpbuf_len, ctx); - goto LBL_OUT; } } -LBL_OUT: - if (decoded_list) der_free_sequence_flexi(decoded_list); if (tmpbuf != NULL) XFREE(tmpbuf); return err; } +/** + Try to decode the public key from a X.509 certificate + @param in The input buffer + @param inlen The length of the input buffer + @param algorithm One out of the enum #public_key_algorithms + @param param_type The parameters' type out of the enum ltc_asn1_type + @param parameters The parameters to include + @param parameters_len [in/out] The number of parameters to include + @param callback The callback + @param ctx The context passed to the callback + @return CRYPT_OK on success, + CRYPT_NOP if no SubjectPublicKeyInfo was found, + another error if decoding or memory allocation failed +*/ +int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned long inlen, + enum ltc_oid_id algorithm, ltc_asn1_type param_type, + ltc_asn1_list* parameters, unsigned long *parameters_len, + public_key_decode_cb callback, void *ctx) +{ + int err; + ltc_asn1_list *decoded_list; + const ltc_asn1_list *spki; + + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(inlen != 0); + LTC_ARGCHK(callback != NULL); + + if ((err = x509_decode_spki(in, inlen, &decoded_list, &spki)) != CRYPT_OK) { + return err; + } + + err = x509_process_public_key_from_spki(spki->data, spki->size, + algorithm, param_type, + parameters, parameters_len, + callback, ctx); + + if (decoded_list) der_free_sequence_flexi(decoded_list); + + return err; +} + #endif diff --git a/src/pk/asn1/x509/x509_decode_spki.c b/src/pk/asn1/x509/x509_decode_spki.c index 147aaf1c6..144441cd2 100644 --- a/src/pk/asn1/x509/x509_decode_spki.c +++ b/src/pk/asn1/x509/x509_decode_spki.c @@ -26,10 +26,10 @@ @param spki [out] A pointer to the SubjectPublicKeyInfo @return CRYPT_OK on success, CRYPT_NOP if no SubjectPublicKeyInfo was found, another error if decoding failed */ -int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, ltc_asn1_list **spki) +int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, const ltc_asn1_list **spki) { int err; - unsigned long tmp_inlen; + unsigned long tmp_inlen, n, element_is_spki; ltc_asn1_list *decoded_list = NULL, *l; LTC_ARGCHK(in != NULL); @@ -49,29 +49,49 @@ int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list if ((l->type == LTC_ASN1_SEQUENCE) && (l->child != NULL)) { l = l->child; if ((l->type == LTC_ASN1_SEQUENCE) && (l->child != NULL)) { + /* TBSCertificate ::= SEQUENCE { + * version [0] EXPLICIT Version DEFAULT v1, + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version MUST be v2 or v3 + * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version MUST be v2 or v3 + * extensions [3] EXPLICIT Extensions OPTIONAL + * -- If present, version MUST be v3 + * } + */ l = l->child; - /* Move forward in the tree until we find this combination - ... - SEQUENCE - SEQUENCE - OBJECT IDENTIFIER - NULL - BIT STRING + /* `l` points now either to 'version' or 'serialNumber', depending on + * whether 'version' is included or defaults to 'v1'. + * 'version' is represented as a LTC_ASN1_CUSTOM_TYPE + * 'serialNumber' is represented as an LTC_ASN1_INTEGER + * Decide now whether to move 5 or 6 elements forward until + * `l` should point to subjectPublicKeyInfo. */ - do { - /* The additional check for l->data is there to make sure - * we won't try to decode a list that has been 'shrunk' - */ - if ((l->type == LTC_ASN1_SEQUENCE) - && (l->data != NULL) - && LOOKS_LIKE_SPKI(l->child)) { - *out = decoded_list; - *spki = l; - return CRYPT_OK; - } + if (l->type == LTC_ASN1_CUSTOM_TYPE) + element_is_spki = 6; + else + element_is_spki = 5; + for (n = 0; n < element_is_spki && l; ++n) { l = l->next; - } while(l); + } + /* The additional check for l->data is there to make sure + * we won't try to decode a list that has been 'shrunk' + */ + if ((l != NULL) + && (l->type == LTC_ASN1_SEQUENCE) + && (l->data != NULL) + && LOOKS_LIKE_SPKI(l->child)) { + *out = decoded_list; + *spki = l; + return CRYPT_OK; + } } } } diff --git a/src/pk/asn1/x509/x509_get_pka.c b/src/pk/asn1/x509/x509_get_pka.c index 23a12edd7..0236c761e 100644 --- a/src/pk/asn1/x509/x509_get_pka.c +++ b/src/pk/asn1/x509/x509_get_pka.c @@ -9,7 +9,7 @@ #ifdef LTC_DER -int x509_get_pka(ltc_asn1_list *pub, enum ltc_pka_id *pka) +int x509_get_pka(const ltc_asn1_list *pub, enum ltc_pka_id *pka) { der_flexi_check flexi_should[4]; ltc_asn1_list *seqid, *id = NULL; @@ -17,7 +17,7 @@ int x509_get_pka(ltc_asn1_list *pub, enum ltc_pka_id *pka) int err; unsigned long n = 0; LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &seqid); - LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_BIT_STRING, NULL); + LTC_SET_DER_FLEXI_CHECK_OPT(flexi_should, n++, LTC_ASN1_BIT_STRING, NULL); LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL); if ((err = der_flexi_sequence_cmp(pub, flexi_should)) != CRYPT_OK) { return err; diff --git a/src/pk/asn1/x509/x509_import_spki.c b/src/pk/asn1/x509/x509_import_spki.c index 8b360852e..73b4dac73 100644 --- a/src/pk/asn1/x509/x509_import_spki.c +++ b/src/pk/asn1/x509/x509_import_spki.c @@ -14,6 +14,7 @@ typedef int (*import_fn)(const unsigned char *, unsigned long, void*); static const import_fn s_import_x509_fns[LTC_PKA_NUM] = { #ifdef LTC_MRSA [LTC_PKA_RSA] = (import_fn)rsa_import_x509, + [LTC_PKA_RSA_PSS] = (import_fn)rsa_import_x509, #endif #ifdef LTC_MDSA [LTC_PKA_DSA] = (import_fn)dsa_import, @@ -30,7 +31,8 @@ static const import_fn s_import_x509_fns[LTC_PKA_NUM] = { int x509_import_spki(const unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, ltc_asn1_list **root) { enum ltc_pka_id pka = LTC_PKA_UNDEF; - ltc_asn1_list *d, *spki; + ltc_asn1_list *d; + const ltc_asn1_list *spki; int err; if ((err = x509_decode_spki(asn1_cert, asn1_len, &d, &spki)) != CRYPT_OK) { return err; diff --git a/src/pk/pka_key.c b/src/pk/pka_key.c index d88ee3d30..c682cfcbf 100644 --- a/src/pk/pka_key.c +++ b/src/pk/pka_key.c @@ -30,6 +30,7 @@ void pka_key_free(ltc_pka_key *key) #endif break; case LTC_PKA_RSA: + case LTC_PKA_RSA_PSS: #if defined(LTC_MRSA) rsa_free(&key->u.rsa); #endif diff --git a/src/pk/rsa/rsa_decrypt_key.c b/src/pk/rsa/rsa_decrypt_key.c index d8e7a546f..a36ecb021 100644 --- a/src/pk/rsa/rsa_decrypt_key.c +++ b/src/pk/rsa/rsa_decrypt_key.c @@ -45,16 +45,8 @@ int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen *stat = 0; /* valid padding? */ - if ((padding != LTC_PKCS_1_V1_5) && - (padding != LTC_PKCS_1_OAEP)) { - return CRYPT_PK_INVALID_PADDING; - } - - if (padding == LTC_PKCS_1_OAEP) { - /* valid hash ? */ - if ((err = hash_is_valid(mgf_hash)) != CRYPT_OK) { - return err; - } + if ((err = rsa_key_valid_op(key, LTC_RSA_CRYPT, padding, mgf_hash)) != CRYPT_OK) { + return err; } /* get modulus len in bits */ diff --git a/src/pk/rsa/rsa_encrypt_key.c b/src/pk/rsa/rsa_encrypt_key.c index 17dd1af5d..83fb2c5a6 100644 --- a/src/pk/rsa/rsa_encrypt_key.c +++ b/src/pk/rsa/rsa_encrypt_key.c @@ -41,9 +41,8 @@ int rsa_encrypt_key_ex(const unsigned char *in, unsigned long inlen, LTC_ARGCHK(key != NULL); /* valid padding? */ - if ((padding != LTC_PKCS_1_V1_5) && - (padding != LTC_PKCS_1_OAEP)) { - return CRYPT_PK_INVALID_PADDING; + if ((err = rsa_key_valid_op(key, LTC_RSA_CRYPT, padding, mgf_hash)) != CRYPT_OK) { + return err; } /* valid prng? */ @@ -51,13 +50,6 @@ int rsa_encrypt_key_ex(const unsigned char *in, unsigned long inlen, return err; } - if (padding == LTC_PKCS_1_OAEP) { - /* valid hash? */ - if ((err = hash_is_valid(mgf_hash)) != CRYPT_OK) { - return err; - } - } - /* get modulus len in bits */ modulus_bitlen = ltc_mp_count_bits( (key->N)); diff --git a/src/pk/rsa/rsa_import.c b/src/pk/rsa/rsa_import.c index 1240a77e7..a52ff154f 100644 --- a/src/pk/rsa/rsa_import.c +++ b/src/pk/rsa/rsa_import.c @@ -9,6 +9,18 @@ #ifdef LTC_MRSA +#ifndef S_RSA_DECODE +#define S_RSA_DECODE +static int s_rsa_decode(const unsigned char *in, unsigned long inlen, rsa_key *key) +{ + /* now it should be SEQUENCE { INTEGER, INTEGER } */ + return der_decode_sequence_multi(in, inlen, + LTC_ASN1_INTEGER, 1UL, key->N, + LTC_ASN1_INTEGER, 1UL, key->e, + LTC_ASN1_EOL, 0UL, NULL); +} +#endif + /** Import an RSAPublicKey or RSAPrivateKey as defined in PKCS #1 v2.1 [two-prime only] @@ -33,10 +45,7 @@ int rsa_import_pkcs1(const unsigned char *in, unsigned long inlen, rsa_key *key) /* the version would fit into an LTC_ASN1_SHORT_INTEGER * so we try to decode as a public key */ - if ((err = der_decode_sequence_multi(in, inlen, - LTC_ASN1_INTEGER, 1UL, key->N, - LTC_ASN1_INTEGER, 1UL, key->e, - LTC_ASN1_EOL, 0UL, NULL)) == CRYPT_OK) { + if ((err = s_rsa_decode(in, inlen, key)) == CRYPT_OK) { key->type = PK_PUBLIC; } goto LBL_OUT; @@ -85,57 +94,30 @@ int rsa_import_pkcs1(const unsigned char *in, unsigned long inlen, rsa_key *key) int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) { int err; - unsigned char *tmpbuf=NULL; - unsigned long tmpbuf_len, len; LTC_ARGCHK(in != NULL); LTC_ARGCHK(key != NULL); LTC_ARGCHK(ltc_mp.name != NULL); + if ((err = rsa_import_x509(in, inlen, key)) == CRYPT_OK) { /* SubjectPublicKeyInfo format */ + return CRYPT_OK; + } + /* init key */ if ((err = rsa_init(key)) != CRYPT_OK) { return err; } - /* see if the OpenSSL DER format RSA public key will work */ - tmpbuf_len = inlen; - tmpbuf = XCALLOC(1, tmpbuf_len); - if (tmpbuf == NULL) { - err = CRYPT_MEM; - goto LBL_ERR; - } - - len = 0; - err = x509_decode_subject_public_key_info(in, inlen, - LTC_OID_RSA, tmpbuf, &tmpbuf_len, - LTC_ASN1_NULL, NULL, &len); - - if (err == CRYPT_OK) { /* SubjectPublicKeyInfo format */ - - /* now it should be SEQUENCE { INTEGER, INTEGER } */ - if ((err = der_decode_sequence_multi(tmpbuf, tmpbuf_len, - LTC_ASN1_INTEGER, 1UL, key->N, - LTC_ASN1_INTEGER, 1UL, key->e, - LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { - goto LBL_ERR; + if ((err = x509_process_public_key_from_spki(in, inlen, + LTC_OID_RSA, + LTC_ASN1_NULL, NULL, NULL, + (public_key_decode_cb)s_rsa_decode, key)) != CRYPT_OK) { + /* not SSL public key, try to match against PKCS #1 standards */ + if ((err = rsa_import_pkcs1(in, inlen, key)) != CRYPT_OK) { + rsa_free(key); } - key->type = PK_PUBLIC; - err = CRYPT_OK; - goto LBL_FREE; } - /* not SSL public key, try to match against PKCS #1 standards */ - if ((err = rsa_import_pkcs1(in, inlen, key)) == CRYPT_OK) { - goto LBL_FREE; - } - -LBL_ERR: - rsa_free(key); - -LBL_FREE: - if (tmpbuf != NULL) { - XFREE(tmpbuf); - } return err; } diff --git a/src/pk/rsa/rsa_import_x509.c b/src/pk/rsa/rsa_import_x509.c index 4d157ead4..f2a489e9e 100644 --- a/src/pk/rsa/rsa_import_x509.c +++ b/src/pk/rsa/rsa_import_x509.c @@ -9,6 +9,8 @@ #ifdef LTC_MRSA +#ifndef S_RSA_DECODE +#define S_RSA_DECODE static int s_rsa_decode(const unsigned char *in, unsigned long inlen, rsa_key *key) { /* now it should be SEQUENCE { INTEGER, INTEGER } */ @@ -17,6 +19,153 @@ static int s_rsa_decode(const unsigned char *in, unsigned long inlen, rsa_key *k LTC_ASN1_INTEGER, 1UL, key->e, LTC_ASN1_EOL, 0UL, NULL); } +#endif + +typedef struct rsa_pss_parameters_data { + ltc_asn1_list params[4], inner[4], hash_alg[2], mgf[2], mgf_hash_alg[2]; + unsigned long hash_alg_oid[LTC_DER_OID_DEFAULT_NODES]; + unsigned long mgf_alg_oid[LTC_DER_OID_DEFAULT_NODES]; + unsigned long mgf1_hash_alg_oid[LTC_DER_OID_DEFAULT_NODES]; + unsigned long salt_length, trailer_field; +} rsa_pss_parameters_data; + +static LTC_INLINE void s_rsa_pss_parameters_data_setup(rsa_pss_parameters_data *d) +{ + unsigned long n; + /* RSASSA-PSS + * + * RSASSA-PSS-params ::= SEQUENCE { + * hashAlgorithm [0] HashAlgorithm DEFAULT sha1, + * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, + * saltLength [2] INTEGER DEFAULT 20, + * trailerField [3] TrailerField DEFAULT trailerFieldBC + * } + */ + + /* HashAlgorithm ::= AlgorithmIdentifier { + * {OAEP-PSSDigestAlgorithms} + * } + */ + LTC_SET_ASN1(d->hash_alg, 0, LTC_ASN1_OBJECT_IDENTIFIER, d->hash_alg_oid, LTC_ARRAY_SIZE(d->hash_alg_oid)); + LTC_SET_ASN1(d->hash_alg, 1, LTC_ASN1_NULL, NULL, 0); + d->hash_alg[1].optional = 1; + + /* MaskGenAlgorithm ::= AlgorithmIdentifier { {PKCS1MGFAlgorithms} } */ + LTC_SET_ASN1(d->mgf_hash_alg, 0, LTC_ASN1_OBJECT_IDENTIFIER, d->mgf1_hash_alg_oid, LTC_ARRAY_SIZE(d->mgf1_hash_alg_oid)); + LTC_SET_ASN1(d->mgf_hash_alg, 1, LTC_ASN1_NULL, NULL, 0); + d->mgf_hash_alg[1].optional = 1; + + /* PKCS1MGFAlgorithms ALGORITHM-IDENTIFIER ::= { + * { OID id-mgf1 PARAMETERS HashAlgorithm }, + * ... -- Allows for future expansion -- + * } + */ + LTC_SET_ASN1(d->mgf, 0, LTC_ASN1_OBJECT_IDENTIFIER, d->mgf_alg_oid, LTC_ARRAY_SIZE(d->mgf_alg_oid)); + LTC_SET_ASN1(d->mgf, 1, LTC_ASN1_SEQUENCE, d->mgf_hash_alg, LTC_ARRAY_SIZE(d->mgf_hash_alg)); + + LTC_SET_ASN1(d->inner, 0, LTC_ASN1_SEQUENCE, d->hash_alg, LTC_ARRAY_SIZE(d->hash_alg)); + LTC_SET_ASN1(d->inner, 1, LTC_ASN1_SEQUENCE, d->mgf, LTC_ARRAY_SIZE(d->mgf)); + LTC_SET_ASN1(d->inner, 2, LTC_ASN1_SHORT_INTEGER, &d->salt_length, 1UL); + LTC_SET_ASN1(d->inner, 3, LTC_ASN1_SHORT_INTEGER, &d->trailer_field, 1UL); + + LTC_SET_ASN1_CUSTOM_CONSTRUCTED(d->params, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0, d->inner); /* context specific 0 */ + LTC_SET_ASN1_CUSTOM_CONSTRUCTED(d->params, 1, LTC_ASN1_CL_CONTEXT_SPECIFIC, 1, d->inner + 1); /* context specific 1 */ + LTC_SET_ASN1_CUSTOM_CONSTRUCTED(d->params, 2, LTC_ASN1_CL_CONTEXT_SPECIFIC, 2, d->inner + 2); /* context specific 2 */ + LTC_SET_ASN1_CUSTOM_CONSTRUCTED(d->params, 3, LTC_ASN1_CL_CONTEXT_SPECIFIC, 3, d->inner + 3); /* context specific 3 */ + for (n = 0; n < 4; ++n) { + d->params[n].optional = 1; + } +} + +int rsa_decode_parameters(const ltc_asn1_list *parameters, ltc_rsa_parameters *rsa_params) +{ + rsa_pss_parameters_data d; + unsigned long n; + enum ltc_oid_id oid_id; + int err, idx; + + s_rsa_pss_parameters_data_setup(&d); + + if ((err = der_decode_sequence(parameters->data, parameters->size, d.params, 4)) != CRYPT_OK) { + return err; + } + + rsa_params->saltlen = 20; + rsa_params->hash_alg = rsa_params->mgf1_hash_alg = "sha1"; + + for (n = 0; n < 4; ++n) { + if (d.params[n].used == 0) + continue; + switch (n) { + case 0: + idx = find_hash_oid(d.hash_alg->data, d.hash_alg->size); + if (idx == -1) { + return CRYPT_INVALID_HASH; + } + rsa_params->hash_alg = hash_descriptor[idx].name; + break; + case 1: + if ((err = pk_get_oid_from_asn1(&d.mgf[0], &oid_id)) != CRYPT_OK) { + return err; + } + if (oid_id != LTC_OID_RSA_MGF1) { + return CRYPT_PK_ASN1_ERROR; + } + idx = find_hash_oid(d.mgf_hash_alg->data, d.mgf_hash_alg->size); + if (idx == -1) { + return CRYPT_INVALID_HASH; + } + rsa_params->mgf1_hash_alg = hash_descriptor[idx].name; + break; + case 2: + rsa_params->saltlen = d.salt_length; + break; + case 3: + if (d.trailer_field != 1) { + return CRYPT_PK_ASN1_ERROR; + } + break; + default: + return CRYPT_PK_ASN1_ERROR; + } + } + + + rsa_params->pss_oaep = 1; + + return CRYPT_OK; +} + +static int s_rsa_import_pss(const unsigned char *in, unsigned long inlen, rsa_key *key) +{ + rsa_pss_parameters_data d; + ltc_asn1_list *decoded_list; + const ltc_asn1_list *spki; + int err; + unsigned long n_params = LTC_ARRAY_SIZE(d.params); + + if ((err = x509_process_public_key_from_spki(in, inlen, + LTC_OID_RSA_PSS, + LTC_ASN1_NULL, NULL, NULL, + (public_key_decode_cb)s_rsa_decode, key)) != CRYPT_OK) { + if ((err = x509_decode_spki(in, inlen, &decoded_list, &spki)) != CRYPT_OK) { + return err; + } + if ((err = x509_process_public_key_from_spki(spki->data, spki->size, + LTC_OID_RSA_PSS, + LTC_ASN1_NULL, NULL, NULL, + (public_key_decode_cb)s_rsa_decode, key)) != CRYPT_OK) { + s_rsa_pss_parameters_data_setup(&d); + err = x509_process_public_key_from_spki(spki->data, spki->size, + LTC_OID_RSA_PSS, + LTC_ASN1_SEQUENCE, d.params, &n_params, + (public_key_decode_cb)s_rsa_decode, key); + } + } + + der_free_sequence_flexi(decoded_list); + return err; +} /** Import an RSA key from a X.509 certificate @@ -41,12 +190,18 @@ int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key) if ((err = x509_decode_public_key_from_certificate(in, inlen, LTC_OID_RSA, LTC_ASN1_NULL, NULL, NULL, - (public_key_decode_cb)s_rsa_decode, key)) != CRYPT_OK) { - rsa_free(key); - } else { + (public_key_decode_cb)s_rsa_decode, key)) == CRYPT_OK) { key->type = PK_PUBLIC; + return CRYPT_OK; } + if ((err = s_rsa_import_pss(in, inlen, key)) == CRYPT_OK) { + key->type = PK_PUBLIC; + return CRYPT_OK; + } + + rsa_free(key); + return err; } diff --git a/src/pk/rsa/rsa_key.c b/src/pk/rsa/rsa_key.c index 7eb21b843..5bb37f7fb 100644 --- a/src/pk/rsa/rsa_key.c +++ b/src/pk/rsa/rsa_key.c @@ -85,6 +85,7 @@ void rsa_shrink_key(rsa_key *key) int rsa_init(rsa_key *key) { LTC_ARGCHK(key != NULL); + XMEMSET(&key->params, 0, sizeof(key->params)); return ltc_mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, LTC_NULL); } @@ -96,6 +97,90 @@ void rsa_free(rsa_key *key) { LTC_ARGCHKVD(key != NULL); ltc_mp_cleanup_multi(&key->q, &key->p, &key->qP, &key->dP, &key->dQ, &key->N, &key->d, &key->e, LTC_NULL); + XMEMSET(&key->params, 0, sizeof(key->params)); +} + +static LTC_INLINE int s_rsa_key_valid_pss_algs(const rsa_key *key, int padding, int hash_idx) +{ + if (!key->params.pss_oaep) { + return CRYPT_OK; + } + if (padding != LTC_PKCS_1_PSS) { + return CRYPT_PK_TYPE_MISMATCH; + } + if (key->params.hash_alg == NULL || find_hash(key->params.hash_alg) != hash_idx) { + return CRYPT_INVALID_HASH; + } + if (key->params.mgf1_hash_alg == NULL) { + return CRYPT_INVALID_HASH; + } + return hash_is_valid(find_hash(key->params.mgf1_hash_alg)); +} + +static LTC_INLINE int s_rsa_key_valid_sign(const rsa_key *key, int padding, int hash_idx) +{ + if ((padding != LTC_PKCS_1_V1_5) && + (padding != LTC_PKCS_1_PSS) && + (padding != LTC_PKCS_1_V1_5_NA1)) { + return CRYPT_PK_INVALID_PADDING; + } + + if (padding != LTC_PKCS_1_V1_5_NA1) { + int err; + /* valid hash ? */ + if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { + return err; + } + } + return s_rsa_key_valid_pss_algs(key, padding, hash_idx); +} + +static LTC_INLINE int s_rsa_key_valid_crypt(const rsa_key *key, int padding, int hash_idx) +{ + if ((padding != LTC_PKCS_1_V1_5) && + (padding != LTC_PKCS_1_OAEP)) { + return CRYPT_PK_INVALID_PADDING; + } + + if (padding == LTC_PKCS_1_OAEP) { + int err; + /* valid hash? */ + if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { + return err; + } + } + return s_rsa_key_valid_pss_algs(key, padding, hash_idx); +} + +int rsa_key_valid_op(const rsa_key *key, ltc_rsa_op op, int padding, int hash_idx) +{ + switch (op) { + case LTC_RSA_SIGN: + return s_rsa_key_valid_sign(key, padding, hash_idx); + case LTC_RSA_CRYPT: + return s_rsa_key_valid_crypt(key, padding, hash_idx); + default: + return CRYPT_ERROR; + } +} + +int rsa_params_equal(const ltc_rsa_parameters *a, const ltc_rsa_parameters *b) +{ + if (!a->pss_oaep) + return 0; + if (a->pss_oaep != b->pss_oaep) + return 0; + if (a->saltlen != b->saltlen) + return 0; + if (!a->hash_alg || !b->hash_alg) + return 0; + if (XSTRCMP(a->hash_alg, b->hash_alg)) + return 0; + if (!a->mgf1_hash_alg || !b->mgf1_hash_alg) + return 0; + if (XSTRCMP(a->mgf1_hash_alg, b->mgf1_hash_alg)) + return 0; + return 1; } #endif diff --git a/src/pk/rsa/rsa_sign_hash.c b/src/pk/rsa/rsa_sign_hash.c index a7a18036d..4445f712b 100644 --- a/src/pk/rsa/rsa_sign_hash.c +++ b/src/pk/rsa/rsa_sign_hash.c @@ -40,10 +40,8 @@ int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, LTC_ARGCHK(key != NULL); /* valid padding? */ - if ((padding != LTC_PKCS_1_V1_5) && - (padding != LTC_PKCS_1_PSS) && - (padding != LTC_PKCS_1_V1_5_NA1)) { - return CRYPT_PK_INVALID_PADDING; + if ((err = rsa_key_valid_op(key, LTC_RSA_SIGN, padding, hash_idx)) != CRYPT_OK) { + return err; } if (padding == LTC_PKCS_1_PSS) { @@ -53,13 +51,6 @@ int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, } } - if (padding != LTC_PKCS_1_V1_5_NA1) { - /* valid hash ? */ - if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { - return err; - } - } - /* get modulus len in bits */ modulus_bitlen = ltc_mp_count_bits((key->N)); diff --git a/src/pk/rsa/rsa_verify_hash.c b/src/pk/rsa/rsa_verify_hash.c index 7303a7b26..ede234497 100644 --- a/src/pk/rsa/rsa_verify_hash.c +++ b/src/pk/rsa/rsa_verify_hash.c @@ -42,18 +42,8 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long sigle *stat = 0; /* valid padding? */ - - if ((padding != LTC_PKCS_1_V1_5) && - (padding != LTC_PKCS_1_PSS) && - (padding != LTC_PKCS_1_V1_5_NA1)) { - return CRYPT_PK_INVALID_PADDING; - } - - if (padding != LTC_PKCS_1_V1_5_NA1) { - /* valid hash ? */ - if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { - return err; - } + if ((err = rsa_key_valid_op(key, LTC_RSA_SIGN, padding, hash_idx)) != CRYPT_OK) { + return err; } /* get modulus len in bits */ From a79274a72242ba69e17d4dc56e6d820527d3236f Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Tue, 2 Sep 2025 17:25:03 +0200 Subject: [PATCH 3/4] Refactor SubjectPublicKeyInfo import Slightly minimize both space and time when importing a SubjectPublicKeyInfo. Time for ECC keys stays the same. Those tests were done with X.509 support already available, but later these commits were split up to be independent of the X.509 feature. Running the entire set of pem files through `x509_verify` via [0] resp. the timing app via [1] resulted in the following data: Before this patch: [0] ``` ==1031519== HEAP SUMMARY: ==1031519== in use at exit: 0 bytes in 0 blocks ==1031519== total heap usage: 424,057 allocs, 424,057 frees, 73,527,730 bytes allocated ``` [1] ``` x509 cert-rsa-pss.pem : 50021 cycles x509 LTC_CA.pem : 10335 cycles x509 LTC_S0.pem : 47284 cycles x509 LTC_SS0.pem : 36687 cycles x509 secp384r1.pem : 1985416 cycles x509 secp521r1.pem : 3287773 cycles x509 LTC_SSS0.pem : 25086 cycles x509 secp224r1.pem : 775807 cycles ``` After this patch: [0] ``` ==1043548== HEAP SUMMARY: ==1043548== in use at exit: 0 bytes in 0 blocks ==1043548== total heap usage: 337,244 allocs, 337,244 frees, 65,047,463 bytes allocated ``` [1] ``` x509 cert-rsa-pss.pem : 32568 cycles x509 LTC_CA.pem : 5478 cycles x509 LTC_S0.pem : 36093 cycles x509 LTC_SS0.pem : 23351 cycles x509 secp384r1.pem : 1984030 cycles x509 secp521r1.pem : 3303396 cycles x509 LTC_SSS0.pem : 13220 cycles x509 secp224r1.pem : 781534 cycles ``` [0] find tests/x509 -name '*.pem' -exec valgrind --leak-check=full --show-leak-kinds=all './x509_verify' {} \+ [1] ./timing x509 Signed-off-by: Steffen Jaeckel --- src/headers/tomcrypt_private.h | 10 +- .../x509_decode_public_key_from_certificate.c | 10 +- src/pk/asn1/x509/x509_import_spki.c | 48 ++++-- src/pk/dsa/dsa_import.c | 58 +++++-- src/pk/rsa/rsa_import.c | 15 +- src/pk/rsa/rsa_import_x509.c | 144 ++++++++++++------ 6 files changed, 197 insertions(+), 88 deletions(-) diff --git a/src/headers/tomcrypt_private.h b/src/headers/tomcrypt_private.h index 7797af0e9..3962ccaa8 100644 --- a/src/headers/tomcrypt_private.h +++ b/src/headers/tomcrypt_private.h @@ -458,6 +458,8 @@ int rsa_make_key_bn_e(prng_state *prng, int wprng, int size, void *e, rsa_key *key); /* used by op-tee */ int rsa_import_pkcs1(const unsigned char *in, unsigned long inlen, rsa_key *key); int rsa_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, rsa_key *key); +int rsa_import_spki(const unsigned char *in, unsigned long inlen, rsa_key *key); +int rsa_decode_parameters(const ltc_asn1_list *parameters, ltc_rsa_parameters *rsa_params); #endif /* LTC_MRSA */ /* ---- DH Routines ---- */ @@ -617,8 +619,8 @@ int dsa_int_validate(const dsa_key *key, int *stat); int dsa_int_validate_xy(const dsa_key *key, int *stat); int dsa_int_validate_pqg(const dsa_key *key, int *stat); int dsa_int_validate_primes(const dsa_key *key, int *stat); -int dsa_import_pkcs1(const unsigned char *in, unsigned long inlen, dsa_key *key); int dsa_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, dsa_key *key); +int dsa_import_spki(const unsigned char *in, unsigned long inlen, dsa_key *key); #endif /* LTC_MDSA */ @@ -733,17 +735,17 @@ int der_teletex_value_decode(int v); int der_utf8_valid_char(const wchar_t c); -typedef int (*public_key_decode_cb)(const unsigned char *in, unsigned long inlen, void *ctx); +typedef int (*public_key_decode_cb)(const unsigned char *in, unsigned long inlen, void *key); int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned long inlen, enum ltc_oid_id algorithm, ltc_asn1_type param_type, ltc_asn1_list* parameters, unsigned long *parameters_len, - public_key_decode_cb callback, void *ctx); + public_key_decode_cb callback, void *key); int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, const ltc_asn1_list **spki); int x509_process_public_key_from_spki(const unsigned char *in, unsigned long inlen, enum ltc_oid_id algorithm, ltc_asn1_type param_type, ltc_asn1_list* parameters, unsigned long *parameters_len, - public_key_decode_cb callback, void *ctx); + public_key_decode_cb callback, void *key); /* SUBJECT PUBLIC KEY INFO */ int x509_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen, diff --git a/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c b/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c index 65623a956..b96db4438 100644 --- a/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c +++ b/src/pk/asn1/x509/x509_decode_public_key_from_certificate.c @@ -24,7 +24,7 @@ int x509_process_public_key_from_spki(const unsigned char *in, unsigned long inlen, enum ltc_oid_id algorithm, ltc_asn1_type param_type, ltc_asn1_list* parameters, unsigned long *parameters_len, - public_key_decode_cb callback, void *ctx) + public_key_decode_cb callback, void *key) { int err; unsigned char *tmpbuf = NULL; @@ -34,7 +34,7 @@ int x509_process_public_key_from_spki(const unsigned char *in, unsigned long inl LTC_ARGCHK(callback != NULL); if (algorithm == LTC_OID_EC) { - err = callback(in, inlen, ctx); + err = callback(in, inlen, key); } else { tmpbuf_len = inlen; @@ -47,7 +47,7 @@ int x509_process_public_key_from_spki(const unsigned char *in, unsigned long inl algorithm, tmpbuf, &tmpbuf_len, param_type, parameters, parameters_len); if (err == CRYPT_OK) { - err = callback(tmpbuf, tmpbuf_len, ctx); + err = callback(tmpbuf, tmpbuf_len, key); } } @@ -73,7 +73,7 @@ int x509_process_public_key_from_spki(const unsigned char *in, unsigned long inl int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned long inlen, enum ltc_oid_id algorithm, ltc_asn1_type param_type, ltc_asn1_list* parameters, unsigned long *parameters_len, - public_key_decode_cb callback, void *ctx) + public_key_decode_cb callback, void *key) { int err; ltc_asn1_list *decoded_list; @@ -90,7 +90,7 @@ int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned lo err = x509_process_public_key_from_spki(spki->data, spki->size, algorithm, param_type, parameters, parameters_len, - callback, ctx); + callback, key); if (decoded_list) der_free_sequence_flexi(decoded_list); diff --git a/src/pk/asn1/x509/x509_import_spki.c b/src/pk/asn1/x509/x509_import_spki.c index 73b4dac73..13057bd31 100644 --- a/src/pk/asn1/x509/x509_import_spki.c +++ b/src/pk/asn1/x509/x509_import_spki.c @@ -9,22 +9,48 @@ #ifdef LTC_DER -typedef int (*import_fn)(const unsigned char *, unsigned long, void*); +typedef int (*import_fn)(const unsigned char *, unsigned long, void *); -static const import_fn s_import_x509_fns[LTC_PKA_NUM] = { +#ifdef LTC_CURVE25519 +static int s_x25519_import_pub(const unsigned char *in, unsigned long inlen, void *key) +{ + return x25519_import_raw(in, inlen, PK_PUBLIC, key); +} +static int s_x25519_import_spki(const unsigned char *in, unsigned long inlen, void *key) +{ + return x509_process_public_key_from_spki(in, inlen, + LTC_OID_X25519, + LTC_ASN1_EOL, NULL, NULL, + s_x25519_import_pub, key); +} + +static int s_ed25519_import_pub(const unsigned char *in, unsigned long inlen, void *key) +{ + return ed25519_import_raw(in, inlen, PK_PUBLIC, key); +} +static int s_ed25519_import_spki(const unsigned char *in, unsigned long inlen, void *key) +{ + return x509_process_public_key_from_spki(in, inlen, + LTC_OID_ED25519, + LTC_ASN1_EOL, NULL, NULL, + s_ed25519_import_pub, key); +} +#endif + +static const import_fn s_import_spki_fns[LTC_PKA_NUM] = { #ifdef LTC_MRSA - [LTC_PKA_RSA] = (import_fn)rsa_import_x509, - [LTC_PKA_RSA_PSS] = (import_fn)rsa_import_x509, + [LTC_PKA_RSA] = (import_fn)rsa_import_spki, + [LTC_PKA_RSA_PSS] = (import_fn)rsa_import_spki, #endif #ifdef LTC_MDSA - [LTC_PKA_DSA] = (import_fn)dsa_import, + [LTC_PKA_DSA] = (import_fn)dsa_import_spki, #endif #ifdef LTC_MECC - [LTC_PKA_EC] = (import_fn)ecc_import_x509, + [LTC_PKA_EC] = (import_fn)ecc_import_subject_public_key_info, #endif #ifdef LTC_CURVE25519 - [LTC_PKA_X25519] = (import_fn)x25519_import_x509, - [LTC_PKA_ED25519] = (import_fn)ed25519_import_x509, + [LTC_PKA_X25519] = (import_fn)s_x25519_import_spki, + [LTC_PKA_ED25519] = (import_fn)s_ed25519_import_spki, #endif }; @@ -41,12 +67,12 @@ int x509_import_spki(const unsigned char *asn1_cert, unsigned long asn1_len, ltc goto err_out; } if (pka < 0 - || pka > LTC_ARRAY_SIZE(s_import_x509_fns) - || s_import_x509_fns[pka] == NULL) { + || pka > LTC_ARRAY_SIZE(s_import_spki_fns) + || s_import_spki_fns[pka] == NULL) { err = CRYPT_PK_INVALID_TYPE; goto err_out; } - if ((err = s_import_x509_fns[pka](asn1_cert, asn1_len, &k->u)) == CRYPT_OK) { + if ((err = s_import_spki_fns[pka](spki->data, spki->size, &k->u)) == CRYPT_OK) { k->id = pka; } err_out: diff --git a/src/pk/dsa/dsa_import.c b/src/pk/dsa/dsa_import.c index 3db1afd32..91ddcc2be 100644 --- a/src/pk/dsa/dsa_import.c +++ b/src/pk/dsa/dsa_import.c @@ -9,7 +9,7 @@ #ifdef LTC_MDSA -int dsa_import_pkcs1(const unsigned char *in, unsigned long inlen, dsa_key *key) +static int s_dsa_import_pkcs1(const unsigned char *in, unsigned long inlen, dsa_key *key) { int err; unsigned long zero = 0; @@ -33,7 +33,7 @@ static int s_dsa_import_y(const unsigned char *in, unsigned long inlen, dsa_key return der_decode_integer(in, inlen, key->y); } -LTC_INLINE static int s_dsa_set_params(dsa_key *key, ltc_asn1_list *params) +static LTC_INLINE int s_dsa_set_params(dsa_key *key, ltc_asn1_list *params) { LTC_SET_ASN1(params, 0, LTC_ASN1_INTEGER, key->p, 1UL); LTC_SET_ASN1(params, 1, LTC_ASN1_INTEGER, key->q, 1UL); @@ -41,6 +41,24 @@ LTC_INLINE static int s_dsa_set_params(dsa_key *key, ltc_asn1_list *params) return 3; } +static LTC_INLINE int s_dsa_validate(dsa_key *key) +{ + int err, stat; + key->qord = ltc_mp_unsigned_bin_size(key->q); + + /* quick p, q, g validation, without primality testing + * + x, y validation */ + if ((err = dsa_int_validate(key, &stat)) != CRYPT_OK) { + return err; + } + + if (stat == 0) { + return CRYPT_INVALID_PACKET; + } + + return CRYPT_OK; +} + static int s_dsa_import_spki(const unsigned char *in, unsigned long inlen, dsa_key *key) { int err; @@ -72,6 +90,28 @@ static int s_dsa_import_spki(const unsigned char *in, unsigned long inlen, dsa_k return err; } +int dsa_import_spki(const unsigned char *in, unsigned long inlen, dsa_key *key) +{ + int err; + + LTC_ARGCHK(in != NULL); + + /* init key */ + if ((err = dsa_int_init(key)) != CRYPT_OK) return err; + + if ((err = s_dsa_import_spki(in, inlen, key)) != CRYPT_OK) { + goto LBL_ERR; + } + if ((err = s_dsa_validate(key)) != CRYPT_OK) { + goto LBL_ERR; + } + + return CRYPT_OK; +LBL_ERR: + dsa_free(key); + return err; +} + static int s_dsa_import_x509(const unsigned char *in, unsigned long inlen, dsa_key *key) { int err; @@ -100,7 +140,7 @@ static int s_dsa_import_x509(const unsigned char *in, unsigned long inlen, dsa_k */ int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key) { - int err, stat; + int err; unsigned char flags[1]; LTC_ARGCHK(in != NULL); @@ -148,7 +188,7 @@ int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key) } } - if (dsa_import_pkcs1(in, inlen, key) == CRYPT_OK) { + if (s_dsa_import_pkcs1(in, inlen, key) == CRYPT_OK) { goto LBL_OK; } if (s_dsa_import_spki(in, inlen, key) == CRYPT_OK) { @@ -159,15 +199,7 @@ int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key) } LBL_OK: - key->qord = ltc_mp_unsigned_bin_size(key->q); - - /* quick p, q, g validation, without primality testing - * + x, y validation */ - if ((err = dsa_int_validate(key, &stat)) != CRYPT_OK) { - goto LBL_ERR; - } - if (stat == 0) { - err = CRYPT_INVALID_PACKET; + if ((err = s_dsa_validate(key)) != CRYPT_OK) { goto LBL_ERR; } diff --git a/src/pk/rsa/rsa_import.c b/src/pk/rsa/rsa_import.c index a52ff154f..bc201ad97 100644 --- a/src/pk/rsa/rsa_import.c +++ b/src/pk/rsa/rsa_import.c @@ -99,7 +99,8 @@ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) LTC_ARGCHK(key != NULL); LTC_ARGCHK(ltc_mp.name != NULL); - if ((err = rsa_import_x509(in, inlen, key)) == CRYPT_OK) { /* SubjectPublicKeyInfo format */ + /* SubjectPublicKeyInfo or X.509 certificate format */ + if (rsa_import_x509(in, inlen, key) == CRYPT_OK) { return CRYPT_OK; } @@ -107,15 +108,9 @@ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) if ((err = rsa_init(key)) != CRYPT_OK) { return err; } - - if ((err = x509_process_public_key_from_spki(in, inlen, - LTC_OID_RSA, - LTC_ASN1_NULL, NULL, NULL, - (public_key_decode_cb)s_rsa_decode, key)) != CRYPT_OK) { - /* not SSL public key, try to match against PKCS #1 standards */ - if ((err = rsa_import_pkcs1(in, inlen, key)) != CRYPT_OK) { - rsa_free(key); - } + /* Try to match against PKCS #1 standards */ + if ((err = rsa_import_pkcs1(in, inlen, key)) != CRYPT_OK) { + rsa_free(key); } return err; diff --git a/src/pk/rsa/rsa_import_x509.c b/src/pk/rsa/rsa_import_x509.c index f2a489e9e..6ebe55669 100644 --- a/src/pk/rsa/rsa_import_x509.c +++ b/src/pk/rsa/rsa_import_x509.c @@ -77,51 +77,44 @@ static LTC_INLINE void s_rsa_pss_parameters_data_setup(rsa_pss_parameters_data * } } -int rsa_decode_parameters(const ltc_asn1_list *parameters, ltc_rsa_parameters *rsa_params) +static int s_rsa_decode_parameters(const rsa_pss_parameters_data *d, ltc_rsa_parameters *rsa_params) { - rsa_pss_parameters_data d; unsigned long n; enum ltc_oid_id oid_id; int err, idx; - s_rsa_pss_parameters_data_setup(&d); - - if ((err = der_decode_sequence(parameters->data, parameters->size, d.params, 4)) != CRYPT_OK) { - return err; - } - rsa_params->saltlen = 20; rsa_params->hash_alg = rsa_params->mgf1_hash_alg = "sha1"; for (n = 0; n < 4; ++n) { - if (d.params[n].used == 0) + if (d->params[n].used == 0) continue; switch (n) { case 0: - idx = find_hash_oid(d.hash_alg->data, d.hash_alg->size); + idx = find_hash_oid(d->hash_alg->data, d->hash_alg->size); if (idx == -1) { return CRYPT_INVALID_HASH; } rsa_params->hash_alg = hash_descriptor[idx].name; break; case 1: - if ((err = pk_get_oid_from_asn1(&d.mgf[0], &oid_id)) != CRYPT_OK) { + if ((err = pk_get_oid_from_asn1(&d->mgf[0], &oid_id)) != CRYPT_OK) { return err; } if (oid_id != LTC_OID_RSA_MGF1) { return CRYPT_PK_ASN1_ERROR; } - idx = find_hash_oid(d.mgf_hash_alg->data, d.mgf_hash_alg->size); + idx = find_hash_oid(d->mgf_hash_alg->data, d->mgf_hash_alg->size); if (idx == -1) { return CRYPT_INVALID_HASH; } rsa_params->mgf1_hash_alg = hash_descriptor[idx].name; break; case 2: - rsa_params->saltlen = d.salt_length; + rsa_params->saltlen = d->salt_length; break; case 3: - if (d.trailer_field != 1) { + if (d->trailer_field != 1) { return CRYPT_PK_ASN1_ERROR; } break; @@ -130,51 +123,76 @@ int rsa_decode_parameters(const ltc_asn1_list *parameters, ltc_rsa_parameters *r } } - rsa_params->pss_oaep = 1; return CRYPT_OK; } -static int s_rsa_import_pss(const unsigned char *in, unsigned long inlen, rsa_key *key) +int rsa_decode_parameters(const ltc_asn1_list *parameters, ltc_rsa_parameters *rsa_params) { - rsa_pss_parameters_data d; - ltc_asn1_list *decoded_list; - const ltc_asn1_list *spki; int err; + rsa_pss_parameters_data d; + + s_rsa_pss_parameters_data_setup(&d); + + if ((err = der_decode_sequence(parameters->data, parameters->size, d.params, 4)) != CRYPT_OK) { + return err; + } + + return s_rsa_decode_parameters(&d, rsa_params); +} + +static LTC_INLINE int s_rsa_1_5_import_spki(const unsigned char *in, unsigned long inlen, rsa_key *key) +{ + return x509_process_public_key_from_spki(in, inlen, + LTC_OID_RSA, + LTC_ASN1_NULL, NULL, NULL, + (public_key_decode_cb)s_rsa_decode, key); +} + +static LTC_INLINE int s_rsa_pss_import_spki(const unsigned char *in, unsigned long inlen, rsa_key *key) +{ + int err; + rsa_pss_parameters_data d; unsigned long n_params = LTC_ARRAY_SIZE(d.params); + if (x509_process_public_key_from_spki(in, inlen, + LTC_OID_RSA_PSS, + LTC_ASN1_NULL, NULL, NULL, + (public_key_decode_cb)s_rsa_decode, key) == CRYPT_OK) { + return CRYPT_OK; + } + s_rsa_pss_parameters_data_setup(&d); if ((err = x509_process_public_key_from_spki(in, inlen, - LTC_OID_RSA_PSS, - LTC_ASN1_NULL, NULL, NULL, - (public_key_decode_cb)s_rsa_decode, key)) != CRYPT_OK) { - if ((err = x509_decode_spki(in, inlen, &decoded_list, &spki)) != CRYPT_OK) { - return err; - } - if ((err = x509_process_public_key_from_spki(spki->data, spki->size, - LTC_OID_RSA_PSS, - LTC_ASN1_NULL, NULL, NULL, - (public_key_decode_cb)s_rsa_decode, key)) != CRYPT_OK) { - s_rsa_pss_parameters_data_setup(&d); - err = x509_process_public_key_from_spki(spki->data, spki->size, - LTC_OID_RSA_PSS, - LTC_ASN1_SEQUENCE, d.params, &n_params, - (public_key_decode_cb)s_rsa_decode, key); - } + LTC_OID_RSA_PSS, + LTC_ASN1_SEQUENCE, d.params, &n_params, + (public_key_decode_cb)s_rsa_decode, key)) != CRYPT_OK) { + return err; + } + return s_rsa_decode_parameters(&d, &key->params); +} + +static LTC_INLINE int s_rsa_import_spki(const unsigned char *in, unsigned long inlen, rsa_key *key) +{ + int err; + if (s_rsa_1_5_import_spki(in, inlen, key) == CRYPT_OK) { + return CRYPT_OK; } - der_free_sequence_flexi(decoded_list); + if ((err = s_rsa_pss_import_spki(in, inlen, key)) == CRYPT_OK) { + return CRYPT_OK; + } return err; } /** - Import an RSA key from a X.509 certificate + Import an RSA key from SubjectPublicKeyInfo @param in The packet to import from @param inlen It's length (octets) @param key [out] Destination for newly imported key @return CRYPT_OK if successful, upon error allocated memory is freed */ -int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key) +int rsa_import_spki(const unsigned char *in, unsigned long inlen, rsa_key *key) { int err; @@ -187,22 +205,58 @@ int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key) return err; } - if ((err = x509_decode_public_key_from_certificate(in, inlen, - LTC_OID_RSA, - LTC_ASN1_NULL, NULL, NULL, - (public_key_decode_cb)s_rsa_decode, key)) == CRYPT_OK) { + if ((err = s_rsa_import_spki(in, inlen, key)) == CRYPT_OK) { key->type = PK_PUBLIC; return CRYPT_OK; } - if ((err = s_rsa_import_pss(in, inlen, key)) == CRYPT_OK) { + rsa_free(key); + + return err; +} + +/** + Import an RSA key from a X.509 certificate + @param in The packet to import from + @param inlen It's length (octets) + @param key [out] Destination for newly imported key + @return CRYPT_OK if successful, upon error allocated memory is freed +*/ +int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key) +{ + ltc_asn1_list *decoded_list; + const ltc_asn1_list *spki; + int err; + + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(key != NULL); + LTC_ARGCHK(ltc_mp.name != NULL); + + /* init key */ + if ((err = rsa_init(key)) != CRYPT_OK) { + return err; + } + + /* First try to decode as SubjectPublicKeyInfo */ + if (s_rsa_import_spki(in, inlen, key) == CRYPT_OK) { key->type = PK_PUBLIC; return CRYPT_OK; } - rsa_free(key); + /* Now try to extract the SubjectPublicKeyInfo from the Certificate */ + if ((err = x509_decode_spki(in, inlen, &decoded_list, &spki)) != CRYPT_OK) { + rsa_free(key); + return err; + } + err = s_rsa_import_spki(spki->data, spki->size, key); - return err; + der_free_sequence_flexi(decoded_list); + if (err != CRYPT_OK) { + rsa_free(key); + return err; + } + key->type = PK_PUBLIC; + return CRYPT_OK; } #endif /* LTC_MRSA */ From 9e47b3aa74d188f3d897aafeced63533cbde280d Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Thu, 23 Oct 2025 00:09:05 +0200 Subject: [PATCH 4/4] Introduce new RSA API. This also: a) deprecates the old RSA and PKCS#1 API. b) reverts the changes done to them in order to make the now deprecated API compatible again with the last release. The fixes commit mentioned below is the testcase for the Bleichenbacher attack, which works now again as expected. Fixes: 9d03c38e ("add flags to `der_decode_sequence()`") Signed-off-by: Steffen Jaeckel --- demos/timing.c | 23 +- doc/crypt.tex | 692 ++++++++++++++++++++---------- src/headers/tomcrypt_pk.h | 132 ++++-- src/headers/tomcrypt_pkcs.h | 17 +- src/headers/tomcrypt_private.h | 94 +++- src/misc/deprecated.c | 359 +++++++++++++++- src/pk/pkcs1/pkcs_1_mgf1.c | 6 +- src/pk/pkcs1/pkcs_1_oaep_decode.c | 48 +-- src/pk/pkcs1/pkcs_1_oaep_encode.c | 50 +-- src/pk/pkcs1/pkcs_1_pss_decode.c | 64 +-- src/pk/pkcs1/pkcs_1_pss_encode.c | 71 +-- src/pk/pkcs1/pkcs_1_v1_5_decode.c | 14 +- src/pk/pkcs1/pkcs_1_v1_5_encode.c | 16 +- src/pk/rsa/rsa_decrypt_key.c | 32 +- src/pk/rsa/rsa_encrypt_key.c | 57 +-- src/pk/rsa/rsa_key.c | 130 ++++-- src/pk/rsa/rsa_sign_hash.c | 78 ++-- src/pk/rsa/rsa_verify_hash.c | 50 +-- tests/deprecated_test.c | 44 ++ tests/pkcs_1_eme_test.c | 22 +- tests/pkcs_1_emsa_test.c | 13 +- tests/pkcs_1_oaep_test.c | 22 +- tests/pkcs_1_pss_test.c | 21 +- tests/pkcs_1_test.c | 59 ++- tests/rsa_test.c | 185 +++++--- 25 files changed, 1549 insertions(+), 750 deletions(-) diff --git a/demos/timing.c b/demos/timing.c index 572756dda..ada3ff345 100644 --- a/demos/timing.c +++ b/demos/timing.c @@ -702,11 +702,21 @@ static void time_rsa(void) unsigned char buf[2][2048] = { 0 }; unsigned long x, y, z, zzz; int err, zz, stat; + ltc_rsa_op_parameters rsa_params = { + .u.crypt.lparam = (const unsigned char *)"testprog", + .u.crypt.lparamlen = 8, + .prng = &yarrow_prng, + .wprng = find_prng("yarrow"), + .params.hash_alg = "sha1", + .params.mgf1_hash_alg = "sha1", + .params.saltlen = 8, + }; if (ltc_mp.name == NULL) return; for (x = 2048; x <= 8192; x <<= 1) { t2 = 0; + rsa_params.padding = LTC_PKCS_1_OAEP; for (y = 0; y < 4; y++) { t_start(); t1 = t_read(); @@ -734,9 +744,7 @@ static void time_rsa(void) t_start(); t1 = t_read(); z = sizeof(buf[1]); - if ((err = rsa_encrypt_key(buf[0], 32, buf[1], &z, (const unsigned char *)"testprog", 8, &yarrow_prng, - find_prng("yarrow"), find_hash("sha1"), - &key)) != CRYPT_OK) { + if ((err = rsa_encrypt_key_v2(buf[0], 32, buf[1], &z, &rsa_params, &key)) != CRYPT_OK) { fprintf(stderr, "\n\nrsa_encrypt_key says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK)); exit(EXIT_FAILURE); } @@ -755,8 +763,7 @@ static void time_rsa(void) t_start(); t1 = t_read(); zzz = sizeof(buf[0]); - if ((err = rsa_decrypt_key(buf[1], z, buf[0], &zzz, (const unsigned char *)"testprog", 8, find_hash("sha1"), - &zz, &key)) != CRYPT_OK) { + if ((err = rsa_decrypt_key_v2(buf[1], z, buf[0], &zzz, &rsa_params, &zz, &key)) != CRYPT_OK) { fprintf(stderr, "\n\nrsa_decrypt_key says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK)); exit(EXIT_FAILURE); } @@ -771,12 +778,12 @@ static void time_rsa(void) fprintf(stderr, "RSA-%lu decrypt_key took %15"PRI64"u cycles\n", x, t2); t2 = 0; + rsa_params.padding = LTC_PKCS_1_PSS; for (y = 0; y < 256; y++) { t_start(); t1 = t_read(); z = sizeof(buf[1]); - if ((err = rsa_sign_hash(buf[0], 20, buf[1], &z, &yarrow_prng, - find_prng("yarrow"), find_hash("sha1"), 8, &key)) != CRYPT_OK) { + if ((err = rsa_sign_hash_v2(buf[0], 20, buf[1], &z, &rsa_params, &key)) != CRYPT_OK) { fprintf(stderr, "\n\nrsa_sign_hash says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK)); exit(EXIT_FAILURE); } @@ -794,7 +801,7 @@ static void time_rsa(void) for (y = 0; y < 2048; y++) { t_start(); t1 = t_read(); - if ((err = rsa_verify_hash(buf[1], z, buf[0], 20, find_hash("sha1"), 8, &stat, &key)) != CRYPT_OK) { + if ((err = rsa_verify_hash_v2(buf[1], z, buf[0], 20, &rsa_params, &stat, &key)) != CRYPT_OK) { fprintf(stderr, "\n\nrsa_verify_hash says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK)); exit(EXIT_FAILURE); } diff --git a/doc/crypt.tex b/doc/crypt.tex index 0894f229f..14fedafdb 100644 --- a/doc/crypt.tex +++ b/doc/crypt.tex @@ -4430,171 +4430,6 @@ \chapter{RSA Public Key Cryptography} padding algorithms for encryption and signatures. The standard includes the \textit{v1.5} and \textit{v2.1} algorithms. To simplify matters a little the v2.1 encryption and signature padding algorithms are called OAEP and PSS respectively. -\mysection{PKCS \#1 Padding} -PKCS \#1 v1.5 padding is so simple that both signature and encryption padding are performed by the same function. Note: the -signature padding does \textbf{not} include the ASN.1 padding required. That is performed by the rsa\_sign\_hash\_ex() function -documented later on in this chapter. - -\subsection{PKCS \#1 v1.5 Encoding} -The following function performs PKCS \#1 v1.5 padding: -\index{pkcs\_1\_v1\_5\_encode()} -\begin{verbatim} -int pkcs_1_v1_5_encode( - const unsigned char *msg, - unsigned long msglen, - int block_type, - unsigned long modulus_bitlen, - prng_state *prng, - int prng_idx, - unsigned char *out, - unsigned long *outlen); -\end{verbatim} - -This will encode the message pointed to by \textit{msg} of length \textit{msglen} octets. The \textit{block\_type} parameter must be set to -\textbf{LTC\_PKCS\_1\_EME} to perform encryption padding. It must be set to \textbf{LTC\_PKCS\_1\_EMSA} to perform signature padding. The \textit{modulus\_bitlen} -parameter indicates the length of the modulus in bits. The padded data is stored in \textit{out} with a length of \textit{outlen} octets. The output will not be -longer than the modulus which helps allocate the correct output buffer size. - -Only encryption padding requires a PRNG. When performing signature padding the \textit{prng\_idx} parameter may be left to zero as it is not checked for validity. - -\subsection{PKCS \#1 v1.5 Decoding} -The following function performs PKCS \#1 v1.5 de--padding: -\index{pkcs\_1\_v1\_5\_decode()} -\begin{verbatim} -int pkcs_1_v1_5_decode( - const unsigned char *msg, - unsigned long msglen, - int block_type, - unsigned long modulus_bitlen, - unsigned char *out, - unsigned long *outlen, - int *is_valid); -\end{verbatim} -\index{LTC\_PKCS\_1\_EME} \index{LTC\_PKCS\_1\_EMSA} -This will remove the PKCS padding data pointed to by \textit{msg} of length \textit{msglen}. The decoded data is stored in \textit{out} of length -\textit{outlen}. If the padding is valid, a 1 is stored in \textit{is\_valid}, otherwise, a 0 is stored. The \textit{block\_type} parameter must be set to either -\textbf{LTC\_PKCS\_1\_EME} or \textbf{LTC\_PKCS\_1\_EMSA} depending on whether encryption or signature padding is being removed. - -\mysection{PKCS \#1 v2.1 Encryption} -PKCS \#1 RSA Encryption amounts to OAEP padding of the input message followed by the modular exponentiation. As far as this portion of -the library is concerned we are only dealing with th OAEP padding of the message. - -\subsection{OAEP Encoding} - -The following function performs PKCS \#1 v2.1 encryption padding: - -\index{pkcs\_1\_oaep\_encode()} -\begin{alltt} -int pkcs_1_oaep_encode( - const unsigned char *msg, - unsigned long msglen, - const unsigned char *lparam, - unsigned long lparamlen, - unsigned long modulus_bitlen, - prng_state *prng, - int prng_idx, - int mgf_hash, - int lparam_hash, - unsigned char *out, - unsigned long *outlen); -\end{alltt} - -This accepts \textit{msg} as input of length \textit{msglen} which will be OAEP padded. The \textit{lparam} variable is an additional system specific -tag that can be applied to the encoding. This is useful to identify which system encoded the message. If no variance is desired then -\textit{lparam} can be set to \textbf{NULL}. - -OAEP encoding requires the length of the modulus in bits in order to calculate the size of the output. This is passed as the parameter -\textit{modulus\_bitlen}. \textit{mgf\_hash} is the index into the hash descriptor table of the hash desired for the mask generation function (MGF). -\textit{lparam\_hash} is the index into the hash descriptor table of the hash desired for the \textit{lparam}. This value can also be set to $-1$ -to indicate usage of the same algorithm than for the MGF. PKCS \#1 allows any hash to be -used but both the encoder and decoder must use the same hash in order for this to succeed. The size of hash output affects the maximum - sized input message. \textit{prng\_idx} and \textit{prng} are the random number generator arguments required to randomize the padding process. -The padded message is stored in \textit{out} along with the length in \textit{outlen}. - -If $h$ is the length of the hash and $m$ the length of the modulus (both in octets) then the maximum payload for \textit{msg} is -$m - 2h - 2$. For example, with a $1024$--bit RSA key and SHA--1 as the hash the maximum payload is $86$ bytes. - -Note that when the message is padded it still has not been RSA encrypted. You must pass the output of this function to -rsa\_exptmod() to encrypt it. - -\subsection{OAEP Decoding} - -\index{pkcs\_1\_oaep\_decode()} -\begin{alltt} -int pkcs_1_oaep_decode( - const unsigned char *msg, - unsigned long msglen, - const unsigned char *lparam, - unsigned long lparamlen, - unsigned long modulus_bitlen, - int mgf_hash, - int lparam_hash, - unsigned char *out, - unsigned long *outlen, - int *res); -\end{alltt} - -This function decodes an OAEP encoded message and outputs the original message that was passed to the OAEP encoder. \textit{msg} is the -output of pkcs\_1\_oaep\_encode() of length \textit{msglen}. \textit{lparam} is the same system variable passed to the OAEP encoder. If it does not -match what was used during encoding this function will not decode the packet. \textit{modulus\_bitlen} is the size of the RSA modulus in bits -and must match what was used during encoding. Similarly the \textit{mgf\_hash} and \textit{lparam\_hash} indexes into the hash descriptor table must -match what was used during encoding. - -If the function succeeds it decodes the OAEP encoded message into \textit{out} of length \textit{outlen} and stores a -$1$ in \textit{res}. If the packet is invalid it stores $0$ in \textit{res} and if the function fails for another reason -it returns an error code. - -\mysection{PKCS \#1 Digital Signatures} - -\subsection{PSS Encoding} -PSS encoding is the second half of the PKCS \#1 standard which is padding to be applied to messages that are signed. - -\index{pkcs\_1\_pss\_encode()} -\begin{alltt} -int pkcs_1_pss_encode( - const unsigned char *msghash, - unsigned long msghashlen, - unsigned long saltlen, - prng_state *prng, - int prng_idx, - int hash_idx, - unsigned long modulus_bitlen, - unsigned char *out, - unsigned long *outlen); -\end{alltt} - -This function assumes the message to be PSS encoded has previously been hashed. The input hash \textit{msghash} is of length -\textit{msghashlen}. PSS allows a variable length random salt (it can be zero length) to be introduced in the signature process. -\textit{hash\_idx} is the index into the hash descriptor table of the hash to use. \textit{prng\_idx} and \textit{prng} are the random -number generator information required for the salt. - -Similar to OAEP encoding \textit{modulus\_bitlen} is the size of the RSA modulus (in bits). It limits the size of the salt. If $m$ is the length -of the modulus $h$ the length of the hash output (in octets) then there can be $m - h - 2$ bytes of salt. - -This function does not actually sign the data it merely pads the hash of a message so that it can be processed by rsa\_exptmod(). - -\subsection{PSS Decoding} - -To decode a PSS encoded signature block you have to use the following. - -\index{pkcs\_1\_pss\_decode()} -\begin{alltt} -int pkcs_1_pss_decode( - const unsigned char *msghash, - unsigned long msghashlen, - const unsigned char *sig, - unsigned long siglen, - unsigned long saltlen, - int hash_idx, - unsigned long modulus_bitlen, - int *res); -\end{alltt} -This will decode the PSS encoded message in \textit{sig} of length \textit{siglen} and compare it to values in \textit{msghash} of length -\textit{msghashlen}. If the block is a valid PSS block and the decoded hash equals the hash supplied \textit{res} is set to non--zero. Otherwise, -it is set to zero. The rest of the parameters are as in the PSS encode call. - -It's important to use the same \textit{saltlen} and hash for both encoding and decoding as otherwise the procedure will not work. - \mysection{RSA Key Operations} \subsection{Background} @@ -4696,6 +4531,73 @@ \subsection{RSA Key Size} \end{verbatim} This can be used to determine the modulus size of an RSA key. +\mysection{RSA Key Operation Parameters} + +The following RSA Key Operations share \code{struct}s which hold the parameters used in the operations. + +\index{RSASSA-PSS-params} +\begin{small} +\begin{verbatim} + RSASSA-PSS-params ::= SEQUENCE { + hashAlgorithm [0] HashAlgorithm DEFAULT sha1, + maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, + saltLength [2] INTEGER DEFAULT 20, + trailerField [3] TrailerField DEFAULT trailerFieldBC + } +\end{verbatim} +\end{small} + +\href{https://datatracker.ietf.org/doc/html/rfc8017}{\textit{RFC 8017}} defines the ASN.1 module for \code{RSASSA-PSS-params} as shown above. + +\index{ltc\_rsa\_parameters} +\begin{small} +\begin{verbatim} +typedef struct ltc_rsa_parameters { + /** PSS/OAEP or PKCS #1 v1.5 style + * 0 -> PKCS #1 v1.5, 1 -> PSS/OAEP */ + int pss_oaep; + /** saltLength is only defined for PSS + * If saltLength == 0 -> OAEP, else -> PSS */ + unsigned long saltlen; + /** lparam hash for OAEP + * resp. + * signature hash for PSS + * and MGF hash algorithms */ + const char *hash_alg, *mgf1_hash_alg; +} ltc_rsa_parameters; +\end{verbatim} +\end{small} + +The \code{struct ltc\_rsa\_parameters} represents the RSA parameters as defined in \code{RSASSA-PSS-params}. +This \code{struct} is used in two points, first when parsing an RSA key which contains those parameters in order to restrict the usage of the RSA key +to the given set of parameters, c.f. TBD. Its second use is explained below and defines the parameters used for an RSA operation. + +\index{ltc\_rsa\_op\_parameters} +\begin{small} +\begin{verbatim} +typedef struct ltc_rsa_op_parameters { + /* pss_oaep flag is unused */ + ltc_rsa_parameters params; + /* The padding type */ + int padding; + /* The PRNG to use. + * Only required for signing and encryption. */ + int wprng; + prng_state *prng; + /* Operation-specific parameters */ + union { + struct { + const unsigned char *lparam; + unsigned long lparamlen; + } crypt; + } u; +} ltc_rsa_op_parameters; +\end{verbatim} +\end{small} + +The \code{struct ltc\_rsa\_op\_parameters} holds all the potential arguments required for one of the four possible RSA operations. + + \mysection{RSA Key Encryption} Normally RSA is used to encrypt short symmetric keys which are then used in block ciphers to encrypt a message. To facilitate encrypting short keys the following functions have been provided. @@ -4718,30 +4620,24 @@ \subsection{RSA Key Size} in \textit{out} of length \textit{outlen} octets. The \textit{lparam} and \textit{lparamlen} are the same parameters you would pass to \index{pkcs\_1\_oaep\_encode()} pkcs\_1\_oaep\_encode(). -\subsection{Extended Encryption} +This API function is implemented as a macro and under the hood uses the API as described in Chapter \ref{rsa-encrypt-v2}. + +\subsection{Extended Encryption v2} +\label{rsa-encrypt-v2} As of v1.15, the library supports both v1.5 and v2.1 PKCS \#1 style paddings in these higher level functions. The following is the extended encryption function: -\index{rsa\_encrypt\_key\_ex()} +\index{rsa\_encrypt\_key\_v2()} \begin{verbatim} -int rsa_encrypt_key_ex( - const unsigned char *in, - unsigned long inlen, - unsigned char *out, - unsigned long *outlen, - const unsigned char *lparam, - unsigned long lparamlen, - prng_state *prng, - int prng_idx, - int mgf_hash, - int lparam_hash, - int padding, - rsa_key *key); +int rsa_encrypt_key_v2(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + ltc_rsa_op_parameters *opts, + const rsa_key *key); \end{verbatim} \index{LTC\_PKCS\_1\_OAEP} \index{LTC\_PKCS\_1\_V1\_5} -The parameters are all the same as for rsa\_encrypt\_key() except for the addition of the \textit{padding} parameter. It must be set to -\textbf{LTC\_PKCS\_1\_V1\_5} to perform v1.5 encryption, or set to \textbf{LTC\_PKCS\_1\_OAEP} to perform v2.1 encryption. +The parameters are all the same as for \code{rsa\_encrypt\_key()} except for the addition of the \textit{padding} parameter. It must be set to +\code{LTC\_PKCS\_1\_V1\_5} to perform v1.5 encryption, or set to \code{LTC\_PKCS\_1\_OAEP} to perform v2.1 encryption. When performing v1.5 encryption, the hash and lparam parameters are totally ignored and can be set to \textbf{NULL} or zero (respectively). @@ -4766,29 +4662,26 @@ \subsection{Extended Encryption} If the RSA decrypted data is not a valid OAEP packet then \textit{stat} is set to $0$. Otherwise, it is set to $1$. -\subsection{Extended Decryption} +This API function is implemented as a macro and under the hood uses the API as described in Chapter \ref{rsa-decrypt-v2}. + +\subsection{Extended Decryption v2} +\label{rsa-decrypt-v2} As of v1.15, the library supports both v1.5 and v2.1 PKCS \#1 style paddings in these higher level functions. The following is the extended decryption function: -\index{rsa\_decrypt\_key\_ex()} +\index{rsa\_decrypt\_key\_v2()} \begin{verbatim} -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 *stat, - rsa_key *key); +int rsa_decrypt_key_v2(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + ltc_rsa_op_parameters *opts, + int *stat, + const rsa_key *key); \end{verbatim} -Similar to the extended encryption, the new parameter \textit{padding} indicates which version of the PKCS \#1 standard to use. -It must be set to \textbf{LTC\_PKCS\_1\_V1\_5} to perform v1.5 decryption, or set to \textbf{LTC\_PKCS\_1\_OAEP} to perform v2.1 decryption. +Similar to the extended encryption, the parameter \textit{opts.padding} indicates which version of the PKCS \#1 standard to use. +It must be set to \code{LTC\_PKCS\_1\_V1\_5} to perform v1.5 decryption, or set to \code{LTC\_PKCS\_1\_OAEP} to perform v2.1 decryption. -When performing v1.5 decryption, the hash and lparam parameters are totally ignored and can be set to \textbf{NULL} or zero (respectively). +When performing v1.5 decryption, the \textit{opts.params.hash\_alg} and \textit{opts.u.crypt.lparam} parameters are totally ignored and can be set to \code{NULL} or zero (respectively). \mysection{RSA Signature Generation} @@ -4816,37 +4709,33 @@ \subsection{Extended Decryption} default value is between 8 and 16 octets. Strictly, it must be small than $modulus\_len - hLen - 2$ where \textit{modulus\_len} is the size of the RSA modulus (in octets), and \textit{hLen} is the length of the message digest produced by the chosen hash. -\subsection{Extended Signatures} +This API function is implemented as a macro and under the hood uses the API as described in Chapter \ref{rsa-sign-v2}. + +\subsection{Extended Signatures v2} +\label{rsa-sign-v2} As of v1.15, the library supports both v1.5 and v2.1 signatures. The extended signature generation function has the following prototype: -\index{rsa\_sign\_hash\_ex()} +\index{rsa\_sign\_hash\_v2()} \begin{verbatim} -int rsa_sign_hash_ex( - const unsigned char *in, - unsigned long inlen, - unsigned char *out, - unsigned long *outlen, - int padding, - prng_state *prng, - int prng_idx, - int hash_idx, - unsigned long saltlen, - rsa_key *key); +int rsa_sign_hash_v2(const unsigned char *hash, unsigned long hashlen, + unsigned char *sig, unsigned long *siglen, + ltc_rsa_op_parameters *opts, + const rsa_key *key); \end{verbatim} This will PKCS encode the message digest pointed to by \textit{in} of length \textit{inlen} octets. Next, the PKCS encoded hash will be RSA -\textit{signed} and the output stored in the buffer pointed to by \textit{out} of length \textit{outlen} octets. The \textit{padding} parameter -must be set to \textbf{LTC\_PKCS\_1\_V1\_5} to produce a v1.5 signature, otherwise, it must be set to \textbf{LTC\_PKCS\_1\_PSS} to produce a +\textit{signed} and the output stored in the buffer pointed to by \textit{out} of length \textit{outlen} octets. The \textit{opts.padding} parameter +must be set to \code{LTC\_PKCS\_1\_V1\_5} to produce a v1.5 signature, otherwise, it must be set to \code{LTC\_PKCS\_1\_PSS} to produce a v2.1 signature. \index{LTC\_PKCS\_1\_V1\_5\_NA1} As of v1.18.0, the library also supports v1.5 signature generation without ASN.1 encoding the signature which can be indicated by passing -\textbf{LTC\_PKCS\_1\_V1\_5\_NA1} as \textit{padding} parameter. This option has been introduced to provide compatibilty to SSL3.0 implementations +\code{LTC\_PKCS\_1\_V1\_5\_NA1} as \textit{opts.padding} parameter. This option has been introduced to provide compatibilty to SSL3.0 implementations which implemented this. -When generating a standard v1.5 signature the \textit{prng}, and \textit{prng\_idx} parameters are ignored. -When generating a v1.5 signature without ASN.1 decoding additionally the textit{hash\_idx} parameter is ignored. +When generating a standard v1.5 signature the \textit{opts.prng}, and \textit{opts.wprng} parameters are ignored. +When generating a v1.5 signature without ASN.1 decoding additionally the \textit{opts.params.hash\_alg} parameter is ignored. \mysection{RSA Signature Verification} \index{rsa\_verify\_hash()} @@ -4867,6 +4756,8 @@ \subsection{Extended Signatures} If the RSA decoded data is not a valid PSS message, or if the PSS decoded hash does not match the \textit{msghash} value, \textit{res} is set to $0$. Otherwise, if the function succeeds, and signature is valid \textit{res} is set to $1$. +This API function is implemented as a macro and under the hood uses the API as described in Chapter \ref{rsa-verify-v2}. + \subsection{RSA Signature Salt Length} The v2.1 signature algorithm requires a salt length to be able to properly @@ -4883,22 +4774,18 @@ \subsection{RSA Signature Salt Length} This function is provided to be able to use other lengths as well and to make sure at runtime that the RSA key can handle the desired salt length. -\subsection{Extended Verification} +\subsection{Extended Verification v2} +\label{rsa-verify-v2} As of v1.15, the library supports both v1.5 and v2.1 signature verification. The extended signature verification function has the following prototype: -\index{rsa\_verify\_hash\_ex()} +\index{rsa\_verify\_hash\_v2()} \begin{verbatim} -int rsa_verify_hash_ex( - const unsigned char *sig, - unsigned long siglen, - const unsigned char *hash, - unsigned long hashlen, - int padding, - int hash_idx, - unsigned long saltlen, - int *stat, - rsa_key *key); +int rsa_verify_hash_v2(const unsigned char *sig, unsigned long siglen, + const unsigned char *hash, unsigned long hashlen, + ltc_rsa_op_parameters *opts, + int *stat, + const rsa_key *key); \end{verbatim} This will RSA \textit{verify} the signature pointed to by \textit{sig} of length \textit{siglen} octets. Next, the RSA decoded data is PKCS decoded @@ -8973,7 +8860,7 @@ \subsection{Installation Directories} The file \textit{tomcrypt\_cfg.h} is what lets you control various high level macros which control the behaviour of the library. Build options are also stored in \textit{tomcrypt\_custom.h} which allow the enabling and disabling of various algorithms. -\subsubsection{ARGTYPE} +\subsection{ARGTYPE} This lets you control how the LTC\_ARGCHK macro will behave. The macro is used to check pointers inside the functions against NULL. There are four settings for ARGTYPE. When set to 0, it will have the default behaviour of printing a message to stderr and raising a SIGABRT signal. This is provided so all platforms that use LibTomCrypt can have an error that functions @@ -8982,7 +8869,7 @@ \subsubsection{ARGTYPE} if you handle signals on your own. When set to 3, it will resolve to a empty macro and no error checking will be performed. Finally, when set to 4, it will return CRYPT\_INVALID\_ARG to the caller. -\subsubsection{Endianness} +\subsection{Endianness} There are five macros related to endianness issues. For little endian platforms define, \textbf{ENDIAN\_LITTLE}. For big endian platforms define \textbf{ENDIAN\_BIG}. Similarly when the default word size of an \textit{unsigned long} is 32-bits define \textbf{ENDIAN\_32BITWORD} or define \textbf{ENDIAN\_64BITWORD} when its 64-bits. If you do not define any of them the library will automatically use \textbf{ENDIAN\_NEUTRAL} @@ -10356,7 +10243,9 @@ \subsection{RSA Functions} Since the function is given the entire RSA key (for private keys only) CRT is possible as prescribed in the PKCS \#1 v2.1 specification. -\mysection{Deprecated API functions} +\chapter{Deprecated API functions} + +\mysection{After v1.18.2} \subsection{Elliptic Curve Cryptography - $GF(p)$} @@ -10408,6 +10297,347 @@ \subsection{Elliptic Curve Cryptography - $GF(p)$} These two ECC verify functions have been deprecated in favor of \code{ecc\_verify\_hash\_v2()}. Please check Chapter \ref{ecc-verify} for details. +\subsection{PKCS \#1 Padding} +PKCS \#1 v1.5 padding is so simple that both signature and encryption padding are performed by the same function. Note: the +signature padding does \textbf{not} include the ASN.1 padding required. That is performed by the rsa\_sign\_hash\_ex() function +documented later on in this chapter. + +\subsection{PKCS \#1 v1.5 Encoding} +The following function performs PKCS \#1 v1.5 padding: +\index{pkcs\_1\_v1\_5\_encode()} +\begin{verbatim} +int pkcs_1_v1_5_encode( + const unsigned char *msg, + unsigned long msglen, + int block_type, + unsigned long modulus_bitlen, + prng_state *prng, + int prng_idx, + unsigned char *out, + unsigned long *outlen); +\end{verbatim} + +This will encode the message pointed to by \textit{msg} of length \textit{msglen} octets. The \textit{block\_type} parameter must be set to +\textbf{LTC\_PKCS\_1\_EME} to perform encryption padding. It must be set to \textbf{LTC\_PKCS\_1\_EMSA} to perform signature padding. The \textit{modulus\_bitlen} +parameter indicates the length of the modulus in bits. The padded data is stored in \textit{out} with a length of \textit{outlen} octets. The output will not be +longer than the modulus which helps allocate the correct output buffer size. + +Only encryption padding requires a PRNG. When performing signature padding the \textit{prng\_idx} parameter may be left to zero as it is not checked for validity. + +\subsection{PKCS \#1 v1.5 Decoding} +The following function performs PKCS \#1 v1.5 de--padding: +\index{pkcs\_1\_v1\_5\_decode()} +\begin{verbatim} +int pkcs_1_v1_5_decode( + const unsigned char *msg, + unsigned long msglen, + int block_type, + unsigned long modulus_bitlen, + unsigned char *out, + unsigned long *outlen, + int *is_valid); +\end{verbatim} +\index{LTC\_PKCS\_1\_EME} \index{LTC\_PKCS\_1\_EMSA} +This will remove the PKCS padding data pointed to by \textit{msg} of length \textit{msglen}. The decoded data is stored in \textit{out} of length +\textit{outlen}. If the padding is valid, a 1 is stored in \textit{is\_valid}, otherwise, a 0 is stored. The \textit{block\_type} parameter must be set to either +\textbf{LTC\_PKCS\_1\_EME} or \textbf{LTC\_PKCS\_1\_EMSA} depending on whether encryption or signature padding is being removed. + +\mysection{PKCS \#1 v2.1 Encryption} +PKCS \#1 RSA Encryption amounts to OAEP padding of the input message followed by the modular exponentiation. As far as this portion of +the library is concerned we are only dealing with the OAEP padding of the message. + +\subsection{OAEP Encoding} + +The following function performs PKCS \#1 v2.1 encryption padding: + +\index{pkcs\_1\_oaep\_encode()} +\begin{alltt} +int pkcs_1_oaep_encode( + const unsigned char *msg, + unsigned long msglen, + const unsigned char *lparam, + unsigned long lparamlen, + unsigned long modulus_bitlen, + prng_state *prng, + int prng_idx, + int mgf_hash, + int lparam_hash, + unsigned char *out, + unsigned long *outlen); +\end{alltt} + +This accepts \textit{msg} as input of length \textit{msglen} which will be OAEP padded. The \textit{lparam} variable is an additional system specific +tag that can be applied to the encoding. This is useful to identify which system encoded the message. If no variance is desired then +\textit{lparam} can be set to \textbf{NULL}. + +OAEP encoding requires the length of the modulus in bits in order to calculate the size of the output. This is passed as the parameter +\textit{modulus\_bitlen}. \textit{mgf\_hash} is the index into the hash descriptor table of the hash desired for the mask generation function (MGF). +\textit{lparam\_hash} is the index into the hash descriptor table of the hash desired for the \textit{lparam}. This value can also be set to $-1$ +to indicate usage of the same algorithm than for the MGF. PKCS \#1 allows any hash to be +used but both the encoder and decoder must use the same hash in order for this to succeed. The size of hash output affects the maximum + sized input message. \textit{prng\_idx} and \textit{prng} are the random number generator arguments required to randomize the padding process. +The padded message is stored in \textit{out} along with the length in \textit{outlen}. + +If $h$ is the length of the hash and $m$ the length of the modulus (both in octets) then the maximum payload for \textit{msg} is +$m - 2h - 2$. For example, with a $1024$--bit RSA key and SHA--1 as the hash the maximum payload is $86$ bytes. + +Note that when the message is padded it still has not been RSA encrypted. You must pass the output of this function to +rsa\_exptmod() to encrypt it. + +\subsection{OAEP Decoding} + +\index{pkcs\_1\_oaep\_decode()} +\begin{alltt} +int pkcs_1_oaep_decode( + const unsigned char *msg, + unsigned long msglen, + const unsigned char *lparam, + unsigned long lparamlen, + unsigned long modulus_bitlen, + int mgf_hash, + int lparam_hash, + unsigned char *out, + unsigned long *outlen, + int *res); +\end{alltt} + +This function decodes an OAEP encoded message and outputs the original message that was passed to the OAEP encoder. \textit{msg} is the +output of pkcs\_1\_oaep\_encode() of length \textit{msglen}. \textit{lparam} is the same system variable passed to the OAEP encoder. If it does not +match what was used during encoding this function will not decode the packet. \textit{modulus\_bitlen} is the size of the RSA modulus in bits +and must match what was used during encoding. Similarly the \textit{mgf\_hash} and \textit{lparam\_hash} indexes into the hash descriptor table must +match what was used during encoding. + +If the function succeeds it decodes the OAEP encoded message into \textit{out} of length \textit{outlen} and stores a +$1$ in \textit{res}. If the packet is invalid it stores $0$ in \textit{res} and if the function fails for another reason +it returns an error code. + +\mysection{PKCS \#1 Digital Signatures} + +\subsection{PSS Encoding} +PSS encoding is the second half of the PKCS \#1 standard which is padding to be applied to messages that are signed. + +\index{pkcs\_1\_pss\_encode()} +\begin{alltt} +int pkcs_1_pss_encode( + const unsigned char *msghash, + unsigned long msghashlen, + unsigned long saltlen, + prng_state *prng, + int prng_idx, + int hash_idx, + unsigned long modulus_bitlen, + unsigned char *out, + unsigned long *outlen); +\end{alltt} + +This function assumes the message to be PSS encoded has previously been hashed. The input hash \textit{msghash} is of length +\textit{msghashlen}. PSS allows a variable length random salt (it can be zero length) to be introduced in the signature process. +\textit{hash\_idx} is the index into the hash descriptor table of the hash to use. \textit{prng\_idx} and \textit{prng} are the random +number generator information required for the salt. + +Similar to OAEP encoding \textit{modulus\_bitlen} is the size of the RSA modulus (in bits). It limits the size of the salt. If $m$ is the length +of the modulus $h$ the length of the hash output (in octets) then there can be $m - h - 2$ bytes of salt. + +This function does not actually sign the data it merely pads the hash of a message so that it can be processed by rsa\_exptmod(). + +\subsection{PSS Decoding} + +To decode a PSS encoded signature block you have to use the following. + +\index{pkcs\_1\_pss\_decode()} +\begin{alltt} +int pkcs_1_pss_decode( + const unsigned char *msghash, + unsigned long msghashlen, + const unsigned char *sig, + unsigned long siglen, + unsigned long saltlen, + int hash_idx, + unsigned long modulus_bitlen, + int *res); +\end{alltt} +This will decode the PSS encoded message in \textit{sig} of length \textit{siglen} and compare it to values in \textit{msghash} of length +\textit{msghashlen}. If the block is a valid PSS block and the decoded hash equals the hash supplied \textit{res} is set to non--zero. Otherwise, +it is set to zero. The rest of the parameters are as in the PSS encode call. + +It's important to use the same \textit{saltlen} and hash for both encoding and decoding as otherwise the procedure will not work. + +\mysection{RSA Key Encryption} + +\index{rsa\_encrypt\_key()} +\begin{verbatim} +int rsa_encrypt_key( + const unsigned char *in, + unsigned long inlen, + unsigned char *out, + unsigned long *outlen, + const unsigned char *lparam, + unsigned long lparamlen, + prng_state *prng, + int prng_idx, + int hash_idx, + rsa_key *key); +\end{verbatim} +This function will OAEP pad \textit{in} of length \textit{inlen} bytes, RSA encrypt it, and store the ciphertext +in \textit{out} of length \textit{outlen} octets. The \textit{lparam} and \textit{lparamlen} are the same parameters you would pass +to \index{pkcs\_1\_oaep\_encode()} pkcs\_1\_oaep\_encode(). + +\subsection{Extended Encryption} +As of v1.15, the library supports both v1.5 and v2.1 PKCS \#1 style paddings in these higher level functions. The following is the extended +encryption function: + +\index{rsa\_encrypt\_key\_ex()} +\begin{verbatim} +int rsa_encrypt_key_ex( + const unsigned char *in, + unsigned long inlen, + unsigned char *out, + unsigned long *outlen, + const unsigned char *lparam, + unsigned long lparamlen, + prng_state *prng, + int prng_idx, + int mgf_hash, + int lparam_hash, + int padding, + rsa_key *key); +\end{verbatim} + +\mysection{RSA Key Decryption} +\index{rsa\_decrypt\_key()} +\begin{verbatim} +int rsa_decrypt_key( + const unsigned char *in, + unsigned long inlen, + unsigned char *out, + unsigned long *outlen, + const unsigned char *lparam, + unsigned long lparamlen, + int mgf_hash, + int lparam_hash, + int *stat, + rsa_key *key); +\end{verbatim} +This function will RSA decrypt \textit{in} of length \textit{inlen} then OAEP de-pad the resulting data and store it in +\textit{out} of length \textit{outlen}. The \textit{lparam} and \textit{lparamlen} are the same parameters you would pass +to pkcs\_1\_oaep\_decode(). + +If the RSA decrypted data is not a valid OAEP packet then \textit{stat} is set to $0$. Otherwise, it is set to $1$. + +\subsection{Extended Decryption} +As of v1.15, the library supports both v1.5 and v2.1 PKCS \#1 style paddings in these higher level functions. The following is the extended +decryption function: + +\index{rsa\_decrypt\_key\_ex()} +\begin{verbatim} +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 *stat, + rsa_key *key); +\end{verbatim} + +\mysection{RSA Signature Generation} +Similar to RSA key encryption RSA is also used to \textit{digitally sign} message digests (hashes). To facilitate this +process the following functions have been provided. + +\index{rsa\_sign\_hash()} +\begin{verbatim} +int rsa_sign_hash(const unsigned char *in, + unsigned long inlen, + unsigned char *out, + unsigned long *outlen, + prng_state *prng, + int prng_idx, + int hash_idx, + unsigned long saltlen, + rsa_key *key); +\end{verbatim} + +This will PSS encode the message digest pointed to by \textit{in} of length \textit{inlen} octets. Next, the PSS encoded hash will be RSA +\textit{signed} and the output stored in the buffer pointed to by \textit{out} of length \textit{outlen} octets. + +The \textit{hash\_idx} parameter indicates which hash will be used to create the PSS encoding. It should be the same as the hash used to +hash the message being signed. The \textit{saltlen} parameter indicates the length of the desired salt, and should typically be small. A good +default value is between 8 and 16 octets. Strictly, it must be small than $modulus\_len - hLen - 2$ where \textit{modulus\_len} is the size of +the RSA modulus (in octets), and \textit{hLen} is the length of the message digest produced by the chosen hash. + +\subsection{Extended Signatures} + +As of v1.15, the library supports both v1.5 and v2.1 signatures. The extended signature generation function has the following prototype: + +\index{rsa\_sign\_hash\_ex()} +\begin{verbatim} +int rsa_sign_hash_ex( + const unsigned char *in, + unsigned long inlen, + unsigned char *out, + unsigned long *outlen, + int padding, + prng_state *prng, + int prng_idx, + int hash_idx, + unsigned long saltlen, + rsa_key *key); +\end{verbatim} + +This will PKCS encode the message digest pointed to by \textit{in} of length \textit{inlen} octets. Next, the PKCS encoded hash will be RSA +\textit{signed} and the output stored in the buffer pointed to by \textit{out} of length \textit{outlen} octets. The \textit{padding} parameter +must be set to \textbf{LTC\_PKCS\_1\_V1\_5} to produce a v1.5 signature, otherwise, it must be set to \textbf{LTC\_PKCS\_1\_PSS} to produce a +v2.1 signature. + +\index{LTC\_PKCS\_1\_V1\_5\_NA1} +As of v1.18.0, the library also supports v1.5 signature generation without ASN.1 encoding the signature which can be indicated by passing +\textbf{LTC\_PKCS\_1\_V1\_5\_NA1} as \textit{padding} parameter. This option has been introduced to provide compatibilty to SSL3.0 implementations +which implemented this. + +When generating a standard v1.5 signature the \textit{prng}, and \textit{prng\_idx} parameters are ignored. +When generating a v1.5 signature without ASN.1 decoding additionally the textit{hash\_idx} parameter is ignored. + +\mysection{RSA Signature Verification} +\index{rsa\_verify\_hash()} +\begin{verbatim} +int rsa_verify_hash(const unsigned char *sig, + unsigned long siglen, + const unsigned char *msghash, + unsigned long msghashlen, + int hash_idx, + unsigned long saltlen, + int *stat, + rsa_key *key); +\end{verbatim} + +This will RSA \textit{verify} the signature pointed to by \textit{sig} of length \textit{siglen} octets. Next, the RSA decoded data is PSS decoded +and the extracted hash is compared against the message digest pointed to by \textit{msghash} of length \textit{msghashlen} octets. + +If the RSA decoded data is not a valid PSS message, or if the PSS decoded hash does not match the \textit{msghash} +value, \textit{res} is set to $0$. Otherwise, if the function succeeds, and signature is valid \textit{res} is set to $1$. + +\subsection{Extended Verification} + +As of v1.15, the library supports both v1.5 and v2.1 signature verification. The extended signature verification function has the following prototype: + +\index{rsa\_verify\_hash\_ex()} +\begin{verbatim} +int rsa_verify_hash_ex( + const unsigned char *sig, + unsigned long siglen, + const unsigned char *hash, + unsigned long hashlen, + int padding, + int hash_idx, + unsigned long saltlen, + int *stat, + rsa_key *key); +\end{verbatim} + + \clearpage \addcontentsline{toc}{chapter}{Index} \printindex diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index d517b2fe4..b3f2e1887 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -70,7 +70,10 @@ typedef struct ltc_rsa_parameters { /** saltLength is only defined for PSS * If saltLength == 0 -> OAEP, else -> PSS */ unsigned long saltlen; - /** hash and MGF hash algorithms */ + /** lparam hash for OAEP + * resp. + * signature hash for PSS + * and MGF hash algorithms */ const char *hash_alg, *mgf1_hash_alg; } ltc_rsa_parameters; @@ -109,52 +112,133 @@ int rsa_exptmod(const unsigned char *in, unsigned long inlen, void rsa_free(rsa_key *key); -/* These use PKCS #1 v2.0 padding */ -#define rsa_encrypt_key(in, inlen, out, outlen, lparam, lparamlen, prng, prng_idx, hash_idx, key) \ - rsa_encrypt_key_ex(in, inlen, out, outlen, lparam, lparamlen, prng, prng_idx, hash_idx, -1, 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, -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, hash_idx, saltlen, key) - -#define rsa_verify_hash(sig, siglen, hash, hashlen, hash_idx, saltlen, stat, key) \ - rsa_verify_hash_ex(sig, siglen, hash, hashlen, LTC_PKCS_1_PSS, hash_idx, hash_idx, saltlen, stat, key) - -#define rsa_sign_saltlen_get_max(hash_idx, key) \ - rsa_sign_saltlen_get_max_ex(LTC_PKCS_1_PSS, hash_idx, key) +typedef struct ltc_rsa_op_parameters { + /* The RSA API will set the `pss_oaep` field for you, + * depending on the value of `padding`. */ + ltc_rsa_parameters params; + /* The padding type */ + int padding; + /* The PRNG to use. + * Only required for signing and encryption. */ + int wprng; + prng_state *prng; + /* Operation-specific parameters */ + union { + struct { + const unsigned char *lparam; + unsigned long lparamlen; + } crypt; + /* let's make space for potential future extensions */ + ulong64 dummy[8]; + } u; +} ltc_rsa_op_parameters; + +int rsa_encrypt_key_v2(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + ltc_rsa_op_parameters *opts, + const rsa_key *key); + +int rsa_decrypt_key_v2(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + ltc_rsa_op_parameters *opts, + int *stat, + const rsa_key *key); + +int rsa_sign_hash_v2(const unsigned char *hash, unsigned long hashlen, + unsigned char *sig, unsigned long *siglen, + ltc_rsa_op_parameters *opts, + const rsa_key *key); + +int rsa_verify_hash_v2(const unsigned char *sig, unsigned long siglen, + const unsigned char *hash, unsigned long hashlen, + ltc_rsa_op_parameters *opts, + int *stat, + const rsa_key *key); +/* These use PKCS #1 v2.0 padding */ +#define ltc_rsa_encrypt_key(in, inlen, out, outlen, lp, lplen, prng_, prng_idx, hash_idx, key) \ + rsa_encrypt_key_v2(in, inlen, out, outlen, \ + &(ltc_rsa_op_parameters){ \ + .u.crypt.lparam = lp, \ + .u.crypt.lparamlen = lplen,\ + .prng = prng_, \ + .wprng = prng_idx, \ + .params.mgf1_hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \ + .params.hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \ + .padding = LTC_PKCS_1_OAEP, \ + }, key) + +#define ltc_rsa_decrypt_key(in, inlen, out, outlen, lp, lplen, hash_idx, stat, key) \ + rsa_decrypt_key_v2(in, inlen, out, outlen, \ + &(ltc_rsa_op_parameters){ \ + .u.crypt.lparam = lp, \ + .u.crypt.lparamlen = lplen,\ + .params.mgf1_hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \ + .params.hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \ + .padding = LTC_PKCS_1_OAEP, \ + }, stat, key) + +#define ltc_rsa_sign_hash(hash, hashlen, sig, siglen, prng_, prng_idx, hash_idx, saltlen_, key) \ + rsa_sign_hash_v2(hash, hashlen, sig, siglen, \ + &(ltc_rsa_op_parameters){ \ + .prng = prng_, \ + .wprng = prng_idx, \ + .params.mgf1_hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \ + .params.hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \ + .params.saltlen = saltlen_, \ + .padding = LTC_PKCS_1_PSS, \ + }, key) + +#define ltc_rsa_verify_hash(sig, siglen, hash, hashlen, hash_idx, saltlen_, stat, key) \ + rsa_verify_hash_v2(sig, siglen, hash, hashlen, \ + &(ltc_rsa_op_parameters){ \ + .params.mgf1_hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \ + .params.hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \ + .params.saltlen = saltlen_, \ + .padding = LTC_PKCS_1_PSS, \ + }, stat, key) + +/* If you used those in v1, they're still working */ +#define rsa_encrypt_key ltc_rsa_encrypt_key +#define rsa_decrypt_key ltc_rsa_decrypt_key +#define rsa_sign_hash ltc_rsa_sign_hash +#define rsa_verify_hash ltc_rsa_verify_hash + +#ifndef LTC_NO_DEPRECATED_APIS /* These can be switched between PKCS #1 v2.x and PKCS #1 v1.5 paddings */ +LTC_DEPRECATED(rsa_encrypt_key_v2) int rsa_encrypt_key_ex(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, const unsigned char *lparam, unsigned long lparamlen, prng_state *prng, int prng_idx, - int mgf_hash, int lparam_hash, - int padding, + int hash_idx, int padding, const rsa_key *key); +LTC_DEPRECATED(rsa_decrypt_key_v2) 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 mgf_hash, int lparam_hash, - int padding, + int hash_idx, int padding, int *stat, const rsa_key *key); +LTC_DEPRECATED(rsa_sign_hash_v2) int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, int padding, prng_state *prng, int prng_idx, - int hash_idx, int mgf_hash_idx, - unsigned long saltlen, + int hash_idx, unsigned long saltlen, const rsa_key *key); +LTC_DEPRECATED(rsa_verify_hash_v2) int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen, const unsigned char *hash, unsigned long hashlen, int padding, - int hash_idx, int mgf_hash_idx, - unsigned long saltlen, + int hash_idx, unsigned long saltlen, int *stat, const rsa_key *key); +#endif /* LTC_NO_DEPRECATED_APIS */ + +#define rsa_sign_saltlen_get_max(hash_idx, key) \ + rsa_sign_saltlen_get_max_ex(LTC_PKCS_1_PSS, hash_idx, key) int rsa_sign_saltlen_get_max_ex(int padding, int hash_idx, const rsa_key *key); diff --git a/src/headers/tomcrypt_pkcs.h b/src/headers/tomcrypt_pkcs.h index cca013c07..f3037f147 100644 --- a/src/headers/tomcrypt_pkcs.h +++ b/src/headers/tomcrypt_pkcs.h @@ -20,14 +20,19 @@ enum ltc_pkcs_1_paddings LTC_PKCS_1_V1_5_NA1 = 4 /* PKCS #1 v1.5 padding - No ASN.1 (\sa ltc_pkcs_1_v1_5_blocks) */ }; +#ifndef LTC_NO_DEPRECATED_APIS +LTC_DEPRECATED(nothing. API will be internal) int pkcs_1_mgf1( int hash_idx, const unsigned char *seed, unsigned long seedlen, unsigned char *mask, unsigned long masklen); +LTC_DEPRECATED(nothing. API will be removed) int pkcs_1_i2osp(void *n, unsigned long modulus_len, unsigned char *out); +LTC_DEPRECATED(nothing. API will be removed) int pkcs_1_os2ip(void *n, unsigned char *in, unsigned long inlen); /* *** v1.5 padding */ +LTC_DEPRECATED(nothing. API will be internal) int pkcs_1_v1_5_encode(const unsigned char *msg, unsigned long msglen, int block_type, @@ -37,6 +42,7 @@ int pkcs_1_v1_5_encode(const unsigned char *msg, unsigned char *out, unsigned long *outlen); +LTC_DEPRECATED(nothing. API will be internal) int pkcs_1_v1_5_decode(const unsigned char *msg, unsigned long msglen, int block_type, @@ -46,30 +52,33 @@ int pkcs_1_v1_5_decode(const unsigned char *msg, int *is_valid); /* *** v2.1 padding */ +LTC_DEPRECATED(nothing. API will be internal) int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, const unsigned char *lparam, unsigned long lparamlen, unsigned long modulus_bitlen, prng_state *prng, - int prng_idx, - int mgf_hash, int lparam_hash, + int prng_idx, int hash_idx, unsigned char *out, unsigned long *outlen); +LTC_DEPRECATED(nothing. API will be internal) int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, const unsigned char *lparam, unsigned long lparamlen, - unsigned long modulus_bitlen, - int mgf_hash, int lparam_hash, + unsigned long modulus_bitlen, int hash_idx, unsigned char *out, unsigned long *outlen, int *res); +LTC_DEPRECATED(nothing. API will be internal) int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, unsigned long saltlen, prng_state *prng, int prng_idx, int hash_idx, unsigned long modulus_bitlen, unsigned char *out, unsigned long *outlen); +LTC_DEPRECATED(nothing. API will be internal) int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, const unsigned char *sig, unsigned long siglen, unsigned long saltlen, int hash_idx, unsigned long modulus_bitlen, int *res); +#endif /* LTC_NO_DEPRECATED_APIS */ #endif /* LTC_PKCS_1 */ diff --git a/src/headers/tomcrypt_private.h b/src/headers/tomcrypt_private.h index 3962ccaa8..ddbbb89a0 100644 --- a/src/headers/tomcrypt_private.h +++ b/src/headers/tomcrypt_private.h @@ -446,13 +446,51 @@ int pk_oid_cmp_with_ulong(const char *o1, const unsigned long *o2, unsigned long /* ---- DH Routines ---- */ #ifdef LTC_MRSA +/* Receiving side, i.e. Decrypt or Verify */ +#define LTC_RSA_OP_RECV 0x00u +/* Sending side, i.e. Encrypt or Sign */ +#define LTC_RSA_OP_SEND 0x01u +/* En- or Decrypt */ +#define LTC_RSA_OP_CRYPT 0x00u +/* Sign or Verify */ +#define LTC_RSA_OP_SIGN 0x02u +/* All combinations of the above + * but only the PKCS#1 de-/encoding part */ +#define LTC_RSA_OP_PKCS1 0x04u + typedef enum ltc_rsa_op { - LTC_RSA_CRYPT, - LTC_RSA_SIGN + LTC_RSA_DECRYPT = LTC_RSA_OP_CRYPT | LTC_RSA_OP_RECV, + LTC_RSA_ENCRYPT = LTC_RSA_OP_CRYPT | LTC_RSA_OP_SEND, + LTC_RSA_VERIFY = LTC_RSA_OP_SIGN | LTC_RSA_OP_RECV, + LTC_RSA_SIGN = LTC_RSA_OP_SIGN | LTC_RSA_OP_SEND, + LTC_PKCS1_ENCRYPT = LTC_RSA_OP_PKCS1 | LTC_RSA_ENCRYPT, + LTC_PKCS1_DECRYPT = LTC_RSA_OP_PKCS1 | LTC_RSA_DECRYPT, + LTC_PKCS1_SIGN = LTC_RSA_OP_PKCS1 | LTC_RSA_SIGN, + LTC_PKCS1_VERIFY = LTC_RSA_OP_PKCS1 | LTC_RSA_VERIFY, } ltc_rsa_op; + +typedef struct ltc_rsa_op_check { + const rsa_key *key; + ltc_rsa_op_parameters *params; + int hash_alg, mgf1_hash_alg; +} ltc_rsa_op_checked; + +#define ltc_rsa_op_checked_init(k, p) { \ + .key = k, \ + .params = p, \ + .hash_alg = -1, \ + .mgf1_hash_alg = -1, \ +} + +#define ltc_pkcs1_op_checked_init(p) ltc_rsa_op_checked_init(NULL, p) + int rsa_init(rsa_key *key); void rsa_shrink_key(rsa_key *key); -int rsa_key_valid_op(const rsa_key *key, ltc_rsa_op op, int padding, int hash_idx); +int rsa_args_to_op_params(const unsigned char *lparam, unsigned long lparamlen, + prng_state *prng, int prng_idx, int hash_idx, + int padding, unsigned long saltlen, + ltc_rsa_op_parameters *params); +int rsa_key_valid_op(ltc_rsa_op op, ltc_rsa_op_checked *params); int rsa_params_equal(const ltc_rsa_parameters *a, const ltc_rsa_parameters *b); int rsa_make_key_bn_e(prng_state *prng, int wprng, int size, void *e, rsa_key *key); /* used by op-tee */ @@ -766,19 +804,43 @@ int pk_oid_cmp_with_asn1(const char *o1, const ltc_asn1_list *o2); /* tomcrypt_pkcs.h */ #ifdef LTC_PKCS_1 - -int pkcs_1_pss_encode_mgf1(const unsigned char *msghash, unsigned long msghashlen, - unsigned long saltlen, - prng_state *prng, int prng_idx, - int hash_idx, int mgf_hash_idx, - unsigned long modulus_bitlen, - unsigned char *out, unsigned long *outlen); -int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashlen, - const unsigned char *sig, unsigned long siglen, - unsigned long saltlen, - int hash_idx, int mgf_hash_idx, - unsigned long modulus_bitlen, int *res); - +int ltc_pkcs_1_mgf1(int hash_idx, + const unsigned char *seed, unsigned long seedlen, + unsigned char *mask, unsigned long masklen); + +int ltc_pkcs_1_pss_encode_mgf1(const unsigned char *msghash, unsigned long msghashlen, + ltc_rsa_op_parameters *params, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen); +int ltc_pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashlen, + const unsigned char *sig, unsigned long siglen, + ltc_rsa_op_parameters *params, + unsigned long modulus_bitlen, int *res); +int ltc_pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, + ltc_rsa_op_parameters *params, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen); +int ltc_pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, + ltc_rsa_op_parameters *params, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen, + int *res); + +int ltc_pkcs_1_v1_5_encode(const unsigned char *msg, + unsigned long msglen, + int block_type, + unsigned long modulus_bitlen, + prng_state *prng, + int prng_idx, + unsigned char *out, + unsigned long *outlen); +int ltc_pkcs_1_v1_5_decode(const unsigned char *msg, + unsigned long msglen, + int block_type, + unsigned long modulus_bitlen, + unsigned char *out, + unsigned long *outlen, + int *is_valid); #endif /* LTC_PKCS_1 */ #ifdef LTC_PKCS_8 diff --git a/src/misc/deprecated.c b/src/misc/deprecated.c index ae434eb25..23de81b01 100644 --- a/src/misc/deprecated.c +++ b/src/misc/deprecated.c @@ -79,10 +79,367 @@ int ecc_verify_hash_rfc7518(const unsigned char *sig, unsigned long siglen, } #endif /* LTC_MECC */ +#ifdef LTC_MRSA +/** + (PKCS #1 v2.0) OAEP pad then encrypt + @param in The plaintext + @param inlen The length of the plaintext (octets) + @param out [out] The ciphertext + @param outlen [in/out] The max size and resulting size of the ciphertext + @param lparam The system "lparam" for the encryption + @param lparamlen The length of lparam (octets) + @param prng An active PRNG + @param prng_idx The index of the desired prng + @param hash_idx The index of the desired hash + @param padding Type of padding (LTC_PKCS_1_OAEP or LTC_PKCS_1_V1_5) + @param key The RSA key to encrypt to + @return CRYPT_OK if successful +*/ +int rsa_encrypt_key_ex(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + const unsigned char *lparam, unsigned long lparamlen, + prng_state *prng, int prng_idx, + int hash_idx, int padding, + const rsa_key *key) +{ + int err; + ltc_rsa_op_parameters params; + if ((err = rsa_args_to_op_params(lparam, lparamlen, + prng, prng_idx, + hash_idx, + padding, 0, + ¶ms)) != CRYPT_OK) { + return err; + } + return rsa_encrypt_key_v2(in, inlen, out, outlen, ¶ms, key); +} + +/** + PKCS #1 decrypt then v1.5 or OAEP depad + @param in The ciphertext + @param inlen The length of the ciphertext (octets) + @param out [out] The plaintext + @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 hash algorithm used + @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 + @return CRYPT_OK if succcessul (even if invalid) +*/ +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 *stat, const rsa_key *key) +{ + int err; + ltc_rsa_op_parameters params; + if ((err = rsa_args_to_op_params(lparam, lparamlen, + NULL, -1, + hash_idx, + padding, 0, + ¶ms)) != CRYPT_OK) { + return err; + } + return rsa_decrypt_key_v2(in, inlen, out, outlen, ¶ms, stat, key); +} + +/** + PKCS #1 pad then sign + @param in The hash to sign + @param inlen The length of the hash to sign (octets) + @param out [out] The signature + @param outlen [in/out] The max size and resulting size of the signature + @param padding Type of padding (LTC_PKCS_1_PSS, LTC_PKCS_1_V1_5 or LTC_PKCS_1_V1_5_NA1) + @param prng An active PRNG state + @param prng_idx The index of the PRNG desired + @param hash_idx The index of the hash desired + @param saltlen The length of the salt desired (octets) + @param key The private RSA key to use + @return CRYPT_OK if successful +*/ +int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + int padding, + prng_state *prng, int prng_idx, + int hash_idx, unsigned long saltlen, + const rsa_key *key) +{ + int err; + ltc_rsa_op_parameters params; + if ((err = rsa_args_to_op_params(NULL, 0, + prng, prng_idx, + hash_idx, + padding, saltlen, + ¶ms)) != CRYPT_OK) { + return err; + } + return rsa_sign_hash_v2(in, inlen, out, outlen, ¶ms, key); +} + +/** + PKCS #1 de-sign then v1.5 or PSS depad + @param sig The signature data + @param siglen The length of the signature data (octets) + @param hash The hash of the message that was signed + @param hashlen The length of the hash of the message that was signed (octets) + @param padding Type of padding (LTC_PKCS_1_PSS, LTC_PKCS_1_V1_5 or LTC_PKCS_1_V1_5_NA1) + @param hash_idx The index of the desired hash + @param saltlen The length of the salt used during signature + @param stat [out] The result of the signature comparison, 1==valid, 0==invalid + @param key The public RSA key corresponding to the key that performed the signature + @return CRYPT_OK on success (even if the signature is invalid) +*/ +int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen, + const unsigned char *hash, unsigned long hashlen, + int padding, + int hash_idx, unsigned long saltlen, + int *stat, const rsa_key *key) +{ + int err; + ltc_rsa_op_parameters params; + if ((err = rsa_args_to_op_params(NULL, 0, + NULL, -1, + hash_idx, + padding, saltlen, + ¶ms)) != CRYPT_OK) { + return err; + } + return rsa_verify_hash_v2(sig, siglen, hash, hashlen, ¶ms, stat, key); +} + +int rsa_args_to_op_params(const unsigned char *lparam, unsigned long lparamlen, + prng_state *prng, int prng_idx, int hash_idx, + int padding, unsigned long saltlen, + ltc_rsa_op_parameters *params) +{ + int err; + ltc_rsa_op_parameters p = { + .u.crypt.lparam = lparam, + .u.crypt.lparamlen = lparamlen, + .prng = prng, + .wprng = prng_idx, + .padding = padding, + .params.saltlen = saltlen, + }; + if ((err = hash_is_valid(hash_idx)) == CRYPT_OK) { + if (hash_descriptor[hash_idx].name == NULL) { + return CRYPT_INVALID_HASH; + } + p.params.hash_alg = hash_descriptor[hash_idx].name; + p.params.mgf1_hash_alg = p.params.hash_alg; + *params = p; + } else if (padding == LTC_PKCS_1_V1_5 || padding == LTC_PKCS_1_V1_5_NA1) { + /* PKCS#1 1.5 does not necessarily require a hash */ + err = CRYPT_OK; + *params = p; + } + return err; +} +#endif /* LTC_MRSA */ + + +#ifdef LTC_PKCS_1 +/** + Perform PKCS #1 MGF1 (internal) + @param hash_idx The index of the hash desired + @param seed The seed for MGF1 + @param seedlen The length of the seed + @param mask [out] The destination + @param masklen The length of the mask desired + @return CRYPT_OK if successful +*/ +int pkcs_1_mgf1(int hash_idx, + const unsigned char *seed, unsigned long seedlen, + unsigned char *mask, unsigned long masklen) +{ + return ltc_pkcs_1_mgf1(hash_idx, seed, seedlen, mask, masklen); +} +/** + PKCS #1 v2.00 OAEP encode + @param msg The data to encode + @param msglen The length of the data to encode (octets) + @param lparam A session or system parameter (can be NULL) + @param lparamlen The length of the lparam data + @param modulus_bitlen The bit length of the RSA modulus + @param prng An active PRNG state + @param prng_idx The index of the PRNG desired + @param hash_idx The index of the hash desired + @param out [out] The destination for the encoded data + @param outlen [in/out] The max size and resulting size of the encoded data + @return CRYPT_OK if successful +*/ +int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, + const unsigned char *lparam, unsigned long lparamlen, + unsigned long modulus_bitlen, prng_state *prng, + int prng_idx, int hash_idx, + unsigned char *out, unsigned long *outlen) +{ + int err; + ltc_rsa_op_parameters params; + if ((err = rsa_args_to_op_params(lparam, lparamlen, + prng, prng_idx, + hash_idx, + LTC_PKCS_1_OAEP, 0, + ¶ms)) != CRYPT_OK) { + return err; + } + return ltc_pkcs_1_oaep_encode(msg, msglen, ¶ms, modulus_bitlen, out, outlen); +} + +/** + PKCS #1 v2.00 OAEP decode + @param msg The encoded data to decode + @param msglen The length of the encoded data (octets) + @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 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 + @return CRYPT_OK if successful +*/ +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 char *out, unsigned long *outlen, + int *res) +{ + int err; + ltc_rsa_op_parameters params; + if ((err = rsa_args_to_op_params(lparam, lparamlen, + NULL, -1, + hash_idx, + LTC_PKCS_1_OAEP, 0, + ¶ms)) != CRYPT_OK) { + return err; + } + return ltc_pkcs_1_oaep_decode(msg, msglen, ¶ms, modulus_bitlen, out, outlen, res); +} + +/** + PKCS #1 v2.00 Signature Encoding using MGF1 and both hashes are the same + @param msghash The hash to encode + @param msghashlen The length of the hash (octets) + @param saltlen The length of the salt desired (octets) + @param prng An active PRNG context + @param prng_idx The index of the PRNG desired + @param hash_idx The index of the hash desired + @param modulus_bitlen The bit length of the RSA modulus + @param out [out] The destination of the encoding + @param outlen [in/out] The max size and resulting size of the encoded data + @return CRYPT_OK if successful +*/ +int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, + unsigned long saltlen, prng_state *prng, + int prng_idx, int hash_idx, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen) +{ + int err; + ltc_rsa_op_parameters params; + if ((err = rsa_args_to_op_params(NULL, 0, + prng, prng_idx, + hash_idx, + LTC_PKCS_1_PSS, saltlen, + ¶ms)) != CRYPT_OK) { + return err; + } + return ltc_pkcs_1_pss_encode_mgf1(msghash, msghashlen, ¶ms, modulus_bitlen, out, outlen); +} + +/** + PKCS #1 v2.00 PSS decode + @param msghash The hash to verify + @param msghashlen The length of the hash (octets) + @param sig The signature data (encoded data) + @param siglen The length of the signature data (octets) + @param saltlen The length of the salt used (octets) + @param hash_idx The index of the hash desired + @param modulus_bitlen The bit length of the RSA modulus + @param res [out] The result of the comparison, 1==valid, 0==invalid + @return CRYPT_OK if successful (even if the comparison failed) +*/ +int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, + const unsigned char *sig, unsigned long siglen, + unsigned long saltlen, int hash_idx, + unsigned long modulus_bitlen, int *res) +{ + int err; + ltc_rsa_op_parameters params; + if ((err = rsa_args_to_op_params(NULL, 0, + NULL, -1, + hash_idx, + LTC_PKCS_1_PSS, saltlen, + ¶ms)) != CRYPT_OK) { + return err; + } + return ltc_pkcs_1_pss_decode_mgf1(msghash, msghashlen, sig, siglen, ¶ms, modulus_bitlen, res); +} + + +/*! \brief PKCS #1 v1.5 encode. + * + * \param msg The data to encode + * \param msglen The length of the data to encode (octets) + * \param block_type Block type to use in padding (\sa ltc_pkcs_1_v1_5_blocks) + * \param modulus_bitlen The bit length of the RSA modulus + * \param prng An active PRNG state (only for LTC_PKCS_1_EME) + * \param prng_idx The index of the PRNG desired (only for LTC_PKCS_1_EME) + * \param out [out] The destination for the encoded data + * \param outlen [in/out] The max size and resulting size of the encoded data + * + * \return CRYPT_OK if successful + */ +int pkcs_1_v1_5_encode(const unsigned char *msg, + unsigned long msglen, + int block_type, + unsigned long modulus_bitlen, + prng_state *prng, + int prng_idx, + unsigned char *out, + unsigned long *outlen) +{ + return ltc_pkcs_1_v1_5_encode(msg, msglen, + block_type, modulus_bitlen, + prng, prng_idx, + out, outlen); +} + +/** @brief PKCS #1 v1.5 decode. + * + * @param msg The encoded data to decode + * @param msglen The length of the encoded data (octets) + * @param block_type Block type to use in padding (\sa ltc_pkcs_1_v1_5_blocks) + * @param modulus_bitlen The bit length of the RSA modulus + * @param out [out] Destination of decoding + * @param outlen [in/out] The max size and resulting size of the decoding + * @param is_valid [out] Boolean whether the padding was valid + * + * @return CRYPT_OK if successful + */ +int pkcs_1_v1_5_decode(const unsigned char *msg, + unsigned long msglen, + int block_type, + unsigned long modulus_bitlen, + unsigned char *out, + unsigned long *outlen, + int *is_valid) +{ + return ltc_pkcs_1_v1_5_decode(msg, msglen, + block_type, modulus_bitlen, + out, outlen, + is_valid); +} +#endif /* LTC_PKCS_1 */ + int compare_testvector(const void* is, const unsigned long is_len, const void* should, const unsigned long should_len, const char* what, int which) { return ltc_compare_testvector(is, is_len, should, should_len, what, which); } - #endif /* LTC_NO_DEPRECATED_APIS */ diff --git a/src/pk/pkcs1/pkcs_1_mgf1.c b/src/pk/pkcs1/pkcs_1_mgf1.c index 7a68e72cd..dfb122cef 100644 --- a/src/pk/pkcs1/pkcs_1_mgf1.c +++ b/src/pk/pkcs1/pkcs_1_mgf1.c @@ -18,9 +18,9 @@ @param masklen The length of the mask desired @return CRYPT_OK if successful */ -int pkcs_1_mgf1(int hash_idx, - const unsigned char *seed, unsigned long seedlen, - unsigned char *mask, unsigned long masklen) +int ltc_pkcs_1_mgf1(int hash_idx, + const unsigned char *seed, unsigned long seedlen, + unsigned char *mask, unsigned long masklen) { unsigned long hLen, x; ulong32 counter; diff --git a/src/pk/pkcs1/pkcs_1_oaep_decode.c b/src/pk/pkcs1/pkcs_1_oaep_decode.c index 14519c1ea..4a2c405fd 100644 --- a/src/pk/pkcs1/pkcs_1_oaep_decode.c +++ b/src/pk/pkcs1/pkcs_1_oaep_decode.c @@ -8,53 +8,41 @@ */ #ifdef LTC_PKCS_1 - /** PKCS #1 v2.00 OAEP decode @param msg The encoded data to decode @param msglen The length of the encoded data (octets) - @param lparam The session or system data (can be NULL) - @param lparamlen The length of the lparam + @param params The PKCS#1 operation's parameters @param modulus_bitlen The bit length of the RSA modulus - @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 @return CRYPT_OK if successful */ -int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, - const unsigned char *lparam, unsigned long lparamlen, - unsigned long modulus_bitlen, - int mgf_hash, int lparam_hash, - unsigned char *out, unsigned long *outlen, - int *res) +int ltc_pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, + ltc_rsa_op_parameters *params, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen, + int *res) { unsigned char *DB, *seed, *mask; unsigned long hLen, x, y, modulus_len; - int err, ret, lparam_hash_used; + int err, ret; + ltc_rsa_op_checked op_checked = ltc_pkcs1_op_checked_init(params); LTC_ARGCHK(msg != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(res != NULL); + if ((err = rsa_key_valid_op(LTC_PKCS1_DECRYPT, &op_checked)) != CRYPT_OK) { + return err; + } + /* default to invalid packet */ *res = 0; - /* test valid hash */ - if ((err = hash_is_valid(mgf_hash)) != CRYPT_OK) { - return err; - } - if (lparam_hash != -1) { - if ((err = hash_is_valid(lparam_hash)) != CRYPT_OK) { - return err; - } - lparam_hash_used = lparam_hash; - } else { - lparam_hash_used = mgf_hash; - } - hLen = hash_descriptor[lparam_hash_used].hashsize; + hLen = hash_descriptor[op_checked.hash_alg].hashsize; modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0); /* test hash/message size */ @@ -104,7 +92,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(mgf_hash, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) { + if ((err = ltc_pkcs_1_mgf1(op_checked.mgf1_hash_alg, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) { goto LBL_ERR; } @@ -114,7 +102,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(mgf_hash, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { + if ((err = ltc_pkcs_1_mgf1(op_checked.mgf1_hash_alg, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { goto LBL_ERR; } @@ -127,13 +115,13 @@ 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(lparam_hash_used, lparam, lparamlen, seed, &x)) != CRYPT_OK) { + if (op_checked.params->u.crypt.lparam != NULL) { + if ((err = hash_memory(op_checked.hash_alg, op_checked.params->u.crypt.lparam, op_checked.params->u.crypt.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(lparam_hash_used, DB, 0, seed, &x)) != CRYPT_OK) { + if ((err = hash_memory(op_checked.hash_alg, DB, 0, seed, &x)) != CRYPT_OK) { goto LBL_ERR; } } diff --git a/src/pk/pkcs1/pkcs_1_oaep_encode.c b/src/pk/pkcs1/pkcs_1_oaep_encode.c index 45aa5ce5c..7e323bd46 100644 --- a/src/pk/pkcs1/pkcs_1_oaep_encode.c +++ b/src/pk/pkcs1/pkcs_1_oaep_encode.c @@ -8,55 +8,35 @@ */ #ifdef LTC_PKCS_1 - /** PKCS #1 v2.00 OAEP encode @param msg The data to encode @param msglen The length of the data to encode (octets) - @param lparam A session or system parameter (can be NULL) - @param lparamlen The length of the lparam data + @param params The PKCS#1 operation's parameters @param modulus_bitlen The bit length of the RSA modulus - @param prng An active PRNG state - @param prng_idx The index of the PRNG desired - @param hash_idx The index of the hash desired @param out [out] The destination for the encoded data @param outlen [in/out] The max size and resulting size of the encoded data @return CRYPT_OK if successful */ -int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, - const unsigned char *lparam, unsigned long lparamlen, - unsigned long modulus_bitlen, prng_state *prng, - int prng_idx, - int mgf_hash, int lparam_hash, - unsigned char *out, unsigned long *outlen) +int ltc_pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, + ltc_rsa_op_parameters *params, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen) { unsigned char *DB, *seed, *mask; unsigned long hLen, x, y, modulus_len; - int err, lparam_hash_used; + int err; + ltc_rsa_op_checked op_checked = ltc_pkcs1_op_checked_init(params); LTC_ARGCHK((msglen == 0) || (msg != NULL)); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); - /* test valid hash */ - if ((err = hash_is_valid(mgf_hash)) != CRYPT_OK) { - return err; - } - if (lparam_hash != -1) { - if ((err = hash_is_valid(lparam_hash)) != CRYPT_OK) { - return err; - } - lparam_hash_used = lparam_hash; - } else { - lparam_hash_used = mgf_hash; - } - - /* valid prng */ - if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) { + if ((err = rsa_key_valid_op(LTC_PKCS1_ENCRYPT, &op_checked)) != CRYPT_OK) { return err; } - hLen = hash_descriptor[lparam_hash_used].hashsize; + hLen = hash_descriptor[op_checked.hash_alg].hashsize; modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0); /* test message size */ @@ -84,13 +64,13 @@ int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, /* get lhash */ /* DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes */ x = modulus_len; - if (lparam != NULL) { - if ((err = hash_memory(lparam_hash_used, lparam, lparamlen, DB, &x)) != CRYPT_OK) { + if (op_checked.params->u.crypt.lparam != NULL) { + if ((err = hash_memory(op_checked.hash_alg, op_checked.params->u.crypt.lparam, op_checked.params->u.crypt.lparamlen, DB, &x)) != CRYPT_OK) { goto LBL_ERR; } } else { /* can't pass hash_memory a NULL so use `out` with zero length */ - if ((err = hash_memory(lparam_hash_used, out, 0, DB, &x)) != CRYPT_OK) { + if ((err = hash_memory(op_checked.hash_alg, out, 0, DB, &x)) != CRYPT_OK) { goto LBL_ERR; } } @@ -111,13 +91,13 @@ int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, } /* now choose a random seed */ - if (prng_descriptor[prng_idx].read(seed, hLen, prng) != hLen) { + if (prng_descriptor[op_checked.params->wprng].read(seed, hLen, op_checked.params->prng) != hLen) { err = CRYPT_ERROR_READPRNG; goto LBL_ERR; } /* compute MGF1 of seed (k - hlen - 1) */ - if ((err = pkcs_1_mgf1(mgf_hash, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { + if ((err = ltc_pkcs_1_mgf1(op_checked.mgf1_hash_alg, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { goto LBL_ERR; } @@ -127,7 +107,7 @@ int pkcs_1_oaep_encode(const unsigned char *msg, unsigned long msglen, } /* compute MGF1 of maskedDB (hLen) */ - if ((err = pkcs_1_mgf1(mgf_hash, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) { + if ((err = ltc_pkcs_1_mgf1(op_checked.mgf1_hash_alg, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) { goto LBL_ERR; } diff --git a/src/pk/pkcs1/pkcs_1_pss_decode.c b/src/pk/pkcs1/pkcs_1_pss_decode.c index fc258ea4f..3fae71bbc 100644 --- a/src/pk/pkcs1/pkcs_1_pss_decode.c +++ b/src/pk/pkcs1/pkcs_1_pss_decode.c @@ -10,46 +10,41 @@ #ifdef LTC_PKCS_1 /** - PKCS #1 v2.00 PSS decode + PKCS #1 v2.00 Signature Verification @param msghash The hash to verify @param msghashlen The length of the hash (octets) @param sig The signature data (encoded data) @param siglen The length of the signature data (octets) - @param saltlen The length of the salt used (octets) - @param hash_idx The index of the hash desired - @param mgf_hash_idx The index of the hash desired for MGF1 + @param params The PKCS#1 operation's parameters @param modulus_bitlen The bit length of the RSA modulus @param res [out] The result of the comparison, 1==valid, 0==invalid @return CRYPT_OK if successful (even if the comparison failed) */ -int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashlen, - const unsigned char *sig, unsigned long siglen, - unsigned long saltlen, - int hash_idx, int mgf_hash_idx, - unsigned long modulus_bitlen, int *res) +int ltc_pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashlen, + const unsigned char *sig, unsigned long siglen, + ltc_rsa_op_parameters *params, + unsigned long modulus_bitlen, int *res) { unsigned char *DB, *mask, *salt, *hash; - unsigned long x, y, hLen, modulus_len; + unsigned long x, y, hLen, modulus_len, saltlen; int err; hash_state md; + ltc_rsa_op_checked op_checked = ltc_pkcs1_op_checked_init(params); LTC_ARGCHK(msghash != NULL); + LTC_ARGCHK(sig != NULL); + LTC_ARGCHK(params != NULL); LTC_ARGCHK(res != NULL); /* default to invalid */ *res = 0; - /* ensure hash is valid */ - if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { + if ((err = rsa_key_valid_op(LTC_PKCS1_VERIFY, &op_checked)) != CRYPT_OK) { return err; } - if (hash_idx != mgf_hash_idx) { - if ((err = hash_is_valid(mgf_hash_idx)) != CRYPT_OK) { - return err; - } - } - hLen = hash_descriptor[hash_idx].hashsize; + hLen = hash_descriptor[op_checked.hash_alg].hashsize; + saltlen = params->params.saltlen; modulus_bitlen--; modulus_len = (modulus_bitlen>>3) + (modulus_bitlen & 7 ? 1 : 0); @@ -102,7 +97,7 @@ int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashle } /* generate mask of length modulus_len - hLen - 1 from hash */ - if ((err = pkcs_1_mgf1(mgf_hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { + if ((err = ltc_pkcs_1_mgf1(op_checked.mgf1_hash_alg, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { goto LBL_ERR; } @@ -131,20 +126,20 @@ int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashle } /* M = (eight) 0x00 || msghash || salt, mask = H(M) */ - if ((err = hash_descriptor[hash_idx].init(&md)) != CRYPT_OK) { + if ((err = hash_descriptor[op_checked.hash_alg].init(&md)) != CRYPT_OK) { goto LBL_ERR; } zeromem(mask, 8); - if ((err = hash_descriptor[hash_idx].process(&md, mask, 8)) != CRYPT_OK) { + if ((err = hash_descriptor[op_checked.hash_alg].process(&md, mask, 8)) != CRYPT_OK) { goto LBL_ERR; } - if ((err = hash_descriptor[hash_idx].process(&md, msghash, msghashlen)) != CRYPT_OK) { + if ((err = hash_descriptor[op_checked.hash_alg].process(&md, msghash, msghashlen)) != CRYPT_OK) { goto LBL_ERR; } - if ((err = hash_descriptor[hash_idx].process(&md, DB+x, saltlen)) != CRYPT_OK) { + if ((err = hash_descriptor[op_checked.hash_alg].process(&md, DB+x, saltlen)) != CRYPT_OK) { goto LBL_ERR; } - if ((err = hash_descriptor[hash_idx].done(&md, mask)) != CRYPT_OK) { + if ((err = hash_descriptor[op_checked.hash_alg].done(&md, mask)) != CRYPT_OK) { goto LBL_ERR; } @@ -170,25 +165,4 @@ int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashle return err; } - -/** - PKCS #1 v2.00 PSS decode - @param msghash The hash to verify - @param msghashlen The length of the hash (octets) - @param sig The signature data (encoded data) - @param siglen The length of the signature data (octets) - @param saltlen The length of the salt used (octets) - @param hash_idx The index of the hash desired - @param modulus_bitlen The bit length of the RSA modulus - @param res [out] The result of the comparison, 1==valid, 0==invalid - @return CRYPT_OK if successful (even if the comparison failed) -*/ -int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, - const unsigned char *sig, unsigned long siglen, - unsigned long saltlen, int hash_idx, - unsigned long modulus_bitlen, int *res) -{ - return pkcs_1_pss_decode_mgf1(msghash, msghashlen, sig, siglen, saltlen, hash_idx, hash_idx, modulus_bitlen, res); -} - #endif /* LTC_PKCS_1 */ diff --git a/src/pk/pkcs1/pkcs_1_pss_encode.c b/src/pk/pkcs1/pkcs_1_pss_encode.c index 01d9636f9..bf5c2992a 100644 --- a/src/pk/pkcs1/pkcs_1_pss_encode.c +++ b/src/pk/pkcs1/pkcs_1_pss_encode.c @@ -13,46 +13,34 @@ PKCS #1 v2.00 Signature Encoding @param msghash The hash to encode @param msghashlen The length of the hash (octets) - @param saltlen The length of the salt desired (octets) - @param prng An active PRNG context - @param prng_idx The index of the PRNG desired - @param hash_idx The index of the hash desired - @param mgf_hash_idx The index of the hash desired for MGF1 + @param params The PKCS#1 operation's parameters @param modulus_bitlen The bit length of the RSA modulus @param out [out] The destination of the encoding @param outlen [in/out] The max size and resulting size of the encoded data @return CRYPT_OK if successful */ -int pkcs_1_pss_encode_mgf1(const unsigned char *msghash, unsigned long msghashlen, - unsigned long saltlen, - prng_state *prng, int prng_idx, - int hash_idx, int mgf_hash_idx, - unsigned long modulus_bitlen, - unsigned char *out, unsigned long *outlen) +int ltc_pkcs_1_pss_encode_mgf1(const unsigned char *msghash, unsigned long msghashlen, + ltc_rsa_op_parameters *params, + unsigned long modulus_bitlen, + unsigned char *out, unsigned long *outlen) { unsigned char *DB, *mask, *salt, *hash; - unsigned long x, y, hLen, modulus_len; + unsigned long x, y, hLen, modulus_len, saltlen; int err; hash_state md; + ltc_rsa_op_checked op_checked = ltc_pkcs1_op_checked_init(params); LTC_ARGCHK(msghash != NULL); + LTC_ARGCHK(params != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); - /* ensure hashes and PRNG are valid */ - if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { - return err; - } - if (hash_idx != mgf_hash_idx) { - if ((err = hash_is_valid(mgf_hash_idx)) != CRYPT_OK) { - return err; - } - } - if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) { + if ((err = rsa_key_valid_op(LTC_PKCS1_SIGN, &op_checked)) != CRYPT_OK) { return err; } - hLen = hash_descriptor[hash_idx].hashsize; + hLen = hash_descriptor[op_checked.hash_alg].hashsize; + saltlen = params->params.saltlen; modulus_bitlen--; modulus_len = (modulus_bitlen>>3) + (modulus_bitlen & 7 ? 1 : 0); @@ -85,27 +73,27 @@ int pkcs_1_pss_encode_mgf1(const unsigned char *msghash, unsigned long ms /* generate random salt */ if (saltlen > 0) { - if (prng_descriptor[prng_idx].read(salt, saltlen, prng) != saltlen) { + if (prng_descriptor[params->wprng].read(salt, saltlen, params->prng) != saltlen) { err = CRYPT_ERROR_READPRNG; goto LBL_ERR; } } /* M = (eight) 0x00 || msghash || salt, hash = H(M) */ - if ((err = hash_descriptor[hash_idx].init(&md)) != CRYPT_OK) { + if ((err = hash_descriptor[op_checked.hash_alg].init(&md)) != CRYPT_OK) { goto LBL_ERR; } zeromem(DB, 8); - if ((err = hash_descriptor[hash_idx].process(&md, DB, 8)) != CRYPT_OK) { + if ((err = hash_descriptor[op_checked.hash_alg].process(&md, DB, 8)) != CRYPT_OK) { goto LBL_ERR; } - if ((err = hash_descriptor[hash_idx].process(&md, msghash, msghashlen)) != CRYPT_OK) { + if ((err = hash_descriptor[op_checked.hash_alg].process(&md, msghash, msghashlen)) != CRYPT_OK) { goto LBL_ERR; } - if ((err = hash_descriptor[hash_idx].process(&md, salt, saltlen)) != CRYPT_OK) { + if ((err = hash_descriptor[op_checked.hash_alg].process(&md, salt, saltlen)) != CRYPT_OK) { goto LBL_ERR; } - if ((err = hash_descriptor[hash_idx].done(&md, hash)) != CRYPT_OK) { + if ((err = hash_descriptor[op_checked.hash_alg].done(&md, hash)) != CRYPT_OK) { goto LBL_ERR; } @@ -118,7 +106,7 @@ int pkcs_1_pss_encode_mgf1(const unsigned char *msghash, unsigned long ms /* x += saltlen; */ /* generate mask of length modulus_len - hLen - 1 from hash */ - if ((err = pkcs_1_mgf1(mgf_hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { + if ((err = ltc_pkcs_1_mgf1(op_checked.mgf1_hash_alg, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) { goto LBL_ERR; } @@ -168,27 +156,4 @@ int pkcs_1_pss_encode_mgf1(const unsigned char *msghash, unsigned long ms return err; } - -/** - PKCS #1 v2.00 Signature Encoding using MGF1 and both hashes are the same - @param msghash The hash to encode - @param msghashlen The length of the hash (octets) - @param saltlen The length of the salt desired (octets) - @param prng An active PRNG context - @param prng_idx The index of the PRNG desired - @param hash_idx The index of the hash desired - @param modulus_bitlen The bit length of the RSA modulus - @param out [out] The destination of the encoding - @param outlen [in/out] The max size and resulting size of the encoded data - @return CRYPT_OK if successful -*/ -int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen, - unsigned long saltlen, prng_state *prng, - int prng_idx, int hash_idx, - unsigned long modulus_bitlen, - unsigned char *out, unsigned long *outlen) -{ - return pkcs_1_pss_encode_mgf1(msghash, msghashlen, saltlen, prng, prng_idx, hash_idx, hash_idx, modulus_bitlen, out, outlen); -} - #endif /* LTC_PKCS_1 */ diff --git a/src/pk/pkcs1/pkcs_1_v1_5_decode.c b/src/pk/pkcs1/pkcs_1_v1_5_decode.c index e98806073..950749a62 100644 --- a/src/pk/pkcs1/pkcs_1_v1_5_decode.c +++ b/src/pk/pkcs1/pkcs_1_v1_5_decode.c @@ -21,13 +21,13 @@ * * @return CRYPT_OK if successful */ -int pkcs_1_v1_5_decode(const unsigned char *msg, - unsigned long msglen, - int block_type, - unsigned long modulus_bitlen, - unsigned char *out, - unsigned long *outlen, - int *is_valid) +int ltc_pkcs_1_v1_5_decode(const unsigned char *msg, + unsigned long msglen, + int block_type, + unsigned long modulus_bitlen, + unsigned char *out, + unsigned long *outlen, + int *is_valid) { unsigned long modulus_len, ps_len, i; int result; diff --git a/src/pk/pkcs1/pkcs_1_v1_5_encode.c b/src/pk/pkcs1/pkcs_1_v1_5_encode.c index a21df4bfe..60ddf8abf 100644 --- a/src/pk/pkcs1/pkcs_1_v1_5_encode.c +++ b/src/pk/pkcs1/pkcs_1_v1_5_encode.c @@ -22,14 +22,14 @@ * * \return CRYPT_OK if successful */ -int pkcs_1_v1_5_encode(const unsigned char *msg, - unsigned long msglen, - int block_type, - unsigned long modulus_bitlen, - prng_state *prng, - int prng_idx, - unsigned char *out, - unsigned long *outlen) +int ltc_pkcs_1_v1_5_encode(const unsigned char *msg, + unsigned long msglen, + int block_type, + unsigned long modulus_bitlen, + prng_state *prng, + int prng_idx, + unsigned char *out, + unsigned long *outlen) { unsigned long modulus_len, ps_len, i; unsigned char *ps; diff --git a/src/pk/rsa/rsa_decrypt_key.c b/src/pk/rsa/rsa_decrypt_key.c index a36ecb021..4d9ed518c 100644 --- a/src/pk/rsa/rsa_decrypt_key.c +++ b/src/pk/rsa/rsa_decrypt_key.c @@ -8,44 +8,37 @@ */ #ifdef LTC_MRSA - /** - PKCS #1 decrypt then v1.5 or OAEP depad + Decrypt then (PKCS #1 v2.0) OAEP or (PKCS #1 v1.5) EME depad @param in The ciphertext @param inlen The length of the ciphertext (octets) @param out [out] The plaintext @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 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 params The RSA operation's parameters @param stat [out] Result of the decryption, 1==valid, 0==invalid @param key The corresponding private RSA key @return CRYPT_OK if succcessul (even if invalid) */ -int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen, +int rsa_decrypt_key_v2(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, - const unsigned char *lparam, unsigned long lparamlen, - int mgf_hash, int lparam_hash, - int padding, + ltc_rsa_op_parameters *params, int *stat, const rsa_key *key) { - unsigned long modulus_bitlen, modulus_bytelen, x; int err; unsigned char *tmp; + unsigned long modulus_bitlen, modulus_bytelen, x; + ltc_rsa_op_checked op_checked = ltc_rsa_op_checked_init(key, params); LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); - LTC_ARGCHK(key != NULL); LTC_ARGCHK(stat != NULL); /* default to invalid */ *stat = 0; /* valid padding? */ - if ((err = rsa_key_valid_op(key, LTC_RSA_CRYPT, padding, mgf_hash)) != CRYPT_OK) { + if ((err = rsa_key_valid_op(LTC_RSA_DECRYPT, &op_checked)) != CRYPT_OK) { return err; } @@ -64,20 +57,19 @@ int rsa_decrypt_key_ex(const unsigned char *in, unsigned long inlen return CRYPT_MEM; } - /* rsa decode the packet */ + /* rsa exptmod the packet */ x = inlen; if ((err = ltc_mp.rsa_me(in, inlen, tmp, &x, PK_PRIVATE, key)) != CRYPT_OK) { XFREE(tmp); return err; } - if (padding == LTC_PKCS_1_OAEP) { - /* now OAEP decode the packet */ - err = pkcs_1_oaep_decode(tmp, x, lparam, lparamlen, modulus_bitlen, mgf_hash, - lparam_hash, out, outlen, stat); + if (params->padding == LTC_PKCS_1_OAEP) { + /* now OAEP depad the packet */ + err = ltc_pkcs_1_oaep_decode(tmp, x, params, modulus_bitlen, 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); + err = ltc_pkcs_1_v1_5_decode(tmp, x, LTC_PKCS_1_EME, modulus_bitlen, out, outlen, stat); } XFREE(tmp); diff --git a/src/pk/rsa/rsa_encrypt_key.c b/src/pk/rsa/rsa_encrypt_key.c index 83fb2c5a6..b8797a169 100644 --- a/src/pk/rsa/rsa_encrypt_key.c +++ b/src/pk/rsa/rsa_encrypt_key.c @@ -8,48 +8,33 @@ */ #ifdef LTC_MRSA - /** - (PKCS #1 v2.0) OAEP pad then encrypt - @param in The plaintext - @param inlen The length of the plaintext (octets) - @param out [out] The ciphertext - @param outlen [in/out] The max size and resulting size of the ciphertext - @param lparam The system "lparam" for the encryption - @param lparamlen The length of lparam (octets) - @param prng An active PRNG - @param prng_idx The index of the desired prng - @param hash_idx The index of the desired hash - @param padding Type of padding (LTC_PKCS_1_OAEP or LTC_PKCS_1_V1_5) - @param key The RSA key to encrypt to - @return CRYPT_OK if successful + (PKCS #1 v2.0) OAEP or (PKCS #1 v1.5) EME pad then encrypt + @param in The plaintext + @param inlen The length of the plaintext (octets) + @param out [out] The ciphertext + @param outlen [in/out] The max size and resulting size of the ciphertext + @param params The RSA operation's parameters + @param key The RSA key to encrypt to + @return CRYPT_OK if successful */ -int rsa_encrypt_key_ex(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, - const unsigned char *lparam, unsigned long lparamlen, - prng_state *prng, int prng_idx, - int mgf_hash, int lparam_hash, - int padding, - const rsa_key *key) +int rsa_encrypt_key_v2(const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen, + ltc_rsa_op_parameters *params, + const rsa_key *key) { - unsigned long modulus_bitlen, modulus_bytelen, x; int err; + unsigned long modulus_bitlen, modulus_bytelen, x; + ltc_rsa_op_checked op_checked = ltc_rsa_op_checked_init(key, params); LTC_ARGCHK((inlen == 0) || (in != NULL)); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); - LTC_ARGCHK(key != NULL); - /* valid padding? */ - if ((err = rsa_key_valid_op(key, LTC_RSA_CRYPT, padding, mgf_hash)) != CRYPT_OK) { + if ((err = rsa_key_valid_op(LTC_RSA_ENCRYPT, &op_checked)) != CRYPT_OK) { return err; } - /* valid prng? */ - if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) { - return err; - } - /* get modulus len in bits */ modulus_bitlen = ltc_mp_count_bits( (key->N)); @@ -60,20 +45,18 @@ int rsa_encrypt_key_ex(const unsigned char *in, unsigned long inlen, return CRYPT_BUFFER_OVERFLOW; } - if (padding == LTC_PKCS_1_OAEP) { + if (params->padding == LTC_PKCS_1_OAEP) { /* OAEP pad the key */ x = *outlen; - if ((err = pkcs_1_oaep_encode(in, inlen, lparam, - lparamlen, modulus_bitlen, prng, prng_idx, mgf_hash, - lparam_hash, out, &x)) != CRYPT_OK) { + if ((err = ltc_pkcs_1_oaep_encode(in, inlen, params, modulus_bitlen, out, &x)) != CRYPT_OK) { return err; } } else { /* PKCS #1 v1.5 pad the key */ x = *outlen; - if ((err = pkcs_1_v1_5_encode(in, inlen, LTC_PKCS_1_EME, - modulus_bitlen, prng, prng_idx, - out, &x)) != CRYPT_OK) { + if ((err = ltc_pkcs_1_v1_5_encode(in, inlen, LTC_PKCS_1_EME, + modulus_bitlen, params->prng, params->wprng, + out, &x)) != CRYPT_OK) { return err; } } diff --git a/src/pk/rsa/rsa_key.c b/src/pk/rsa/rsa_key.c index 5bb37f7fb..533a58b60 100644 --- a/src/pk/rsa/rsa_key.c +++ b/src/pk/rsa/rsa_key.c @@ -100,68 +100,134 @@ void rsa_free(rsa_key *key) XMEMSET(&key->params, 0, sizeof(key->params)); } -static LTC_INLINE int s_rsa_key_valid_pss_algs(const rsa_key *key, int padding, int hash_idx) +static LTC_INLINE int s_rsa_key_valid_rsa_params(ltc_rsa_op_checked *check) { - if (!key->params.pss_oaep) { + const ltc_rsa_parameters *key_params, *op_params; + /* This is called from PKCS#1 de-/encoder code, so we can't check the key */ + if (check->key == NULL) { return CRYPT_OK; } - if (padding != LTC_PKCS_1_PSS) { + key_params = &check->key->params; + op_params = &check->params->params; + /* The key is restricted to PSS, so check the op's params */ + if (key_params->pss_oaep + && !rsa_params_equal(key_params, op_params)) { return CRYPT_PK_TYPE_MISMATCH; } - if (key->params.hash_alg == NULL || find_hash(key->params.hash_alg) != hash_idx) { + /* No PSS or OAEP, so we're fine. */ + if (!key_params->pss_oaep + || !op_params->pss_oaep) { + return CRYPT_OK; + } + /* Verify hash algs */ + if (key_params->hash_alg == NULL + || find_hash(key_params->hash_alg) != check->hash_alg) { return CRYPT_INVALID_HASH; } - if (key->params.mgf1_hash_alg == NULL) { + if (key_params->mgf1_hash_alg == NULL + || find_hash(key_params->mgf1_hash_alg) != check->mgf1_hash_alg) { return CRYPT_INVALID_HASH; } - return hash_is_valid(find_hash(key->params.mgf1_hash_alg)); + return CRYPT_OK; } -static LTC_INLINE int s_rsa_key_valid_sign(const rsa_key *key, int padding, int hash_idx) +static LTC_INLINE int s_rsa_key_set_hash_algs(ltc_rsa_op_checked *check) { - if ((padding != LTC_PKCS_1_V1_5) && - (padding != LTC_PKCS_1_PSS) && - (padding != LTC_PKCS_1_V1_5_NA1)) { - return CRYPT_PK_INVALID_PADDING; + ltc_rsa_op_parameters *params = check->params; + if (params->params.hash_alg == NULL + || (check->hash_alg = find_hash(params->params.hash_alg)) == -1) { + return CRYPT_INVALID_HASH; + } + if (params->params.mgf1_hash_alg == NULL) { + if (!params->params.pss_oaep) + return CRYPT_OK; + } else if ((check->mgf1_hash_alg = find_hash(params->params.mgf1_hash_alg)) != -1) { + return CRYPT_OK; + } + return CRYPT_INVALID_HASH; +} + +static LTC_INLINE int s_rsa_key_valid_sign(ltc_rsa_op_checked *check) +{ + ltc_rsa_op_parameters *params = check->params; + if ((params->padding != LTC_PKCS_1_V1_5) + && (params->padding != LTC_PKCS_1_PSS) + && (params->padding != LTC_PKCS_1_V1_5_NA1)) { + return CRYPT_PK_INVALID_PADDING; } - if (padding != LTC_PKCS_1_V1_5_NA1) { - int err; - /* valid hash ? */ - if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { - return err; + if (params->padding != LTC_PKCS_1_V1_5_NA1) { + int err = s_rsa_key_set_hash_algs(check); + if (err != CRYPT_OK) { + return err; } } - return s_rsa_key_valid_pss_algs(key, padding, hash_idx); + if (params->padding == LTC_PKCS_1_V1_5) { + /* not all hashes have OIDs... so sad */ + if (check->hash_alg == -1 + || hash_descriptor[check->hash_alg].OIDlen == 0) { + return CRYPT_INVALID_ARG; + } + } + return s_rsa_key_valid_rsa_params(check); } -static LTC_INLINE int s_rsa_key_valid_crypt(const rsa_key *key, int padding, int hash_idx) +static LTC_INLINE int s_rsa_key_valid_crypt(ltc_rsa_op_checked *check) { - if ((padding != LTC_PKCS_1_V1_5) && - (padding != LTC_PKCS_1_OAEP)) { + ltc_rsa_op_parameters *params = check->params; + if ((params->padding != LTC_PKCS_1_V1_5) && + (params->padding != LTC_PKCS_1_OAEP)) { return CRYPT_PK_INVALID_PADDING; } - if (padding == LTC_PKCS_1_OAEP) { - int err; - /* valid hash? */ - if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { - return err; + if (params->padding == LTC_PKCS_1_OAEP) { + int err = s_rsa_key_set_hash_algs(check); + if (err != CRYPT_OK) { + return err; } } - return s_rsa_key_valid_pss_algs(key, padding, hash_idx); + return s_rsa_key_valid_rsa_params(check); +} + +static LTC_INLINE int s_rsa_check_prng(ltc_rsa_op_parameters *params) +{ + if (params->padding != LTC_PKCS_1_PSS) + return CRYPT_OK; + if (params->prng == NULL) + return CRYPT_INVALID_PRNG; + /* valid prng ? */ + return prng_is_valid(params->wprng); } -int rsa_key_valid_op(const rsa_key *key, ltc_rsa_op op, int padding, int hash_idx) +int rsa_key_valid_op(ltc_rsa_op op, ltc_rsa_op_checked *check) { + int err; + check->hash_alg = check->mgf1_hash_alg = -1; + LTC_ARGCHK(check->params != NULL); + if ((op & LTC_RSA_OP_PKCS1) != LTC_RSA_OP_PKCS1) { + /* PKCS#1 ops don't need an RSA key */ + LTC_ARGCHK(check->key != NULL); + } + check->params->params.pss_oaep = check->params->padding == LTC_PKCS_1_OAEP + || check->params->padding == LTC_PKCS_1_PSS; + if ((op & LTC_RSA_OP_SEND) == LTC_RSA_OP_SEND) { + if ((err = s_rsa_check_prng(check->params)) != CRYPT_OK) { + return err; + } + } switch (op) { + case LTC_RSA_ENCRYPT: + case LTC_RSA_DECRYPT: + case LTC_PKCS1_ENCRYPT: + case LTC_PKCS1_DECRYPT: + return s_rsa_key_valid_crypt(check); case LTC_RSA_SIGN: - return s_rsa_key_valid_sign(key, padding, hash_idx); - case LTC_RSA_CRYPT: - return s_rsa_key_valid_crypt(key, padding, hash_idx); - default: - return CRYPT_ERROR; + case LTC_RSA_VERIFY: + case LTC_PKCS1_SIGN: + case LTC_PKCS1_VERIFY: + return s_rsa_key_valid_sign(check); } + return CRYPT_ERROR; } int rsa_params_equal(const ltc_rsa_parameters *a, const ltc_rsa_parameters *b) diff --git a/src/pk/rsa/rsa_sign_hash.c b/src/pk/rsa/rsa_sign_hash.c index 4445f712b..6c0fc4f80 100644 --- a/src/pk/rsa/rsa_sign_hash.c +++ b/src/pk/rsa/rsa_sign_hash.c @@ -8,64 +8,48 @@ */ #ifdef LTC_MRSA - /** PKCS #1 pad then sign - @param in The hash to sign - @param inlen The length of the hash to sign (octets) - @param out [out] The signature - @param outlen [in/out] The max size and resulting size of the signature - @param padding Type of padding (LTC_PKCS_1_PSS, LTC_PKCS_1_V1_5 or LTC_PKCS_1_V1_5_NA1) - @param prng An active PRNG state - @param prng_idx The index of the PRNG desired - @param hash_idx The index of the hash desired - @param saltlen The length of the salt desired (octets) + @param hash The hash to sign + @param hashlen The length of the hash to sign (octets) + @param sig [out] The signature + @param siglen [in/out] The max size and resulting size of the signature + @param params The RSA operation parameters @param key The private RSA key to use @return CRYPT_OK if successful */ -int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, - int padding, - prng_state *prng, int prng_idx, - int hash_idx, int mgf_hash_idx, - unsigned long saltlen, - const rsa_key *key) +int rsa_sign_hash_v2(const unsigned char *hash, unsigned long hashlen, + unsigned char *sig, unsigned long *siglen, + ltc_rsa_op_parameters *params, + const rsa_key *key) { unsigned long modulus_bitlen, modulus_bytelen, x, y; int err; + ltc_rsa_op_checked op_check = ltc_rsa_op_checked_init(key, params); - LTC_ARGCHK(in != NULL); - LTC_ARGCHK(out != NULL); - LTC_ARGCHK(outlen != NULL); + LTC_ARGCHK(hash != NULL); + LTC_ARGCHK(sig != NULL); + LTC_ARGCHK(siglen != NULL); LTC_ARGCHK(key != NULL); - /* valid padding? */ - if ((err = rsa_key_valid_op(key, LTC_RSA_SIGN, padding, hash_idx)) != CRYPT_OK) { + if ((err = rsa_key_valid_op(LTC_RSA_SIGN, &op_check)) != CRYPT_OK) { return err; } - if (padding == LTC_PKCS_1_PSS) { - /* valid prng ? */ - if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) { - return err; - } - } - /* get modulus len in bits */ modulus_bitlen = ltc_mp_count_bits((key->N)); - /* outlen must be at least the size of the modulus */ + /* siglen must be at least the size of the modulus */ modulus_bytelen = ltc_mp_unsigned_bin_size((key->N)); - if (modulus_bytelen > *outlen) { - *outlen = modulus_bytelen; + if (modulus_bytelen > *siglen) { + *siglen = modulus_bytelen; return CRYPT_BUFFER_OVERFLOW; } - if (padding == LTC_PKCS_1_PSS) { + if (params->padding == LTC_PKCS_1_PSS) { /* PSS pad the key */ - x = *outlen; - if ((err = pkcs_1_pss_encode_mgf1(in, inlen, saltlen, prng, prng_idx, - hash_idx, mgf_hash_idx, modulus_bitlen, out, &x)) != CRYPT_OK) { + x = *siglen; + if ((err = ltc_pkcs_1_pss_encode_mgf1(hash, hashlen, params, modulus_bitlen, sig, &x)) != CRYPT_OK) { return err; } } else { @@ -73,12 +57,8 @@ int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, unsigned char *tmpin = NULL; const unsigned char *tmpin_ro; - if (padding == LTC_PKCS_1_V1_5) { + if (params->padding == LTC_PKCS_1_V1_5) { ltc_asn1_list digestinfo[2], siginfo[2]; - /* not all hashes have OIDs... so sad */ - if (hash_descriptor[hash_idx].OIDlen == 0) { - return CRYPT_INVALID_ARG; - } /* construct the SEQUENCE SEQUENCE { @@ -88,10 +68,10 @@ int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, hash OCTET STRING } */ - LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, hash_descriptor[hash_idx].OID, hash_descriptor[hash_idx].OIDlen); + LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, hash_descriptor[op_check.hash_alg].OID, hash_descriptor[op_check.hash_alg].OIDlen); LTC_SET_ASN1(digestinfo, 1, LTC_ASN1_NULL, NULL, 0); LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE, digestinfo, 2); - LTC_SET_ASN1(siginfo, 1, LTC_ASN1_OCTET_STRING, in, inlen); + LTC_SET_ASN1(siginfo, 1, LTC_ASN1_OCTET_STRING, hash, hashlen); /* allocate memory for the encoding */ y = ltc_mp_unsigned_bin_size(key->N); @@ -107,14 +87,14 @@ int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, tmpin_ro = tmpin; } else { /* set the pointer and data-length to the input values */ - tmpin_ro = in; - y = inlen; + tmpin_ro = hash; + y = hashlen; } - x = *outlen; - err = pkcs_1_v1_5_encode(tmpin_ro, y, LTC_PKCS_1_EMSA, modulus_bitlen, NULL, 0, out, &x); + x = *siglen; + err = ltc_pkcs_1_v1_5_encode(tmpin_ro, y, LTC_PKCS_1_EMSA, modulus_bitlen, NULL, 0, sig, &x); - if (padding == LTC_PKCS_1_V1_5) { + if (params->padding == LTC_PKCS_1_V1_5) { XFREE(tmpin); } @@ -124,7 +104,7 @@ int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen, } /* RSA encode it */ - return ltc_mp.rsa_me(out, x, out, outlen, PK_PRIVATE, key); + return ltc_mp.rsa_me(sig, x, sig, siglen, PK_PRIVATE, key); } #endif /* LTC_MRSA */ diff --git a/src/pk/rsa/rsa_verify_hash.c b/src/pk/rsa/rsa_verify_hash.c index ede234497..836fae5f7 100644 --- a/src/pk/rsa/rsa_verify_hash.c +++ b/src/pk/rsa/rsa_verify_hash.c @@ -1,5 +1,6 @@ /* LibTomCrypt, modular cryptographic library -- Tom St Denis */ /* SPDX-License-Identifier: Unlicense */ +#define LTC_DEPRECATED(x) #include "tomcrypt_private.h" /** @@ -8,30 +9,27 @@ */ #ifdef LTC_MRSA - /** PKCS #1 de-sign then v1.5 or PSS depad @param sig The signature data @param siglen The length of the signature data (octets) @param hash The hash of the message that was signed @param hashlen The length of the hash of the message that was signed (octets) - @param padding Type of padding (LTC_PKCS_1_PSS, LTC_PKCS_1_V1_5 or LTC_PKCS_1_V1_5_NA1) - @param hash_idx The index of the desired hash - @param saltlen The length of the salt used during signature + @param params The RSA operation parameters @param stat [out] The result of the signature comparison, 1==valid, 0==invalid @param key The public RSA key corresponding to the key that performed the signature @return CRYPT_OK on success (even if the signature is invalid) */ -int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen, - const unsigned char *hash, unsigned long hashlen, - int padding, - int hash_idx, int mgf_hash_idx, - unsigned long saltlen, - int *stat, const rsa_key *key) +int rsa_verify_hash_v2(const unsigned char *sig, unsigned long siglen, + const unsigned char *hash, unsigned long hashlen, + ltc_rsa_op_parameters *params, + int *stat, + const rsa_key *key) { unsigned long modulus_bitlen, modulus_bytelen, x; int err; unsigned char *tmpbuf; + ltc_rsa_op_checked op_check = ltc_rsa_op_checked_init(key, params); LTC_ARGCHK(hash != NULL); LTC_ARGCHK(sig != NULL); @@ -41,8 +39,7 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long sigle /* default to invalid */ *stat = 0; - /* valid padding? */ - if ((err = rsa_key_valid_op(key, LTC_RSA_SIGN, padding, hash_idx)) != CRYPT_OK) { + if ((err = rsa_key_valid_op(LTC_RSA_VERIFY, &op_check)) != CRYPT_OK) { return err; } @@ -74,14 +71,14 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long sigle return CRYPT_INVALID_PACKET; } - if (padding == LTC_PKCS_1_PSS) { + if (params->padding == LTC_PKCS_1_PSS) { /* PSS decode and verify it */ if(modulus_bitlen%8 == 1){ - err = pkcs_1_pss_decode_mgf1(hash, hashlen, tmpbuf+1, x-1, saltlen, hash_idx, mgf_hash_idx, modulus_bitlen, stat); + err = ltc_pkcs_1_pss_decode_mgf1(hash, hashlen, tmpbuf+1, x-1, params, modulus_bitlen, stat); } else{ - err = pkcs_1_pss_decode_mgf1(hash, hashlen, tmpbuf, x, saltlen, hash_idx, mgf_hash_idx, modulus_bitlen, stat); + err = ltc_pkcs_1_pss_decode_mgf1(hash, hashlen, tmpbuf, x, params, modulus_bitlen, stat); } } else { @@ -98,21 +95,15 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long sigle goto bail_2; } - if ((err = pkcs_1_v1_5_decode(tmpbuf, x, LTC_PKCS_1_EMSA, modulus_bitlen, out, &outlen, &decoded)) != CRYPT_OK) { + if ((err = ltc_pkcs_1_v1_5_decode(tmpbuf, x, LTC_PKCS_1_EMSA, modulus_bitlen, out, &outlen, &decoded)) != CRYPT_OK) { XFREE(out); goto bail_2; } - if (padding == LTC_PKCS_1_V1_5) { + if (params->padding == LTC_PKCS_1_V1_5) { unsigned long loid[16], reallen; ltc_asn1_list digestinfo[2], siginfo[2]; - /* not all hashes have OIDs... so sad */ - if (hash_descriptor[hash_idx].OIDlen == 0) { - err = CRYPT_INVALID_ARG; - goto bail_2; - } - /* now we must decode out[0...outlen-1] using ASN.1, test the OID and then test the hash */ /* construct the SEQUENCE SEQUENCE { @@ -124,16 +115,13 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long sigle */ LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, loid, LTC_ARRAY_SIZE(loid)); LTC_SET_ASN1(digestinfo, 1, LTC_ASN1_NULL, NULL, 0); + digestinfo[1].optional = 1; LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE, digestinfo, 2); LTC_SET_ASN1(siginfo, 1, LTC_ASN1_OCTET_STRING, tmpbuf, siglen); if (der_decode_sequence_strict(out, outlen, siginfo, 2) != CRYPT_OK) { - /* fallback to Legacy:missing NULL */ - LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE, digestinfo, 1); - if ((err = der_decode_sequence_strict(out, outlen, siginfo, 2)) != CRYPT_OK) { - XFREE(out); - goto bail_2; - } + XFREE(out); + goto bail_2; } if ((err = der_length_sequence(siginfo, 2, &reallen)) != CRYPT_OK) { @@ -143,8 +131,8 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long sigle /* test OID */ if ((reallen == outlen) && - (digestinfo[0].size == hash_descriptor[hash_idx].OIDlen) && - (XMEMCMP(digestinfo[0].data, hash_descriptor[hash_idx].OID, sizeof(unsigned long) * hash_descriptor[hash_idx].OIDlen) == 0) && + (digestinfo[0].size == hash_descriptor[op_check.hash_alg].OIDlen) && + (XMEMCMP(digestinfo[0].data, hash_descriptor[op_check.hash_alg].OID, sizeof(unsigned long) * hash_descriptor[op_check.hash_alg].OIDlen) == 0) && (siginfo[1].size == hashlen) && (XMEMCMP(siginfo[1].data, hash, hashlen) == 0)) { *stat = 1; diff --git a/tests/deprecated_test.c b/tests/deprecated_test.c index f2ed3638b..57215d4e3 100644 --- a/tests/deprecated_test.c +++ b/tests/deprecated_test.c @@ -1,5 +1,6 @@ /* LibTomCrypt, modular cryptographic library -- Tom St Denis */ /* SPDX-License-Identifier: Unlicense */ +#ifndef LTC_NO_DEPRECATED_APIS #define LTC_DEPRECATED(x) #include @@ -39,10 +40,53 @@ static void s_ecc_test(void) } #endif +#ifdef LTC_MRSA +extern const unsigned char ltc_rsa_private_test_key[]; +extern const unsigned long ltc_rsa_private_test_key_sz; +extern const unsigned char ltc_openssl_public_rsa[]; +extern const unsigned long ltc_openssl_public_rsa_sz; +static void s_rsa_test(void) +{ + rsa_key key, pubkey; + int stat; + const unsigned char tv[] = "test"; + unsigned char buf0[1024], buf1[1024]; + unsigned long buf0len, buf1len; + + /* We need an MPI provider for RSA */ + if (ltc_mp.name == NULL) return; + + DO(rsa_import(ltc_rsa_private_test_key, ltc_rsa_private_test_key_sz, &key)); + DO(rsa_import(ltc_openssl_public_rsa, ltc_openssl_public_rsa_sz, &pubkey)); + + buf0len = sizeof(buf0); + DO(rsa_sign_hash_ex(tv, 4, buf0, &buf0len, LTC_PKCS_1_PSS, &yarrow_prng, find_prng("yarrow"), find_hash("sha1"), 8, &key)); + buf1len = sizeof(buf1); + DO(rsa_verify_hash_ex(buf0, buf0len, tv, 4, LTC_PKCS_1_PSS, find_hash("sha1"), 8, &stat, &pubkey)); + ENSURE(stat == 1); + + buf0len = sizeof(buf0); + DO(rsa_encrypt_key_ex(tv, 4, buf0, &buf0len, NULL, 0, &yarrow_prng, find_prng("yarrow"), find_hash("sha1"), LTC_PKCS_1_OAEP, &pubkey)); + buf1len = sizeof(buf1); + DO(rsa_decrypt_key_ex(buf0, buf0len, buf1, &buf1len, NULL, 0, find_hash("sha1"), LTC_PKCS_1_OAEP, &stat, &key)); + ENSURE(stat == 1); + COMPARE_TESTVECTOR(buf1, buf1len, tv, 4, "s_rsa_test", 0); + + rsa_free(&pubkey); + rsa_free(&key); +} +#endif +#endif /* LTC_NO_DEPRECATED_APIS */ + int deprecated_test(void) { +#ifndef LTC_NO_DEPRECATED_APIS #ifdef LTC_MECC s_ecc_test(); #endif +#ifdef LTC_MRSA + s_rsa_test(); +#endif +#endif /* LTC_NO_DEPRECATED_APIS */ return 0; } diff --git a/tests/pkcs_1_eme_test.c b/tests/pkcs_1_eme_test.c index 9e818ace6..26944f658 100644 --- a/tests/pkcs_1_eme_test.c +++ b/tests/pkcs_1_eme_test.c @@ -11,16 +11,16 @@ int pkcs_1_eme_test(void) { struct ltc_prng_descriptor* no_prng_desc = no_prng_desc_get(); - int prng_idx = register_prng(no_prng_desc); - int hash_idx = find_hash("sha1"); - unsigned int i; - unsigned int j; + ltc_rsa_op_parameters rsa_params = { + .wprng = register_prng(no_prng_desc), + .prng = (void*)no_prng_desc, + .params.hash_alg = "sha1", + .padding = LTC_PKCS_1_V1_5 + }; + unsigned int i, j; if (ltc_mp.name == NULL) return CRYPT_NOP; - DO(prng_is_valid(prng_idx)); - DO(hash_is_valid(hash_idx)); - for (i = 0; i < LTC_ARRAY_SIZE(testcases_eme); ++i) { testcase_t* t = &testcases_eme[i]; rsa_key k, *key = &k; @@ -41,11 +41,11 @@ int pkcs_1_eme_test(void) unsigned char buf[256], obuf[256]; unsigned long buflen = sizeof(buf), obuflen = sizeof(obuf); int stat; - 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, -1, LTC_PKCS_1_V1_5, key), s->name); + prng_descriptor[rsa_params.wprng].add_entropy(s->o2, s->o2_l, (void*)rsa_params.prng); + DOX(rsa_encrypt_key_v2(s->o1, s->o1_l, obuf, &obuflen, &rsa_params, 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, -1, LTC_PKCS_1_V1_5, &stat, key), s->name); - DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, s->name); + DOX(rsa_decrypt_key_v2(obuf, obuflen, buf, &buflen, &rsa_params, &stat, key), s->name); + ENSUREX(stat == 1, s->name); } /* for */ ltc_mp_deinit_multi(key->d, key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, LTC_NULL); diff --git a/tests/pkcs_1_emsa_test.c b/tests/pkcs_1_emsa_test.c index 327f2b5df..4d2bc112f 100644 --- a/tests/pkcs_1_emsa_test.c +++ b/tests/pkcs_1_emsa_test.c @@ -10,9 +10,12 @@ int pkcs_1_emsa_test(void) { + ltc_rsa_op_parameters rsa_params = { + .params.hash_alg = "sha1", + .padding = LTC_PKCS_1_V1_5 + }; int hash_idx = find_hash("sha1"); - unsigned int i; - unsigned int j; + unsigned int i, j; if (ltc_mp.name == NULL) return CRYPT_NOP; @@ -39,10 +42,10 @@ int pkcs_1_emsa_test(void) unsigned long buflen = sizeof(buf), obuflen = sizeof(obuf); int stat; DOX(hash_memory(hash_idx, s->o1, s->o1_l, buf, &buflen), s->name); - DOX(rsa_sign_hash_ex(buf, buflen, obuf, &obuflen, LTC_PKCS_1_V1_5, NULL, -1, hash_idx, -1, 0, key), s->name); + DOX(rsa_sign_hash_v2(buf, buflen, obuf, &obuflen, &rsa_params, key), s->name); COMPARE_TESTVECTOR(obuf, obuflen, s->o2, s->o2_l,s->name, j); - DOX(rsa_verify_hash_ex(obuf, obuflen, buf, buflen, LTC_PKCS_1_V1_5, hash_idx, -1, 0, &stat, key), s->name); - DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, s->name); + DOX(rsa_verify_hash_v2(obuf, obuflen, buf, buflen, &rsa_params, &stat, key), s->name); + ENSUREX(stat == 1, s->name); } /* for */ ltc_mp_deinit_multi(key->d, key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, LTC_NULL); diff --git a/tests/pkcs_1_oaep_test.c b/tests/pkcs_1_oaep_test.c index 76157c2c0..c09268301 100644 --- a/tests/pkcs_1_oaep_test.c +++ b/tests/pkcs_1_oaep_test.c @@ -11,15 +11,17 @@ int pkcs_1_oaep_test(void) { struct ltc_prng_descriptor* no_prng_desc = no_prng_desc_get(); - int prng_idx = register_prng(no_prng_desc); - int hash_idx = find_hash("sha1"); - unsigned int i; - unsigned int j; + ltc_rsa_op_parameters rsa_params = { + .wprng = register_prng(no_prng_desc), + .prng = (void*)no_prng_desc, + .params.hash_alg = "sha1", + .params.mgf1_hash_alg = "sha1", + .padding = LTC_PKCS_1_OAEP + }; + unsigned int i, j; if (ltc_mp.name == NULL) return CRYPT_NOP; - DO(prng_is_valid(prng_idx)); - DO(hash_is_valid(hash_idx)); for (i = 0; i < LTC_ARRAY_SIZE(testcases_oaep); ++i) { testcase_t* t = &testcases_oaep[i]; @@ -41,11 +43,11 @@ int pkcs_1_oaep_test(void) unsigned char buf[256], obuf[256]; unsigned long buflen = sizeof(buf), obuflen = sizeof(obuf); int stat; - prng_descriptor[prng_idx].add_entropy(s->o2, s->o2_l, (void*)no_prng_desc); - DOX(rsa_encrypt_key(s->o1, s->o1_l, obuf, &obuflen, NULL, 0, (void*)no_prng_desc, prng_idx, hash_idx, key), s->name); + prng_descriptor[rsa_params.wprng].add_entropy(s->o2, s->o2_l, rsa_params.prng); + DOX(rsa_encrypt_key_v2(s->o1, s->o1_l, obuf, &obuflen, &rsa_params, key), s->name); COMPARE_TESTVECTOR(obuf, obuflen, s->o3, s->o3_l,s->name, j); - DOX(rsa_decrypt_key(obuf, obuflen, buf, &buflen, NULL, 0, hash_idx, &stat, key), s->name); - DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, s->name); + DOX(rsa_decrypt_key_v2(obuf, obuflen, buf, &buflen, &rsa_params, &stat, key), s->name); + ENSUREX(stat == 1, s->name); } /* for */ ltc_mp_deinit_multi(key->d, key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, LTC_NULL); diff --git a/tests/pkcs_1_pss_test.c b/tests/pkcs_1_pss_test.c index a86e473ac..bf4816e64 100644 --- a/tests/pkcs_1_pss_test.c +++ b/tests/pkcs_1_pss_test.c @@ -11,14 +11,18 @@ int pkcs_1_pss_test(void) { struct ltc_prng_descriptor* no_prng_desc = no_prng_desc_get(); - int prng_idx = register_prng(no_prng_desc); + ltc_rsa_op_parameters rsa_params = { + .wprng = register_prng(no_prng_desc), + .prng = (void*)no_prng_desc, + .params.hash_alg = "sha1", + .params.mgf1_hash_alg = "sha1", + .padding = LTC_PKCS_1_PSS + }; int hash_idx = find_hash("sha1"); - unsigned int i; - unsigned int j; + unsigned int i, j; if (ltc_mp.name == NULL) return CRYPT_NOP; - DO(prng_is_valid(prng_idx)); DO(hash_is_valid(hash_idx)); for (i = 0; i < LTC_ARRAY_SIZE(testcases_pss); ++i) { @@ -41,12 +45,13 @@ int pkcs_1_pss_test(void) unsigned char buf[20], obuf[256]; unsigned long buflen = sizeof(buf), obuflen = sizeof(obuf); int stat; - prng_descriptor[prng_idx].add_entropy(s->o2, s->o2_l, (void*)no_prng_desc); + prng_descriptor[rsa_params.wprng].add_entropy(s->o2, s->o2_l, rsa_params.prng); DOX(hash_memory(hash_idx, s->o1, s->o1_l, buf, &buflen), s->name); - DOX(rsa_sign_hash(buf, buflen, obuf, &obuflen, (void*)no_prng_desc, prng_idx, hash_idx, s->o2_l, key), s->name); + rsa_params.params.saltlen = s->o2_l; + DOX(rsa_sign_hash_v2(buf, buflen, obuf, &obuflen, &rsa_params, key), s->name); COMPARE_TESTVECTOR(obuf, obuflen, s->o3, s->o3_l,s->name, j); - DOX(rsa_verify_hash(obuf, obuflen, buf, buflen, hash_idx, s->o2_l, &stat, key), s->name); - DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, s->name); + DOX(rsa_verify_hash_v2(obuf, obuflen, buf, buflen, &rsa_params, &stat, key), s->name); + ENSUREX(stat == 1, s->name); } /* for */ ltc_mp_deinit_multi(key->d, key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, LTC_NULL); diff --git a/tests/pkcs_1_test.c b/tests/pkcs_1_test.c index de0f7d307..3f0e3cda4 100644 --- a/tests/pkcs_1_test.c +++ b/tests/pkcs_1_test.c @@ -13,18 +13,15 @@ int pkcs_1_test(void) { unsigned char buf[3][128]; - int res1, res2, res3, prng_idx, hash_idx; - unsigned long x, y, l1, l2, l3, i1, lparamlen, saltlen, modlen; + int res1, res2, res3; + unsigned long x, y, l1, l2, l3, i1, modlen; static const unsigned char lparam[] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 }; - - /* get hash/prng */ - hash_idx = find_hash("sha1"); - prng_idx = find_prng("yarrow"); - - if (hash_idx == -1 || prng_idx == -1) { - fprintf(stderr, "pkcs_1 tests require sha1/yarrow"); - return 1; - } + ltc_rsa_op_parameters rsa_params = { + .wprng = find_prng("yarrow"), + .prng = &yarrow_prng, + .params.hash_alg = "sha1", + .params.mgf1_hash_alg = "sha1", + }; srand(LTC_TEST_RAND_SEED); /* do many tests */ @@ -36,49 +33,43 @@ int pkcs_1_test(void) for (y = 0; y < l3; y++) buf[0][y] = rand() & 255; /* pick a random lparam len [0..16] */ - lparamlen = abs(rand()) % 17; + rsa_params.u.crypt.lparamlen = abs(rand()) % 17; /* pick a random saltlen 0..16 */ - saltlen = abs(rand()) % 17; + rsa_params.params.saltlen = abs(rand()) % 17; /* PKCS #1 v2.0 supports modlens not multiple of 8 */ modlen = 800 + (abs(rand()) % 224); /* encode it */ l1 = sizeof(buf[1]); - DO(pkcs_1_oaep_encode(buf[0], l3, lparam, lparamlen, modlen, &yarrow_prng, prng_idx, hash_idx, -1, buf[1], &l1)); + rsa_params.padding = LTC_PKCS_1_OAEP; + rsa_params.u.crypt.lparam = lparam; + DO(ltc_pkcs_1_oaep_encode(buf[0], l3, &rsa_params, modlen, buf[1], &l1)); /* decode it */ l2 = sizeof(buf[2]); - 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); - fprintf(stderr, "ORIGINAL:\n"); - for (x = 0; x < l3; x++) { - fprintf(stderr, "%02x ", buf[0][x]); - } - fprintf(stderr, "\nRESULT:\n"); - for (x = 0; x < l2; x++) { - fprintf(stderr, "%02x ", buf[2][x]); - } - fprintf(stderr, "\n\n"); - return 1; - } + DO(ltc_pkcs_1_oaep_decode(buf[1], l1, &rsa_params, modlen, buf[2], &l2, &res1)); + + ENSURE(res1 == 1); + COMPARE_TESTVECTOR(buf[0], l3, buf[2], l2, "PKCS#1 OAEP", x); /* test PSS */ l1 = sizeof(buf[1]); - DO(pkcs_1_pss_encode(buf[0], l3, saltlen, &yarrow_prng, prng_idx, hash_idx, modlen, buf[1], &l1)); - DO(pkcs_1_pss_decode(buf[0], l3, buf[1], l1, saltlen, hash_idx, modlen, &res1)); + rsa_params.padding = LTC_PKCS_1_PSS; + rsa_params.u.crypt.lparam = NULL; + rsa_params.u.crypt.lparamlen = 0; + DO(ltc_pkcs_1_pss_encode_mgf1(buf[0], l3, &rsa_params, modlen, buf[1], &l1)); + DO(ltc_pkcs_1_pss_decode_mgf1(buf[0], l3, buf[1], l1, &rsa_params, modlen, &res1)); buf[0][i1 = abs(rand()) % l3] ^= 1; - DO(pkcs_1_pss_decode(buf[0], l3, buf[1], l1, saltlen, hash_idx, modlen, &res2)); + DO(ltc_pkcs_1_pss_decode_mgf1(buf[0], l3, buf[1], l1, &rsa_params, modlen, &res2)); buf[0][i1] ^= 1; buf[1][abs(rand()) % (l1 - 1)] ^= 1; - pkcs_1_pss_decode(buf[0], l3, buf[1], l1, saltlen, hash_idx, modlen, &res3); + ltc_pkcs_1_pss_decode_mgf1(buf[0], l3, buf[1], l1, &rsa_params, modlen, &res3); if (!(res1 == 1 && res2 == 0 && res3 == 0)) { - fprintf(stderr, "PSS failed: %d, %d, %d, %lu, %lu\n", res1, res2, res3, l3, saltlen); + fprintf(stderr, "PSS failed: %d, %d, %d, %lu, %lu\n", res1, res2, res3, l3, rsa_params.params.saltlen); return 1; } } diff --git a/tests/rsa_test.c b/tests/rsa_test.c index acc82d5b8..20e6083dc 100644 --- a/tests/rsa_test.c +++ b/tests/rsa_test.c @@ -134,7 +134,7 @@ static const char *hex_key[] = { "DCCC27C8E4DC6248D59BAFF5AB60F621FD53E2B75D09C91AA104A9FC612C5D04583A5A39F14A215667FDCC20A38F78185A793D2E8E7E860AE6A833C104174A9F" }; /*** openssl public RSA key in DER format */ -static const unsigned char openssl_public_rsa[] = { +const unsigned char ltc_openssl_public_rsa[] = { 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xcf, 0x9a, 0xde, 0x64, 0x8a, 0xda, 0xc8, 0x33, 0x20, 0xa9, 0xd7, 0x83, 0x31, 0x19, 0x54, 0xb2, 0x9a, 0x85, 0xa7, @@ -146,6 +146,7 @@ static const unsigned char openssl_public_rsa[] = { 0xe2, 0x76, 0x0c, 0xc9, 0x63, 0x6c, 0x49, 0x58, 0x93, 0xed, 0xcc, 0xaa, 0xdc, 0x25, 0x3b, 0x0a, 0x60, 0x3f, 0x8b, 0x54, 0x3a, 0xc3, 0x4d, 0x31, 0xe7, 0x94, 0xa4, 0x44, 0xfd, 0x02, 0x03, 0x01, 0x00, 0x01, }; +const unsigned long ltc_openssl_public_rsa_sz = sizeof(ltc_openssl_public_rsa); /* same key but with extra headers stripped */ static const unsigned char openssl_public_rsa_stripped[] = { @@ -184,22 +185,24 @@ static int rsa_compat_test(void) int stat, i; unsigned char buf[1024], key_parts[8][128]; unsigned long len, key_lens[8]; + ltc_rsa_op_parameters rsa_params = {0}; /* try reading the key */ DO(rsa_import(ltc_rsa_private_test_key, sizeof(ltc_rsa_private_test_key), &key)); - DO(rsa_import(openssl_public_rsa, sizeof(openssl_public_rsa), &pubkey)); + DO(rsa_import(ltc_openssl_public_rsa, sizeof(ltc_openssl_public_rsa), &pubkey)); /* sign-verify a message with PKCS #1 v1.5 no ASN.1 */ len = sizeof(buf); - DO(rsa_sign_hash_ex((unsigned char*)"test", 4, buf, &len, LTC_PKCS_1_V1_5_NA1, NULL, 0, 0, 0, 0, &key)); + rsa_params.padding = LTC_PKCS_1_V1_5_NA1; + DO(rsa_sign_hash_v2((unsigned char*)"test", 4, buf, &len, &rsa_params, &key)); if (len != sizeof(openssl_rsautl_pkcs) || memcmp(buf, openssl_rsautl_pkcs, len)) { - fprintf(stderr, "RSA rsa_sign_hash_ex + LTC_PKCS_1_V1_5_NA1 failed\n"); + fprintf(stderr, "RSA rsa_sign_hash_v2 + LTC_PKCS_1_V1_5_NA1 failed\n"); return 1; } stat = 0; - DO(rsa_verify_hash_ex(openssl_rsautl_pkcs, sizeof(openssl_rsautl_pkcs), (unsigned char*)"test", 4, LTC_PKCS_1_V1_5_NA1, 0, 0, 0, &stat, &pubkey)); + DO(rsa_verify_hash_v2(openssl_rsautl_pkcs, sizeof(openssl_rsautl_pkcs), (unsigned char*)"test", 4, &rsa_params, &stat, &pubkey)); if (stat != 1) { - fprintf(stderr, "RSA rsa_verify_hash_ex + LTC_PKCS_1_V1_5_NA1 failed\n"); + fprintf(stderr, "RSA rsa_verify_hash_v2 + LTC_PKCS_1_V1_5_NA1 failed\n"); return 1; } rsa_free(&pubkey); @@ -222,7 +225,7 @@ static int rsa_compat_test(void) rsa_free(&key); /* try reading the public key */ - DO(rsa_import(openssl_public_rsa, sizeof(openssl_public_rsa), &key)); + DO(rsa_import(ltc_openssl_public_rsa, sizeof(ltc_openssl_public_rsa), &key)); len = sizeof(buf); DO(rsa_export(buf, &len, PK_PUBLIC, &key)); COMPARE_TESTVECTOR(buf, len, openssl_public_rsa_stripped, sizeof(openssl_public_rsa_stripped), "RSA public export (from OpenSSL)", 0); @@ -257,10 +260,10 @@ static int rsa_compat_test(void) rsa_free(&key); /* try export in SubjectPublicKeyInfo format of the public key */ - DO(rsa_import(openssl_public_rsa, sizeof(openssl_public_rsa), &key)); + DO(rsa_import(ltc_openssl_public_rsa, sizeof(ltc_openssl_public_rsa), &key)); len = sizeof(buf); DO(rsa_export(buf, &len, PK_PUBLIC | PK_STD, &key)); - COMPARE_TESTVECTOR(buf, len, openssl_public_rsa, sizeof(openssl_public_rsa), "RSA public export (X.509)", 0); + COMPARE_TESTVECTOR(buf, len, ltc_openssl_public_rsa, sizeof(ltc_openssl_public_rsa), "RSA public export (X.509)", 0); rsa_free(&key); return 0; @@ -319,6 +322,7 @@ static int s_rsa_cryptx_issue_69(void) unsigned char buf0[512], buf1[512]; unsigned long l0, l1; int stat; + ltc_rsa_op_parameters rsa_params = {0}; l0 = sizeof(buf0); l1 = sizeof(buf1); @@ -331,9 +335,10 @@ static int s_rsa_cryptx_issue_69(void) l1 = sizeof(buf1); DO(radix_to_bin(sig1, 16, buf0, &l0)); DO(radix_to_bin(hash, 16, buf1, &l1)); - SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, 0, &stat, &key)); + rsa_params.padding = LTC_PKCS_1_V1_5; + SHOULD_FAIL(rsa_verify_hash_v2(buf0, l0, buf1, l1, &rsa_params, &stat, &key)); DO(radix_to_bin(sig2, 16, buf0, &l0)); - SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, 0, &stat, &key)); + SHOULD_FAIL(rsa_verify_hash_v2(buf0, l0, buf1, l1, &rsa_params, &stat, &key)); rsa_free(&key); return CRYPT_OK; } @@ -448,17 +453,81 @@ static int s_rsa_import_pkcs8(const void *in, unsigned long inlen, void *key) #endif #endif +static int s_rsa_macros_test(void) +{ + rsa_key key, pubkey; + int stat; + const unsigned char tv[] = "test"; + unsigned char buf0[1024], buf1[1024]; + unsigned long buf0len, buf1len; + + DO(rsa_import(ltc_rsa_private_test_key, sizeof(ltc_rsa_private_test_key), &key)); + DO(rsa_import(ltc_openssl_public_rsa, sizeof(ltc_openssl_public_rsa), &pubkey)); + + buf0len = sizeof(buf0); + DO(ltc_rsa_sign_hash(tv, 4, buf0, &buf0len, &yarrow_prng, find_prng("yarrow"), find_hash("sha1"), 8, &key)); + buf1len = sizeof(buf1); + DO(ltc_rsa_verify_hash(buf0, buf0len, tv, 4, find_hash("sha1"), 8, &stat, &key)); + ENSURE(stat == 1); + + buf0len = sizeof(buf0); + DO(ltc_rsa_encrypt_key(tv, 4, buf0, &buf0len, NULL, 0, &yarrow_prng, find_prng("yarrow"), find_hash("sha1"), &pubkey)); + buf1len = sizeof(buf1); + DO(ltc_rsa_decrypt_key(buf0, buf0len, buf1, &buf1len, NULL, 0, find_hash("sha1"), &stat, &key)); + ENSURE(stat == 1); + COMPARE_TESTVECTOR(buf1, buf1len, tv, 4, "s_rsa_macros_test", 0); + + rsa_free(&pubkey); + rsa_free(&key); + + return CRYPT_OK; +} + +static int s_rsa_pss_test(void) +{ + rsa_key key; + const unsigned char tv[] = "test"; + unsigned char buf0[1024]; + unsigned long buf0len; + ltc_rsa_op_parameters rsa_oparams = { + .prng = &yarrow_prng, + .wprng = find_prng("yarrow"), + .padding = LTC_PKCS_1_OAEP, + .u.crypt.lparam = tv, + .u.crypt.lparamlen = (unsigned long)4, + .params.hash_alg = "sha1", + .params.mgf1_hash_alg = "sha256", + .params.saltlen = 7, + }; + + DO(rsa_import(ltc_rsa_private_test_key, sizeof(ltc_rsa_private_test_key), &key)); + + buf0len = sizeof(buf0); + DO(rsa_encrypt_key_v2(tv, 4, buf0, &buf0len, &rsa_oparams, &key)); + DO(rsa_encrypt_key_v2(tv, 4, buf0, &buf0len, &rsa_oparams, &key)); + key.params = rsa_oparams.params; + DO(rsa_encrypt_key_v2(tv, 4, buf0, &buf0len, &rsa_oparams, &key)); + /* If the key is a PSS key, we must do a PSS operation */ + rsa_oparams.padding = LTC_PKCS_1_V1_5; + SHOULD_FAIL(rsa_encrypt_key_v2(tv, 4, buf0, &buf0len, &rsa_oparams, &key)); + + rsa_free(&key); + + return CRYPT_OK; +} + int rsa_test(void) { unsigned char in[1024], out[1024], tmp[3072]; rsa_key key, privKey, pubKey; - int hash_idx, prng_idx, stat, stat2, i, mgf_hash, label_hash; - unsigned long rsa_msgsize, len, len2, len3, cnt, cnt2, max_msgsize; + int prng_idx, stat, stat2, i, mgf_hash; + unsigned long rsa_msgsize, len, len2, len3, cnt, cnt2, max_msgsize, label_hash; static unsigned char lparam[] = { 0x01, 0x02, 0x03, 0x04 }; void* dP; unsigned char* p; unsigned char* p2; unsigned char* p3; + ltc_rsa_op_parameters rsa_params = {0}; if (ltc_mp.name == NULL) return CRYPT_NOP; @@ -466,12 +535,15 @@ int rsa_test(void) return 1; } - hash_idx = find_hash("sha1"); - prng_idx = find_prng("yarrow"); - if (hash_idx == -1 || prng_idx == -1) { + rsa_params.params.hash_alg = "sha1"; + rsa_params.wprng = find_prng("yarrow"); + mgf_hash = find_hash(rsa_params.params.hash_alg); + if (mgf_hash == -1 || rsa_params.wprng == -1) { fprintf(stderr, "rsa_test requires LTC_SHA1 and yarrow"); return 1; } + rsa_params.prng = &yarrow_prng; + prng_idx = rsa_params.wprng; #ifdef LTC_TEST_READDIR DO(test_process_dir("tests/rsa", &key, s_rsa_import_x509, NULL, (dir_cleanup_cb)rsa_free, "rsa_test")); @@ -481,6 +553,8 @@ int rsa_test(void) DO(test_process_dir("tests/rsa-pkcs8", &key, s_rsa_import_pkcs8, NULL, (dir_cleanup_cb)rsa_free, "rsa_pkcs8_test")); #endif + DO(s_rsa_pss_test()); + DO(s_rsa_macros_test()); DO(s_rsa_cryptx_issue_69()); DO(s_rsa_issue_301(prng_idx)); DO(s_rsa_public_ubin_e(prng_idx)); @@ -512,13 +586,13 @@ print_hex("q", tmp, len); /* make a random key/msg */ ENSURE(yarrow_read(in, 117, &yarrow_prng) == 117); + rsa_params.padding = LTC_PKCS_1_OAEP; #ifdef LTC_TEST_EXT for (mgf_hash = 0; mgf_hash < TAB_SIZE; ++mgf_hash) { if (hash_is_valid(mgf_hash) != CRYPT_OK) continue; #else { - mgf_hash = hash_idx; #endif for (label_hash = 0; label_hash < TAB_SIZE; ++label_hash) { if (hash_is_valid(label_hash) != CRYPT_OK) @@ -526,6 +600,8 @@ print_hex("q", tmp, len); if (2 * hash_descriptor[label_hash].hashsize > 126) continue; max_msgsize = 128 - (2 * hash_descriptor[label_hash].hashsize) - 2; + rsa_params.params.hash_alg = hash_descriptor[label_hash].name; + rsa_params.params.mgf1_hash_alg = hash_descriptor[mgf_hash].name; #if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1 fprintf(stderr, "Test MGF(%s), Labelhash(%s) with max_msgsize %lu\n", hash_descriptor[mgf_hash].name, hash_descriptor[label_hash].name, max_msgsize); @@ -536,59 +612,66 @@ print_hex("q", tmp, len); len = sizeof(out); len2 = rsa_msgsize; - DO(rsa_encrypt_key_ex(in, rsa_msgsize, out, &len, NULL, 0, &yarrow_prng, prng_idx, mgf_hash, label_hash, LTC_PKCS_1_OAEP, &key)); + DO(rsa_encrypt_key_v2(in, rsa_msgsize, out, &len, &rsa_params, &key)); /* change a byte */ out[8] ^= 1; - SHOULD_FAIL(rsa_decrypt_key_ex(out, len, tmp, &len2, NULL, 0, mgf_hash, label_hash, LTC_PKCS_1_OAEP, &stat2, &key)); + SHOULD_FAIL(rsa_decrypt_key_v2(out, len, tmp, &len2, &rsa_params, &stat2, &key)); /* change a byte back */ out[8] ^= 1; ENSURE(len2 == rsa_msgsize); len2 = rsa_msgsize; - DO(rsa_decrypt_key_ex(out, len, tmp, &len2, NULL, 0, mgf_hash, label_hash, LTC_PKCS_1_OAEP, &stat, &key)); + DO(rsa_decrypt_key_v2(out, len, tmp, &len2, &rsa_params, &stat, &key)); ENSUREX(stat == 1 && stat2 == 0, "rsa_decrypt_key (without lparam)"); COMPARE_TESTVECTOR(tmp, len2, in, rsa_msgsize, "rsa_decrypt_key (without lparam)", cnt << 8 | rsa_msgsize); } /* encrypt the key (with lparam) */ + rsa_params.u.crypt.lparam = lparam; + rsa_params.u.crypt.lparamlen = sizeof(lparam); for (rsa_msgsize = 0; rsa_msgsize <= max_msgsize; rsa_msgsize++) { len = sizeof(out); len2 = rsa_msgsize; - DO(rsa_encrypt_key_ex(rsa_msgsize ? in : NULL, rsa_msgsize, out, &len, lparam, sizeof(lparam), &yarrow_prng, prng_idx, mgf_hash, label_hash, LTC_PKCS_1_OAEP, &key)); + DO(rsa_encrypt_key_v2(rsa_msgsize ? in : NULL, rsa_msgsize, out, &len, &rsa_params, &key)); /* change a byte */ out[8] ^= 1; - SHOULD_FAIL(rsa_decrypt_key_ex(out, len, tmp, &len2, lparam, sizeof(lparam), mgf_hash, label_hash, LTC_PKCS_1_OAEP, &stat2, &key)); + SHOULD_FAIL(rsa_decrypt_key_v2(out, len, tmp, &len2, &rsa_params, &stat2, &key)); ENSURE(len2 == rsa_msgsize); /* change a byte back */ out[8] ^= 1; len2 = rsa_msgsize; - DO(rsa_decrypt_key_ex(out, len, tmp, &len2, lparam, sizeof(lparam), mgf_hash, label_hash, LTC_PKCS_1_OAEP, &stat, &key)); + DO(rsa_decrypt_key_v2(out, len, tmp, &len2, &rsa_params, &stat, &key)); ENSURE(stat == 1 && stat2 == 0); COMPARE_TESTVECTOR(tmp, len2, in, rsa_msgsize, "rsa_decrypt_key (with lparam)", rsa_msgsize); } + rsa_params.u.crypt.lparam = NULL; + rsa_params.u.crypt.lparamlen = 0; } } - + rsa_params.params.hash_alg = "sha1"; + rsa_params.params.mgf1_hash_alg = "sha1"; /* encrypt the key PKCS #1 v1.5 (payload from 1 to 117 bytes) */ + rsa_params.padding = LTC_PKCS_1_V1_5; for (rsa_msgsize = 0; rsa_msgsize <= 117; rsa_msgsize++) { len = sizeof(out); len2 = rsa_msgsize; - DO(rsa_encrypt_key_ex(in, rsa_msgsize, out, &len, NULL, 0, &yarrow_prng, prng_idx, 0, -1, LTC_PKCS_1_V1_5, &key)); + DO(rsa_encrypt_key_v2(in, rsa_msgsize, out, &len, &rsa_params, &key)); len2 = rsa_msgsize; - DO(rsa_decrypt_key_ex(out, len, tmp, &len2, NULL, 0, 0, -1, LTC_PKCS_1_V1_5, &stat, &key)); + DO(rsa_decrypt_key_v2(out, len, tmp, &len2, &rsa_params, &stat, &key)); ENSURE(stat == 1); COMPARE_TESTVECTOR(tmp, len2, in, rsa_msgsize, "rsa_decrypt_key_ex", rsa_msgsize); } /* sign a message (unsalted, lower cholestorol and Atkins approved) now */ len = sizeof(out); - DO(rsa_sign_hash(in, 20, out, &len, &yarrow_prng, prng_idx, hash_idx, 0, &key)); + rsa_params.padding = LTC_PKCS_1_PSS; + DO(rsa_sign_hash_v2(in, 20, out, &len, &rsa_params, &key)); /* export key and import as both private and public */ len2 = sizeof(tmp); @@ -607,20 +690,20 @@ print_hex("q", tmp, len); dbg_malloc_stats(); /* verify with original */ - DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat, &key)); + DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat, &key)); /* change a byte */ in[0] ^= 1; - DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat2, &key)); + DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat2, &key)); ENSUREX(stat == 1 && stat2 == 0, "rsa_verify_hash (unsalted, origKey) failed"); /* verify with privKey */ /* change byte back to original */ in[0] ^= 1; - DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat, &privKey)); + DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat, &privKey)); /* change a byte */ in[0] ^= 1; - DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat2, &privKey)); + DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat2, &privKey)); if (!(stat == 1 && stat2 == 0)) { fprintf(stderr, "rsa_verify_hash (unsalted, privKey) failed, %d, %d", stat, stat2); @@ -636,10 +719,10 @@ print_hex("q", tmp, len); privKey.dP = NULL; /* change byte back to original */ in[0] ^= 1; - DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat, &privKey)); + DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat, &privKey)); /* change a byte */ in[0] ^= 1; - DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat2, &privKey)); + DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat2, &privKey)); if (!(stat == 1 && stat2 == 0)) { fprintf(stderr, "rsa_verify_hash (unsalted, privKey) failed, %d, %d", stat, stat2); @@ -653,10 +736,10 @@ print_hex("q", tmp, len); /* verify with pubKey */ /* change byte back to original */ in[0] ^= 1; - DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat, &pubKey)); + DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat, &pubKey)); /* change a byte */ in[0] ^= 1; - DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat2, &pubKey)); + DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat2, &pubKey)); if (!(stat == 1 && stat2 == 0)) { fprintf(stderr, "rsa_verify_hash (unsalted, pubkey) failed, %d, %d", stat, stat2); @@ -668,11 +751,12 @@ print_hex("q", tmp, len); /* sign a message (salted) now (use privKey to make, pubKey to verify) */ len = sizeof(out); - DO(rsa_sign_hash(in, 20, out, &len, &yarrow_prng, prng_idx, hash_idx, 8, &privKey)); - DO(rsa_verify_hash(out, len, in, 20, hash_idx, 8, &stat, &pubKey)); + rsa_params.params.saltlen = 8; + DO(rsa_sign_hash_v2(in, 20, out, &len, &rsa_params, &privKey)); + DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat, &pubKey)); /* change a byte */ in[0] ^= 1; - DO(rsa_verify_hash(out, len, in, 20, hash_idx, 8, &stat2, &pubKey)); + DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat2, &pubKey)); if (!(stat == 1 && stat2 == 0)) { fprintf(stderr, "rsa_verify_hash (salted) failed, %d, %d", stat, stat2); @@ -681,17 +765,19 @@ print_hex("q", tmp, len); rsa_free(&privKey); return 1; } + rsa_params.params.saltlen = 0; /* sign a message with PKCS #1 v1.5 */ len = sizeof(out); - DO(rsa_sign_hash_ex(in, 20, out, &len, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 0, 8, &privKey)); - DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 0, 8, &stat, &pubKey)); + rsa_params.padding = LTC_PKCS_1_V1_5; + DO(rsa_sign_hash_v2(in, 20, out, &len, &rsa_params, &privKey)); + DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat, &pubKey)); /* change a byte */ in[0] ^= 1; - DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 0, 8, &stat2, &pubKey)); + DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat2, &pubKey)); if (!(stat == 1 && stat2 == 0)) { - fprintf(stderr, "rsa_verify_hash_ex failed, %d, %d", stat, stat2); + fprintf(stderr, "rsa_verify_hash_v2 failed, %d, %d", stat, stat2); rsa_free(&key); rsa_free(&pubKey); rsa_free(&privKey); @@ -717,14 +803,14 @@ print_hex("q", tmp, len); p = in; p2 = out; p3 = tmp; - for (i = 0; i < 9; ++i) { + for (i = 0; i < 10; ++i) { len = sizeof(in); len2 = sizeof(out); /* (1) */ - DO(rsa_sign_hash_ex(p, 20, p2, &len2, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 0, 8, &privKey)); + DO(rsa_sign_hash_v2(p, 20, p2, &len2, &rsa_params, &privKey)); /* (2) */ - DOX(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, 0, -1, &stat, &pubKey), "should succeed"); - DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, "should succeed"); + DOX(rsa_verify_hash_v2(p2, len2, p, 20, &rsa_params, &stat, &pubKey), "should succeed"); + ENSURE(stat == 1); len3 = sizeof(tmp); /* (3) */ DO(ltc_mp.rsa_me(p2, len2, p3, &len3, PK_PUBLIC, &key)); @@ -757,8 +843,11 @@ print_hex("q", tmp, len); len3 = sizeof(tmp); /* (6) */ - SHOULD_FAIL(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, -1, &stat, &pubKey)); - DOX(stat == 0?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, "should fail"); + if (i < 8) + SHOULD_FAIL(rsa_verify_hash_v2(p2, len2, p, 20, &rsa_params, &stat, &pubKey)); + else + DO(rsa_verify_hash_v2(p2, len2, p, 20, &rsa_params, &stat, &pubKey)); + ENSURE(stat == 0); } rsa_free(&key);