view release on metacpan or search on metacpan
MicroECC.xs view on Meta::CPAN
END
int
curve_public_key_size(int curve_id)
CODE:
RETVAL = uECC_curve_public_key_size(get_curve(curve_id));
OUTPUT:
RETVAL
int
curve_private_key_size(int curve_id)
CODE:
RETVAL = uECC_curve_private_key_size(get_curve(curve_id));
OUTPUT:
RETVAL
void
make_key(int curve_id)
INIT:
int pubkey_len, privkey_len;
uint8_t *pubkey, *privkey;
uECC_Curve curve;
int res;
PPCODE:
curve = get_curve(curve_id);
pubkey_len = uECC_curve_public_key_size(curve);
privkey_len = uECC_curve_private_key_size(curve);
pubkey = (uint8_t *)malloc(pubkey_len);
privkey = (uint8_t *)malloc(privkey_len);
res = uECC_make_key(pubkey, privkey, curve);
if(res) {
XPUSHs(sv_2mortal(newSVpv(pubkey, pubkey_len)));
XPUSHs(sv_2mortal(newSVpv(privkey, privkey_len)));
}
else {
XPUSHs(sv_2mortal(newSVnv(errno)));
MicroECC.xs view on Meta::CPAN
}
else {
d = sv_newmortal();
}
free(secret);
RETVAL = d;
OUTPUT:
RETVAL
SV *
compute_public_key(const uint8_t *private_key, int curve_id)
CODE:
int public_key_size = uECC_curve_public_key_size(get_curve(curve_id));
uint8_t *public_key = (uint8_t *)malloc(public_key_size);
int res = uECC_compute_public_key(private_key, public_key, get_curve(curve_id));
SV *d;
if(res) {
d = newSVpv(public_key, public_key_size);
}
else {
d = sv_newmortal();
}
free(public_key);
RETVAL = d;
OUTPUT:
RETVAL
SV *
sign(SV *sv_private_key, SV *sv_hash, int curve_id)
CODE:
STRLEN hash_size, key_size;
char *hash = (char *)SvPVbyte(sv_hash, hash_size);
char *private_key = (char *)SvPVbyte(sv_private_key, key_size);
int public_key_size = uECC_curve_public_key_size(get_curve(curve_id));
//printf("key size: %d, hash size: %d\n", key_size, hash_size);
uint8_t *signature = (uint8_t *)malloc(public_key_size);
int res = uECC_sign(private_key, hash, hash_size, signature, get_curve(curve_id));
SV* d;
if(res) {
d = newSVpv(signature, public_key_size);
}
else {
d = sv_newmortal();
}
free(signature);
RETVAL = d;
OUTPUT:
lib/MicroECC.pm view on Meta::CPAN
# Items to export into callers namespace by default. Note: do not export
# names by default without a very good reason. Use EXPORT_OK instead.
# Do not simply export all your public functions/methods/constants.
# This allows declaration use MicroECC ':all';
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
# will save memory.
our %EXPORT_TAGS = ( 'all' => [ qw(
secp160r1 secp192r1 secp224r1 secp256r1 secp256k1
make_key valid_public_key shared_secret curve_public_key_size curve_private_key_size
compute_public_key verify sign
) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(
);
our $VERSION = '0.04';
lib/MicroECC.pm view on Meta::CPAN
MicroECC - Perl wrapper for the micro-ecc ECDH and ECDSA library
=head1 SYNOPSIS
use MicroECC;
use Digest::SHA qw/sha1 sha256/;
#curves: secp160r1 secp192r1 secp224r1 secp256r1 secp256k1
my $curve = MicroECC::secp160r1();
printf "Public key size: %d, private key size: %d.\n",
MicroECC::curve_public_key_size($curve), MicroECC::curve_private_key_size($curve);
my ($pubkey, $privkey) = MicroECC::make_key($curve);
if(!MicroECC::valid_public_key($pubkey, $curve)){
print "Invalid public key.\n";
}
else {
print "Valid public key.\n";
}
# make shared secret with other people's public key.
micro-ecc/uECC.c view on Meta::CPAN
#endif
void uECC_set_rng(uECC_RNG_Function rng_function) {
g_rng_function = rng_function;
}
uECC_RNG_Function uECC_get_rng(void) {
return g_rng_function;
}
int uECC_curve_private_key_size(uECC_Curve curve) {
return BITS_TO_BYTES(curve->num_n_bits);
}
int uECC_curve_public_key_size(uECC_Curve curve) {
return 2 * curve->num_bytes;
}
#if !asm_clear
uECC_VLI_API void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words) {
wordcount_t i;
micro-ecc/uECC.c view on Meta::CPAN
wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
bitcount_t num_n_bits = curve->num_n_bits;
uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) ||
(num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) &&
uECC_vli_testBit(k0, num_n_bits));
uECC_vli_add(k1, k0, curve->n, num_n_words);
return carry;
}
static uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
uECC_word_t *private_key,
uECC_Curve curve) {
uECC_word_t tmp1[uECC_MAX_WORDS];
uECC_word_t tmp2[uECC_MAX_WORDS];
uECC_word_t *p2[2] = {tmp1, tmp2};
uECC_word_t carry;
/* Regularize the bitcount for the private key so that attackers cannot use a side channel
attack to learn the number of leading zeros. */
carry = regularize_k(private_key, tmp1, tmp2, curve);
EccPoint_mult(result, curve->G, p2[!carry], 0, curve->num_n_bits + 1, curve);
if (EccPoint_isZero(result, curve)) {
return 0;
}
return 1;
}
#if uECC_WORD_SIZE == 1
micro-ecc/uECC.c view on Meta::CPAN
random[num_words - 1] &= mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits));
if (!uECC_vli_isZero(random, num_words) &&
uECC_vli_cmp(top, random, num_words) == 1) {
return 1;
}
}
return 0;
}
int uECC_make_key(uint8_t *public_key,
uint8_t *private_key,
uECC_Curve curve) {
#if uECC_VLI_NATIVE_LITTLE_ENDIAN
uECC_word_t *_private = (uECC_word_t *)private_key;
uECC_word_t *_public = (uECC_word_t *)public_key;
#else
uECC_word_t _private[uECC_MAX_WORDS];
uECC_word_t _public[uECC_MAX_WORDS * 2];
#endif
uECC_word_t tries;
for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
if (!uECC_generate_random_int(_private, curve->n, BITS_TO_WORDS(curve->num_n_bits))) {
return 0;
}
if (EccPoint_compute_public_key(_public, _private, curve)) {
#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0
uECC_vli_nativeToBytes(private_key, BITS_TO_BYTES(curve->num_n_bits), _private);
uECC_vli_nativeToBytes(public_key, curve->num_bytes, _public);
uECC_vli_nativeToBytes(
public_key + curve->num_bytes, curve->num_bytes, _public + curve->num_words);
#endif
return 1;
}
}
return 0;
}
int uECC_shared_secret(const uint8_t *public_key,
const uint8_t *private_key,
uint8_t *secret,
uECC_Curve curve) {
uECC_word_t _public[uECC_MAX_WORDS * 2];
uECC_word_t _private[uECC_MAX_WORDS];
uECC_word_t tmp[uECC_MAX_WORDS];
uECC_word_t *p2[2] = {_private, tmp};
uECC_word_t *initial_Z = 0;
uECC_word_t carry;
wordcount_t num_words = curve->num_words;
wordcount_t num_bytes = curve->num_bytes;
#if uECC_VLI_NATIVE_LITTLE_ENDIAN
bcopy((uint8_t *) _private, private_key, num_bytes);
bcopy((uint8_t *) _public, public_key, num_bytes*2);
#else
uECC_vli_bytesToNative(_private, private_key, BITS_TO_BYTES(curve->num_n_bits));
uECC_vli_bytesToNative(_public, public_key, num_bytes);
uECC_vli_bytesToNative(_public + num_words, public_key + num_bytes, num_bytes);
#endif
/* Regularize the bitcount for the private key so that attackers cannot use a side channel
attack to learn the number of leading zeros. */
carry = regularize_k(_private, _private, tmp, curve);
/* If an RNG function was specified, try to get a random initial Z value to improve
protection against side-channel attacks. */
micro-ecc/uECC.c view on Meta::CPAN
#endif
#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0
uECC_vli_bytesToNative(_public, public_key, curve->num_bytes);
uECC_vli_bytesToNative(
_public + curve->num_words, public_key + curve->num_bytes, curve->num_bytes);
#endif
return uECC_valid_point(_public, curve);
}
int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) {
#if uECC_VLI_NATIVE_LITTLE_ENDIAN
uECC_word_t *_private = (uECC_word_t *)private_key;
uECC_word_t *_public = (uECC_word_t *)public_key;
#else
uECC_word_t _private[uECC_MAX_WORDS];
uECC_word_t _public[uECC_MAX_WORDS * 2];
#endif
#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0
uECC_vli_bytesToNative(_private, private_key, BITS_TO_BYTES(curve->num_n_bits));
#endif
/* Make sure the private key is in the range [1, n-1]. */
if (uECC_vli_isZero(_private, BITS_TO_WORDS(curve->num_n_bits))) {
return 0;
}
if (uECC_vli_cmp(curve->n, _private, BITS_TO_WORDS(curve->num_n_bits)) != 1) {
return 0;
}
micro-ecc/uECC.c view on Meta::CPAN
*ptr = (temp >> shift) | carry;
carry = temp << (uECC_WORD_BITS - shift);
}
/* Reduce mod curve_n */
if (uECC_vli_cmp_unsafe(curve->n, native, num_n_words) != 1) {
uECC_vli_sub(native, native, curve->n, num_n_words);
}
}
static int uECC_sign_with_k(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
uECC_word_t *k,
uint8_t *signature,
uECC_Curve curve) {
uECC_word_t tmp[uECC_MAX_WORDS];
uECC_word_t s[uECC_MAX_WORDS];
uECC_word_t *k2[2] = {tmp, s};
#if uECC_VLI_NATIVE_LITTLE_ENDIAN
micro-ecc/uECC.c view on Meta::CPAN
bits of k / the private key by premultiplying by a random number */
uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */
uECC_vli_modInv(k, k, curve->n, num_n_words); /* k = 1 / k' */
uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */
#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0
uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */
#endif
#if uECC_VLI_NATIVE_LITTLE_ENDIAN
bcopy((uint8_t *) tmp, private_key, BITS_TO_BYTES(curve->num_n_bits));
#else
uECC_vli_bytesToNative(tmp, private_key, BITS_TO_BYTES(curve->num_n_bits)); /* tmp = d */
#endif
s[num_n_words - 1] = 0;
uECC_vli_set(s, p, num_words);
uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */
bits2int(tmp, message_hash, hash_size, curve);
uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */
uECC_vli_modMult(s, s, k, curve->n, num_n_words); /* s = (e + r*d) / k */
if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) {
return 0;
}
#if uECC_VLI_NATIVE_LITTLE_ENDIAN
bcopy((uint8_t *) signature + curve->num_bytes, (uint8_t *) s, curve->num_bytes);
#else
uECC_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s);
#endif
return 1;
}
int uECC_sign(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
uint8_t *signature,
uECC_Curve curve) {
uECC_word_t k[uECC_MAX_WORDS];
uECC_word_t tries;
for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
if (!uECC_generate_random_int(k, curve->n, BITS_TO_WORDS(curve->num_n_bits))) {
return 0;
}
if (uECC_sign_with_k(private_key, message_hash, hash_size, k, signature, curve)) {
return 1;
}
}
return 0;
}
/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always
the same size as the hash result size. */
static void HMAC_init(const uECC_HashContext *hash_context, const uint8_t *K) {
uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size;
micro-ecc/uECC.c view on Meta::CPAN
HMAC_update(hash_context, V, hash_context->result_size);
HMAC_finish(hash_context, K, V);
}
/* Deterministic signing, similar to RFC 6979. Differences are:
* We just use H(m) directly rather than bits2octets(H(m))
(it is not reduced modulo curve_n).
* We generate a value for k (aka T) directly rather than converting endianness.
Layout of hash_context->tmp: <K> | <V> | (1 byte overlapped 0x00 or 0x01) / <HMAC pad> */
int uECC_sign_deterministic(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
const uECC_HashContext *hash_context,
uint8_t *signature,
uECC_Curve curve) {
uint8_t *K = hash_context->tmp;
uint8_t *V = K + hash_context->result_size;
wordcount_t num_bytes = curve->num_bytes;
wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
bitcount_t num_n_bits = curve->num_n_bits;
micro-ecc/uECC.c view on Meta::CPAN
unsigned i;
for (i = 0; i < hash_context->result_size; ++i) {
V[i] = 0x01;
K[i] = 0;
}
/* K = HMAC_K(V || 0x00 || int2octets(x) || h(m)) */
HMAC_init(hash_context, K);
V[hash_context->result_size] = 0x00;
HMAC_update(hash_context, V, hash_context->result_size + 1);
HMAC_update(hash_context, private_key, num_bytes);
HMAC_update(hash_context, message_hash, hash_size);
HMAC_finish(hash_context, K, K);
update_V(hash_context, K, V);
/* K = HMAC_K(V || 0x01 || int2octets(x) || h(m)) */
HMAC_init(hash_context, K);
V[hash_context->result_size] = 0x01;
HMAC_update(hash_context, V, hash_context->result_size + 1);
HMAC_update(hash_context, private_key, num_bytes);
HMAC_update(hash_context, message_hash, hash_size);
HMAC_finish(hash_context, K, K);
update_V(hash_context, K, V);
for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
uECC_word_t T[uECC_MAX_WORDS];
uint8_t *T_ptr = (uint8_t *)T;
wordcount_t T_bytes = 0;
for (;;) {
micro-ecc/uECC.c view on Meta::CPAN
}
}
}
filled:
if ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8 > num_n_bits) {
uECC_word_t mask = (uECC_word_t)-1;
T[num_n_words - 1] &=
mask >> ((bitcount_t)(num_n_words * uECC_WORD_SIZE * 8 - num_n_bits));
}
if (uECC_sign_with_k(private_key, message_hash, hash_size, T, signature, curve)) {
return 1;
}
/* K = HMAC_K(V || 0x00) */
HMAC_init(hash_context, K);
V[hash_context->result_size] = 0x00;
HMAC_update(hash_context, V, hash_context->result_size + 1);
HMAC_finish(hash_context, K, K);
update_V(hash_context, K, V);
micro-ecc/uECC.h view on Meta::CPAN
rng_function - The function that will be used to generate random bytes.
*/
void uECC_set_rng(uECC_RNG_Function rng_function);
/* uECC_get_rng() function.
Returns the function that will be used to generate random bytes.
*/
uECC_RNG_Function uECC_get_rng(void);
/* uECC_curve_private_key_size() function.
Returns the size of a private key for the curve in bytes.
*/
int uECC_curve_private_key_size(uECC_Curve curve);
/* uECC_curve_public_key_size() function.
Returns the size of a public key for the curve in bytes.
*/
int uECC_curve_public_key_size(uECC_Curve curve);
/* uECC_make_key() function.
Create a public/private key pair.
Outputs:
public_key - Will be filled in with the public key. Must be at least 2 * the curve size
(in bytes) long. For example, if the curve is secp256r1, public_key must be 64
bytes long.
private_key - Will be filled in with the private key. Must be as long as the curve order; this
is typically the same as the curve size, except for secp160r1. For example, if the
curve is secp256r1, private_key must be 32 bytes long.
For secp160r1, private_key must be 21 bytes long! Note that the first byte will
almost always be 0 (there is about a 1 in 2^80 chance of it being non-zero).
Returns 1 if the key pair was generated successfully, 0 if an error occurred.
*/
int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve);
/* uECC_shared_secret() function.
Compute a shared secret given your secret key and someone else's public key.
Note: It is recommended that you hash the result of uECC_shared_secret() before using it for
symmetric encryption or HMAC.
Inputs:
public_key - The public key of the remote party.
private_key - Your private key.
Outputs:
secret - Will be filled in with the shared secret value. Must be the same size as the
curve size; for example, if the curve is secp256r1, secret must be 32 bytes long.
Returns 1 if the shared secret was generated successfully, 0 if an error occurred.
*/
int uECC_shared_secret(const uint8_t *public_key,
const uint8_t *private_key,
uint8_t *secret,
uECC_Curve curve);
#if uECC_SUPPORT_COMPRESSED_POINT
/* uECC_compress() function.
Compress a public key.
Inputs:
public_key - The public key to compress.
micro-ecc/uECC.h view on Meta::CPAN
public_key - The public key to check.
Returns 1 if the public key is valid, 0 if it is invalid.
*/
int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve);
/* uECC_compute_public_key() function.
Compute the corresponding public key for a private key.
Inputs:
private_key - The private key to compute the public key for
Outputs:
public_key - Will be filled in with the corresponding public key
Returns 1 if the key was computed successfully, 0 if an error occurred.
*/
int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve);
/* uECC_sign() function.
Generate an ECDSA signature for a given hash value.
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to
this function along with your private key.
Inputs:
private_key - Your private key.
message_hash - The hash of the message to sign.
hash_size - The size of message_hash in bytes.
Outputs:
signature - Will be filled in with the signature value. Must be at least 2 * curve size long.
For example, if the curve is secp256r1, signature must be 64 bytes long.
Returns 1 if the signature generated successfully, 0 if an error occurred.
*/
int uECC_sign(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
uint8_t *signature,
uECC_Curve curve);
/* uECC_HashContext structure.
This is used to pass in an arbitrary hash function to uECC_sign_deterministic().
The structure will be used for multiple hash computations; each time a new hash
is computed, init_hash() will be called, followed by one or more calls to
update_hash(), and finally a call to finish_hash() to produce the resulting hash.
micro-ecc/uECC.h view on Meta::CPAN
Generate an ECDSA signature for a given hash value, using a deterministic algorithm
(see RFC 6979). You do not need to set the RNG using uECC_set_rng() before calling
this function; however, if the RNG is defined it will improve resistance to side-channel
attacks.
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it to
this function along with your private key and a hash context. Note that the message_hash
does not need to be computed with the same hash function used by hash_context.
Inputs:
private_key - Your private key.
message_hash - The hash of the message to sign.
hash_size - The size of message_hash in bytes.
hash_context - A hash context to use.
Outputs:
signature - Will be filled in with the signature value.
Returns 1 if the signature generated successfully, 0 if an error occurred.
*/
int uECC_sign_deterministic(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
const uECC_HashContext *hash_context,
uint8_t *signature,
uECC_Curve curve);
/* uECC_verify() function.
Verify an ECDSA signature.
Usage: Compute the hash of the signed data using the same hash as the signer and