Curve25519 support
This commit is contained in:
16
ChangeLog
16
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.
|
||||
|
||||
2
chopstx
2
chopstx
Submodule chopstx updated: 43bd3bcefd...2bb0e0de5d
@@ -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 =
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
switch (algo_attr_p[1])
|
||||
{
|
||||
case ALGO_RSA4K:
|
||||
return algorithm_attr_rsa4k;
|
||||
else if (algo_attr_p[1] == ALGO_NISTP256R1)
|
||||
case ALGO_NISTP256R1:
|
||||
return algorithm_attr_p256r1;
|
||||
else if (algo_attr_p[1] == ALGO_SECP256K1)
|
||||
case ALGO_SECP256K1:
|
||||
return algorithm_attr_p256k1;
|
||||
else if (algo_attr_p[1] == ALGO_ED25519)
|
||||
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 (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;
|
||||
else if (algo_attr_p[1] == ALGO_NISTP256R1 || algo_attr_p[1] == ALGO_SECP256K1)
|
||||
case ALGO_NISTP256R1:
|
||||
case ALGO_SECP256K1:
|
||||
if (s == GPG_KEY_STORAGE)
|
||||
return 128;
|
||||
else if (s == GPG_KEY_PUBLIC)
|
||||
return 64;
|
||||
else
|
||||
return 32;
|
||||
else /* ED25519 */
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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,10 +954,24 @@ 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
|
||||
|
||||
Reference in New Issue
Block a user