Skip to content

Commit a0478cc

Browse files
committed
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 <s@jaeckel.eu>
1 parent aa0d319 commit a0478cc

File tree

9 files changed

+112
-38
lines changed

9 files changed

+112
-38
lines changed

src/headers/tomcrypt_pk.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,10 @@ void rsa_free(rsa_key *key);
103103
rsa_decrypt_key_ex(in, inlen, out, outlen, lparam, lparamlen, hash_idx, -1, LTC_PKCS_1_OAEP, stat, key)
104104

105105
#define rsa_sign_hash(in, inlen, out, outlen, prng, prng_idx, hash_idx, saltlen, key) \
106-
rsa_sign_hash_ex(in, inlen, out, outlen, LTC_PKCS_1_PSS, prng, prng_idx, hash_idx, saltlen, key)
106+
rsa_sign_hash_ex(in, inlen, out, outlen, LTC_PKCS_1_PSS, prng, prng_idx, hash_idx, hash_idx, saltlen, key)
107107

108108
#define rsa_verify_hash(sig, siglen, hash, hashlen, hash_idx, saltlen, stat, key) \
109-
rsa_verify_hash_ex(sig, siglen, hash, hashlen, LTC_PKCS_1_PSS, hash_idx, saltlen, stat, key)
109+
rsa_verify_hash_ex(sig, siglen, hash, hashlen, LTC_PKCS_1_PSS, hash_idx, hash_idx, saltlen, stat, key)
110110

111111
#define rsa_sign_saltlen_get_max(hash_idx, key) \
112112
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
130130
int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen,
131131
unsigned char *out, unsigned long *outlen,
132132
int padding,
133-
prng_state *prng, int prng_idx,
134-
int hash_idx, unsigned long saltlen,
133+
prng_state *prng, int prng_idx,
134+
int hash_idx, int mgf_hash_idx,
135+
unsigned long saltlen,
135136
const rsa_key *key);
136137

137138
int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
138139
const unsigned char *hash, unsigned long hashlen,
139140
int padding,
140-
int hash_idx, unsigned long saltlen,
141+
int hash_idx, int mgf_hash_idx,
142+
unsigned long saltlen,
141143
int *stat, const rsa_key *key);
142144

143145
int rsa_sign_saltlen_get_max_ex(int padding, int hash_idx, const rsa_key *key);

src/headers/tomcrypt_private.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,18 @@ int x509_get_serial(const ltc_asn1_list *asn1, ltc_x509_string *serial);
702702

703703
/* tomcrypt_pkcs.h */
704704

705+
int pkcs_1_pss_encode_mgf1(const unsigned char *msghash, unsigned long msghashlen,
706+
unsigned long saltlen,
707+
prng_state *prng, int prng_idx,
708+
int hash_idx, int mgf_hash_idx,
709+
unsigned long modulus_bitlen,
710+
unsigned char *out, unsigned long *outlen);
711+
int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashlen,
712+
const unsigned char *sig, unsigned long siglen,
713+
unsigned long saltlen,
714+
int hash_idx, int mgf_hash_idx,
715+
unsigned long modulus_bitlen, int *res);
716+
705717
#ifdef LTC_PKCS_8
706718

707719
/* Public-Key Cryptography Standards (PKCS) #8:

src/pk/asn1/x509/x509_utils.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ LTC_INLINE static int s_pka_verify(const unsigned char *msg, unsigned long msgle
1717
#ifdef LTC_MRSA
1818
case LTC_PKA_RSA:
1919
/* Hard-code Padding to PSS and SaltLen to 20, as specified in RFC 4055 */
20-
return rsa_verify_hash_ex(sig, siglen, msg, msglen, LTC_PKCS_1_PSS, hash_idx, 20, stat, &key->u.rsa);
20+
return rsa_verify_hash_ex(sig, siglen, msg, msglen, LTC_PKCS_1_PSS, hash_idx, hash_idx, 20, stat, &key->u.rsa);
2121
#endif
2222
#ifdef LTC_MDSA
2323
case LTC_PKA_DSA:

