Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/rfc6979 #477

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions doc/crypt.tex
Original file line number Diff line number Diff line change
Expand Up @@ -5518,8 +5518,11 @@ \subsection{Signature Generation}
\end{verbatim}

This function will ECDSA sign the message digest stored in the array pointed to by \textit{in} of length \textit{inlen} octets. The signature
will be stored in the array pointed to by \textit{out} of length \textit{outlen} octets. The function requires a properly seeded PRNG, and
the ECC \textit{key} provided must be a private key.
will be stored in the array pointed to by \textit{out} of length \textit{outlen} octets. The function requires that the ECC
\textit{key} provided must be a private key.

It requires a properly seeded PRNG for standard ECDSA, or if \textit{prng} is NULL and/or \textit{wprng} is less than zero,
the private key and the message itself will be used to create a deterministic signature according to RFC6979.

\index{ecc\_sign\_hash\_rfc7518()}
\begin{verbatim}
Expand Down
4 changes: 4 additions & 0 deletions libtomcrypt_VS2008.vcproj
Original file line number Diff line number Diff line change
Expand Up @@ -2382,6 +2382,10 @@
RelativePath="src\pk\ecc\ecc_recover_key.c"
>
</File>
<File
RelativePath="src\pk\ecc\ecc_rfc6979_key.c"
>
</File>
<File
RelativePath="src\pk\ecc\ecc_set_curve.c"
>
Expand Down
8 changes: 4 additions & 4 deletions makefile.mingw
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,10 @@ src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o src/pk/ecc/ecc_find_curv
src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/pk/ecc/ecc_get_size.o \
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_pkcs8.o \
src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o \
src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o \
src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o \
src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ltc_ecc_export_point.o \
src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
src/pk/ecc/ecc_rfc6979_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o \
src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \
Expand Down
8 changes: 4 additions & 4 deletions makefile.msvc
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,10 @@ src/pk/ecc/ecc_export.obj src/pk/ecc/ecc_export_openssl.obj src/pk/ecc/ecc_find_
src/pk/ecc/ecc_free.obj src/pk/ecc/ecc_get_key.obj src/pk/ecc/ecc_get_oid_str.obj src/pk/ecc/ecc_get_size.obj \
src/pk/ecc/ecc_import.obj src/pk/ecc/ecc_import_openssl.obj src/pk/ecc/ecc_import_pkcs8.obj \
src/pk/ecc/ecc_import_x509.obj src/pk/ecc/ecc_make_key.obj src/pk/ecc/ecc_recover_key.obj \
src/pk/ecc/ecc_set_curve.obj src/pk/ecc/ecc_set_curve_internal.obj src/pk/ecc/ecc_set_key.obj \
src/pk/ecc/ecc_shared_secret.obj src/pk/ecc/ecc_sign_hash.obj src/pk/ecc/ecc_sizes.obj \
src/pk/ecc/ecc_ssh_ecdsa_encode_name.obj src/pk/ecc/ecc_verify_hash.obj src/pk/ecc/ltc_ecc_export_point.obj \
src/pk/ecc/ltc_ecc_import_point.obj src/pk/ecc/ltc_ecc_is_point.obj \
src/pk/ecc/ecc_rfc6979_key.obj src/pk/ecc/ecc_set_curve.obj src/pk/ecc/ecc_set_curve_internal.obj \
src/pk/ecc/ecc_set_key.obj src/pk/ecc/ecc_shared_secret.obj src/pk/ecc/ecc_sign_hash.obj \
src/pk/ecc/ecc_sizes.obj src/pk/ecc/ecc_ssh_ecdsa_encode_name.obj src/pk/ecc/ecc_verify_hash.obj \
src/pk/ecc/ltc_ecc_export_point.obj src/pk/ecc/ltc_ecc_import_point.obj src/pk/ecc/ltc_ecc_is_point.obj \
src/pk/ecc/ltc_ecc_is_point_at_infinity.obj src/pk/ecc/ltc_ecc_map.obj src/pk/ecc/ltc_ecc_mul2add.obj \
src/pk/ecc/ltc_ecc_mulmod.obj src/pk/ecc/ltc_ecc_mulmod_timing.obj src/pk/ecc/ltc_ecc_points.obj \
src/pk/ecc/ltc_ecc_projective_add_point.obj src/pk/ecc/ltc_ecc_projective_dbl_point.obj \
Expand Down
8 changes: 4 additions & 4 deletions makefile.unix
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,10 @@ src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o src/pk/ecc/ecc_find_curv
src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/pk/ecc/ecc_get_size.o \
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_pkcs8.o \
src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o \
src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o \
src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o \
src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ltc_ecc_export_point.o \
src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
src/pk/ecc/ecc_rfc6979_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o \
src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \
Expand Down
8 changes: 4 additions & 4 deletions makefile_include.mk
Original file line number Diff line number Diff line change
Expand Up @@ -354,10 +354,10 @@ src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o src/pk/ecc/ecc_find_curv
src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/pk/ecc/ecc_get_size.o \
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_pkcs8.o \
src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o \
src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o \
src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o \
src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ltc_ecc_export_point.o \
src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
src/pk/ecc/ecc_rfc6979_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o \
src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \
Expand Down
1 change: 1 addition & 0 deletions src/headers/tomcrypt_pk.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ int ecc_get_size(const ecc_key *key);
int ecc_find_curve(const char* name_or_oid, const ltc_ecc_curve** cu);
int ecc_set_curve(const ltc_ecc_curve *cu, ecc_key *key);
int ecc_generate_key(prng_state *prng, int wprng, ecc_key *key);
int ecc_rfc6979_key(const ecc_key *priv, const unsigned char *in, int inlen, ecc_key *key);
int ecc_set_key(const unsigned char *in, unsigned long inlen, int type, ecc_key *key);
int ecc_get_key(unsigned char *out, unsigned long *outlen, int type, const ecc_key *key);
int ecc_get_oid_str(char *out, unsigned long *outlen, const ecc_key *key);
Expand Down
143 changes: 143 additions & 0 deletions src/pk/ecc/ecc_rfc6979_key.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*/

