Skip to content

Commit

Permalink
Implement FrodoKEM and eFrodoKEM according to ISO 20230314
Browse files Browse the repository at this point in the history
Integrated into CLI benchmarking tool and X.509 tests

Co-Authored-By: René Meusel <[email protected]>
  • Loading branch information
atreiber94 and reneme committed Oct 9, 2023
1 parent 4aebdb5 commit ea6d352
Show file tree
Hide file tree
Showing 20 changed files with 3,925 additions and 6 deletions.
8 changes: 7 additions & 1 deletion doc/api_ref/pubkey.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ Post-quantum secure signature scheme based on lattice problems.
Kyber
~~~~~~~~~~~

Post-quantum key encapsulation scheme based on lattices.
Post-quantum key encapsulation scheme based on (structured) lattices.

Ed25519
~~~~~~~~~~
Expand All @@ -122,6 +122,11 @@ security of a hash function. Unlike XMSS, it is a stateless signature
scheme, meaning that the private key does not change with each signature. It
has high security but very long signatures and high runtime.

FrodoKEM
~~~~~~~~

A post-quantum secure key encapsulation scheme based on (unstructured) lattices.

McEliece
~~~~~~~~~~

Expand Down Expand Up @@ -900,6 +905,7 @@ Botan implements the following KEM schemes:

1. RSA
#. Kyber
#. FrodoKEM
#. McEliece

Code Example
Expand Down
18 changes: 18 additions & 0 deletions doc/dev_ref/oids.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,24 @@ Values currently assigned are::
-- { publicKey 5 } previously used for XMSS draft 6
gost-3410-with-sha256 OBJECT IDENTIFIER ::= { publicKey 6 1 }

frodokem-shake OBJECT IDENTIFIER ::= { publicKey 13 }
efrodokem-shake OBJECT IDENTIFIER ::= { publicKey 15 }
frodokem-aes OBJECT IDENTIFIER ::= { publicKey 14 }
efrodokem-aes OBJECT IDENTIFIER ::= { publicKey 16 }

frodokem-640-shake OBJECT_IDENTIFIER : { frodokem-shake 1 }
frodokem-976-shake OBJECT_IDENTIFIER : { frodokem-shake 2 }
frodokem-1344-shake OBJECT_IDENTIFIER : { frodokem-shake 3 }
frodokem-640-aes OBJECT_IDENTIFIER : { frodokem-aes 1 }
frodokem-976-aes OBJECT_IDENTIFIER : { frodokem-aes 2 }
frodokem-1344-aes OBJECT_IDENTIFIER : { frodokem-aes 3 }
efrodokem-640-shake OBJECT_IDENTIFIER : { efrodokem-shake 1 }
efrodokem-976-shake OBJECT_IDENTIFIER : { efrodokem-shake 2 }
efrodokem-1344-shake OBJECT_IDENTIFIER : { efrodokem-shake 3 }
efrodokem-640-aes OBJECT_IDENTIFIER : { efrodokem-aes 1 }
efrodokem-976-aes OBJECT_IDENTIFIER : { efrodokem-aes 2 }
efrodokem-1344-aes OBJECT_IDENTIFIER : { efrodokem-aes 3 }

kyber OBJECT IDENTIFIER ::= { publicKey 7 }
kyber-90s OBJECT IDENTIFIER ::= { publicKey 11 }

Expand Down
14 changes: 14 additions & 0 deletions src/build-data/oids.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@
1.3.101.110 = Curve25519
1.3.101.112 = Ed25519

# FrodoKEM OIDs are currently in Botan's private arc
1.3.6.1.4.1.25258.1.13.1 = FrodoKEM-640-SHAKE
1.3.6.1.4.1.25258.1.13.2 = FrodoKEM-976-SHAKE
1.3.6.1.4.1.25258.1.13.3 = FrodoKEM-1344-SHAKE
1.3.6.1.4.1.25258.1.14.1 = FrodoKEM-640-AES
1.3.6.1.4.1.25258.1.14.2 = FrodoKEM-976-AES
1.3.6.1.4.1.25258.1.14.3 = FrodoKEM-1344-AES
1.3.6.1.4.1.25258.1.15.1 = eFrodoKEM-640-SHAKE
1.3.6.1.4.1.25258.1.15.2 = eFrodoKEM-976-SHAKE
1.3.6.1.4.1.25258.1.15.3 = eFrodoKEM-1344-SHAKE
1.3.6.1.4.1.25258.1.16.1 = eFrodoKEM-640-AES
1.3.6.1.4.1.25258.1.16.2 = eFrodoKEM-976-AES
1.3.6.1.4.1.25258.1.16.3 = eFrodoKEM-1344-AES

# Kyber OIDs are currently in Botan's private arc
1.3.6.1.4.1.25258.1.7.1 = Kyber-512-r3
1.3.6.1.4.1.25258.1.7.2 = Kyber-768-r3
Expand Down
39 changes: 38 additions & 1 deletion src/cli/speed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@
#include <botan/sphincsplus.h>
#endif

#if defined(BOTAN_HAS_FRODOKEM)
#include <botan/frodokem.h>
#endif