src/pk/pkcs1/pkcs_1_pss_decode.c

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@
1717
@param siglen The length of the signature data (octets)
1818
@param saltlen The length of the salt used (octets)
1919
@param hash_idx The index of the hash desired
20+
@param mgf_hash_idx The index of the hash desired for MGF1
2021
@param modulus_bitlen The bit length of the RSA modulus
2122
@param res [out] The result of the comparison, 1==valid, 0==invalid
2223
@return CRYPT_OK if successful (even if the comparison failed)
2324
*/
24-
int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
25-
const unsigned char *sig, unsigned long siglen,
26-
unsigned long saltlen, int hash_idx,
27-
unsigned long modulus_bitlen, int *res)
25+
int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashlen,
26+
const unsigned char *sig, unsigned long siglen,
27+
unsigned long saltlen,
28+
int hash_idx, int mgf_hash_idx,
29+
unsigned long modulus_bitlen, int *res)
2830
{
2931
unsigned char *DB, *mask, *salt, *hash;
3032
unsigned long x, y, hLen, modulus_len;
@@ -41,6 +43,11 @@ int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
4143
if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
4244
return err;
4345
}
46+
if (hash_idx != mgf_hash_idx) {
47+
if ((err = hash_is_valid(mgf_hash_idx)) != CRYPT_OK) {
48+
return err;
49+
}
50+
}
4451

4552
hLen = hash_descriptor[hash_idx].hashsize;
4653
modulus_bitlen--;
@@ -95,7 +102,7 @@ int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
95102
}
96103

