Skip to content
Merged
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
15 changes: 9 additions & 6 deletions src/headers/tomcrypt_pk.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ enum {
/* Indicates standard output formats that can be read e.g. by OpenSSL or GnuTLS */
#define PK_STD 0x1000

/* iterations limit for retry-loops */
#define PK_MAX_RETRIES 20

int rand_prime(void *N, long len, prng_state *prng, int wprng);
int rand_bn_bits(void *N, int bits, prng_state *prng, int wprng);
int rand_bn_range(void *N, void *limit, prng_state *prng, int wprng);
Expand Down Expand Up @@ -314,17 +317,17 @@ int ecc_decrypt_key(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
ecc_key *key);

int ecc_sign_hash_raw(const unsigned char *in, unsigned long inlen,
void *r, void *s,
prng_state *prng, int wprng, ecc_key *key);
int ecc_sign_hash_rfc7518(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, ecc_key *key);

int ecc_sign_hash(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, ecc_key *key);

int ecc_verify_hash_raw( void *r, void *s,
const unsigned char *hash, unsigned long hashlen,
int *stat, ecc_key *key);
int ecc_verify_hash_rfc7518(const unsigned char *sig, unsigned long siglen,
const unsigned char *hash, unsigned long hashlen,
int *stat, ecc_key *key);

int ecc_verify_hash(const unsigned char *sig, unsigned long siglen,
const unsigned char *hash, unsigned long hashlen,
Expand Down
159 changes: 88 additions & 71 deletions src/pk/ecc/ecc_sign_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,29 @@
* guarantee it works.
*/

/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
*
* All curves taken from NIST recommendation paper of July 1999
* Available at http://csrc.nist.gov/cryptval/dss.htm
*/
#include "tomcrypt.h"

#ifdef LTC_MECC

/**
@file ecc_sign_hash.c
ECC Crypto, Tom St Denis
*/

#ifdef LTC_MECC

/**
Sign a hash with ECC
@param in The hash to sign
@param inlen The length of the hash to sign
@param r The "r" integer of the signature (caller must initialize with mp_init() first)
@param s The "s" integer of the signature (caller must initialize with mp_init() first)
@param prng An active PRNG state
@param wprng The index of the PRNG desired
@param key A private ECC key
@return CRYPT_OK if successful
*/
int ecc_sign_hash_raw(const unsigned char *in, unsigned long inlen,
void *r, void *s,
prng_state *prng, int wprng, ecc_key *key)
static int _ecc_sign_hash(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, ecc_key *key, int sigformat)
{
ecc_key pubkey;
void *e, *p;
int err;
void *r, *s, *e, *p;
int err, max_iterations = PK_MAX_RETRIES;
unsigned long pbits, pbytes, i, shift_right;
unsigned char ch, buf[MAXBLOCKSIZE];

LTC_ARGCHK(in != NULL);
LTC_ARGCHK(r != NULL);
LTC_ARGCHK(s != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(key != NULL);

/* is this a private key? */
if (key->type != PK_PRIVATE) {
Expand All @@ -59,46 +45,83 @@ int ecc_sign_hash_raw(const unsigned char *in, unsigned long inlen,
return err;
}

/* get the hash and load it as a bignum into 'e' */
/* init the bignums */
if ((err = mp_init_multi(&p, &e, NULL)) != CRYPT_OK) {
if ((err = mp_init_multi(&r, &s, &p, &e, NULL)) != CRYPT_OK) {
return err;
}
if ((err = mp_read_radix(p, (char *)key->dp->order, 16)) != CRYPT_OK) { goto errnokey; }
if ((err = mp_read_unsigned_bin(e, (unsigned char *)in, (int)inlen)) != CRYPT_OK) { goto errnokey; }
if ((err = mp_read_radix(p, (char *)key->dp->order, 16)) != CRYPT_OK) { goto errnokey; }

/* get the hash and load it as a bignum into 'e' */
pbits = mp_count_bits(p);
pbytes = (pbits+7) >> 3;
if (pbits > inlen*8) {
if ((err = mp_read_unsigned_bin(e, (unsigned char *)in, inlen)) != CRYPT_OK) { goto errnokey; }
}
else if (pbits % 8 == 0) {
if ((err = mp_read_unsigned_bin(e, (unsigned char *)in, pbytes)) != CRYPT_OK) { goto errnokey; }
}
else {
shift_right = 8 - pbits % 8;
for (i=0, ch=0; i<pbytes; i++) {
buf[i] = ch;
ch = (in[i] << (8-shift_right));
buf[i] = buf[i] ^ (in[i] >> shift_right);
}
if ((err = mp_read_unsigned_bin(e, (unsigned char *)buf, pbytes)) != CRYPT_OK) { goto errnokey; }
}

/* make up a key and export the public copy */
for (;;) {
do {
if ((err = ecc_make_key_ex(prng, wprng, &pubkey, key->dp)) != CRYPT_OK) {
goto errnokey;
}

/* find r = x1 mod n */
if ((err = mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK) { goto error; }
if ((err = mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK) { goto error; }

if (mp_iszero(r) == LTC_MP_YES) {
ecc_free(&pubkey);
} else {
/* find s = (e + xr)/k */
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_add(e, s, s)) != CRYPT_OK) { goto error; } /* s = e + xr */
if ((err = mp_mod(s, p, s)) != CRYPT_OK) { goto error; } /* s = e + xr */
if ((err = mp_mulmod(s, pubkey.k, p, s)) != CRYPT_OK) { goto error; } /* s = (e + xr)/k */
ecc_free(&pubkey);
if (mp_iszero(s) == LTC_MP_NO) {
break;
}
/* find s = (e + xr)/k */
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_add(e, s, s)) != CRYPT_OK) { goto error; } /* s = e + xr */
if ((err = mp_mod(s, p, s)) != CRYPT_OK) { goto error; } /* s = e + xr */
if ((err = mp_mulmod(s, pubkey.k, p, s)) != CRYPT_OK) { goto error; } /* s = (e + xr)/k */
ecc_free(&pubkey);
if (mp_iszero(s) == LTC_MP_NO) {
break;
}
}
} while (--max_iterations > 0);

if (max_iterations == 0) {
goto errnokey;
}

err = CRYPT_OK;
if (sigformat == 1) {
/* RFC7518 format */
if (*outlen < 2*pbytes) { err = CRYPT_MEM; goto errnokey; }
zeromem(out, 2*pbytes);
i = mp_unsigned_bin_size(r);
if ((err = mp_to_unsigned_bin(r, out + (pbytes - i))) != CRYPT_OK) { goto errnokey; }
i = mp_unsigned_bin_size(s);
if ((err = mp_to_unsigned_bin(s, out + (2*pbytes - i))) != CRYPT_OK) { goto errnokey; }
*outlen = 2*pbytes;
err = CRYPT_OK;
}
else {
/* store as ASN.1 SEQUENCE { r, s -- integer } */
err = der_encode_sequence_multi(out, outlen,
LTC_ASN1_INTEGER, 1UL, r,
LTC_ASN1_INTEGER, 1UL, s,
LTC_ASN1_EOL, 0UL, NULL);
}
goto errnokey;

error:
ecc_free(&pubkey);
errnokey:
mp_clear_multi(p, e, NULL);
mp_clear_multi(r, s, p, e, NULL);
return err;
}

Expand All @@ -117,35 +140,29 @@ int ecc_sign_hash(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, ecc_key *key)
{
void *r, *s;
int err;

LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(key != NULL);

if (mp_init_multi(&r, &s, NULL) != CRYPT_OK) {
return CRYPT_MEM;
}

if ((err = ecc_sign_hash_raw(in, inlen, r, s, prng, wprng, key)) != CRYPT_OK) {
goto error;
}

/* store as SEQUENCE { r, s -- integer } */
err = der_encode_sequence_multi(out, outlen,
LTC_ASN1_INTEGER, 1UL, r,
LTC_ASN1_INTEGER, 1UL, s,
LTC_ASN1_EOL, 0UL, NULL);
return _ecc_sign_hash(in, inlen, out, outlen, prng, wprng, key, 0);
}

error:
mp_clear_multi(r, s, NULL);
return err;
/**
Sign a message digest in RFC7518 format
@param in The message digest to sign
@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 key A private ECC key
@return CRYPT_OK if successful
*/
int ecc_sign_hash_rfc7518(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen,
prng_state *prng, int wprng, ecc_key *key)
{
return _ecc_sign_hash(in, inlen, out, outlen, prng, wprng, key, 1);
}

#endif

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

Loading