Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PQC: Classic McEliece #3883

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
48 changes: 48 additions & 0 deletions doc/api_ref/pubkey.rst
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ McEliece
Post-quantum secure key encapsulation scheme based on the hardness of certain
decoding problems.

Classic McEliece
~~~~~~~~~~~~~~~~
reneme marked this conversation as resolved.
Show resolved Hide resolved
FAlbertDev marked this conversation as resolved.
Show resolved Hide resolved

Post-quantum secure, code-based key encapsulation scheme.

ElGamal
~~~~~~~~

Expand Down Expand Up @@ -1205,6 +1210,7 @@ Botan implements the following KEM schemes:
#. ML-KEM (Kyber)
#. FrodoKEM
#. McEliece
#. Classic McEliece

.. _mlkem_example:

Expand Down Expand Up @@ -1271,6 +1277,48 @@ parameters n and t, and have the corresponding key sizes listed:
You can check the speed of McEliece with the suggested parameters above
using ``botan speed McEliece``

Classic McEliece KEM
--------------------

`Classic McEliece <https://classic.mceliece.org/>`_ is an IND-CCA2 secure key
encapsulation algorithm based on the McEliece cryptosystem introduced in 1978.
It is a code-based scheme that relies on conservative security assumptions and
is considered secure against quantum computers. It is an alternative to
lattice-based schemes.

Other advantages of Classic McEliece are the small ciphertext size and the fast
encapsulation. Key generation and decapsulation are slower than in lattice-based
schemes. The main disadvantage of Classic McEliece is the large public key size,
ranging from 0.26 MB to 1.36 MB, depending on the instance. Due to its large key
size, Classic McEliece is recommended for applications where the public key is
stored for a long time, and memory is not a critical resource. Usage with
ephemeral keys is not recommended.

Botan's implementation covers the parameter sets of the `NIST round 4
specification <https://classic.mceliece.org/mceliece-spec-20221023.pdf#page=15>`_
and the `Classic McEliece ISO draft specification
<https://classic.mceliece.org/iso-mceliece-20230419.pdf#page=13>`_.
These are the following:

+------------------+-------------------+-------------------+--------------------+-------------------+
| Set without f/pc | Set with f | Set with pc | Set with pcf | Public Key Size |
+==================+===================+===================+====================+===================+
| mceliece348864 | mceliece348864f | | | 0.26 MB |
+------------------+-------------------+-------------------+--------------------+-------------------+
| mceliece460896 | mceliece460896f | | | 0.52 MB |
+------------------+-------------------+-------------------+--------------------+-------------------+
| mceliece6688128 | mceliece6688128f | mceliece6688128pc | mceliece6688128pcf | 1.04 MB |
+------------------+-------------------+-------------------+--------------------+-------------------+
| mceliece6960119 | mceliece6960119f | mceliece6960119pc | mceliece6960119pcf | 1.05 MB |
+------------------+-------------------+-------------------+--------------------+-------------------+
| mceliece8192128 | mceliece8192128f | mceliece8192128pc | mceliece8192128pcf | 1.36 MB |
+------------------+-------------------+-------------------+--------------------+-------------------+

The instances with the suffix 'f' use a faster key generation algorithm that is more consistent in
runtime. The instances with the suffix 'pc' use plaintext confirmation, which is only specified in
the ISO document. The instances mceliece348864(f) and mceliece460896(f) are only defined in the
NIST round 4 submission.


eXtended Merkle Signature Scheme (XMSS)
----------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions doc/credits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ snail-mail address (S), and Bitcoin address (B).
N: Fabian Albert
E: fabian.albert@rohde-schwarz.com
W: https://www.rohde-schwarz.com/cybersecurity
D: SLH-DSA, Ed/X448, HSS/LMS, ML-KEM, ML-DSA, TLS-Anvil tests
D: SLH-DSA, Ed/X448, HSS/LMS, ML-KEM, ML-DSA, Classic McEliece, TLS-Anvil tests
S: Bochum, Germany

N: Alexander Bluhm
Expand Down Expand Up @@ -159,7 +159,7 @@ snail-mail address (S), and Bitcoin address (B).
N: Amos Treiber
E: amos.treiber@rohde-schwarz.com
W: https://www.rohde-schwarz.com/cybersecurity
D: SLH-DSA, TPM 2.0, FrodoKEM, ML-KEM, ML-DSA
D: SLH-DSA, TPM 2.0, FrodoKEM, Classic McEliece, ML-KEM, ML-DSA
S: Cologne, Germany

N: Daniel Seither
Expand Down
9 changes: 9 additions & 0 deletions doc/dev_ref/oids.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ Values currently assigned are::

