1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 /**
6    @file dsa_sign_hash.c
7    DSA implementation, sign a hash, Tom St Denis
8 */
9 
10 #ifdef LTC_MDSA
11 
12 /**
13   Sign a hash with DSA
14   @param in       The hash to sign
15   @param inlen    The length of the hash to sign
16   @param r        The "r" integer of the signature (caller must initialize with mp_init() first)
17   @param s        The "s" integer of the signature (caller must initialize with mp_init() first)
18   @param prng     An active PRNG state
19   @param wprng    The index of the PRNG desired
20   @param key      A private DSA key
21   @return CRYPT_OK if successful
22 */
dsa_sign_hash_raw(const unsigned char * in,unsigned long inlen,void * r,void * s,prng_state * prng,int wprng,const dsa_key * key)23 int dsa_sign_hash_raw(const unsigned char *in,  unsigned long inlen,
24                                    void   *r,   void *s,
25                                prng_state *prng, int wprng, const dsa_key *key)
26 {
27    void         *k, *kinv, *tmp;
28    unsigned char *buf;
29    int            err, qbits;
30 
31    LTC_ARGCHK(in  != NULL);
32    LTC_ARGCHK(r   != NULL);
33    LTC_ARGCHK(s   != NULL);
34    LTC_ARGCHK(key != NULL);
35 
36    if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
37       return err;
38    }
39    if (key->type != PK_PRIVATE) {
40       return CRYPT_PK_NOT_PRIVATE;
41    }
42 
43    /* check group order size  */
44    if (key->qord >= LTC_MDSA_MAX_GROUP) {
45       return CRYPT_INVALID_ARG;
46    }
47 
48    buf = XMALLOC(LTC_MDSA_MAX_GROUP);
49    if (buf == NULL) {
50       return CRYPT_MEM;
51    }
52 
53    /* Init our temps */
54    if ((err = mp_init_multi(&k, &kinv, &tmp, LTC_NULL)) != CRYPT_OK)                   { goto ERRBUF; }
55 
56    qbits = mp_count_bits(key->q);
57 retry:
58 
59    do {
60       /* gen random k */
61       if ((err = rand_bn_bits(k, qbits, prng, wprng)) != CRYPT_OK)                     { goto error; }
62 
63       /* k should be from range: 1 <= k <= q-1 (see FIPS 186-4 B.2.2) */
64       if (mp_cmp_d(k, 0) != LTC_MP_GT || mp_cmp(k, key->q) != LTC_MP_LT)               { goto retry; }
65 
66       /* test gcd */
67       if ((err = mp_gcd(k, key->q, tmp)) != CRYPT_OK)                                  { goto error; }
68    } while (mp_cmp_d(tmp, 1) != LTC_MP_EQ);
69 
70    /* now find 1/k mod q */
71    if ((err = mp_invmod(k, key->q, kinv)) != CRYPT_OK)                                 { goto error; }
72 
73    /* now find r = g^k mod p mod q */
74    if ((err = mp_exptmod(key->g, k, key->p, r)) != CRYPT_OK)                           { goto error; }
75    if ((err = mp_mod(r, key->q, r)) != CRYPT_OK)                                       { goto error; }
76 
77    if (mp_iszero(r) == LTC_MP_YES)                                                     { goto retry; }
78 
79    /* FIPS 186-4 4.6: use leftmost min(bitlen(q), bitlen(hash)) bits of 'hash'*/
80    inlen = MIN(inlen, (unsigned long)(key->qord));
81 
82    /* now find s = (in + xr)/k mod q */
83    if ((err = mp_read_unsigned_bin(tmp, (unsigned char *)in, inlen)) != CRYPT_OK)      { goto error; }
84    if ((err = mp_mul(key->x, r, s)) != CRYPT_OK)                                       { goto error; }
85    if ((err = mp_add(s, tmp, s)) != CRYPT_OK)                                          { goto error; }
86    if ((err = mp_mulmod(s, kinv, key->q, s)) != CRYPT_OK)                              { goto error; }
87 
88    if (mp_iszero(s) == LTC_MP_YES)                                                     { goto retry; }
89 
90    err = CRYPT_OK;
91 error:
92    mp_clear_multi(k, kinv, tmp, LTC_NULL);
93 ERRBUF:
94 #ifdef LTC_CLEAN_STACK
95    zeromem(buf, LTC_MDSA_MAX_GROUP);
96 #endif
97    XFREE(buf);
98    return err;
99 }
100 
101 /**
102   Sign a hash with DSA
103   @param in       The hash to sign
104   @param inlen    The length of the hash to sign
105   @param out      [out] Where to store the signature
106   @param outlen   [in/out] The max size and resulting size of the signature
107   @param prng     An active PRNG state
108   @param wprng    The index of the PRNG desired
109   @param key      A private DSA key
110   @return CRYPT_OK if successful
111 */
dsa_sign_hash(const unsigned char * in,unsigned long inlen,unsigned char * out,unsigned long * outlen,prng_state * prng,int wprng,const dsa_key * key)112 int dsa_sign_hash(const unsigned char *in,  unsigned long inlen,
113                         unsigned char *out, unsigned long *outlen,
114                         prng_state *prng, int wprng, const dsa_key *key)
115 {
116    void         *r, *s;
117    int           err;
118 
119    LTC_ARGCHK(in      != NULL);
120    LTC_ARGCHK(out     != NULL);
121    LTC_ARGCHK(outlen  != NULL);
122    LTC_ARGCHK(key     != NULL);
123 
124    if (mp_init_multi(&r, &s, LTC_NULL) != CRYPT_OK) {
125       return CRYPT_MEM;
126    }
127 
128    if ((err = dsa_sign_hash_raw(in, inlen, r, s, prng, wprng, key)) != CRYPT_OK) {
129       goto error;
130    }
131 
132    err = der_encode_sequence_multi(out, outlen,
133                              LTC_ASN1_INTEGER, 1UL, r,
134                              LTC_ASN1_INTEGER, 1UL, s,
135                              LTC_ASN1_EOL,     0UL, NULL);
136 
137 error:
138    mp_clear_multi(r, s, LTC_NULL);
139    return err;
140 }
141 
142 #endif
143