summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2024-11-13 15:58:31 +0100
committerWerner Koch <wk@gnupg.org>2024-11-13 16:13:43 +0100
commit6b02292d315d829bc05816dac7975a94aaeae718 (patch)
tree5361067c63c536664d415c53c0b461cec0dad487
parentgpgconf: Show also the used nPth version with -V (diff)
downloadgnupg2-6b02292d315d829bc05816dac7975a94aaeae718.tar.xz
gnupg2-6b02292d315d829bc05816dac7975a94aaeae718.zip
gpg: Add option to create Kyber with --full-gen-key.
* g10/keygen.c (PQC_STD_KEY_PARAM_PRI, PQC_STD_KEY_PARAM_SUB): New. (PQC_STD_KEY_PARAM): Construct from above. (gen_kyber): Allow short curve names. (ask_algo): Add Entry for ecc+kyber. (ask_kyber_variant): New. (generate_keypair): Generate ECC primary and Kyber sub. -- GnuPG-bug-id: 6638
-rw-r--r--NEWS2
-rw-r--r--g10/keygen.c173
2 files changed, 167 insertions, 8 deletions
diff --git a/NEWS b/NEWS
index cebb2e6d0..5f68a5f20 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
Noteworthy changes in version 2.5.2 (unreleased)
------------------------------------------------
+ * gpg: Add option 16 to --full-gen-key to create ECC+Kyber. [T6638]
+
* dirmngr: A list of used URLs for loaded CRLs is printed first in
the output of the LISTCRL command. [T7337]
diff --git a/g10/keygen.c b/g10/keygen.c
index bdb3cd43a..77feb8e72 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -54,7 +54,9 @@
* keep the values set in generate_subkeypair in sync. */
#define DEFAULT_STD_KEY_PARAM "ed25519/cert,sign+cv25519/encr"
#define FUTURE_STD_KEY_PARAM "ed25519/cert,sign+cv25519/encr"
-#define PQC_STD_KEY_PARAM "bp384/cert,sign+kyber768_bp256/encr"
+#define PQC_STD_KEY_PARAM_PRI "bp384/cert,sign"
+#define PQC_STD_KEY_PARAM_SUB "kyber768_bp256/encr"
+#define PQC_STD_KEY_PARAM PQC_STD_KEY_PARAM_PRI "+" PQC_STD_KEY_PARAM_SUB
/* When generating keys using the streamlined key generation dialog,
use this as a default expiration interval. */
@@ -2181,8 +2183,9 @@ gen_kyber (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root,
*keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
- if (!strcmp (curve, "Curve25519"))
+ if (!strcmp (curve, "Curve25519") || !ascii_strcasecmp (curve, "cv25519"))
{
+ curve = "Curve25519";
keyparms1 = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))",
strlen (curve), curve,
@@ -2190,8 +2193,9 @@ gen_kyber (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root,
&& (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
" transient-key" : ""));
}
- else if (!strcmp (curve, "X448"))
+ else if (!strcmp (curve, "X448") || !ascii_strcasecmp (curve, "cv448"))
{
+ curve = "X448";
keyparms1 = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags comp%s)))",
strlen (curve), curve,
@@ -2591,10 +2595,11 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
if (r_keygrip)
tty_printf (_(" (%d) Existing key from card%s\n"), 14, "");
- /* Reserve 15 for ECC or Dilithium primary + Kyber subkey. */
+ /* Reserve 15 for Dilithium primary + Kyber subkey. */
+ tty_printf (_(" (%d) ECC and Kyber%s\n"), 16, "");
if (addmode)
{
- tty_printf (_(" (%d) Kyber (encrypt only)%s\n"), 16, "");
+ tty_printf (_(" (%d) Kyber (encrypt only)%s\n"), 17, "");
}
for (;;)
@@ -2882,7 +2887,13 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
free_keypair_info (keypairlist);
break;
}
- else if ((algo == 16 || !strcmp (answer, "kyber")) && addmode)
+ else if ((algo == 16 || !strcmp (answer, "ecc+kyber")) && !addmode)
+ {
+ algo = PUBKEY_ALGO_ECDSA;
+ *r_subkey_algo = PUBKEY_ALGO_KYBER;
+ break;
+ }
+ else if ((algo == 17 || !strcmp (answer, "kyber")) && addmode)
{
algo = PUBKEY_ALGO_KYBER;
*r_usage = PUBKEY_USAGE_ENC;
@@ -3219,6 +3230,77 @@ ask_curve (int *algo, int *subkey_algo, const char *current)
}
+/* Ask for the Kyber variant. Returns a const algo string like
+ * kyber768_bp256 or NULL on error. */
+const char *
+ask_kyber_variant (void)
+{
+ struct {
+ const char *desc; /* e.g. "Kyber 768" */
+ const char *variant; /* e.g. "kyber768_bp256" */
+ unsigned int de_vs : 1; /* Allowed in CO_DE_VS. */
+ } table[] = {
+ { "Kyber 768", "kyber768_bp256", 1 },
+ { "Kyber 1024", "kyber1024_bp384", 1 },
+ { "Kyber 768 (X25519)", "kyber768_cv25519", 0 },
+ { "Kyber 1024 (X448)", "kyber1024_cv448", 0 },
+ };
+ int idx;
+ char *answer;
+ const char *result = NULL;
+
+ tty_printf (_("Please select the %s variant you want:\n"), "Kyber");
+
+ for (idx=0; idx < DIM(table); idx++)
+ {
+ if (opt.compliance==CO_DE_VS)
+ {
+ if (!table[idx].de_vs)
+ continue; /* Not allowed. */
+ }
+
+ tty_printf (" (%d) %s%s\n", idx + 1,
+ table[idx].desc,
+ idx == 0? _(" *default*"):"");
+ }
+
+ for (;;)
+ {
+ answer = cpr_get ("keygen.kyber_variant", _("Your selection? "));
+ cpr_kill_prompt ();
+ idx = *answer? atoi (answer) : 1 /* default */;
+ if (*answer && !idx)
+ {
+ /* See whether the user entered the name of the algo. */
+ for (idx=0; idx < DIM(table); idx++)
+ {
+ if (!stricmp (table[idx].variant, answer))
+ break;
+ }
+ if (idx == DIM(table))
+ idx = -1;
+ }
+ else
+ idx--; /* Map back to 0 based index. */
+ xfree(answer);
+ answer = NULL;
+ if (idx < 0 || idx >= DIM (table)
+ || (opt.compliance==CO_DE_VS && !table[idx].de_vs))
+ tty_printf (_("Invalid selection.\n"));
+ else
+ {
+ result = table[idx].variant;
+ break;
+ }
+ }
+
+ if (!result)
+ result = table[0].variant;
+
+ return result;
+}
+
+
/****************
* Parse an expire string and return its value in seconds.
* Returns (u32)-1 on error.
@@ -5296,7 +5378,7 @@ quickgen_set_para (struct para_data_s *para, int for_subkey,
}
/* Always store the size - although not required for ECC it is
- * required for compiste algos. Should not harm anyway. */
+ * required for composite algos. Should not harm anyway. */
r = xmalloc_clear (sizeof *r + 20);
r->key = for_subkey? pSUBKEYLENGTH : pKEYLENGTH;
sprintf (r->u.value, "%u", nbits);
@@ -5699,7 +5781,82 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
{
const char *curve = NULL;
- if (subkey_algo)
+ if (algo == PUBKEY_ALGO_ECDSA && subkey_algo == PUBKEY_ALGO_KYBER)
+ {
+ /* Create primary and subkey at once. */
+ const char *subalgostr;
+ const char *s;
+ const char *pricurve;
+ int prialgo = PUBKEY_ALGO_ECDSA;
+
+ both = 1;
+ subalgostr = ask_kyber_variant ();
+ if (!subalgostr) /* Should not happen. */
+ subalgostr = PQC_STD_KEY_PARAM_SUB;
+
+ /* Determine the primary key algo from the subkey algo. */
+ if (strstr (subalgostr, "bp384"))
+ pricurve = "brainpoolP384r1";
+ else if (strstr (subalgostr, "bp256"))
+ pricurve = "brainpoolP256r1";
+ else if (strstr (subalgostr, "cv448"))
+ {
+ pricurve = "Ed448";
+ prialgo = PUBKEY_ALGO_EDDSA;
+ }
+ else
+ {
+ pricurve = "Ed25519";
+ prialgo = PUBKEY_ALGO_EDDSA;
+ }
+
+ r = xmalloc_clear (sizeof *r + 20);
+ r->key = pKEYTYPE;
+ sprintf (r->u.value, "%d", prialgo);
+ r->next = para;
+ para = r;
+
+ r = xmalloc_clear (sizeof *r + strlen (pricurve));
+ r->key = pKEYCURVE;
+ strcpy (r->u.value, pricurve);
+ r->next = para;
+ para = r;
+
+ r = xmalloc_clear (sizeof *r + 20);
+ r->key = pKEYUSAGE;
+ strcpy (r->u.value, "sign");
+ r->next = para;
+ para = r;
+
+ r = xmalloc_clear (sizeof *r + 20);
+ r->key = pSUBKEYTYPE;
+ sprintf (r->u.value, "%d", PUBKEY_ALGO_KYBER);
+ r->next = para;
+ para = r;
+
+ r = xmalloc_clear (sizeof *r + 20);
+ r->key = pSUBKEYLENGTH;
+ sprintf (r->u.value, "%u",
+ strstr (subalgostr, "768_")? 768 : 1024);
+ r->next = para;
+ para = r;
+
+ s = strchr (subalgostr, '_');
+ log_assert (s && s[1]);
+ s++;
+ r = xmalloc_clear (sizeof *r + strlen (s));
+ r->key = pSUBKEYCURVE;
+ strcpy (r->u.value, s);
+ r->next = para;
+ para = r;
+
+ r = xmalloc_clear (sizeof *r + 20);
+ r->key = pSUBKEYUSAGE;
+ strcpy( r->u.value, "encrypt" );
+ r->next = para;
+ para = r;
+ }
+ else if (subkey_algo)
{
/* Create primary and subkey at once. */
both = 1;