#if defined(BOTAN_HAS_ECDSA)
#include <botan/ecdsa.h>
#endif
Expand Down Expand Up @@ -404,7 +408,8 @@ class Speed final : public Command {
"Curve25519",
"McEliece",
"Kyber",
"SPHINCS+"
"SPHINCS+",
"FrodoKEM"
};
// clang-format on
}
Expand Down Expand Up @@ -614,6 +619,11 @@ class Speed final : public Command {
bench_sphincs_plus(provider, msec);
}
#endif
#if defined(BOTAN_HAS_FRODOKEM)
else if(algo == "FrodoKEM") {
bench_frodokem(provider, msec);
}
#endif
#if defined(BOTAN_HAS_SCRYPT)
else if(algo == "scrypt") {
bench_scrypt(provider, msec);
Expand Down Expand Up @@ -2037,6 +2047,33 @@ class Speed final : public Command {
}
#endif

#if defined(BOTAN_HAS_FRODOKEM)
void bench_frodokem(const std::string& provider, std::chrono::milliseconds msec) {
std::vector<Botan::FrodoKEMMode> frodo_modes {
Botan::FrodoKEMMode::FrodoKEM640_SHAKE, Botan::FrodoKEMMode::FrodoKEM976_SHAKE,
Botan::FrodoKEMMode::FrodoKEM1344_SHAKE, Botan::FrodoKEMMode::eFrodoKEM640_SHAKE,
Botan::FrodoKEMMode::eFrodoKEM976_SHAKE, Botan::FrodoKEMMode::eFrodoKEM1344_SHAKE,
#if defined(BOTAN_HAS_AES)
Botan::FrodoKEMMode::FrodoKEM640_AES, Botan::FrodoKEMMode::FrodoKEM976_AES,
Botan::FrodoKEMMode::FrodoKEM1344_AES, Botan::FrodoKEMMode::eFrodoKEM640_AES,
Botan::FrodoKEMMode::eFrodoKEM976_AES, Botan::FrodoKEMMode::eFrodoKEM1344_AES,
#endif
};

for(auto modet : frodo_modes) {
Botan::FrodoKEMMode mode(modet);

auto keygen_timer = make_timer(mode.to_string(), provider, "keygen");

auto key = keygen_timer->run([&] { return Botan::FrodoKEM_PrivateKey(rng(), mode); });

record_result(keygen_timer);

bench_pk_kem(key, mode.to_string(), provider, "KDF2(SHA-256)", msec);
}
}
#endif

#if defined(BOTAN_HAS_XMSS_RFC8391)
void bench_xmss(const std::string& provider, std::chrono::milliseconds msec) {
/*
Expand Down
26 changes: 25 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 2023-05-30
* This file was automatically generated by ./src/scripts/dev_tools/gen_oids.py on 2023-09-29
*
* All manual edits to this file will be lost. Edit the script
* then regenerate this source file.
Expand Down Expand Up @@ -162,6 +162,18 @@ std::unordered_map<std::string, std::string> OID_Map::load_oid2str_map() {
{"1.3.6.1.4.1.25258.1.12.3.4", "SphincsPlus-haraka-192f-r3.1"},
{"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"},
{"1.3.6.1.4.1.25258.1.13.1", "FrodoKEM-640-SHAKE"},
{"1.3.6.1.4.1.25258.1.13.2", "FrodoKEM-976-SHAKE"},
{"1.3.6.1.4.1.25258.1.13.3", "FrodoKEM-1344-SHAKE"},
{"1.3.6.1.4.1.25258.1.14.1", "FrodoKEM-640-AES"},
{"1.3.6.1.4.1.25258.1.14.2", "FrodoKEM-976-AES"},
{"1.3.6.1.4.1.25258.1.14.3", "FrodoKEM-1344-AES"},
{"1.3.6.1.4.1.25258.1.15.1", "eFrodoKEM-640-SHAKE"},
{"1.3.6.1.4.1.25258.1.15.2", "eFrodoKEM-976-SHAKE"},
{"1.3.6.1.4.1.25258.1.15.3", "eFrodoKEM-1344-SHAKE"},
{"1.3.6.1.4.1.25258.1.16.1", "eFrodoKEM-640-AES"},
{"1.3.6.1.4.1.25258.1.16.2", "eFrodoKEM-976-AES"},
{"1.3.6.1.4.1.25258.1.16.3", "eFrodoKEM-1344-AES"},
{"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 @@ -367,6 +379,12 @@ std::unordered_map<std::string, OID> OID_Map::load_str2oid_map() {
{"ECKCDSA/SHA-256", OID({1, 2, 410, 200004, 1, 100, 4, 5})},
{"Ed25519", OID({1, 3, 101, 112})},
{"ElGamal", OID({1, 3, 6, 1, 4, 1, 3029, 1, 2, 1})},
{"FrodoKEM-1344-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 14, 3})},
{"FrodoKEM-1344-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 13, 3})},
{"FrodoKEM-640-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 14, 1})},
{"FrodoKEM-640-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 13, 1})},
{"FrodoKEM-976-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 14, 2})},
{"FrodoKEM-976-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 13, 2})},
{"GOST-34.10", OID({1, 2, 643, 2, 2, 19})},
{"GOST-34.10-2012-256", OID({1, 2, 643, 7, 1, 1, 1, 1})},
{"GOST-34.10-2012-256/SHA-256", OID({1, 3, 6, 1, 4, 1, 25258, 1, 6, 1})},
Expand Down Expand Up @@ -540,6 +558,12 @@ std::unordered_map<std::string, OID> OID_Map::load_str2oid_map() {
{"brainpool320r1", OID({1, 3, 36, 3, 3, 2, 8, 1, 1, 9})},
{"brainpool384r1", OID({1, 3, 36, 3, 3, 2, 8, 1, 1, 11})},
{"brainpool512r1", OID({1, 3, 36, 3, 3, 2, 8, 1, 1, 13})},
{"eFrodoKEM-1344-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 16, 3})},
{"eFrodoKEM-1344-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 15, 3})},
{"eFrodoKEM-640-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 16, 1})},
{"eFrodoKEM-640-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 15, 1})},
{"eFrodoKEM-976-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 16, 2})},
{"eFrodoKEM-976-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 15, 2})},
{"frp256v1", OID({1, 2, 250, 1, 223, 101, 256, 1})},
{"gost_256A", OID({1, 2, 643, 7, 1, 2, 1, 1, 1})},
{"gost_256B", OID({1, 2, 643, 7, 1, 2, 1, 1, 2})},
Expand Down
110 changes: 110 additions & 0 deletions src/lib/pubkey/frodokem/frodo_constants.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* FrodoKEM modes and constants
* Based on the MIT licensed reference implementation by the designers
* (https://github.com/microsoft/PQCrypto-LWEKE/tree/master/src)
*
* The Fellowship of the FrodoKEM:
* (C) 2023 Jack Lloyd
* 2023 René Meusel, Amos Treiber - Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/internal/frodo_constants.h>

#include <botan/xof.h>

namespace Botan {

FrodoKEMConstants::FrodoKEMConstants(FrodoKEMMode mode) : m_mode(mode) {
#if !defined(BOTAN_HAS_AES)
BOTAN_ARG_CHECK(!mode.is_aes(), "cannot instantiate AES-based FrodoKEM: This build does not support AES");
#endif

//Common for all parameter sets:
m_n_bar = 8;
m_len_a = 128;

if(mode.is_ephemeral()) {
m_len_salt = 0;
}

switch(mode.mode()) {
case FrodoKEMMode::FrodoKEM640_SHAKE:
case FrodoKEMMode::FrodoKEM640_AES:
case FrodoKEMMode::eFrodoKEM640_SHAKE:
case FrodoKEMMode::eFrodoKEM640_AES:
m_nist_strength = 128;
m_d = 15;
m_n = 640;
m_b = 2;
if(mode.is_static()) {
m_len_salt = 256;
m_len_se = 256;
} else if(mode.is_ephemeral()) {
m_len_se = 128;
} else {
BOTAN_ASSERT_UNREACHABLE();
}

m_cdf_table = {4643, 13363, 20579, 25843, 29227, 31145, 32103, 32525, 32689, 32745, 32762, 32766, 32767};

m_shake = "SHAKE-128";
break;

case FrodoKEMMode::FrodoKEM976_SHAKE:
case FrodoKEMMode::FrodoKEM976_AES:
case FrodoKEMMode::eFrodoKEM976_SHAKE:
case FrodoKEMMode::eFrodoKEM976_AES:
m_nist_strength = 192;
m_d = 16;
m_n = 976;
m_b = 3;
if(mode.is_static()) {
m_len_salt = 384;
m_len_se = 384;
} else if(mode.is_ephemeral()) {
m_len_se = 192;
} else {
BOTAN_ASSERT_UNREACHABLE();
}

m_cdf_table = {5638, 15915, 23689, 28571, 31116, 32217, 32613, 32731, 32760, 32766, 32767};

m_shake = "SHAKE-256";
break;

case FrodoKEMMode::FrodoKEM1344_SHAKE:
case FrodoKEMMode::FrodoKEM1344_AES:
case FrodoKEMMode::eFrodoKEM1344_SHAKE:
case FrodoKEMMode::eFrodoKEM1344_AES:
m_nist_strength = 256;
m_d = 16;
m_n = 1344;
m_b = 4;
if(mode.is_static()) {
m_len_salt = 512;
m_len_se = 512;
} else if(mode.is_ephemeral()) {
m_len_se = 256;
} else {
BOTAN_ASSERT_UNREACHABLE();
}

m_cdf_table = {9142, 23462, 30338, 32361, 32725, 32765, 32767};

m_shake = "SHAKE-256";
break;
}

m_shake_xof = XOF::create_or_throw(m_shake);
}

FrodoKEMConstants::~FrodoKEMConstants() = default;

XOF& FrodoKEMConstants::SHAKE_XOF() const {
m_shake_xof->clear();
return *m_shake_xof;
}

} // namespace Botan
Loading

0 comments on commit ea6d352

Please sign in to comment.