Skip to content

Commit 0ee3bb5

Browse files
karel-msjaeckel
authored andcommitted
refactor ecc_sign_hash_ex
1 parent c996610 commit 0ee3bb5

8 files changed

Lines changed: 328 additions & 165 deletions

File tree

src/headers/tomcrypt_pk.h

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -337,23 +337,33 @@ int ecc_decrypt_key(const unsigned char *in, unsigned long inlen,
337337
unsigned char *out, unsigned long *outlen,
338338
const ecc_key *key);
339339

340-
#define ecc_sign_hash_rfc7518(in_, inlen_, out_, outlen_, prng_, wprng_, key_) \
341-
ecc_sign_hash_ex(in_, inlen_, out_, outlen_, prng_, wprng_, LTC_ECCSIG_RFC7518, NULL, key_)
340+
int ecc_sign_hash(const unsigned char *in, unsigned long inlen,
341+
unsigned char *out, unsigned long *outlen,
342+
prng_state *prng, int wprng, const ecc_key *key);
342343

343-
#define ecc_sign_hash(in_, inlen_, out_, outlen_, prng_, wprng_, key_) \
344-
ecc_sign_hash_ex(in_, inlen_, out_, outlen_, prng_, wprng_, LTC_ECCSIG_ANSIX962, NULL, key_)
344+
int ecc_sign_hash_rfc7518(const unsigned char *in, unsigned long inlen,
345+
unsigned char *out, unsigned long *outlen,
346+
prng_state *prng, int wprng, const ecc_key *key);
347+
348+
int ecc_sign_hash_rfc7518_ex(const unsigned char *in, unsigned long inlen,
349+
unsigned char *out, unsigned long *outlen,
350+
prng_state *prng, int wprng,
351+
int *recid, const ecc_key *key);
352+
353+
int ecc_sign_hash_rfc5656(const unsigned char *in, unsigned long inlen,
354+
unsigned char *out, unsigned long *outlen,
355+
prng_state *prng, int wprng, const ecc_key *key);
356+
357+
int ecc_sign_hash_eth27(const unsigned char *in, unsigned long inlen,
358+
unsigned char *out, unsigned long *outlen,
359+
prng_state *prng, int wprng, const ecc_key *key);
345360

346361
#define ecc_verify_hash_rfc7518(sig_, siglen_, hash_, hashlen_, stat_, key_) \
347362
ecc_verify_hash_ex(sig_, siglen_, hash_, hashlen_, LTC_ECCSIG_RFC7518, stat_, key_)
348363

349364
#define ecc_verify_hash(sig_, siglen_, hash_, hashlen_, stat_, key_) \
350365
ecc_verify_hash_ex(sig_, siglen_, hash_, hashlen_, LTC_ECCSIG_ANSIX962, stat_, key_)
351366

352-
int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen,
353-
unsigned char *out, unsigned long *outlen,
354-
prng_state *prng, int wprng, ecc_signature_type sigformat,
355-
int *recid, const ecc_key *key);
356-
357367
int ecc_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
358368
const unsigned char *hash, unsigned long hashlen,
359369
ecc_signature_type sigformat, int *stat, const ecc_key *key);

src/headers/tomcrypt_private.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,10 @@ int ecc_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, ecc_ke
420420
int ecc_import_with_curve(const unsigned char *in, unsigned long inlen, int type, ecc_key *key);
421421
int ecc_import_with_oid(const unsigned char *in, unsigned long inlen, unsigned long *oid, unsigned long oid_len, int type, ecc_key *key);
422422

423+
int ecc_sign_hash_internal(const unsigned char *in, unsigned long inlen,
424+
void *r, void *s, prng_state *prng, int wprng,
425+
int *recid, const ecc_key *key);
426+
423427
#ifdef LTC_SSH
424428
int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key *key);
425429
#endif

src/pk/ecc/ecc_sign_hash.c

Lines changed: 14 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -6,175 +6,36 @@
66
#ifdef LTC_MECC
77

