ECC keygen
authorNIIBE Yutaka <gniibe@fsij.org>
Mon, 20 Jul 2015 09:01:21 +0000 (18:01 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Mon, 20 Jul 2015 09:01:21 +0000 (18:01 +0900)
ChangeLog
src/call-ec.c
src/ec_p256k1.h
src/ec_p256r1.h
src/ecc.c
src/gnuk.h
src/openpgp-do.c

index d98e19c..3ae6661 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
index 51d38e6..1350369 100644 (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);
+}
index d2893ac..ec0e213 100644 (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);
index 3ae4651..c8b9742 100644 (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);
index d3b57b2..9541965 100644 (file)
--- a/src/ecc.c
+++ b/src/ecc.c
@@ -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);
+}
index 0545fe8..21159ab 100644 (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);
 
index 0781d9d..a60f5cd 100644 (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 ();
-      return;
+      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];
 
-  p_q = p_q_modulus;
-  modulus = p_q_modulus + pubkey_len;
+      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;
+    }
 
-  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 ();