97104
/* generate mask of length modulus_len - hLen - 1 from hash */
98-
if ((err = pkcs_1_mgf1(hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
105+
if ((err = pkcs_1_mgf1(mgf_hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
99106
goto LBL_ERR;
100107
}
101108

@@ -163,4 +170,25 @@ int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
163170
return err;
164171
}
165172

173+
174+
/**
175+
PKCS #1 v2.00 PSS decode
176+
@param msghash The hash to verify
177+
@param msghashlen The length of the hash (octets)
178+
@param sig The signature data (encoded data)
179+
@param siglen The length of the signature data (octets)
180+
@param saltlen The length of the salt used (octets)
181+
@param hash_idx The index of the hash desired
182+
@param modulus_bitlen The bit length of the RSA modulus
183+
@param res [out] The result of the comparison, 1==valid, 0==invalid
184+
@return CRYPT_OK if successful (even if the comparison failed)
185+
*/
186+
int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
187+
const unsigned char *sig, unsigned long siglen,
188+
unsigned long saltlen, int hash_idx,
189+
unsigned long modulus_bitlen, int *res)
190+
{
191+
return pkcs_1_pss_decode_mgf1(msghash, msghashlen, sig, siglen, saltlen, hash_idx, hash_idx, modulus_bitlen, res);
192+
}
193+
166194
#endif /* LTC_PKCS_1 */

src/pk/pkcs1/pkcs_1_pss_encode.c

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,18 @@
1717
@param prng An active PRNG context
1818
@param prng_idx The index of the PRNG desired
1919
@param hash_idx The index of the hash desired
20+
@param mgf_hash_idx The index of the hash desired for MGF1
2021
@param modulus_bitlen The bit length of the RSA modulus
2122
@param out [out] The destination of the encoding
2223
@param outlen [in/out] The max size and resulting size of the encoded data
2324
@return CRYPT_OK if successful
2425
*/
25-
int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen,
26-
unsigned long saltlen, prng_state *prng,
27-
int prng_idx, int hash_idx,
28-
unsigned long modulus_bitlen,
29-
unsigned char *out, unsigned long *outlen)
26+
int pkcs_1_pss_encode_mgf1(const unsigned char *msghash, unsigned long msghashlen,
27+
unsigned long saltlen,
28+
prng_state *prng, int prng_idx,
29+
int hash_idx, int mgf_hash_idx,
30+
unsigned long modulus_bitlen,
31+
unsigned char *out, unsigned long *outlen)
3032
{
3133
unsigned char *DB, *mask, *salt, *hash;
3234
unsigned long x, y, hLen, modulus_len;
@@ -37,10 +39,15 @@ int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen,
3739
LTC_ARGCHK(out != NULL);
3840
LTC_ARGCHK(outlen != NULL);
3941

40-
/* ensure hash and PRNG are valid */
42+
/* ensure hashes and PRNG are valid */
4143
if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
4244
return err;
4345
}
46+
if (hash_idx != mgf_hash_idx) {
47+
if ((err = hash_is_valid(mgf_hash_idx)) != CRYPT_OK) {
48+
return err;
49+
}
50+
}
4451
if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
4552
return err;
4653
}
@@ -111,7 +118,7 @@ int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen,
111118
/* x += saltlen; */
112119

113120
/* generate mask of length modulus_len - hLen - 1 from hash */
114-
if ((err = pkcs_1_mgf1(hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
121+
if ((err = pkcs_1_mgf1(mgf_hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
115122
goto LBL_ERR;
116123
}
117124

@@ -161,4 +168,27 @@ int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen,
161168
return err;
162169
}
163170

171+
172+
/**
173+
PKCS #1 v2.00 Signature Encoding using MGF1 and both hashes are the same
174+
@param msghash The hash to encode
175+
@param msghashlen The length of the hash (octets)
176+
@param saltlen The length of the salt desired (octets)
177+
@param prng An active PRNG context
178+
@param prng_idx The index of the PRNG desired
179+
@param hash_idx The index of the hash desired
180+
@param modulus_bitlen The bit length of the RSA modulus
181+
@param out [out] The destination of the encoding
182+
@param outlen [in/out] The max size and resulting size of the encoded data
183+
@return CRYPT_OK if successful
184+
*/
185+
int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen,
186+
unsigned long saltlen, prng_state *prng,
187+
int prng_idx, int hash_idx,
188+
unsigned long modulus_bitlen,
189+
unsigned char *out, unsigned long *outlen)
190+
{
191+
return pkcs_1_pss_encode_mgf1(msghash, msghashlen, saltlen, prng, prng_idx, hash_idx, hash_idx, modulus_bitlen, out, outlen);
192+
}
193+
164194
#endif /* LTC_PKCS_1 */

src/pk/rsa/rsa_sign_hash.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@
2626
int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen,
2727
unsigned char *out, unsigned long *outlen,
2828
int padding,
29-
prng_state *prng, int prng_idx,
30-
int hash_idx, unsigned long saltlen,
31-
const rsa_key *key)
29+
prng_state *prng, int prng_idx,
30+
int hash_idx, int mgf_hash_idx,
31+
unsigned long saltlen,
32+
const rsa_key *key)
3233
{
3334
unsigned long modulus_bitlen, modulus_bytelen, x, y;
3435
int err;
@@ -72,8 +73,8 @@ int rsa_sign_hash_ex(const unsigned char *in, unsigned long inlen,
7273
if (padding == LTC_PKCS_1_PSS) {
7374
/* PSS pad the key */
7475
x = *outlen;
75-
if ((err = pkcs_1_pss_encode(in, inlen, saltlen, prng, prng_idx,
76-
hash_idx, modulus_bitlen, out, &x)) != CRYPT_OK) {
76+
if ((err = pkcs_1_pss_encode_mgf1(in, inlen, saltlen, prng, prng_idx,
77+
hash_idx, mgf_hash_idx, modulus_bitlen, out, &x)) != CRYPT_OK) {
7778
return err;
7879
}
7980
} else {

src/pk/rsa/rsa_verify_hash.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
2626
const unsigned char *hash, unsigned long hashlen,
2727
int padding,
28-
int hash_idx, unsigned long saltlen,
28+
int hash_idx, int mgf_hash_idx,
29+
unsigned long saltlen,
2930
int *stat, const rsa_key *key)
3031
{
3132
unsigned long modulus_bitlen, modulus_bytelen, x;
@@ -87,10 +88,10 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long sigle
8788
/* PSS decode and verify it */
8889

8990
if(modulus_bitlen%8 == 1){
90-
err = pkcs_1_pss_decode(hash, hashlen, tmpbuf+1, x-1, saltlen, hash_idx, modulus_bitlen, stat);
91+
err = pkcs_1_pss_decode_mgf1(hash, hashlen, tmpbuf+1, x-1, saltlen, hash_idx, mgf_hash_idx, modulus_bitlen, stat);
9192
}
9293
else{
93-
err = pkcs_1_pss_decode(hash, hashlen, tmpbuf, x, saltlen, hash_idx, modulus_bitlen, stat);
94+
err = pkcs_1_pss_decode_mgf1(hash, hashlen, tmpbuf, x, saltlen, hash_idx, mgf_hash_idx, modulus_bitlen, stat);
9495
}
9596

9697
} else {

tests/pkcs_1_emsa_test.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ int pkcs_1_emsa_test(void)
4040
unsigned long buflen = sizeof(buf), obuflen = sizeof(obuf);
4141
int stat;
4242
DOX(hash_memory(hash_idx, s->o1, s->o1_l, buf, &buflen), s->name);
43-
DOX(rsa_sign_hash_ex(buf, buflen, obuf, &obuflen, LTC_PKCS_1_V1_5, NULL, -1, hash_idx, 0, key), s->name);
43+
DOX(rsa_sign_hash_ex(buf, buflen, obuf, &obuflen, LTC_PKCS_1_V1_5, NULL, -1, hash_idx, -1, 0, key), s->name);
4444
COMPARE_TESTVECTOR(obuf, obuflen, s->o2, s->o2_l,s->name, j);
45-
DOX(rsa_verify_hash_ex(obuf, obuflen, buf, buflen, LTC_PKCS_1_V1_5, hash_idx, 0, &stat, key), s->name);
45+
DOX(rsa_verify_hash_ex(obuf, obuflen, buf, buflen, LTC_PKCS_1_V1_5, hash_idx, -1, 0, &stat, key), s->name);
4646
DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, s->name);
4747
} /* for */
4848

tests/rsa_test.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -191,13 +191,13 @@ static int rsa_compat_test(void)
191191

192192
/* sign-verify a message with PKCS #1 v1.5 no ASN.1 */
193193
len = sizeof(buf);
194-
DO(rsa_sign_hash_ex((unsigned char*)"test", 4, buf, &len, LTC_PKCS_1_V1_5_NA1, NULL, 0, 0, 0, &key));
194+
DO(rsa_sign_hash_ex((unsigned char*)"test", 4, buf, &len, LTC_PKCS_1_V1_5_NA1, NULL, 0, 0, 0, 0, &key));
195195
if (len != sizeof(openssl_rsautl_pkcs) || memcmp(buf, openssl_rsautl_pkcs, len)) {
196196
fprintf(stderr, "RSA rsa_sign_hash_ex + LTC_PKCS_1_V1_5_NA1 failed\n");
197197
return 1;
198198
}
199199
stat = 0;
200-
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));
200+
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));
201201
if (stat != 1) {
202202
fprintf(stderr, "RSA rsa_verify_hash_ex + LTC_PKCS_1_V1_5_NA1 failed\n");
203203
return 1;
@@ -331,9 +331,9 @@ static int s_rsa_cryptx_issue_69(void)
331331
l1 = sizeof(buf1);
332332
DO(radix_to_bin(sig1, 16, buf0, &l0));
333333
DO(radix_to_bin(hash, 16, buf1, &l1));
334-
SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, &stat, &key));
334+
SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, 0, &stat, &key));
335335
DO(radix_to_bin(sig2, 16, buf0, &l0));
336-
SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, &stat, &key));
336+
SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, 0, &stat, &key));
337337
rsa_free(&key);
338338
return CRYPT_OK;
339339
}
@@ -683,11 +683,11 @@ print_hex("q", tmp, len);
683683

