Skip to content

Commit

Permalink
Classic McEliece implementation
Browse files Browse the repository at this point in the history
This is an implementation of the Classic McEliece KEM according to the
NIST Round 4 submission and the ISO draft 20230419.

Co-Authored-By: Amos Treiber <[email protected]>
  • Loading branch information
FAlbertDev and atreiber94 committed Nov 20, 2024
1 parent b5b78fe commit ab1d559
Show file tree
Hide file tree
Showing 40 changed files with 4,164 additions and 8 deletions.
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
~~~~~~~~~~~~~~~~

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: [email protected]
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: [email protected]
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

0 comments on commit ab1d559

Please sign in to comment.