Curve25519 support
authorNIIBE Yutaka <gniibe@fsij.org>
Tue, 7 Jul 2015 06:42:00 +0000 (15:42 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Tue, 7 Jul 2015 23:49:05 +0000 (08:49 +0900)
ChangeLog
chopstx
src/Makefile.in
src/ecc-mont.c
src/gnuk.h
src/openpgp-do.c
src/openpgp.c

index 6dc8cb2..84eed6e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2015-07-07  Niibe Yutaka  <gniibe@fsij.org>
+
+       * src/Makefile.in (CSRC): Add ecc-mont.c.
+
+       * src/ecc-mont.c (mod25638_mul_121665): Fix.
+       (ecdh_compute_public_25519, ecdh_decrypt_curve25519): New.
+
+       * src/openpgp.c (cmd_pso): Support ALGO_CURVE25519.
+
+       * src/openpgp-do.c (algorithm_attr_cv25519): New.
+       (rw_algorithm_attr, get_algo_attr_data_object)
+       (gpg_get_algo_attr_key_size, gpg_do_write_prvkey)
+       (proc_key_import, gpg_do_public_key): Support ALGO_CURVE25519.
+
+       * src/gnuk.h (ALGO_CURVE25519): New.
+
 2015-07-06  Niibe Yutaka  <gniibe@fsij.org>
 
        Enhancement for FSM-55.
diff --git a/chopstx b/chopstx
index 43bd3bc..2bb0e0d 160000 (submodule)
--- a/chopstx
+++ b/chopstx
@@ -1 +1 @@
-Subproject commit 43bd3bcefd6dbd28e3fd68ca8ff6b9a877009774
+Subproject commit 2bb0e0de5d7d25d0bb036e6ee9cc0c94b62375ec
index 0e916e0..2dd3360 100644 (file)
@@ -15,7 +15,7 @@ CSRC = main.c usb_stm32f103.c adc_stm32f103.c \
        bn.c mod.c \
        modp256r1.c jpc_p256r1.c ec_p256r1.c call-ec_p256r1.c \
        modp256k1.c jpc_p256k1.c ec_p256k1.c call-ec_p256k1.c \
-       mod25638.c ecc-edwards.c sha512.c \
+       mod25638.c ecc-edwards.c ecc-mont.c sha512.c \
        random.c neug.c sha256.c sys.c
 
 INCDIR =
index 804419d..25f2fdd 100644 (file)
@@ -2,7 +2,7 @@
  * ecc-mont.c - Elliptic curve computation for
  *              the Montgomery curve: y^2 = x^3 + 486662*x^2 + x.
  *
- * Copyright (C) 2014 Free Software Initiative of Japan
+ * Copyright (C) 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.
@@ -24,6 +24,7 @@
 
 #include <stdint.h>
 #include <string.h>
+#include <stdlib.h>
 #include "bn.h"
 #include "mod25638.h"
 #include "mod.h"
@@ -78,6 +79,7 @@ mod25638_mul_121665 (bn256 *x, const bn256 *a)
 
   s = a->word;
   d = x->word;
+  memset (d, 0, sizeof (bn256));
   w = 121665;
   MULADD_256_ASM (s, d, w, c);
 #else
@@ -143,7 +145,7 @@ mont_d_and_a (pt *prd, pt *sum, pt *q0, pt *q1, const bn256 *dif_x)
  * @param Q_X  x-coordinate of Q
  *
  */
-void
+static void
 compute_nQ (bn256 *res, const bn256 *n, const bn256 *q_x)
 {
   int i, j;
@@ -194,3 +196,37 @@ compute_nQ (bn256 *res, const bn256 *n, const bn256 *q_x)
   mod25638_mul (res, res, p0->x);
   mod25519_reduce (res);
 }
+
+
+uint8_t *
+ecdh_compute_public_25519 (const uint8_t *key_data)
+{
+  uint8_t *p;
+  bn256 gx[1];
+  bn256 k[1];
+
+  memset (gx, 0, sizeof (bn256));
+  gx[0].word[0] = 9;                   /* Gx = 9 */
+  memcpy (k, key_data, sizeof (bn256));
+  p = (uint8_t *)malloc (sizeof (bn256));
+  if (p == NULL)
+    return NULL;
+
+  compute_nQ ((bn256 *)p, k, gx);
+  return p;
+}
+
+int
+ecdh_decrypt_curve25519 (const uint8_t *input, uint8_t *output,
+                        const uint8_t *key_data)
+{
+  bn256 q_x[1];
+  bn256 k[1];
+  bn256 shared[1];
+
+  memcpy (q_x, input, sizeof (bn256));
+  memcpy (k, key_data, sizeof (bn256));
+  compute_nQ (shared, k, q_x);
+  memcpy (output, shared, sizeof (bn256));
+  return 0;
+}
index e096f78..1afb25a 100644 (file)
@@ -116,6 +116,7 @@ const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
 #define ALGO_NISTP256R1 1
 #define ALGO_SECP256K1  2
 #define ALGO_ED25519    3
+#define ALGO_CURVE25519 4
 #define ALGO_RSA2K      255
 
 enum kind_of_key {
@@ -279,6 +280,9 @@ int eddsa_sign_25519 (const uint8_t *input, size_t ilen, uint32_t *output,
                      const uint8_t *sk_a, const uint8_t *seed,
                      const uint8_t *pk);
 uint8_t *eddsa_compute_public_25519 (const uint8_t *a);
+uint8_t *ecdh_compute_public_25519 (const uint8_t *a);
+int ecdh_decrypt_curve25519 (const uint8_t *input, uint8_t *output,
+                            const uint8_t *key_data);
 
 const uint8_t *gpg_do_read_simple (uint8_t);
 void gpg_do_write_simple (uint8_t, const uint8_t *, int);
index 6d91b69..d9d4dc3 100644 (file)
@@ -170,6 +170,13 @@ static const uint8_t algorithm_attr_ed25519[] __attribute__ ((aligned (1))) = {
   0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01
 };
 
+static const uint8_t algorithm_attr_cv25519[] __attribute__ ((aligned (1))) = {
+  11,
+  OPENPGP_ALGO_ECDH,
+  /* OID of the curve Curve25519 */
+  0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01
+};
+
 
 /*
  * Representation of PW1_LIFETIME:
@@ -246,16 +253,21 @@ get_algo_attr_data_object (enum kind_of_key kk)
   if (algo_attr_p == NULL)
     return algorithm_attr_rsa2k;
 
-  if (algo_attr_p[1] == ALGO_RSA4K)
-    return algorithm_attr_rsa4k;
-  else if (algo_attr_p[1] == ALGO_NISTP256R1)
-    return algorithm_attr_p256r1;
-  else if (algo_attr_p[1] == ALGO_SECP256K1)
-    return algorithm_attr_p256k1;
-  else if (algo_attr_p[1] == ALGO_ED25519)
-    return algorithm_attr_ed25519;
-
-  return algorithm_attr_rsa2k;
+  switch (algo_attr_p[1])
+    {
+    case ALGO_RSA4K:
+      return algorithm_attr_rsa4k;
+    case ALGO_NISTP256R1:
+      return algorithm_attr_p256r1;
+    case ALGO_SECP256K1:
+      return algorithm_attr_p256k1;
+    case ALGO_ED25519:
+      return algorithm_attr_ed25519;
+    case ALGO_CURVE25519:
+      return algorithm_attr_cv25519;
+    default:
+      return algorithm_attr_rsa2k;
+    }
 }
 
 int
@@ -263,30 +275,43 @@ gpg_get_algo_attr_key_size (enum kind_of_key kk, enum size_of_key s)
 {
   const uint8_t *algo_attr_p = *get_algo_attr_pointer (kk);
 
-  if (algo_attr_p == NULL)
-    if (s == GPG_KEY_STORAGE)
-      return 512;
-    else
-      return 256;
-  else if (algo_attr_p[1] == ALGO_RSA4K)
-    if (s == GPG_KEY_STORAGE)
-      return 1024;
-    else
-      return 512;
-  else if (algo_attr_p[1] == ALGO_NISTP256R1 || algo_attr_p[1] == ALGO_SECP256K1)
-    if (s == GPG_KEY_STORAGE)
-      return 128;
-    else if (s == GPG_KEY_PUBLIC)
-      return 64;
-    else
-      return 32;
-  else                         /* ED25519 */
-    if (s == GPG_KEY_STORAGE)
-      return 128;
-    else if (s == GPG_KEY_PUBLIC)
-      return 32;
-    else
-      return 64;
+  if (algo_attr_p == NULL)     /* RSA-2048 */
+    goto rsa2k;
+
+  switch (algo_attr_p[1])
+    {
+    case ALGO_RSA4K:
+      if (s == GPG_KEY_STORAGE)
+       return 1024;
+      else
+       return 512;
+    case ALGO_NISTP256R1:
+    case ALGO_SECP256K1:
+      if (s == GPG_KEY_STORAGE)
+       return 128;
+      else if (s == GPG_KEY_PUBLIC)
+       return 64;
+      else
+       return 32;
+    case ALGO_ED25519:
+      if (s == GPG_KEY_STORAGE)
+       return 128;
+      else if (s == GPG_KEY_PUBLIC)
+       return 32;
+      else
+       return 64;
+    case ALGO_CURVE25519:
+      if (s == GPG_KEY_STORAGE)
+       return 64;
+      else
+       return 32;
+    default:
+    rsa2k:
+      if (s == GPG_KEY_STORAGE)
+       return 512;
+      else
+       return 256;
+    }
 }
 
 
@@ -724,6 +749,8 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
        algo = ALGO_NISTP256R1;
       else if (len == 10 && memcmp (data, algorithm_attr_ed25519+1, 10) == 0)
        algo = ALGO_ED25519;
+      else if (len == 11 && memcmp (data, algorithm_attr_cv25519+1, 11) == 0)
+       algo = ALGO_CURVE25519;
 
       if (algo < 0)
        return 0;               /* Error */
@@ -1049,6 +1076,12 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
       if (prvkey_len != 64)
        return -1;
     }
