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: FrodoKEM #3679

Merged
merged 5 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
18 changes: 16 additions & 2 deletions src/build-data/oids.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Regenerate with ./src/scripts/oids.py oids > src/lib/asn1/oid_maps.cpp
# AND ./src/scripts/oids.py dn_ub > src/lib/x509/x509_dn_ub.cpp
# Regenerate with ./src/scripts/dev_tools/oids.py oids > src/lib/asn1/oid_maps.cpp
# AND ./src/scripts/dev_tools/oids.py dn_ub > src/lib/x509/x509_dn_ub.cpp
# (if you modified something under [dn]

# Public key types
Expand All @@ -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