Skip to content

Commit 9ba9641

Browse files
rmw42sjaeckel
authored andcommitted
RFC6979: implementation, tests, docs
1 parent d448df1 commit 9ba9641

File tree

5 files changed

+162
-4
lines changed

5 files changed

+162
-4
lines changed

doc/crypt.tex

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5827,8 +5827,11 @@ \subsection{Signature Generation}
58275827
\end{verbatim}
58285828

58295829
This function will \textit{ECDSA} sign the message digest stored in the array pointed to by \code{in} of length \code{inlen} octets. The signature
5830-
will be stored in the array pointed to by \code{out} of length \code{outlen} octets. The function requires a properly seeded \textit{PRNG}, and
5831-
the \textit{ECC} \code{key} provided must be a private key.
5830+
will be stored in the array pointed to by \code{out} of length \code{outlen} octets. The function requires that the \textit{ECC}
5831+
\code{key} provided must be a private key.
5832+
5833+
It requires a properly seeded \textit{PRNG} for standard \textit{ECDSA}, or if \code{prng} is NULL and/or \code{wprng} is less than zero,
5834+
the private key and the message itself will be used to create a deterministic signature according to \textit{RFC6979}.
58325835

58335836
\index{ecc\_sign\_hash\_rfc7518()}
58345837
\begin{verbatim}

src/headers/tomcrypt_pk.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ int ecc_get_size(const ecc_key *key);
304304
int ecc_find_curve(const char* name_or_oid, const ltc_ecc_curve** cu);
305305
int ecc_set_curve(const ltc_ecc_curve *cu, ecc_key *key);
306306
int ecc_generate_key(prng_state *prng, int wprng, ecc_key *key);
307+
int ecc_rfc6979_key(const ecc_key *priv, const unsigned char *in, int inlen, ecc_key *key);
307308
int ecc_set_key(const unsigned char *in, unsigned long inlen, int type, ecc_key *key);
308309
int ecc_get_key(unsigned char *out, unsigned long *outlen, int type, const ecc_key *key);
309310
int ecc_get_oid_str(char *out, unsigned long *outlen, const ecc_key *key);