88
/**
9-
@file ecc_sign_hash.c
10-
ECC Crypto, Tom St Denis
11-
*/
12-
13-
/**
14-
Sign a message digest
9+
Sign a message digest (ANSI X9.62 format)
1510
@param in The message digest to sign
1611
@param inlen The length of the digest
1712
@param out [out] The destination for the signature
1813
@param outlen [in/out] The max size and resulting size of the signature
1914
@param prng An active PRNG state
2015
@param wprng The index of the PRNG you wish to use
21-
@param sigformat The format of the signature to generate (ecc_signature_type)
22-
@param recid [out] The recovery ID for this signature (optional)
2316
@param key A private ECC key
2417
@return CRYPT_OK if successful
2518
*/
26-
int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen,
27-
unsigned char *out, unsigned long *outlen,
28-
prng_state *prng, int wprng, ecc_signature_type sigformat,
29-
int *recid, const ecc_key *key)
19+
int ecc_sign_hash(const unsigned char *in, unsigned long inlen,
20+
unsigned char *out, unsigned long *outlen,
21+
prng_state *prng, int wprng, const ecc_key *key)
3022
{
31-
ecc_key pubkey;
32-
void *r, *s, *e, *p, *b;
33-
int v = 0;
34-
int err, max_iterations = LTC_PK_MAX_RETRIES;
35-
unsigned long pbits, pbytes, i, shift_right;
36-
unsigned char ch, buf[MAXBLOCKSIZE];
23+
int err;
24+
void *r, *s;
3725

38-
LTC_ARGCHK(in != NULL);
3926
LTC_ARGCHK(out != NULL);
4027
LTC_ARGCHK(outlen != NULL);
41-
LTC_ARGCHK(key != NULL);
42-
43-
/* is this a private key? */
44-
if (key->type != PK_PRIVATE) {
45-
return CRYPT_PK_NOT_PRIVATE;
46-
}
47-
48-
/* init the bignums */
49-
if ((err = ltc_mp_init_multi(&r, &s, &e, &b, LTC_NULL)) != CRYPT_OK) {
50-
return err;
51-
}
52-
53-
/* get the hash and load it as a bignum into 'e' */
54-
p = key->dp.order;
55-
pbits = ltc_mp_count_bits(p);
56-
pbytes = (pbits+7) >> 3;
57-
if (pbits > inlen*8) {
58-
if ((err = ltc_mp_read_unsigned_bin(e, in, inlen)) != CRYPT_OK) { goto errnokey; }
59-
}
60-
else if (pbits % 8 == 0) {
61-
if ((err = ltc_mp_read_unsigned_bin(e, in, pbytes)) != CRYPT_OK) { goto errnokey; }
62-
}
63-
else {
64-
shift_right = 8 - pbits % 8;
65-
for (i=0, ch=0; i<pbytes; i++) {
66-
buf[i] = ch;
67-
ch = (in[i] << (8-shift_right));
68-
buf[i] = buf[i] ^ (in[i] >> shift_right);
69-
}
70-
if ((err = ltc_mp_read_unsigned_bin(e, buf, pbytes)) != CRYPT_OK) { goto errnokey; }
71-
}
72-
73-
/* make up a key and export the public copy */
74-
do {
75-
if ((err = ecc_copy_curve(key, &pubkey)) != CRYPT_OK) { goto errnokey; }
76-
if ((err = ecc_generate_key(prng, wprng, &pubkey)) != CRYPT_OK) { goto errnokey; }
7728

78-
/* find r = x1 mod n */
79-
if ((err = ltc_mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK) { goto error; }
80-
81-
if (recid || sigformat==LTC_ECCSIG_ETH27) {
82-
/* find recovery ID (if needed) */
83-
v = 0;
84-
if (ltc_mp_copy(pubkey.pubkey.x, s) != CRYPT_OK) { goto error; }
85-
while (ltc_mp_cmp_d(s, 0) == LTC_MP_GT && ltc_mp_cmp(s, p) != LTC_MP_LT) {
86-
/* Compute x1 div n... this will almost never be reached for curves with order 1 */
87-
v += 2;
88-
if ((err = ltc_mp_sub(s, p, s)) != CRYPT_OK) { goto error; }
89-
}
90-
if (ltc_mp_isodd(pubkey.pubkey.y)) v += 1;
91-
}
92-
93-
if (ltc_mp_iszero(r) == LTC_MP_YES) {
94-
ecc_free(&pubkey);
95-
} else {
96-
if ((err = rand_bn_upto(b, p, prng, wprng)) != CRYPT_OK) { goto error; } /* b = blinding value */
97-
/* find s = (e + xr)/k */
98-
if ((err = ltc_mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = kb */
99-
if ((err = ltc_mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = 1/kb */
100-
if ((err = ltc_mp_mulmod(key->k, r, p, s)) != CRYPT_OK) { goto error; } /* s = xr */
101-
if ((err = ltc_mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK) { goto error; } /* s = xr/kb */
102-
if ((err = ltc_mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK) { goto error; } /* e = e/kb */
103-
if ((err = ltc_mp_add(e, s, s)) != CRYPT_OK) { goto error; } /* s = e/kb + xr/kb */
104-
if ((err = ltc_mp_mulmod(s, b, p, s)) != CRYPT_OK) { goto error; } /* s = b(e/kb + xr/kb) = (e + xr)/k */
105-
ecc_free(&pubkey);
106-
if (ltc_mp_iszero(s) == LTC_MP_NO) {
107-
break;
108-
}
109-
}
110-
} while (--max_iterations > 0);
111-
112-
if (max_iterations == 0) {
113-
goto errnokey;
114-
}
115-
116-
if (recid) *recid = v;
117-
118-
if (sigformat == LTC_ECCSIG_ANSIX962) {
119-
/* store as ASN.1 SEQUENCE { r, s -- integer } */
120-
err = der_encode_sequence_multi(out, outlen,
121-
LTC_ASN1_INTEGER, 1UL, r,
122-
LTC_ASN1_INTEGER, 1UL, s,
123-
LTC_ASN1_EOL, 0UL, NULL);
124-
}
125-
else if (sigformat == LTC_ECCSIG_RFC7518) {
126-
/* RFC7518 format - raw (r,s) */
127-
if (*outlen < 2*pbytes) { err = CRYPT_MEM; goto errnokey; }
128-
zeromem(out, 2*pbytes);
129-
i = ltc_mp_unsigned_bin_size(r);
130-
if ((err = ltc_mp_to_unsigned_bin(r, out + (pbytes - i))) != CRYPT_OK) { goto errnokey; }
131-
i = ltc_mp_unsigned_bin_size(s);
132-
if ((err = ltc_mp_to_unsigned_bin(s, out + (2*pbytes - i))) != CRYPT_OK) { goto errnokey; }
133-
*outlen = 2*pbytes;
134-
err = CRYPT_OK;
135-
}
136-
else if (sigformat == LTC_ECCSIG_ETH27) {
137-
/* Ethereum (v,r,s) format */
138-
if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
139-
/* Only valid for secp256k1 - OID 1.3.132.0.10 */
140-
err = CRYPT_ERROR; goto errnokey;
141-
}
142-
if (*outlen < 65) { err = CRYPT_MEM; goto errnokey; }
143-
zeromem(out, 65);
144-
i = ltc_mp_unsigned_bin_size(r);
145-
if ((err = ltc_mp_to_unsigned_bin(r, out + 32 - i)) != CRYPT_OK) { goto errnokey; }
146-
i = ltc_mp_unsigned_bin_size(s);
147-
if ((err = ltc_mp_to_unsigned_bin(s, out + 64 - i)) != CRYPT_OK) { goto errnokey; }
148-
out[64] = (unsigned char)(v + 27); /* Recovery ID is 27/28 for Ethereum */
149-
*outlen = 65;
150-
err = CRYPT_OK;
151-
}
152-
#ifdef LTC_SSH
153-
else if (sigformat == LTC_ECCSIG_RFC5656) {
154-
/* Get identifier string */
155-
char name[64];
156-
unsigned long namelen = sizeof(name);
157-
if ((err = ecc_ssh_ecdsa_encode_name(name, &namelen, key)) != CRYPT_OK) { goto errnokey; }
158-
159-
/* Store as SSH data sequence, per RFC4251 */
160-
err = ssh_encode_sequence_multi(out, outlen,
161-
LTC_SSHDATA_STRING, name, namelen,
162-
LTC_SSHDATA_MPINT, r,
163-
LTC_SSHDATA_MPINT, s,
164-
LTC_SSHDATA_EOL, NULL);
165-
}
166-
#endif
167-
else {
168-
/* Unknown signature format */
169-
err = CRYPT_ERROR;
170-
goto error;
171-
}
29+
if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
30+
if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, NULL, key)) != CRYPT_OK) goto error;
17231

173-
goto errnokey;
32+
/* store as ASN.1 SEQUENCE { r, s -- integer } */
33+
err = der_encode_sequence_multi(out, outlen,
34+
LTC_ASN1_INTEGER, 1UL, r,
35+
LTC_ASN1_INTEGER, 1UL, s,
36+
LTC_ASN1_EOL, 0UL, NULL);
17437
error:
175-
ecc_free(&pubkey);
176-
errnokey:
177-
ltc_mp_deinit_multi(r, s, e, b, LTC_NULL);
38+
ltc_mp_deinit_multi(r, s, LTC_NULL);
17839
return err;
17940
}
18041

src/pk/ecc/ecc_sign_hash_eth27.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2+
/* SPDX-License-Identifier: Unlicense */
3+
4+
#include "tomcrypt_private.h"
5+
6+
#ifdef LTC_MECC
7+
8+
/**
9+
Sign a message digest (Ethereum format with recovery_id+27)
10+
@param in The message digest to sign
11+
@param inlen The length of the digest
12+
@param out [out] The destination for the signature
13+
@param outlen [in/out] The max size and resulting size of the signature
14+
@param prng An active PRNG state
15+
@param wprng The index of the PRNG you wish to use
16+
@param key A private ECC key
17+
@return CRYPT_OK if successful
18+
*/
19+
int ecc_sign_hash_eth27(const unsigned char *in, unsigned long inlen,
20+
unsigned char *out, unsigned long *outlen,
21+
prng_state *prng, int wprng, const ecc_key *key)
22+
{
23+
int err, recid;
24+
void *r, *s;
25+
unsigned long i;
26+
27+
LTC_ARGCHK(out != NULL);
28+
LTC_ARGCHK(outlen != NULL);
29+
LTC_ARGCHK(key != NULL);
30+
31+
/* Only valid for secp256k1 - OID 1.3.132.0.10 */
32+
if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
33+
return CRYPT_ERROR;
34+
}
35+
if (*outlen < 65) {
36+
*outlen = 65;
37+
return CRYPT_BUFFER_OVERFLOW;
38+
}
39+
40+
if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
41+
if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, &recid, key)) != CRYPT_OK) goto error;
42+
43+
zeromem(out, 65);
44+
*outlen = 65;
45+
i = ltc_mp_unsigned_bin_size(r);
46+
if ((err = ltc_mp_to_unsigned_bin(r, out + 32 - i)) != CRYPT_OK) goto error;
47+
i = ltc_mp_unsigned_bin_size(s);
48+
if ((err = ltc_mp_to_unsigned_bin(s, out + 64 - i)) != CRYPT_OK) goto error;
49+
out[64] = (unsigned char)(recid + 27); /* Recovery ID is 27/28 for Ethereum */
50+
err = CRYPT_OK;
51+
52+
error:
53+
ltc_mp_deinit_multi(r, s, LTC_NULL);
54+
return err;
55+
}
56+
57+
#endif

0 commit comments

Comments
 (0)