1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-05-27 21:41:23 +02:00

gpg: Add X448 support.

* common/openpgp-oid.c (oidtable): Add X448.
(oid_x448,openpgp_oidbuf_is_x448,openpgp_oid_is_x448): New.
* common/util.h (openpgp_oid_is_x448): New.
* g10/ecdh.c (gen_k): Add handling of opaque MPI and support
endianness.
(pk_ecdh_generate_ephemeral_key): X448 requires opaque MPI.
* g10/keygen.c (gen_ecc): Add support for X448.
(ask_algo, parse_key_parameter_part): Likewise.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2020-06-09 14:56:50 +09:00
parent f5bc945554
commit e9760eb9e7
4 changed files with 70 additions and 2 deletions

View File

@ -48,6 +48,7 @@ static struct {
{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH }, { "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH },
{ "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA }, { "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA },
{ "X448", "1.3.101.111", 448, "x448", PUBKEY_ALGO_ECDH },
{ "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" }, { "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" },
{ "NIST P-384", "1.3.132.0.34", 384, "nistp384" }, { "NIST P-384", "1.3.132.0.34", 384, "nistp384" },
@ -71,6 +72,9 @@ static const char oid_ed25519[] =
static const char oid_cv25519[] = static const char oid_cv25519[] =
{ 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 }; { 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 };
/* The OID for X448 in OpenPGP format. */
static const char oid_x448[] = { 0x03, 0x2b, 0x65, 0x6f };
/* A table to store keyalgo strings like "rsa2048 or "ed25519" so that /* A table to store keyalgo strings like "rsa2048 or "ed25519" so that
* we do not need to allocate them. This is currently a simple array * we do not need to allocate them. This is currently a simple array
* but may eventually be changed to a fast data structure. Noet that * but may eventually be changed to a fast data structure. Noet that
@ -334,6 +338,15 @@ openpgp_oidbuf_is_cv25519 (const void *buf, size_t len)
} }
/* Return true if (BUF,LEN) represents the OID for X448. */
static int
openpgp_oidbuf_is_x448 (const void *buf, size_t len)
{
return (buf && len == DIM (oid_x448)
&& !memcmp (buf, oid_x448, DIM (oid_x448)));
}
/* Return true if the MPI A represents the OID for Curve25519. */ /* Return true if the MPI A represents the OID for Curve25519. */
int int
openpgp_oid_is_cv25519 (gcry_mpi_t a) openpgp_oid_is_cv25519 (gcry_mpi_t a)
@ -349,6 +362,21 @@ openpgp_oid_is_cv25519 (gcry_mpi_t a)
} }
/* Return true if the MPI A represents the OID for X448. */
int
openpgp_oid_is_x448 (gcry_mpi_t a)
{
const unsigned char *buf;
unsigned int nbits;
if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
return 0;
buf = gcry_mpi_get_opaque (a, &nbits);
return openpgp_oidbuf_is_x448 (buf, (nbits+7)/8);
}
/* Map the Libgcrypt ECC curve NAME to an OID. If R_NBITS is not NULL /* Map the Libgcrypt ECC curve NAME to an OID. If R_NBITS is not NULL
store the bit size of the curve there. Returns NULL for unknown store the bit size of the curve there. Returns NULL for unknown
curve names. If R_ALGO is not NULL and a specific ECC algorithm is curve names. If R_ALGO is not NULL and a specific ECC algorithm is

View File

@ -238,6 +238,7 @@ int openpgp_oidbuf_is_ed25519 (const void *buf, size_t len);
int openpgp_oid_is_ed25519 (gcry_mpi_t a); int openpgp_oid_is_ed25519 (gcry_mpi_t a);
int openpgp_oidbuf_is_cv25519 (const void *buf, size_t len); int openpgp_oidbuf_is_cv25519 (const void *buf, size_t len);
int openpgp_oid_is_cv25519 (gcry_mpi_t a); int openpgp_oid_is_cv25519 (gcry_mpi_t a);
int openpgp_oid_is_x448 (gcry_mpi_t a);
const char *openpgp_curve_to_oid (const char *name, const char *openpgp_curve_to_oid (const char *name,
unsigned int *r_nbits, int *r_algo); unsigned int *r_nbits, int *r_algo);
const char *openpgp_oid_to_curve (const char *oid, int canon); const char *openpgp_oid_to_curve (const char *oid, int canon);

View File

@ -422,10 +422,27 @@ pk_ecdh_encrypt_with_shared_point (gcry_mpi_t shared_mpi,
static gcry_mpi_t static gcry_mpi_t
gen_k (unsigned nbits) gen_k (unsigned nbits, int little_endian, int is_opaque)
{ {
gcry_mpi_t k; gcry_mpi_t k;
if (is_opaque)
{
unsigned char *p;
size_t nbytes = (nbits+7)/8;
p = gcry_random_bytes_secure (nbytes, GCRY_STRONG_RANDOM);
if ((nbits % 8))
{
if (little_endian)
p[nbytes-1] &= ((1 << (nbits % 8)) - 1);
else
p[0] &= ((1 << (nbits % 8)) - 1);
}
k = gcry_mpi_set_opaque (NULL, p, nbits);
return k;
}
k = gcry_mpi_snew (nbits); k = gcry_mpi_snew (nbits);
if (DBG_CRYPTO) if (DBG_CRYPTO)
log_debug ("choosing a random k of %u bits\n", nbits); log_debug ("choosing a random k of %u bits\n", nbits);
@ -453,13 +470,21 @@ pk_ecdh_generate_ephemeral_key (gcry_mpi_t *pkey, gcry_mpi_t *r_k)
{ {
unsigned int nbits; unsigned int nbits;
gcry_mpi_t k; gcry_mpi_t k;
int is_little_endian = 0;
int require_opaque = 0;
if (openpgp_oid_is_x448 (pkey[0]))
{
is_little_endian = 1;
require_opaque = 1;
}
*r_k = NULL; *r_k = NULL;
nbits = pubkey_nbits (PUBKEY_ALGO_ECDH, pkey); nbits = pubkey_nbits (PUBKEY_ALGO_ECDH, pkey);
if (!nbits) if (!nbits)
return gpg_error (GPG_ERR_TOO_SHORT); return gpg_error (GPG_ERR_TOO_SHORT);
k = gen_k (nbits); k = gen_k (nbits, is_little_endian, require_opaque);
if (!k) if (!k)
BUG (); BUG ();

View File

@ -1748,6 +1748,8 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
curve = "Curve25519"; curve = "Curve25519";
else if (!ascii_strcasecmp (curve, "ed25519")) else if (!ascii_strcasecmp (curve, "ed25519"))
curve = "Ed25519"; curve = "Ed25519";
else if (!ascii_strcasecmp (curve, "x448"))
curve = "X448";
/* Note that we use the "comp" flag with EdDSA to request the use of /* Note that we use the "comp" flag with EdDSA to request the use of
a 0x40 compression prefix octet. */ a 0x40 compression prefix octet. */
@ -1765,6 +1767,13 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
(((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
" transient-key" : "")); " transient-key" : ""));
else if (algo == PUBKEY_ALGO_ECDH && !strcmp (curve, "X448"))
keyparms = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags comp%s)))",
strlen (curve), curve,
(((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
" transient-key" : ""));
else else
keyparms = xtryasprintf keyparms = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags nocomp%s)))", ("(genkey(ecc(curve %zu:%s)(flags nocomp%s)))",
@ -2319,6 +2328,8 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
kpi->algo = PUBKEY_ALGO_EDDSA; kpi->algo = PUBKEY_ALGO_EDDSA;
else if (!strcmp (algostr, "cv25519")) else if (!strcmp (algostr, "cv25519"))
kpi->algo = PUBKEY_ALGO_ECDH; kpi->algo = PUBKEY_ALGO_ECDH;
else if (!strcmp (algostr, "x448"))
kpi->algo = PUBKEY_ALGO_ECDH;
else if ((kpi->usage & GCRY_PK_USAGE_ENCR)) else if ((kpi->usage & GCRY_PK_USAGE_ENCR))
kpi->algo = PUBKEY_ALGO_ECDH; kpi->algo = PUBKEY_ALGO_ECDH;
else else
@ -3472,6 +3483,8 @@ parse_key_parameter_part (ctrl_t ctrl,
algo = PUBKEY_ALGO_EDDSA; algo = PUBKEY_ALGO_EDDSA;
else if (!strcmp (algostr, "cv25519")) else if (!strcmp (algostr, "cv25519"))
algo = PUBKEY_ALGO_ECDH; algo = PUBKEY_ALGO_ECDH;
else if (!strcmp (algostr, "x448"))
algo = PUBKEY_ALGO_ECDH;
else if ((kpi->usage & GCRY_PK_USAGE_ENCR)) else if ((kpi->usage & GCRY_PK_USAGE_ENCR))
algo = PUBKEY_ALGO_ECDH; algo = PUBKEY_ALGO_ECDH;
else else
@ -3599,6 +3612,7 @@ parse_key_parameter_part (ctrl_t ctrl,
* elg2048 := Elgamal with 2048 bit. * elg2048 := Elgamal with 2048 bit.
* ed25519 := EDDSA using curve Ed25519. * ed25519 := EDDSA using curve Ed25519.
* cv25519 := ECDH using curve Curve25519. * cv25519 := ECDH using curve Curve25519.
* x448 := ECDH using curve X448.
* nistp256:= ECDSA or ECDH using curve NIST P-256 * nistp256:= ECDSA or ECDH using curve NIST P-256
* *
* All strings with an unknown prefix are considered an elliptic * All strings with an unknown prefix are considered an elliptic