HSS-LMS-Private-Key OBJECT IDENTIFIER ::= { publicKey 13 }

mceliece OBJECT IDENTIFIER ::= { publicKey 18 }

mceliece6688128pc OBJECT IDENTIFIER ::= { mceliece 1 }
mceliece6688128pcf OBJECT IDENTIFIER ::= { mceliece 2 }
mceliece6960119pc OBJECT IDENTIFIER ::= { mceliece 3 }
mceliece6960119pcf OBJECT IDENTIFIER ::= { mceliece 4 }
mceliece8192128pc OBJECT IDENTIFIER ::= { mceliece 5 }
mceliece8192128pcf OBJECT IDENTIFIER ::= { mceliece 6 }

symmetricKey OBJECT IDENTIFIER ::= { randombit 3 }

ocbModes OBJECT IDENTIFIER ::= { symmetricKey 2 }
Expand Down
22 changes: 21 additions & 1 deletion src/build-data/oids.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Regenerate with ./src/scripts/dev_tools/gen_oids.py oids > src/lib/asn1/oid_maps.cpp
# AND ./src/scripts/dev_tools/gen_oids.py dn_ub > src/lib/x509/x509_dn_ub.cpp
# (if you modified something under [dn]
# (if you modified something under [dn])

# Public key types
[pubkey]
Expand Down Expand Up @@ -98,6 +98,26 @@
1.3.6.1.4.1.25258.1.12.3.5 = SphincsPlus-haraka-256s-r3.1
1.3.6.1.4.1.25258.1.12.3.6 = SphincsPlus-haraka-256f-r3.1

# Classic McEliece OID selection from IETF Hackathon/BouncyCastle for non PC instances
1.3.6.1.4.1.22554.5.1.1 = mceliece348864
1.3.6.1.4.1.22554.5.1.2 = mceliece348864f
1.3.6.1.4.1.22554.5.1.3 = mceliece460896
1.3.6.1.4.1.22554.5.1.4 = mceliece460896f
1.3.6.1.4.1.22554.5.1.5 = mceliece6688128
1.3.6.1.4.1.22554.5.1.6 = mceliece6688128f
1.3.6.1.4.1.22554.5.1.7 = mceliece6960119
1.3.6.1.4.1.22554.5.1.8 = mceliece6960119f
1.3.6.1.4.1.22554.5.1.9 = mceliece8192128
1.3.6.1.4.1.22554.5.1.10 = mceliece8192128f

# Classic McEliece PC OIDs are currently in Botan's private arc
1.3.6.1.4.1.25258.1.18.1 = mceliece6688128pc
1.3.6.1.4.1.25258.1.18.2 = mceliece6688128pcf
1.3.6.1.4.1.25258.1.18.3 = mceliece6960119pc
1.3.6.1.4.1.25258.1.18.4 = mceliece6960119pcf
1.3.6.1.4.1.25258.1.18.5 = mceliece8192128pc
1.3.6.1.4.1.25258.1.18.6 = mceliece8192128pcf

# XMSS
1.3.6.1.4.1.25258.1.5 = XMSS-draft6
1.3.6.1.4.1.25258.1.8 = XMSS-draft12
Expand Down
33 changes: 33 additions & 0 deletions src/cli/perf_pk_kem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,37 @@ BOTAN_REGISTER_PERF_TEST("FrodoKEM", PerfTest_FrodoKEM);

#endif

#if defined(BOTAN_HAS_CLASSICMCELIECE)

class PerfTest_Classic_McEliece final : public PerfTest_PK_KEM {
public:
std::string algo() const override { return "ClassicMcEliece"; }

std::vector<std::string> keygen_params(const PerfConfig& config) const override {
BOTAN_UNUSED(config);
return {
"mceliece348864",
"mceliece348864f",
"mceliece460896",
"mceliece460896f",
"mceliece6688128",
"mceliece6688128f",
"mceliece6688128pc",
"mceliece6688128pcf",
"mceliece6960119",
"mceliece6960119f",
"mceliece6960119pc",
"mceliece6960119pcf",
"mceliece8192128",
"mceliece8192128f",
"mceliece8192128pc",
"mceliece8192128pcf",
};
}
};

BOTAN_REGISTER_PERF_TEST("ClassicMcEliece", PerfTest_Classic_McEliece);