684684
/* sign a message with PKCS #1 v1.5 */
685685
len = sizeof(out);
686-
DO(rsa_sign_hash_ex(in, 20, out, &len, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 8, &privKey));
687-
DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 8, &stat, &pubKey));
686+
DO(rsa_sign_hash_ex(in, 20, out, &len, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 0, 8, &privKey));
687+
DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 0, 8, &stat, &pubKey));
688688
/* change a byte */
689689
in[0] ^= 1;
690-
DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 8, &stat2, &pubKey));
690+
DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 0, 8, &stat2, &pubKey));
691691

692692
if (!(stat == 1 && stat2 == 0)) {
693693
fprintf(stderr, "rsa_verify_hash_ex failed, %d, %d", stat, stat2);
@@ -720,9 +720,9 @@ print_hex("q", tmp, len);
720720
len = sizeof(in);
721721
len2 = sizeof(out);
722722
/* (1) */
723-
DO(rsa_sign_hash_ex(p, 20, p2, &len2, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 8, &privKey));
723+
DO(rsa_sign_hash_ex(p, 20, p2, &len2, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 0, 8, &privKey));
724724
/* (2) */
725-
DOX(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, &stat, &pubKey), "should succeed");
725+
DOX(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, 0, -1, &stat, &pubKey), "should succeed");
726726
DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, "should succeed");
727727
len3 = sizeof(tmp);
728728
/* (3) */
@@ -756,7 +756,7 @@ print_hex("q", tmp, len);
756756

757757
len3 = sizeof(tmp);
758758
/* (6) */
759-
SHOULD_FAIL(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, &stat, &pubKey));
759+
SHOULD_FAIL(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, -1, &stat, &pubKey));
760760
DOX(stat == 0?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, "should fail");
761761
}
762762
rsa_free(&key);

0 commit comments

Comments
 (0)