src/pk/ecc/ecc_rfc6979_key.c

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
2+
*
3+
* LibTomCrypt is a library that provides various cryptographic
4+
* algorithms in a highly modular and flexible manner.
5+
*
6+
* The library is free for all purposes without any express
7+
* guarantee it works.
8+
*/
9+
10+
#include "tomcrypt_private.h"
11+
12+
/**
13+
@file ecc_rfc6979_key.c
14+
ECC Crypto, Russ Williams
15+
*/
16+
17+
#ifdef LTC_MECC
18+
#ifdef LTC_SHA256
19+
20+
/**
21+
Make deterministic ECC key using the RFC6979 method
22+
@param priv [in] Private key for HMAC
23+
@param in Message to sign for HMAC
24+
@param inlen Length of the message
25+
@param key [out] Newly created deterministic key
26+
@return CRYPT_OK if successful, upon error all allocated memory will be freed
27+
*/
28+
int ecc_rfc6979_key(const ecc_key *priv, const unsigned char *in, int inlen, ecc_key *key)
29+
{
30+
int err, hash, i;
31+
unsigned char v[32], k[32], digest[32]; /* No way to determine hash so always use SHA256 */
32+
unsigned char buffer[256];
33+
unsigned long outlen, buflen, qlen;
34+
35+
LTC_ARGCHK(ltc_mp.name != NULL);
36+
LTC_ARGCHK(key != NULL);
37+
LTC_ARGCHK(key->dp.size > 0);
38+
39+
hash = find_hash("sha256");
40+
if (hash == -1) {err = CRYPT_ERROR; goto error;}
41+
42+
/* Length, in bytes, of key */
43+
i = mp_count_bits(key->dp.order);
44+
qlen = (i+7) >> 3;
45+
46+
/* RFC6979 3.2b, set V */
47+
for (i=0; i<32; i++) v[i] = 0x01;
48+
49+
/* RFC6979 3.2c, set K */
50+
for (i=0; i<32; i++) k[i] = 0x00;
51+
52+
/* RFC6979 3.2d, set K to HMAC_K(V::0x00::priv::in) */
53+
XMEMCPY(&buffer[0], v, 32);
54+
buffer[32] = 0x00;
55+
if ((err = mp_to_unsigned_bin(priv->k, &buffer[33]) != CRYPT_OK)) { goto error; }
56+
XMEMCPY(&buffer[33+qlen], in, inlen);
57+
buflen = 32 + 1 + qlen + inlen;
58+
outlen = sizeof(digest);
59+
if((err = hmac_memory(hash, k, 32, buffer, buflen, digest, &outlen)) != CRYPT_OK) { goto error; }
60+
XMEMCPY(k, digest, 32);
61+
62+
/* RFC6979 3.2e, set V = HMAC_K(V) */
63+
outlen = sizeof(digest);
64+
if((err = hmac_memory(hash, k, 32, v, 32, digest, &outlen)) != CRYPT_OK) { goto error; }
65+
XMEMCPY(v, digest, 32);
66+
67+
/* RFC6979 3.2f, set K to HMAC_K(V::0x01::priv::in) */
68+
XMEMCPY(&buffer[0], v, 32);
69+
buffer[32] = 0x01;
70+
if ((err = mp_to_unsigned_bin(priv->k, &buffer[33]) != CRYPT_OK)) { goto error; }
71+
XMEMCPY(&buffer[33+qlen], in, inlen);
72+
buflen = 32 + 1 + qlen + inlen;
73+
outlen = sizeof(digest);
74+
if((err = hmac_memory(hash, k, 32, buffer, buflen, digest, &outlen)) != CRYPT_OK) { goto error; }
75+
XMEMCPY(k, digest, 32);
76+
77+
/* RFC6979 3.2g, set V = HMAC_K(V) */
78+
outlen = sizeof(digest);
79+
if((err = hmac_memory(hash, k, 32, v, 32, digest, &outlen)) != CRYPT_OK) { goto error; }
80+
XMEMCPY(v, digest, 32);
81+
82+
/* RFC6979 3.2h, generate and check key */
83+
do {
84+
/* concatenate hash bits into T */
85+
buflen = 0;
86+
while (buflen < qlen) {
87+
outlen = sizeof(digest);
88+
if((err = hmac_memory(hash, k, 32, v, 32, digest, &outlen)) != CRYPT_OK) { goto error; }
89+
XMEMCPY(v, digest, 32);
90+
XMEMCPY(&buffer[buflen], v, 32);
91+
buflen += 32;
92+
}
93+
94+
/* key->k = bits2int(T) */
95+
if ((err = mp_read_unsigned_bin(key->k, (unsigned char *)buffer, qlen)) != CRYPT_OK) { goto error; }
96+
97+
/* make the public key */
98+
if ((err = ltc_mp.ecc_ptmul(key->k, &key->dp.base, &key->pubkey, key->dp.A, key->dp.prime, 1)) != CRYPT_OK) {
99+
goto error;
100+
}
101+
102+
/* check that k is in range [1,q-1] */
103+
if (mp_cmp_d(key->k, 0) == LTC_MP_GT && mp_cmp(key->k, key->dp.order) == LTC_MP_LT) {
104+
/* TODO: Check that pubkey.x != 0 (mod p) */
105+
106+
/* if we have a valid key, exit loop */
107+
break;
108+
} else {
109+
/* K = HMAC_K(V::0x00) */
110+
XMEMCPY(&buffer[0], v, 32);
111+
buffer[32] = 0x00;
112+
buflen = 32 + 1;
113+
outlen = sizeof(digest);
114+
if((err = hmac_memory(hash, k, 32, buffer, buflen, digest, &outlen)) != CRYPT_OK) { goto error; }
115+
XMEMCPY(k, digest, 32);
116+
117+
/* V = HMAC_K(V) */
118+
outlen = sizeof(digest);
119+
if((err = hmac_memory(hash, k, 32, v, 32, digest, &outlen)) != CRYPT_OK) { goto error; }
120+
XMEMCPY(v, digest, 32);
121+
122+
/* ... and try again! */
123+
}
124+
} while (1);
125+
126+
key->type = PK_PRIVATE;
127+
128+
/* success */
129+
err = CRYPT_OK;
130+
goto cleanup;
131+
132+
error:
133+
ecc_free(key);
134+
cleanup:
135+
return err;
136+
}
137+
138+
#endif
139+
#endif
140+
/* ref: $Format:%D$ */
141+
/* git commit: $Format:%H$ */
142+
/* commit time: $Format:%ai$ */
143+

src/pk/ecc/ecc_sign_hash.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
@param inlen The length of the digest
1212
@param out [out] The destination for the signature
1313
@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
14+
@param prng An active PRNG state, NULL for RFC6979 deterministic signatures
15+
@param wprng The index of the PRNG you wish to use, -1 for RFC6979 deterministic signatures
16+
@param sigformat The format of the signature to generate (ecc_signature_type)
17+
@param recid [out] The recovery ID for this signature (optional)
1618
@param key A private ECC key
1719
@return CRYPT_OK if successful
1820
*/

tests/ecc_test.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,15 @@ static int s_ecc_new_api(void)
642642
}
643643
#endif
644644

645+
#ifdef LTC_SHA256
646+
/* test RFC6979 signature */
647+
len = sizeof(buf);
648+
DO(ecc_sign_hash(data16, 16, buf, &len, NULL, -1, &privkey));
649+
stat = 0;
650+
DO(ecc_verify_hash(buf, len, data16, 16, &stat, &pubkey));
651+
if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
652+
#endif
653+
645654
/* test encryption */
646655
len = sizeof(buf);
647656
DO(ecc_encrypt_key(data16, 16, buf, &len, &yarrow_prng, find_prng("yarrow"), find_hash("sha256"), &pubkey));

0 commit comments

Comments
 (0)