#include "tomcrypt_private.h"

/**
@file ecc_rfc6979_key.c
ECC Crypto, Russ Williams
*/

#ifdef LTC_MECC
#ifdef LTC_SHA256

/**
Make deterministic ECC key using the RFC6979 method
@param priv [in] Private key for HMAC
@param in Message to sign for HMAC
@param inlen Length of the message
@param key [out] Newly created deterministic key
@return CRYPT_OK if successful, upon error all allocated memory will be freed
*/
int ecc_rfc6979_key(const ecc_key *priv, const unsigned char *in, int inlen, ecc_key *key)
{
int err, hash, i;
unsigned char v[32], k[32], digest[32]; /* No way to determine hash so always use SHA256 */
unsigned char buffer[256];
unsigned long outlen, buflen, qlen;

LTC_ARGCHK(ltc_mp.name != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(key->dp.size > 0);

hash = find_hash("sha256");
if (hash == -1) {err = CRYPT_ERROR; goto error;}

/* Length, in bytes, of key */
i = mp_count_bits(key->dp.order);
qlen = (i+7) >> 3;

/* RFC6979 3.2b, set V */
for (i=0; i<32; i++) v[i] = 0x01;

/* RFC6979 3.2c, set K */
for (i=0; i<32; i++) k[i] = 0x00;

/* RFC6979 3.2d, set K to HMAC_K(V::0x00::priv::in) */
XMEMCPY(&buffer[0], v, 32);
buffer[32] = 0x00;
if ((err = mp_to_unsigned_bin(priv->k, &buffer[33]) != CRYPT_OK)) { goto error; }
XMEMCPY(&buffer[33+qlen], in, inlen);
buflen = 32 + 1 + qlen + inlen;
outlen = sizeof(digest);
if((err = hmac_memory(hash, k, 32, buffer, buflen, digest, &outlen)) != CRYPT_OK) { goto error; }
XMEMCPY(k, digest, 32);

/* RFC6979 3.2e, set V = HMAC_K(V) */
outlen = sizeof(digest);
if((err = hmac_memory(hash, k, 32, v, 32, digest, &outlen)) != CRYPT_OK) { goto error; }
XMEMCPY(v, digest, 32);

/* RFC6979 3.2f, set K to HMAC_K(V::0x01::priv::in) */
XMEMCPY(&buffer[0], v, 32);
buffer[32] = 0x01;
if ((err = mp_to_unsigned_bin(priv->k, &buffer[33]) != CRYPT_OK)) { goto error; }
XMEMCPY(&buffer[33+qlen], in, inlen);
buflen = 32 + 1 + qlen + inlen;
outlen = sizeof(digest);
if((err = hmac_memory(hash, k, 32, buffer, buflen, digest, &outlen)) != CRYPT_OK) { goto error; }
XMEMCPY(k, digest, 32);

/* RFC6979 3.2g, set V = HMAC_K(V) */
outlen = sizeof(digest);
if((err = hmac_memory(hash, k, 32, v, 32, digest, &outlen)) != CRYPT_OK) { goto error; }
XMEMCPY(v, digest, 32);

/* RFC6979 3.2h, generate and check key */
do {
/* concatenate hash bits into T */
buflen = 0;
while (buflen < qlen) {
outlen = sizeof(digest);
if((err = hmac_memory(hash, k, 32, v, 32, digest, &outlen)) != CRYPT_OK) { goto error; }
XMEMCPY(v, digest, 32);
XMEMCPY(&buffer[buflen], v, 32);
buflen += 32;
}

/* key->k = bits2int(T) */
if ((err = mp_read_unsigned_bin(key->k, (unsigned char *)buffer, qlen)) != CRYPT_OK) { goto error; }

/* make the public key */
if ((err = ltc_mp.ecc_ptmul(key->k, &key->dp.base, &key->pubkey, key->dp.A, key->dp.prime, 1)) != CRYPT_OK) {
goto error;
}

/* check that k is in range [1,q-1] */
if (mp_cmp_d(key->k, 0) == LTC_MP_GT && mp_cmp(key->k, key->dp.order) == LTC_MP_LT) {
/* TODO: Check that pubkey.x != 0 (mod p) */

/* if we have a valid key, exit loop */
break;
} else {
/* K = HMAC_K(V::0x00) */
XMEMCPY(&buffer[0], v, 32);
buffer[32] = 0x00;
buflen = 32 + 1;
outlen = sizeof(digest);
if((err = hmac_memory(hash, k, 32, buffer, buflen, digest, &outlen)) != CRYPT_OK) { goto error; }
XMEMCPY(k, digest, 32);

/* V = HMAC_K(V) */
outlen = sizeof(digest);
if((err = hmac_memory(hash, k, 32, v, 32, digest, &outlen)) != CRYPT_OK) { goto error; }
XMEMCPY(v, digest, 32);

/* ... and try again! */
}
} while (1);

key->type = PK_PRIVATE;

/* success */
err = CRYPT_OK;
goto cleanup;

error:
ecc_free(key);
cleanup:
return err;
}

#endif
#endif
/* ref: $Format:%D$ */
/* git commit: $Format:%H$ */
/* commit time: $Format:%ai$ */

37 changes: 26 additions & 11 deletions src/pk/ecc/ecc_sign_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
@param inlen The length of the digest
@param out [out] The destination for the signature
@param outlen [in/out] The max size and resulting size of the signature
@param prng An active PRNG state
@param wprng The index of the PRNG you wish to use
@param prng An active PRNG state, NULL for RFC6979 deterministic signatures
@param wprng The index of the PRNG you wish to use, -1 for RFC6979 deterministic signatures
@param sigformat The format of the signature to generate (ecc_signature_type)
@param recid [out] The recovery ID for this signature (optional)
@param key A private ECC key
Expand All @@ -37,6 +37,7 @@ int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen,
ecc_key pubkey;
void *r, *s, *e, *p, *b;
int v = 0;
int blinding = 1;
int err, max_iterations = LTC_PK_MAX_RETRIES;
unsigned long pbits, pbytes, i, shift_right;
unsigned char ch, buf[MAXBLOCKSIZE];
Expand Down Expand Up @@ -79,7 +80,13 @@ int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen,
/* make up a key and export the public copy */
do {
if ((err = ecc_copy_curve(key, &pubkey)) != CRYPT_OK) { goto errnokey; }
if ((err = ecc_generate_key(prng, wprng, &pubkey)) != CRYPT_OK) { goto errnokey; }

if (wprng < 0 || prng == NULL) {
blinding = 0;
if ((err = ecc_rfc6979_key(key, in, inlen, &pubkey)) != CRYPT_OK) { goto errnokey; }
} else {
if ((err = ecc_generate_key(prng, wprng, &pubkey)) != CRYPT_OK) { goto errnokey; }
}

/* find r = x1 mod n */
if ((err = mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK) { goto error; }
Expand All @@ -99,15 +106,23 @@ int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen,
if (mp_iszero(r) == LTC_MP_YES) {
ecc_free(&pubkey);
} else {
if ((err = rand_bn_upto(b, p, prng, wprng)) != CRYPT_OK) { goto error; } /* b = blinding value */
/* find s = (e + xr)/k */
if ((err = mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = kb */
if ((err = mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = 1/kb */
if ((err = mp_mulmod(key->k, r, p, s)) != CRYPT_OK) { goto error; } /* s = xr */
if ((err = mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK) { goto error; } /* s = xr/kb */
if ((err = mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK) { goto error; } /* e = e/kb */
if ((err = mp_add(e, s, s)) != CRYPT_OK) { goto error; } /* s = e/kb + xr/kb */
if ((err = mp_mulmod(s, b, p, s)) != CRYPT_OK) { goto error; } /* s = b(e/kb + xr/kb) = (e + xr)/k */
if (blinding) {
if ((err = rand_bn_upto(b, p, prng, wprng)) != CRYPT_OK) { goto error; } /* b = blinding value */
if ((err = mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = kb */
if ((err = mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = 1/kb */
if ((err = mp_mulmod(key->k, r, p, s)) != CRYPT_OK) { goto error; } /* s = xr */
if ((err = mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK) { goto error; } /* s = xr/kb */
if ((err = mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK) { goto error; } /* e = e/kb */
if ((err = mp_add(e, s, s)) != CRYPT_OK) { goto error; } /* s = e/kb + xr/kb */
if ((err = mp_mulmod(s, b, p, s)) != CRYPT_OK) { goto error; } /* s = b(e/kb + xr/kb) = (e + xr)/k */
} else {
if ((err = mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = 1/k */
if ((err = mp_mulmod(key->k, r, p, s)) != CRYPT_OK) { goto error; } /* s = xr */
if ((err = mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK) { goto error; } /* s = xr/k */
if ((err = mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK) { goto error; } /* e = e/k */
if ((err = mp_add(e, s, s)) != CRYPT_OK) { goto error; } /* s = (e + xr)/k */
}
ecc_free(&pubkey);
if (mp_iszero(s) == LTC_MP_NO) {
break;
Expand Down
9 changes: 9 additions & 0 deletions tests/ecc_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,15 @@ static int _ecc_new_api(void)
}
#endif

#ifdef LTC_SHA256
/* test RFC6979 signature */
len = sizeof(buf);
DO(ecc_sign_hash(data16, 16, buf, &len, NULL, -1, &privkey));
stat = 0;
DO(ecc_verify_hash(buf, len, data16, 16, &stat, &pubkey));
if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
#endif

/* test encryption */
len = sizeof(buf);
DO(ecc_encrypt_key(data16, 16, buf, &len, &yarrow_prng, find_prng("yarrow"), find_hash("sha256"), &pubkey));
Expand Down