diff --git a/doc/gpg.texi b/doc/gpg.texi index 10a1937f6..446189b4b 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -3146,6 +3146,15 @@ This option adjusts the compliance mode "de-vs" for stricter key size requirements. For example, a value of 3000 turns rsa2048 and dsa2048 keys into non-VS-NfD compliant keys. +@item --require-pqc-encryption +@opindex require-pqc-encryption +This option forces the use of quantum-resistant encryption algorithms. +If not all public keys are quantum-resistant the encryption will fail. +On decryption a warning is printed for all non-quantum-resistant keys. +As of now the Kyber (ML-KEM768 and ML-KEM1024) algorithms are +considered quantum-resistant; Kyber is always used in a composite +scheme along with a classic ECC algorithm. + @item --require-compliance @opindex require-compliance To check that data has been encrypted according to the rules of the diff --git a/g10/getkey.c b/g10/getkey.c index ce59628a0..f2d1e7d7b 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -3779,6 +3779,16 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, continue; } + if (opt.flags.require_pqc_encryption + && (req_usage & PUBKEY_USAGE_ENC) + && pk->pubkey_algo != PUBKEY_ALGO_KYBER) + { + if (DBG_LOOKUP) + log_debug ("\tsubkey is not quantum-resistant\n"); + continue; + } + + if (want_secret) { int secret_key_avail = agent_probe_secret_key (NULL, pk); @@ -3857,6 +3867,13 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact, if (DBG_LOOKUP) log_debug ("\tprimary key has expired\n"); } + else if (opt.flags.require_pqc_encryption + && (req_usage & PUBKEY_USAGE_ENC) + && pk->pubkey_algo != PUBKEY_ALGO_KYBER) + { + if (DBG_LOOKUP) + log_debug ("\tprimary key is not quantum-resistant\n"); + } else /* Okay. */ { if (DBG_LOOKUP) diff --git a/g10/gpg.c b/g10/gpg.c index 658fb7cf1..82745fa18 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -456,6 +456,7 @@ enum cmd_and_opt_values oAssertSigner, oAssertPubkeyAlgo, oKbxBufferSize, + oRequirePQCEncryption, oNoop }; @@ -896,7 +897,7 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_s (oCipherAlgo, "cipher-algo", "@"), ARGPARSE_s_s (oDigestAlgo, "digest-algo", "@"), ARGPARSE_s_s (oCertDigestAlgo, "cert-digest-algo", "@"), - + ARGPARSE_s_n (oRequirePQCEncryption, "require-pqc-encryption", "@"), ARGPARSE_header (NULL, N_("Options for unattended use")), @@ -3071,6 +3072,9 @@ main (int argc, char **argv) break; case oMinRSALength: opt.min_rsa_length = pargs.r.ret_ulong; break; + case oRequirePQCEncryption: + opt.flags.require_pqc_encryption = 1; + break; case oRFC2440Text: opt.rfc2440_text=1; break; case oNoRFC2440Text: opt.rfc2440_text=0; break; diff --git a/g10/mainproc.c b/g10/mainproc.c index 48bc463c5..91ababbb6 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -578,6 +578,10 @@ print_pkenc_list (ctrl_t ctrl, struct pubkey_enc_list *list) openpgp_pk_algo_name (list->pubkey_algo), keystr(list->keyid)); + if (opt.flags.require_pqc_encryption + && pk->pubkey_algo != PUBKEY_ALGO_KYBER) + log_info (_("WARNING: key is not quantum-resistant\n")); + free_public_key (pk); } } diff --git a/g10/options.h b/g10/options.h index 2fe4f5bbf..ae429fcc1 100644 --- a/g10/options.h +++ b/g10/options.h @@ -283,6 +283,7 @@ struct /* Fail if an operation can't be done in the requested compliance * mode. */ unsigned int require_compliance:1; + unsigned int require_pqc_encryption:1; } flags; /* Linked list of ways to find a key if the key isn't on the local