|
18 | 18 | ECC Crypto, Russ Williams |
19 | 19 | */ |
20 | 20 |
|
21 | | -static int _ecc_recover_key(const unsigned char *sig, unsigned long siglen, |
22 | | - const unsigned char *hash, unsigned long hashlen, |
23 | | - int recid, ecc_key *key) |
| 21 | +/** |
| 22 | + Recover ECC public key from signature and hash |
| 23 | + @param sig The signature to verify |
| 24 | + @param siglen The length of the signature (octets) |
| 25 | + @param hash The hash (message digest) that was signed |
| 26 | + @param hashlen The length of the hash (octets) |
| 27 | + @param recid The recovery ID ("v"), can be -1 if signature contains it |
| 28 | + @param sigformat The format of the signature (ecc_signature_type) |
| 29 | + @param key The recovered public ECC key |
| 30 | + @return CRYPT_OK if successful (even if the signature is not valid) |
| 31 | +*/ |
| 32 | +int ecc_recover_key(const unsigned char *sig, unsigned long siglen, |
| 33 | + const unsigned char *hash, unsigned long hashlen, |
| 34 | + int recid, ecc_signature_type sigformat, ecc_key *key) |
24 | 35 | { |
25 | 36 | ecc_point *mG = NULL, *mQ = NULL, *mR = NULL; |
26 | 37 | void *p, *m, *a, *b; |
@@ -62,11 +73,56 @@ static int _ecc_recover_key(const unsigned char *sig, unsigned long siglen, |
62 | 73 | goto error; |
63 | 74 | } |
64 | 75 |
|
65 | | - /* Only ASN.1 format signatures supported for now */ |
66 | | - if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT, |
| 76 | + if (sigformat == LTC_ECCSIG_ANSIX962) { |
| 77 | + /* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) } */ |
| 78 | + if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT, |
67 | 79 | LTC_ASN1_INTEGER, 1UL, r, |
68 | 80 | LTC_ASN1_INTEGER, 1UL, s, |
69 | 81 | LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { goto error; } |
| 82 | + } |
| 83 | + else if (sigformat == LTC_ECCSIG_RFC7518) { |
| 84 | + /* RFC7518 format - raw (r,s) */ |
| 85 | + i = mp_unsigned_bin_size(key->dp.order); |
| 86 | + if (siglen != (2*i)) { |
| 87 | + err = CRYPT_INVALID_PACKET; |
| 88 | + goto error; |
| 89 | + } |
| 90 | + if ((err = mp_read_unsigned_bin(r, (unsigned char *)sig, i)) != CRYPT_OK) { goto error; } |
| 91 | + if ((err = mp_read_unsigned_bin(s, (unsigned char *)sig+i, i)) != CRYPT_OK) { goto error; } |
| 92 | + } |
| 93 | + else if (sigformat == LTC_ECCSIG_ETH27) { |
| 94 | + /* Ethereum (v,r,s) format */ |
| 95 | + if (key->dp.oidlen != 5 || key->dp.oid[0] != 1 || key->dp.oid[1] != 3 || |
| 96 | + key->dp.oid[2] != 132 || key->dp.oid[3] != 0 || key->dp.oid[4] != 10) { |
| 97 | + /* Only valid for secp256k1 - OID 1.3.132.0.10 */ |
| 98 | + err = CRYPT_ERROR; goto error; |
| 99 | + } |
| 100 | + if (siglen != 65) { /* Only secp256k1 curves use this format, so must be 65 bytes long */ |
| 101 | + err = CRYPT_INVALID_PACKET; |
| 102 | + goto error; |
| 103 | + } |
| 104 | + i = (unsigned long)sig[64]; |
| 105 | + if ((i>=27) && (i<31)) i -= 27; /* Ethereum adds 27 to recovery ID */ |
| 106 | + if (recid >= 0 && ((unsigned long)recid != i)) { |
| 107 | + /* Recovery ID specified, but doesn't match signature */ |
| 108 | + err = CRYPT_INVALID_PACKET; |
| 109 | + goto error; |
| 110 | + } |
| 111 | + recid = i; |
| 112 | + if ((err = mp_read_unsigned_bin(r, (unsigned char *)sig, 32)) != CRYPT_OK) { goto error; } |
| 113 | + if ((err = mp_read_unsigned_bin(s, (unsigned char *)sig+32, 32)) != CRYPT_OK) { goto error; } |
| 114 | + } |
| 115 | + else { |
| 116 | + /* Unknown signature format */ |
| 117 | + err = CRYPT_ERROR; |
| 118 | + goto error; |
| 119 | + } |
| 120 | + |
| 121 | + if (recid < 0 || (unsigned long)recid >= 2*(key->dp.cofactor+1)) { |
| 122 | + /* Recovery ID is out of range, reject it */ |
| 123 | + err = CRYPT_INVALID_ARG; |
| 124 | + goto error; |
| 125 | + } |
70 | 126 |
|
71 | 127 | /* check for zero */ |
72 | 128 | if (mp_cmp_d(r, 0) != LTC_MP_GT || mp_cmp_d(s, 0) != LTC_MP_GT || |
@@ -181,27 +237,10 @@ static int _ecc_recover_key(const unsigned char *sig, unsigned long siglen, |
181 | 237 | if (mR != NULL) ltc_ecc_del_point(mR); |
182 | 238 | if (mQ != NULL) ltc_ecc_del_point(mQ); |
183 | 239 | if (mG != NULL) ltc_ecc_del_point(mG); |
184 | | - mp_clear_multi(r, s, v, w, t1, t2, u1, u2, v1, v2, e, x, y, a_plus3, NULL); |
| 240 | + mp_clear_multi(a_plus3, y, x, e, v2, v1, u2, u1, t2, t1, w, v, s, r, NULL); |
185 | 241 | return err; |
186 | 242 | } |
187 | 243 |
|
188 | | -/** |
189 | | - Recover ECC public key from signature and hash |
190 | | - @param sig The signature to verify |
191 | | - @param siglen The length of the signature (octets) |
192 | | - @param hash The hash (message digest) that was signed |
193 | | - @param hashlen The length of the hash (octets) |
194 | | - @param recid 0 or 1 to select parity ("v") |
195 | | - @param key The recovered public ECC key |
196 | | - @return CRYPT_OK if successful (even if the signature is not valid) |
197 | | -*/ |
198 | | -int ecc_recover_key(const unsigned char *sig, unsigned long siglen, |
199 | | - const unsigned char *hash, unsigned long hashlen, |
200 | | - int recid, ecc_key *key) |
201 | | -{ |
202 | | - return _ecc_recover_key(sig, siglen, hash, hashlen, recid, key); |
203 | | -} |
204 | | - |
205 | 244 | #endif |
206 | 245 | #endif |
207 | 246 |
|
|
0 commit comments