+  else if (attr == ALGO_CURVE25519)
+    {
+      pubkey_len = prvkey_len;
+      if (prvkey_len != 32)
+       return -1;
+    }
   else                         /* RSA */
     {
       int key_size = gpg_get_algo_attr_key_size (kk, GPG_KEY_STORAGE);
@@ -1066,6 +1099,8 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
        pubkey_allocated_here = ecc_compute_public_p256r1 (key_data);
       else if (attr == ALGO_ED25519)
        pubkey_allocated_here = eddsa_compute_public_25519 (key_data);
+      else if (attr == ALGO_CURVE25519)
+       pubkey_allocated_here = ecdh_compute_public_25519 (key_data);
       else                             /* RSA */
        pubkey_allocated_here = modulus_calc (key_data, prvkey_len);
 
@@ -1292,7 +1327,7 @@ kkb_to_kk (uint8_t kk_byte)
 static int
 proc_key_import (const uint8_t *data, int len)
 {
-  int r;
+  int r = -1;
   enum kind_of_key kk;
   const uint8_t *keystring_admin;
   int attr;
@@ -1328,7 +1363,7 @@ proc_key_import (const uint8_t *data, int len)
   attr = gpg_get_algo_attr (kk);
 
   if ((len <= 12 && (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1
-                    || attr == ALGO_ED25519))
+                    || attr == ALGO_ED25519 || attr == ALGO_CURVE25519))
       || (len <= 22 && attr == ALGO_RSA2K) || (len <= 24 && attr == ALGO_RSA4K))
     {                                      /* Deletion of the key */
       gpg_do_delete_prvkey (kk, CLEAN_SINGLE);
@@ -1343,7 +1378,7 @@ proc_key_import (const uint8_t *data, int len)
     r = gpg_do_write_prvkey (kk, &data[28], len - 28, keystring_admin, NULL);
   else if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
     r = gpg_do_write_prvkey (kk, &data[12], len - 12, keystring_admin, NULL);
-  else /* if (attr == ALGO_ED25519) */
+  else if (attr == ALGO_ED25519)
     {
       uint8_t hash[64];
 
@@ -1356,6 +1391,18 @@ proc_key_import (const uint8_t *data, int len)
       hash[31] |= 64;
       r = gpg_do_write_prvkey (kk, hash, 64, keystring_admin, NULL);
     }
+  else if (attr == ALGO_CURVE25519)
+    {
+      uint8_t priv[32];
+      int i;
+
+      if (len - 12 != 32)
+       return 1;               /* Error.  */
+
+      for (i = 0; i < 32; i++)
+       priv[31-i] = data[12+i];
+      r = gpg_do_write_prvkey (kk, priv, 32, keystring_admin, NULL);
+    }
 
   if (r < 0)
     return 0;
@@ -1910,14 +1957,14 @@ gpg_do_public_key (uint8_t kk_byte)
        res_p += 64;
       }
     }
