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   @file ecc_sign_hash.c
10   ECC Crypto, Tom St Denis
11 */
12 
13 /**
14   Sign a message digest
15   @param in        The message digest to sign
16   @param inlen     The length of the digest
17   @param out       [out] The destination for the signature
18   @param outlen    [in/out] The max size and resulting size of the signature
19   @param prng      An active PRNG state
20   @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)
23   @param key       A private ECC key
24   @return CRYPT_OK if successful
25 */
ecc_sign_hash_ex(const unsigned char * in,unsigned long inlen,unsigned char * out,unsigned long * outlen,prng_state * prng,int wprng,ecc_signature_type sigformat,int * recid,const ecc_key * key)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)
30 {
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];
37 
38    LTC_ARGCHK(in     != NULL);
39    LTC_ARGCHK(out    != NULL);
40    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 = 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 = mp_count_bits(p);
56    pbytes = (pbits+7) >> 3;
57    if (pbits > inlen*8) {
58       if ((err = mp_read_unsigned_bin(e, (unsigned char *)in, inlen)) != CRYPT_OK)    { goto errnokey; }
59    }
60    else if (pbits % 8 == 0) {
61       if ((err = mp_read_unsigned_bin(e, (unsigned char *)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 = mp_read_unsigned_bin(e, (unsigned char *)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; }
77 
78       /* find r = x1 mod n */
79       if ((err = 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 (mp_copy(pubkey.pubkey.x, s) != CRYPT_OK)                      { goto error; }
85          while (mp_cmp_d(s, 0) == LTC_MP_GT && 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 = mp_sub(s, p, s)) != CRYPT_OK)                       { goto error; }
89          }
90          if (mp_isodd(pubkey.pubkey.y)) v += 1;
91       }
92 
93       if (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 = mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK)      { goto error; } /* k = kb */
99          if ((err = mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK)         { goto error; } /* k = 1/kb */
100          if ((err = mp_mulmod(key->k, r, p, s)) != CRYPT_OK)               { goto error; } /* s = xr */
101          if ((err = mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK)             { goto error; } /* s = xr/kb */
102          if ((err = mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK)             { goto error; } /* e = e/kb */
103          if ((err = mp_add(e, s, s)) != CRYPT_OK)                          { goto error; } /* s = e/kb + xr/kb */
104          if ((err = 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 (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 = mp_unsigned_bin_size(r);
130       if ((err = mp_to_unsigned_bin(r, out + (pbytes - i)))   != CRYPT_OK) { goto errnokey; }
131       i = mp_unsigned_bin_size(s);
132       if ((err = 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 = mp_unsigned_bin_size(r);
145       if ((err = mp_to_unsigned_bin(r, out + 32 - i)) != CRYPT_OK) { goto errnokey; }
146       i = mp_unsigned_bin_size(s);
147       if ((err = 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    }
172 
173    goto errnokey;
174 error:
175    ecc_free(&pubkey);
176 errnokey:
177    mp_clear_multi(r, s, e, b, LTC_NULL);
178    return err;
179 }
180 
181 #endif
182