#endif

} // namespace Botan_CLI
34 changes: 33 additions & 1 deletion src/lib/asn1/oid_maps.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* OID maps
*
* This file was automatically generated by ./src/scripts/dev_tools/gen_oids.py on 2024-10-15
* This file was automatically generated by ./src/scripts/dev_tools/gen_oids.py on 2024-10-18
*
* All manual edits to this file will be lost. Edit the script
* then regenerate this source file.
Expand Down Expand Up @@ -142,6 +142,16 @@ std::unordered_map<std::string, std::string> OID_Map::load_oid2str_map() {
{"1.3.36.3.3.2.8.1.1.9", "brainpool320r1"},
{"1.3.6.1.4.1.11591.15.1", "OpenPGP.Ed25519"},
{"1.3.6.1.4.1.11591.4.11", "Scrypt"},
{"1.3.6.1.4.1.22554.5.1.1", "mceliece348864"},
{"1.3.6.1.4.1.22554.5.1.10", "mceliece8192128f"},
{"1.3.6.1.4.1.22554.5.1.2", "mceliece348864f"},
{"1.3.6.1.4.1.22554.5.1.3", "mceliece460896"},
{"1.3.6.1.4.1.22554.5.1.4", "mceliece460896f"},
{"1.3.6.1.4.1.22554.5.1.5", "mceliece6688128"},
{"1.3.6.1.4.1.22554.5.1.6", "mceliece6688128f"},
{"1.3.6.1.4.1.22554.5.1.7", "mceliece6960119"},
{"1.3.6.1.4.1.22554.5.1.8", "mceliece6960119f"},
{"1.3.6.1.4.1.22554.5.1.9", "mceliece8192128"},
{"1.3.6.1.4.1.25258.1.10.1", "Dilithium-4x4-AES-r3"},
{"1.3.6.1.4.1.25258.1.10.2", "Dilithium-6x5-AES-r3"},
{"1.3.6.1.4.1.25258.1.10.3", "Dilithium-8x7-AES-r3"},
Expand Down Expand Up @@ -179,6 +189,12 @@ std::unordered_map<std::string, std::string> OID_Map::load_oid2str_map() {
{"1.3.6.1.4.1.25258.1.17.1", "eFrodoKEM-640-AES"},
{"1.3.6.1.4.1.25258.1.17.2", "eFrodoKEM-976-AES"},
{"1.3.6.1.4.1.25258.1.17.3", "eFrodoKEM-1344-AES"},
{"1.3.6.1.4.1.25258.1.18.1", "mceliece6688128pc"},
{"1.3.6.1.4.1.25258.1.18.2", "mceliece6688128pcf"},
{"1.3.6.1.4.1.25258.1.18.3", "mceliece6960119pc"},
{"1.3.6.1.4.1.25258.1.18.4", "mceliece6960119pcf"},
{"1.3.6.1.4.1.25258.1.18.5", "mceliece8192128pc"},
{"1.3.6.1.4.1.25258.1.18.6", "mceliece8192128pcf"},
{"1.3.6.1.4.1.25258.1.3", "McEliece"},
{"1.3.6.1.4.1.25258.1.5", "XMSS-draft6"},
{"1.3.6.1.4.1.25258.1.6.1", "GOST-34.10-2012-256/SHA-256"},
Expand Down Expand Up @@ -621,6 +637,22 @@ std::unordered_map<std::string, OID> OID_Map::load_str2oid_map() {
{"gost_256B", OID({1, 2, 643, 7, 1, 2, 1, 1, 2})},
{"gost_512A", OID({1, 2, 643, 7, 1, 2, 1, 2, 1})},
{"gost_512B", OID({1, 2, 643, 7, 1, 2, 1, 2, 2})},
{"mceliece348864", OID({1, 3, 6, 1, 4, 1, 22554, 5, 1, 1})},
{"mceliece348864f", OID({1, 3, 6, 1, 4, 1, 22554, 5, 1, 2})},
{"mceliece460896", OID({1, 3, 6, 1, 4, 1, 22554, 5, 1, 3})},
{"mceliece460896f", OID({1, 3, 6, 1, 4, 1, 22554, 5, 1, 4})},
{"mceliece6688128", OID({1, 3, 6, 1, 4, 1, 22554, 5, 1, 5})},
{"mceliece6688128f", OID({1, 3, 6, 1, 4, 1, 22554, 5, 1, 6})},
{"mceliece6688128pc", OID({1, 3, 6, 1, 4, 1, 25258, 1, 18, 1})},
{"mceliece6688128pcf", OID({1, 3, 6, 1, 4, 1, 25258, 1, 18, 2})},
{"mceliece6960119", OID({1, 3, 6, 1, 4, 1, 22554, 5, 1, 7})},
{"mceliece6960119f", OID({1, 3, 6, 1, 4, 1, 22554, 5, 1, 8})},
{"mceliece6960119pc", OID({1, 3, 6, 1, 4, 1, 25258, 1, 18, 3})},
{"mceliece6960119pcf", OID({1, 3, 6, 1, 4, 1, 25258, 1, 18, 4})},
{"mceliece8192128", OID({1, 3, 6, 1, 4, 1, 22554, 5, 1, 9})},
{"mceliece8192128f", OID({1, 3, 6, 1, 4, 1, 22554, 5, 1, 10})},
{"mceliece8192128pc", OID({1, 3, 6, 1, 4, 1, 25258, 1, 18, 5})},
{"mceliece8192128pcf", OID({1, 3, 6, 1, 4, 1, 25258, 1, 18, 6})},
{"numsp256d1", OID({1, 3, 6, 1, 4, 1, 25258, 4, 1})},
{"numsp384d1", OID({1, 3, 6, 1, 4, 1, 25258, 4, 2})},
{"numsp512d1", OID({1, 3, 6, 1, 4, 1, 25258, 4, 3})},
Expand Down
16 changes: 16 additions & 0 deletions src/lib/ffi/ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -1556,6 +1556,22 @@ int botan_privkey_load_frodokem(botan_privkey_t* key, const uint8_t privkey[], s
BOTAN_FFI_EXPORT(3, 6)
int botan_pubkey_load_frodokem(botan_pubkey_t* key, const uint8_t pubkey[], size_t key_len, const char* frodo_mode);

/**
* Algorithm specific key operation: Classic McEliece
*/

BOTAN_FFI_EXPORT(3, 6)
int botan_privkey_load_classic_mceliece(botan_privkey_t* key,
const uint8_t privkey[],
size_t key_len,
const char* cmce_mode);

BOTAN_FFI_EXPORT(3, 6)
int botan_pubkey_load_classic_mceliece(botan_pubkey_t* key,
const uint8_t pubkey[],
size_t key_len,
const char* cmce_mode);

/*
* Algorithm specific key operations: ML-KEM
*/
Expand Down
54 changes: 54 additions & 0 deletions src/lib/ffi/ffi_pkey_algs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@
#include <botan/slh_dsa.h>
#endif

#if defined(BOTAN_HAS_CLASSICMCELIECE)
#include <botan/cmce.h>
#endif

namespace {

#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
Expand Down Expand Up @@ -1243,6 +1247,56 @@ int botan_pubkey_load_frodokem(botan_pubkey_t* key, const uint8_t pubkey[], size
#endif
}

/*
* Algorithm specific key operations : Classic McEliece
*/

int botan_privkey_load_classic_mceliece(botan_privkey_t* key,
const uint8_t privkey[],
size_t key_len,
const char* cmce_mode) {
#if defined(BOTAN_HAS_CLASSICMCELIECE)
if(key == nullptr || privkey == nullptr || cmce_mode == nullptr) {
return BOTAN_FFI_ERROR_NULL_POINTER;
}

*key = nullptr;

return ffi_guard_thunk(__func__, [=]() -> int {
const auto mode = Botan::Classic_McEliece_Parameter_Set::from_string(cmce_mode);
auto cmce_key = std::make_unique<Botan::Classic_McEliece_PrivateKey>(std::span{privkey, key_len}, mode);
*key = new botan_privkey_struct(std::move(cmce_key));
return BOTAN_FFI_SUCCESS;
});
#else
BOTAN_UNUSED(key, privkey, key_len, cmce_mode);
return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
}

int botan_pubkey_load_classic_mceliece(botan_pubkey_t* key,
const uint8_t pubkey[],
size_t key_len,
const char* cmce_mode) {
#if defined(BOTAN_HAS_CLASSICMCELIECE)
if(key == nullptr || pubkey == nullptr || cmce_mode == nullptr) {
return BOTAN_FFI_ERROR_NULL_POINTER;
}

*key = nullptr;

return ffi_guard_thunk(__func__, [=]() -> int {
const auto mode = Botan::Classic_McEliece_Parameter_Set::from_string(cmce_mode);
auto cmce_key = std::make_unique<Botan::Classic_McEliece_PublicKey>(std::span{pubkey, key_len}, mode);
*key = new botan_pubkey_struct(std::move(cmce_key));
return BOTAN_FFI_SUCCESS;
});
#else
BOTAN_UNUSED(key, pubkey, key_len, cmce_mode);
return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
}

int botan_pubkey_view_ec_public_point(const botan_pubkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
return BOTAN_FFI_VISIT(key, [=](const auto& k) -> int {
Expand Down
Loading
Loading