ECC keygen

This commit is contained in:
NIIBE Yutaka
2015-07-20 18:01:21 +09:00
parent edf1a0cdd7
commit 5f21a44058
7 changed files with 141 additions and 18 deletions

View File

@@ -1,3 +1,9 @@
2015-07-20 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp-do.c (gpg_do_keygen): Support ECC.
* src/call-ec.c (ecc_check_secret): New.
* src/ecc.c (check_secret): New.
2015-07-18 Niibe Yutaka <gniibe@fsij.org>
* src/configure (keygen): It's always enabled.

View File

@@ -124,3 +124,20 @@ FUNC(ecdh_decrypt) (const uint8_t *input, uint8_t *output,
return r;
}
/**
* @brief Check if a secret d0 is valid or not
*
* @param D0 scalar D0: secret
* @param D1 scalar D1: secret candidate N-D0
*
* Return 0 on error.
* Return -1 when D1 should be used as the secret
* Return 1 when D0 should be used as the secret
*/
int
FUNC(ecc_check_secret) (const uint8_t *d0, uint8_t *d1)
{
return FUNC(check_secret) ((const bn256 *)d0, (bn256 *)d1);
}

View File

@@ -1,4 +1,4 @@
int compute_kP_p256k1 (ac *X, const bn256 *K, const ac *P);
int compute_kG_p256k1 (ac *X, const bn256 *K);
void ecdsa_p256k1 (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d);
int check_secret_p256k1 (const bn256 *q, bn256 *d1);

View File

@@ -1,5 +1,4 @@
int compute_kP_p256r1 (ac *X, const bn256 *K, const ac *P);
int compute_kG_p256r1 (ac *X, const bn256 *K);
void ecdsa_p256r1 (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d);
int check_secret_p256r1 (const bn256 *q, bn256 *d1);

View File

@@ -1,7 +1,8 @@
/* -*- coding: utf-8 -*-
* ecc.c - Elliptic curve over GF(prime)
*
* Copyright (C) 2011, 2013, 2014 Free Software Initiative of Japan
* Copyright (C) 2011, 2013, 2014, 2015
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -366,3 +367,32 @@ FUNC(ecdsa) (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d)
#undef tmp_k
#undef borrow
}
/**
* @brief Check if a secret d0 is valid or not
*
* @param D0 scalar D0: secret
* @param D1 scalar D1: secret candidate N-D0
*
* Return 0 on error.
* Return -1 when D1 should be used as the secret
* Return 1 when D0 should be used as the secret
*/
int
FUNC(check_secret) (const bn256 *d0, bn256 *d1)
{
ac Q0[1], Q1[1];
if (bn256_is_zero (d0) || bn256_sub (d1, N, d0) <= 0)
/* == 0 or >= N, it's not valid. */
return 0;
FUNC(compute_kG) (Q0, d0);
FUNC(compute_kG) (Q1, d1);
/*
* Jivsov compliant key check
*/
return bn256_cmp (Q1[0].y, Q0[0].y);
}

View File

@@ -267,12 +267,14 @@ uint8_t *rsa_genkey (int);
int ecdsa_sign_p256r1 (const uint8_t *hash, uint8_t *output,
const uint8_t *key_data);
uint8_t *ecc_compute_public_p256r1 (const uint8_t *key_data);
int ecc_check_secret_p256r1 (const uint8_t *d0, uint8_t *d1);
int ecdh_decrypt_p256r1 (const uint8_t *input, uint8_t *output,
const uint8_t *key_data);
int ecdsa_sign_p256k1 (const uint8_t *hash, uint8_t *output,
const uint8_t *key_data);
uint8_t *ecc_compute_public_p256k1 (const uint8_t *key_data);
int ecc_check_secret_p256k1 (const uint8_t *d0, uint8_t *d1);
int ecdh_decrypt_p256k1 (const uint8_t *input, uint8_t *output,
const uint8_t *key_data);

View File

@@ -1,7 +1,7 @@
/*
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling
*
* Copyright (C) 2010, 2011, 2012, 2013, 2014
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
@@ -2034,11 +2034,14 @@ void
gpg_do_keygen (uint8_t kk_byte)
{
enum kind_of_key kk = kkb_to_kk (kk_byte);
int pubkey_len = gpg_get_algo_attr_key_size (kk, GPG_KEY_PUBLIC);
int attr = gpg_get_algo_attr (kk);;
int prvkey_len = gpg_get_algo_attr_key_size (kk, GPG_KEY_PRIVATE);
const uint8_t *keystring_admin;
uint8_t *p_q_modulus;
const uint8_t *p_q;
const uint8_t *modulus;
uint8_t *p_q_modulus = NULL;
uint8_t d[64];
const uint8_t *rnd;
const uint8_t *prv;
const uint8_t *pubkey;
int r;
DEBUG_INFO ("Keygen\r\n");
@@ -2049,19 +2052,85 @@ gpg_do_keygen (uint8_t kk_byte)
else
keystring_admin = NULL;
p_q_modulus = rsa_genkey (pubkey_len);
if (p_q_modulus == NULL)
if (attr == ALGO_RSA2K || attr == ALGO_RSA4K)
{
GPG_MEMORY_FAILURE ();
p_q_modulus = rsa_genkey (prvkey_len);
if (p_q_modulus == NULL)
{
GPG_MEMORY_FAILURE ();
return;
}
prv = p_q_modulus;
pubkey = p_q_modulus + prvkey_len;
}
else if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
{
uint8_t d1[32];
const uint8_t *p;
int i, r;
rnd = NULL;
do
{
if (rnd)
random_bytes_free (rnd);
rnd = random_bytes_get ();
if (attr == ALGO_NISTP256R1)
r = ecc_check_secret_p256r1 (rnd, d1);
else
r = ecc_check_secret_p256k1 (rnd, d1);
}
while (r == 0);
/* Convert it to big endian */
if (r < 0)
p = (const uint8_t *)d1;
else
p = rnd;
for (i = 0; i < 32; i++)
d[32 - i - 1] = p[i];
random_bytes_free (rnd);
prv = d;
pubkey = NULL;
}
else if (attr == ALGO_ED25519)
{
rnd = random_bytes_get ();
sha512 (rnd, 32, d);
random_bytes_free (rnd);
d[0] &= 248;
d[31] &= 127;
d[31] |= 64;
prv = d;
pubkey = NULL;
}
else if (attr == ALGO_CURVE25519)
{
rnd = random_bytes_get ();
memcpy (d, rnd, 32);
random_bytes_free (rnd);
d[0] &= 248;
d[31] &= 127;
d[31] |= 64;
prv = d;
pubkey = NULL;
}
else
{
GPG_CONDITION_NOT_SATISFIED ();
return;
}
p_q = p_q_modulus;
modulus = p_q_modulus + pubkey_len;
r = gpg_do_write_prvkey (kk, p_q, pubkey_len, keystring_admin, modulus);
memset (p_q_modulus, 0, pubkey_len * 2);
free (p_q_modulus);
r = gpg_do_write_prvkey (kk, prv, prvkey_len, keystring_admin, pubkey);
if (p_q_modulus)
{
memset (p_q_modulus, 0, prvkey_len * 2);
free (p_q_modulus);
}
if (r < 0)
{
GPG_ERROR ();