-  else if (attr == ALGO_ED25519)
-    {                          /* EdDSA */
+  else if (attr == ALGO_ED25519 || attr == ALGO_CURVE25519)
+    {                          /* EdDSA or ECDH on curve25519 */
       /* LEN */
       *res_p++ = 2 + 32;
       {
        /*TAG*/          /* LEN = 32 */
        *res_p++ = 0x86; *res_p++ = 0x20;
-       /* 32-byte binary (little endian): Y with parity */
+       /* 32-byte binary (little endian): Y with parity or X*/
        memcpy (res_p, pubkey, 32);
        res_p += 32;
       }
index 9468ee7..a89b540 100644 (file)
@@ -942,15 +942,11 @@ cmd_pso (void)
        }
       else if (attr == ALGO_NISTP256R1 || attr == ALGO_SECP256K1)
        {
-         int header_size = -1;
-
-         if (len == 65)
-           header_size = 0;
-         else if (len == 65 + ECC_CIPHER_DO_HEADER_SIZE)
-           header_size = ECC_CIPHER_DO_HEADER_SIZE;
+         int header = ECC_CIPHER_DO_HEADER_SIZE;
 
          /* Format is in big endian MPI: 04 || x || y */
-         if (header_size < 0 || apdu.cmd_apdu_data[header_size] != 4)
+         if (len != 65 + ECC_CIPHER_DO_HEADER_SIZE
+             || apdu.cmd_apdu_data[header] != 0x04)
            {
              GPG_CONDITION_NOT_SATISFIED ();
              return;
@@ -958,12 +954,26 @@ cmd_pso (void)
 
          result_len = 65;
          if (attr == ALGO_NISTP256R1)
-           r = ecdh_decrypt_p256r1 (apdu.cmd_apdu_data + header_size, res_APDU,
+           r = ecdh_decrypt_p256r1 (apdu.cmd_apdu_data + header, res_APDU,
                                     kd[GPG_KEY_FOR_DECRYPTION].data);
          else
-           r = ecdh_decrypt_p256k1 (apdu.cmd_apdu_data + header_size, res_APDU,
+           r = ecdh_decrypt_p256k1 (apdu.cmd_apdu_data + header, res_APDU,
                                     kd[GPG_KEY_FOR_DECRYPTION].data);
        }
+      else if (attr == ALGO_CURVE25519)
+       {
+         int header = ECC_CIPHER_DO_HEADER_SIZE;
+
+         if (len != 32 + ECC_CIPHER_DO_HEADER_SIZE)
+           {
+             GPG_CONDITION_NOT_SATISFIED ();
+             return;
+           }
+
+         result_len = 32;
+         r = ecdh_decrypt_curve25519 (apdu.cmd_apdu_data + header, res_APDU,
+                                      kd[GPG_KEY_FOR_DECRYPTION].data);
+       }
       else
        {
          DEBUG_INFO ("unknown algo.");