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 Jan 2, 2024
1 parent fac04ab commit 21b52d3
Show file tree
Hide file tree
Showing 24 changed files with 3,993 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.

.. note::

Expand Down Expand Up @@ -131,6 +131,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 @@ -1121,6 +1126,7 @@ Botan implements the following KEM schemes:

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

.. _kyber_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 14 }
efrodokem-shake OBJECT IDENTIFIER ::= { publicKey 16 }
frodokem-aes OBJECT IDENTIFIER ::= { publicKey 15 }
efrodokem-aes OBJECT IDENTIFIER ::= { publicKey 17 }

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.14.1 = FrodoKEM-640-SHAKE
1.3.6.1.4.1.25258.1.14.2 = FrodoKEM-976-SHAKE
1.3.6.1.4.1.25258.1.14.3 = FrodoKEM-1344-SHAKE
1.3.6.1.4.1.25258.1.15.1 = FrodoKEM-640-AES
1.3.6.1.4.1.25258.1.15.2 = FrodoKEM-976-AES
1.3.6.1.4.1.25258.1.15.3 = FrodoKEM-1344-AES
1.3.6.1.4.1.25258.1.16.1 = eFrodoKEM-640-SHAKE
1.3.6.1.4.1.25258.1.16.2 = eFrodoKEM-976-SHAKE
1.3.6.1.4.1.25258.1.16.3 = eFrodoKEM-1344-SHAKE
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

# 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
47 changes: 46 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,41 @@ 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,
Botan::FrodoKEMMode::FrodoKEM640_AES,
Botan::FrodoKEMMode::FrodoKEM976_AES,
Botan::FrodoKEMMode::FrodoKEM1344_AES,
Botan::FrodoKEMMode::eFrodoKEM640_AES,
Botan::FrodoKEMMode::eFrodoKEM976_AES,
Botan::FrodoKEMMode::eFrodoKEM1344_AES,
};

for(auto modet : frodo_modes) {
if(!modet.is_available()) {
continue;
}

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-11-02
*
* 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.14.1", "FrodoKEM-640-SHAKE"},
{"1.3.6.1.4.1.25258.1.14.2", "FrodoKEM-976-SHAKE"},
{"1.3.6.1.4.1.25258.1.14.3", "FrodoKEM-1344-SHAKE"},
{"1.3.6.1.4.1.25258.1.15.1", "FrodoKEM-640-AES"},
{"1.3.6.1.4.1.25258.1.15.2", "FrodoKEM-976-AES"},
{"1.3.6.1.4.1.25258.1.15.3", "FrodoKEM-1344-AES"},
{"1.3.6.1.4.1.25258.1.16.1", "eFrodoKEM-640-SHAKE"},
{"1.3.6.1.4.1.25258.1.16.2", "eFrodoKEM-976-SHAKE"},
{"1.3.6.1.4.1.25258.1.16.3", "eFrodoKEM-1344-SHAKE"},
{"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.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, 15, 3})},
{"FrodoKEM-1344-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 14, 3})},
{"FrodoKEM-640-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 15, 1})},
{"FrodoKEM-640-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 14, 1})},
{"FrodoKEM-976-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 15, 2})},
{"FrodoKEM-976-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 14, 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, 17, 3})},
{"eFrodoKEM-1344-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 16, 3})},
{"eFrodoKEM-640-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 17, 1})},
{"eFrodoKEM-640-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 16, 1})},
{"eFrodoKEM-976-AES", OID({1, 3, 6, 1, 4, 1, 25258, 1, 17, 2})},
{"eFrodoKEM-976-SHAKE", OID({1, 3, 6, 1, 4, 1, 25258, 1, 16, 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
40 changes: 40 additions & 0 deletions src/lib/pubkey/frodokem/frodokem/frodo_shake_generator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* FrodoKEM matrix generator based on SHAKE
*
* 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)
*/

#ifndef BOTAN_FRODOKEM_SHAKE_GENERATOR_H_
#define BOTAN_FRODOKEM_SHAKE_GENERATOR_H_

#include <botan/internal/frodo_constants.h>
#include <botan/internal/frodo_types.h>
#include <botan/internal/loadstor.h>
#include <botan/internal/shake_xof.h>

#include <span>

namespace Botan {

inline auto create_shake_row_generator(const FrodoKEMConstants& constants, StrongSpan<const FrodoSeedA> seed_a) {
BOTAN_ASSERT_NOMSG(constants.mode().is_shake());

return [xof = SHAKE_128_XOF(), a = FrodoSeedA(seed_a)](std::span<uint8_t> out, uint16_t i) mutable {
xof.clear();
// TODO: update that once #3707 is merged
// potentially add a new method: std::array<uint8_t, XX> as_le(uintXX_t)
std::array<uint8_t, 2> le;
store_le(i, le.data());
xof.update(le);
xof.update(a);
xof.output(out);
};
}

} // namespace Botan

#endif
12 changes: 12 additions & 0 deletions src/lib/pubkey/frodokem/frodokem/info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<defines>
FRODOKEM_SHAKE -> 20231114
</defines>

<module_info>
name -> "FrodoKEM"
</module_info>

<requires>
shake_xof
frodokem_common
</requires>
56 changes: 56 additions & 0 deletions src/lib/pubkey/frodokem/frodokem_aes/frodo_aes_generator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* FrodoKEM matrix generator based on AES
*
* 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)
*/

#ifndef BOTAN_FRODOKEM_AES_GENERATOR_H_
#define BOTAN_FRODOKEM_AES_GENERATOR_H_

#include <botan/internal/aes.h>
#include <botan/internal/frodo_constants.h>
#include <botan/internal/frodo_types.h>
#include <botan/internal/loadstor.h>
#include <botan/internal/stl_util.h>

#include <functional>
#include <span>

namespace Botan {

inline auto create_aes_row_generator(const FrodoKEMConstants& constants, StrongSpan<const FrodoSeedA> seed_a) {
BOTAN_ASSERT_NOMSG(constants.mode().is_aes());

auto setup_aes = [](StrongSpan<const FrodoSeedA> seed) {
AES_128 aes;
aes.set_key(seed);
return aes;
};

return [n = constants.n(), aes = setup_aes(seed_a)](std::span<uint8_t> out, uint16_t i) {
BufferStuffer out_bs(out);

for(size_t j = 0; j < n; j += 8) {
// set up the to-be-encrypted 'b' value in the out variable
// for in-place encryption of the block cipher
auto out_coefs = out_bs.next(aes.block_size());

// b = i || j || 0000...
store_le(static_cast<uint16_t>(i), out_coefs.data());
store_le(static_cast<uint16_t>(j), out_coefs.data() + sizeof(uint16_t));
for(size_t ii = 4; ii < out_coefs.size(); ++ii) {
out_coefs[ii] = 0;
}

aes.encrypt(out_coefs);
}
};
}

} // namespace Botan

#endif
12 changes: 12 additions & 0 deletions src/lib/pubkey/frodokem/frodokem_aes/info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<defines>
FRODOKEM_AES -> 20231103
</defines>

<module_info>
name -> "FrodoKEM (AES)"
</module_info>

<requires>
aes
frodokem_common
</requires>
Loading

0 comments on commit 21b52d3

Please sign in to comment.