163 lines
5.8 KiB
C
163 lines
5.8 KiB
C
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
|
/* SPDX-License-Identifier: Unlicense */
|
|
|
|
#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, unsigned long inlen, ecc_key *key)
|
|
{
|
|
int err, hash = -1;
|
|
unsigned char v[MAXBLOCKSIZE], k[MAXBLOCKSIZE];
|
|
unsigned char buffer[256], sep[1], privkey[128];
|
|
unsigned long order_bits, len_diff, pk_len, zero_extend, outlen, klen, vlen, buflen, qlen, hashsize;
|
|
void *r, *d;
|
|
|
|
LTC_ARGCHK(ltc_mp.name != NULL);
|
|
LTC_ARGCHK(priv != NULL);
|
|
LTC_ARGCHK(key != NULL);
|
|
LTC_ARGCHK(key->dp.size > 0);
|
|
|
|
if (priv->rfc6979_hash_alg == NULL) {
|
|
return CRYPT_INVALID_ARG;
|
|
}
|
|
hash = find_hash(priv->rfc6979_hash_alg);
|
|
if ((err = hash_is_valid(hash)) != CRYPT_OK) {
|
|
return err;
|
|
}
|
|
|
|
hashsize = hash_descriptor[hash].hashsize;
|
|
|
|
if ((err = ltc_mp_init_multi(&r, &d, NULL)) != CRYPT_OK) {
|
|
return err;
|
|
}
|
|
|
|
/* Length, in bytes, of key */
|
|
order_bits = ltc_mp_count_bits(key->dp.order);
|
|
qlen = (order_bits+7) >> 3;
|
|
len_diff = qlen > inlen ? qlen - inlen : 0;
|
|
pk_len = (ltc_mp_count_bits(priv->k)+7) >> 3;
|
|
zero_extend = qlen - pk_len;
|
|
XMEMSET(buffer, 0x00, len_diff + zero_extend);
|
|
|
|
/* RFC6979 3.2b, set V */
|
|
XMEMSET(v, 0x01, hashsize);
|
|
|
|
/* RFC6979 3.2c, set K */
|
|
XMEMSET(k, 0x00, hashsize);
|
|
|
|
if ((err = ltc_mp_to_unsigned_bin(priv->k, privkey) != CRYPT_OK)) { goto error; }
|
|
/* RFC6979 3.2d, set K to HMAC_K(V::0x00::priv::in) */
|
|
sep[0] = 0;
|
|
klen = sizeof(k);
|
|
if((err = hmac_memory_multi(hash,
|
|
k, hashsize,
|
|
k, &klen,
|
|
v, hashsize,
|
|
sep, 1,
|
|
buffer, zero_extend,
|
|
privkey, qlen - zero_extend,
|
|
buffer, len_diff,
|
|
in, qlen - len_diff,
|
|
LTC_NULL)) != CRYPT_OK) { goto error; }
|
|
|
|
/* RFC6979 3.2e, set V = HMAC_K(V) */
|
|
vlen = sizeof(v);
|
|
if((err = hmac_memory(hash, k, klen, v, hashsize, v, &vlen)) != CRYPT_OK) { goto error; }
|
|
|
|
/* RFC6979 3.2f, set K to HMAC_K(V::0x01::priv::in) */
|
|
sep[0] = 0x01;
|
|
outlen = sizeof(k);
|
|
if((err = hmac_memory_multi(hash,
|
|
k, klen,
|
|
k, &klen,
|
|
v, hashsize,
|
|
sep, 1,
|
|
buffer, zero_extend,
|
|
privkey, qlen - zero_extend,
|
|
buffer, len_diff,
|
|
in, qlen - len_diff,
|
|
LTC_NULL)) != CRYPT_OK) { goto error; }
|
|
|
|
/* RFC6979 3.2g, set V = HMAC_K(V) */
|
|
outlen = sizeof(v);
|
|
if((err = hmac_memory(hash, k, klen, v, hashsize, v, &outlen)) != CRYPT_OK) { goto error; }
|
|
|
|
/* RFC6979 3.2h, generate and check key */
|
|
do {
|
|
/* concatenate hash bits into T */
|
|
buflen = 0;
|
|
while (buflen < qlen) {
|
|
if (buflen + hashsize >= sizeof(buffer) || buflen + hashsize < buflen) {
|
|
err = CRYPT_BUFFER_OVERFLOW;
|
|
goto error;
|
|
}
|
|
outlen = sizeof(v);
|
|
if((err = hmac_memory(hash, k, klen, v, hashsize, v, &outlen)) != CRYPT_OK) { goto error; }
|
|
XMEMCPY(&buffer[buflen], v, hashsize);
|
|
buflen += hashsize;
|
|
}
|
|
|
|
/* key->k = bits2int(T) */
|
|
if ((err = ltc_mp_read_unsigned_bin(r, buffer, qlen)) != CRYPT_OK) { goto error; }
|
|
if ((qlen * 8) > order_bits) {
|
|
if ((err = ltc_mp_2expt(d, (qlen * 8) - order_bits)) != CRYPT_OK) { goto error; }
|
|
if ((err = ltc_mp_div(r, d, r, NULL)) != CRYPT_OK) { goto error; }
|
|
if ((err = ltc_mp_to_unsigned_bin(r, buffer)) != CRYPT_OK) { goto error; }
|
|
qlen = ltc_mp_unsigned_bin_size(r);
|
|
}
|
|
|
|
if ((err = ecc_set_key(buffer, qlen, PK_PRIVATE, key))!= CRYPT_OK) { goto error; }
|
|
|
|
/* check that k is in range [1,q-1] */
|
|
if (ltc_mp_cmp_d(key->k, 0) == LTC_MP_GT && ltc_mp_cmp(key->k, key->dp.order) == LTC_MP_LT) {
|
|
/* Check that pubkey.x != 0 (mod p) */
|
|
if ((err = ltc_mp_mod(key->pubkey.x, key->dp.order, r)) != CRYPT_OK) { goto error; }
|
|
|
|
/* if we have a valid key, exit loop */
|
|
if (ltc_mp_iszero(r) == LTC_MP_NO)
|
|
break;
|
|
} else {
|
|
/* K = HMAC_K(V::0x00) */
|
|
buffer[0] = 0x0;
|
|
outlen = sizeof(k);
|
|
if((err = hmac_memory_multi(hash, k, klen, k, &klen, v, hashsize, buffer, 1, LTC_NULL)) != CRYPT_OK) { goto error; }
|
|
|
|
/* V = HMAC_K(V) */
|
|
outlen = sizeof(v);
|
|
if((err = hmac_memory(hash, k, klen, v, hashsize, v, &outlen)) != CRYPT_OK) { goto error; }
|
|
|
|
/* ... and try again! */
|
|
}
|
|
} while (1);
|
|
|
|
key->type = PK_PRIVATE;
|
|
|
|
/* success */
|
|
err = CRYPT_OK;
|
|
goto cleanup;
|
|
|
|
error:
|
|
ecc_free(key);
|
|
cleanup:
|
|
ltc_mp_cleanup_multi(&d, &r, NULL);
|
|
return err;
|
|
}
|
|
|
|
#endif
|
|
#endif
|