Files
data-lite-c/Sources/DataLiteC/libtomcrypt/pk/ecc/ecc_rfc6979_key.c
2025-10-24 19:33:21 +03:00

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