Skip to content

Commit

Permalink
Support eFrodoKEM in TLS 1.3 (also as hybrid PQ/T)
Browse files Browse the repository at this point in the history
Co-Authored-By: René Meusel <[email protected]>
  • Loading branch information
atreiber94 and reneme committed Nov 16, 2023
1 parent 9b30439 commit 0c780c6
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 5 deletions.
36 changes: 36 additions & 0 deletions src/lib/tls/tls13_pqc/hybrid_public_key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,33 @@ std::vector<std::pair<std::string, std::string>> algorithm_specs_for_group(Group
return {{"Curve25519", "Curve25519"}, {"Kyber", "Kyber-512-r3"}};
case Group_Params::HYBRID_X25519_KYBER_768_R3_OQS:
return {{"Curve25519", "Curve25519"}, {"Kyber", "Kyber-768-r3"}};
case Group_Params::HYBRID_X25519_eFRODOKEM_640_SHAKE_OQS:
return {{"Curve25519", "Curve25519"}, {"FrodoKEM", "eFrodoKEM-640-SHAKE"}};
case Group_Params::HYBRID_X25519_eFRODOKEM_640_AES_OQS:
return {{"Curve25519", "Curve25519"}, {"FrodoKEM", "eFrodoKEM-640-AES"}};

case Group_Params::HYBRID_SECP256R1_KYBER_512_R3_OQS:
return {{"ECDH", "secp256r1"}, {"Kyber", "Kyber-512-r3"}};
case Group_Params::HYBRID_SECP256R1_KYBER_768_R3_OQS:
return {{"ECDH", "secp256r1"}, {"Kyber", "Kyber-768-r3"}};
case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_SHAKE_OQS:
return {{"ECDH", "secp256r1"}, {"FrodoKEM", "eFrodoKEM-640-SHAKE"}};
case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_AES_OQS:
return {{"ECDH", "secp256r1"}, {"FrodoKEM", "eFrodoKEM-640-AES"}};

case Group_Params::HYBRID_SECP384R1_KYBER_768_R3_OQS:
return {{"ECDH", "secp384r1"}, {"Kyber", "Kyber-768-r3"}};
case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_SHAKE_OQS:
return {{"ECDH", "secp384r1"}, {"FrodoKEM", "eFrodoKEM-976-SHAKE"}};
case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_AES_OQS:
return {{"ECDH", "secp384r1"}, {"FrodoKEM", "eFrodoKEM-976-AES"}};

case Group_Params::HYBRID_SECP521R1_KYBER_1024_R3_OQS:
return {{"ECDH", "secp521r1"}, {"Kyber", "Kyber-1024-r3"}};
case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_SHAKE_OQS:
return {{"ECDH", "secp521r1"}, {"FrodoKEM", "eFrodoKEM-1344-SHAKE"}};
case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_AES_OQS:
return {{"ECDH", "secp521r1"}, {"FrodoKEM", "eFrodoKEM-1344-AES"}};

default:
return {};
Expand Down Expand Up @@ -79,13 +97,31 @@ std::vector<size_t> public_value_lengths_for_group(Group_Params group) {
return {32, 800};
case Group_Params::HYBRID_X25519_KYBER_768_R3_OQS:
return {32, 1184};
case Group_Params::HYBRID_X25519_eFRODOKEM_640_SHAKE_OQS:
return {32, 9616};
case Group_Params::HYBRID_X25519_eFRODOKEM_640_AES_OQS:
return {32, 9616};

case Group_Params::HYBRID_SECP256R1_KYBER_512_R3_OQS:
return {32, 800};
case Group_Params::HYBRID_SECP256R1_KYBER_768_R3_OQS:
return {32, 1184};
case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_SHAKE_OQS:
return {32, 9616};
case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_AES_OQS:
return {32, 9616};

case Group_Params::HYBRID_SECP384R1_KYBER_768_R3_OQS:
return {48, 1184};
case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_SHAKE_OQS:
return {48, 15632};
case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_AES_OQS:
return {48, 15632};

case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_SHAKE_OQS:
return {66, 21520};
case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_AES_OQS:
return {66, 21520};
case Group_Params::HYBRID_SECP521R1_KYBER_1024_R3_OQS:
return {66, 1568};

Expand Down
76 changes: 75 additions & 1 deletion src/lib/tls/tls_algos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,29 +183,73 @@ std::optional<Group_Params> Group_Params::from_string(std::string_view group_nam
return Group_Params::KYBER_1024_R3_OQS;
}

if(group_name == "eFrodoKEM-640-SHAKE") {
return Group_Params::eFRODOKEM_640_SHAKE_OQS;
}
if(group_name == "eFrodoKEM-976-SHAKE") {
return Group_Params::eFRODOKEM_976_SHAKE_OQS;
}
if(group_name == "eFrodoKEM-1344-SHAKE") {
return Group_Params::eFRODOKEM_1344_SHAKE_OQS;
}
if(group_name == "eFrodoKEM-640-AES") {
return Group_Params::eFRODOKEM_640_AES_OQS;
}
if(group_name == "eFrodoKEM-976-AES") {
return Group_Params::eFRODOKEM_976_AES_OQS;
}
if(group_name == "eFrodoKEM-1344-AES") {
return Group_Params::eFRODOKEM_1344_AES_OQS;
}

if(group_name == "x25519/Kyber-512-r3/cloudflare") {
return Group_Params::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE;
}

if(group_name == "x25519/Kyber-512-r3") {
return Group_Params::HYBRID_X25519_KYBER_512_R3_OQS;
}
if(group_name == "x25519/Kyber-768-r3") {
return Group_Params::HYBRID_X25519_KYBER_768_R3_OQS;
}
if(group_name == "x25519/eFrodoKEM-640-SHAKE") {
return Group_Params::HYBRID_X25519_eFRODOKEM_640_SHAKE_OQS;
}
if(group_name == "x25519/eFrodoKEM-640-AES") {
return Group_Params::HYBRID_X25519_eFRODOKEM_640_AES_OQS;
}

if(group_name == "secp256r1/Kyber-512-r3") {
return Group_Params::HYBRID_SECP256R1_KYBER_512_R3_OQS;
}
if(group_name == "secp256r1/Kyber-768-r3") {
return Group_Params::HYBRID_SECP256R1_KYBER_768_R3_OQS;
}
if(group_name == "secp256r1/eFrodoKEM-640-SHAKE") {
return Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_SHAKE_OQS;
}
if(group_name == "secp256r1/eFrodoKEM-640-AES") {
return Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_AES_OQS;
}

if(group_name == "secp384r1/Kyber-768-r3") {
return Group_Params::HYBRID_SECP384R1_KYBER_768_R3_OQS;
}
if(group_name == "secp384r1/eFrodoKEM-976-SHAKE") {
return Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_SHAKE_OQS;
}
if(group_name == "secp384r1/eFrodoKEM-976-AES") {
return Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_AES_OQS;
}

if(group_name == "secp521r1/Kyber-1024-r3") {
return Group_Params::HYBRID_SECP521R1_KYBER_1024_R3_OQS;
}
if(group_name == "secp521r1/eFrodoKEM-1344-SHAKE") {
return Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_SHAKE_OQS;
}
if(group_name == "secp521r1/eFrodoKEM-1344-AES") {
return Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_AES_OQS;
}

return std::nullopt;
}
Expand Down Expand Up @@ -245,6 +289,36 @@ std::optional<std::string> Group_Params::to_string() const {
case Group_Params::KYBER_1024_R3_OQS:
return "Kyber-1024-r3";

case Group_Params::eFRODOKEM_640_SHAKE_OQS:
return "eFrodoKEM-640-SHAKE";
case Group_Params::eFRODOKEM_976_SHAKE_OQS:
return "eFrodoKEM-976-SHAKE";
case Group_Params::eFRODOKEM_1344_SHAKE_OQS:
return "eFrodoKEM-1344-SHAKE";
case Group_Params::eFRODOKEM_640_AES_OQS:
return "eFrodoKEM-640-AES";
case Group_Params::eFRODOKEM_976_AES_OQS:
return "eFrodoKEM-976-AES";
case Group_Params::eFRODOKEM_1344_AES_OQS:
return "eFrodoKEM-1344-AES";

case Group_Params::HYBRID_X25519_eFRODOKEM_640_SHAKE_OQS:
return "x25519/eFrodoKEM-640-SHAKE";
case Group_Params::HYBRID_X25519_eFRODOKEM_640_AES_OQS:
return "x25519/eFrodoKEM-640-AES";
case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_SHAKE_OQS:
return "secp256r1/eFrodoKEM-640-SHAKE";
case Group_Params::HYBRID_SECP256R1_eFRODOKEM_640_AES_OQS:
return "secp256r1/eFrodoKEM-640-AES";
case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_SHAKE_OQS:
return "secp384r1/eFrodoKEM-976-SHAKE";
case Group_Params::HYBRID_SECP384R1_eFRODOKEM_976_AES_OQS:
return "secp384r1/eFrodoKEM-976-AES";
case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_SHAKE_OQS:
return "secp521r1/eFrodoKEM-1344-SHAKE";
case Group_Params::HYBRID_SECP521R1_eFRODOKEM_1344_AES_OQS:
return "secp521r1/eFrodoKEM-1344-AES";

case Group_Params::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE:
return "x25519/Kyber-512-r3/cloudflare";

Expand Down
46 changes: 42 additions & 4 deletions src/lib/tls/tls_algos.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ enum class Group_Params_Code : uint16_t {
KYBER_768_R3_OQS = 0x023C,
KYBER_1024_R3_OQS = 0x023D,

eFRODOKEM_640_SHAKE_OQS = 0x0201,
eFRODOKEM_976_SHAKE_OQS = 0x0203,
eFRODOKEM_1344_SHAKE_OQS = 0x0205,
eFRODOKEM_640_AES_OQS = 0x0200,
eFRODOKEM_976_AES_OQS = 0x0202,
eFRODOKEM_1344_AES_OQS = 0x0204,

// Cloudflare code points for hybrid PQC
// https://blog.cloudflare.com/post-quantum-for-all/
HYBRID_X25519_KYBER_512_R3_CLOUDFLARE = 0xFE30,
Expand All @@ -117,8 +124,22 @@ enum class Group_Params_Code : uint16_t {

HYBRID_SECP256R1_KYBER_512_R3_OQS = 0x2F3A,
HYBRID_SECP256R1_KYBER_768_R3_OQS = 0x639A,

HYBRID_SECP384R1_KYBER_768_R3_OQS = 0x2F3C,

HYBRID_SECP521R1_KYBER_1024_R3_OQS = 0x2F3D,

HYBRID_X25519_eFRODOKEM_640_SHAKE_OQS = 0x2F81,
HYBRID_X25519_eFRODOKEM_640_AES_OQS = 0x2F80,

HYBRID_SECP256R1_eFRODOKEM_640_SHAKE_OQS = 0x2F01,
HYBRID_SECP256R1_eFRODOKEM_640_AES_OQS = 0x2F00,

HYBRID_SECP384R1_eFRODOKEM_976_SHAKE_OQS = 0x2F03,
HYBRID_SECP384R1_eFRODOKEM_976_AES_OQS = 0x2F02,

HYBRID_SECP521R1_eFRODOKEM_1344_SHAKE_OQS = 0x2F05,
HYBRID_SECP521R1_eFRODOKEM_1344_AES_OQS = 0x2F04,
};

class BOTAN_PUBLIC_API(3, 2) Group_Params final {
Expand Down Expand Up @@ -170,21 +191,38 @@ class BOTAN_PUBLIC_API(3, 2) Group_Params final {
m_code == Group_Params_Code::KYBER_1024_R3_OQS;
}

constexpr bool is_pure_frodokem() const {
return m_code == Group_Params_Code::eFRODOKEM_640_SHAKE_OQS ||
m_code == Group_Params_Code::eFRODOKEM_976_SHAKE_OQS ||
m_code == Group_Params_Code::eFRODOKEM_1344_SHAKE_OQS ||
m_code == Group_Params_Code::eFRODOKEM_640_AES_OQS ||
m_code == Group_Params_Code::eFRODOKEM_976_AES_OQS ||
m_code == Group_Params_Code::eFRODOKEM_1344_AES_OQS;
}

constexpr bool is_pure_ecc_group() const { return is_x25519() || is_ecdh_named_curve(); }

constexpr bool is_post_quantum() const { return is_pure_kyber() || is_pqc_hybrid(); }
constexpr bool is_post_quantum() const { return is_pure_kyber() || is_pure_frodokem() || is_pqc_hybrid(); }

constexpr bool is_pqc_hybrid() const {
return m_code == Group_Params::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE ||
return m_code == Group_Params_Code::HYBRID_X25519_KYBER_512_R3_CLOUDFLARE ||
m_code == Group_Params_Code::HYBRID_X25519_KYBER_512_R3_OQS ||
m_code == Group_Params_Code::HYBRID_X25519_KYBER_768_R3_OQS ||
m_code == Group_Params_Code::HYBRID_X25519_eFRODOKEM_640_SHAKE_OQS ||
m_code == Group_Params_Code::HYBRID_X25519_eFRODOKEM_640_AES_OQS ||
m_code == Group_Params_Code::HYBRID_SECP256R1_KYBER_512_R3_OQS ||
m_code == Group_Params_Code::HYBRID_SECP256R1_KYBER_768_R3_OQS ||
m_code == Group_Params_Code::HYBRID_SECP256R1_eFRODOKEM_640_SHAKE_OQS ||
m_code == Group_Params_Code::HYBRID_SECP256R1_eFRODOKEM_640_AES_OQS ||
m_code == Group_Params_Code::HYBRID_SECP384R1_KYBER_768_R3_OQS ||
m_code == Group_Params_Code::HYBRID_SECP521R1_KYBER_1024_R3_OQS;
m_code == Group_Params_Code::HYBRID_SECP384R1_eFRODOKEM_976_SHAKE_OQS ||
m_code == Group_Params_Code::HYBRID_SECP384R1_eFRODOKEM_976_AES_OQS ||
m_code == Group_Params_Code::HYBRID_SECP521R1_KYBER_1024_R3_OQS ||
m_code == Group_Params_Code::HYBRID_SECP521R1_eFRODOKEM_1344_SHAKE_OQS ||
m_code == Group_Params_Code::HYBRID_SECP521R1_eFRODOKEM_1344_AES_OQS;
}

constexpr bool is_kem() const { return is_pure_kyber() || is_pqc_hybrid(); }
constexpr bool is_kem() const { return is_pure_kyber() || is_pure_frodokem() || is_pqc_hybrid(); }

// Returns std::nullopt if the param has no known name
std::optional<std::string> to_string() const;
Expand Down
16 changes: 16 additions & 0 deletions src/lib/tls/tls_callbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
#include <botan/kyber.h>
#endif

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

#if defined(BOTAN_HAS_TLS_13_PQC)
#include <botan/internal/hybrid_public_key.h>
#endif
Expand Down Expand Up @@ -147,6 +151,12 @@ std::unique_ptr<Private_Key> TLS::Callbacks::tls_kem_generate_key(TLS::Group_Par
}
#endif

#if defined(BOTAN_HAS_FRODOKEM)
if(group.is_pure_frodokem()) {
return std::make_unique<FrodoKEM_PrivateKey>(rng, FrodoKEMMode(group.to_string().value()));
}
#endif

#if defined(BOTAN_HAS_TLS_13_PQC)
if(group.is_pqc_hybrid()) {
return Hybrid_KEM_PrivateKey::generate_from_group(group, rng);
Expand Down Expand Up @@ -175,6 +185,12 @@ KEM_Encapsulation TLS::Callbacks::tls_kem_encapsulate(TLS::Group_Params group,
}
#endif

#if defined(BOTAN_HAS_FRODOKEM)
if(group.is_pure_frodokem()) {
return std::make_unique<FrodoKEM_PublicKey>(encoded_public_key, FrodoKEMMode(group.to_string().value()));
}
#endif

throw TLS_Exception(Alert::IllegalParameter, "KEM is not supported");
}();

Expand Down
14 changes: 14 additions & 0 deletions src/scripts/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,20 @@ def get_oqs_ports():
TestConfig("test.openquantumsafe.org", "Kyber-512-r3", port=oqsp['kyber512'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "Kyber-768-r3", port=oqsp['kyber768'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "Kyber-1024-r3", port=oqsp['kyber1024'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "eFrodoKEM-640-SHAKE", port=oqsp['frodo640shake'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "eFrodoKEM-976-SHAKE", port=oqsp['frodo976shake'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "eFrodoKEM-1344-SHAKE", port=oqsp['frodo1344shake'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "eFrodoKEM-640-AES", port=oqsp['frodo640aes'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "eFrodoKEM-976-AES", port=oqsp['frodo976aes'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "eFrodoKEM-1344-AES", port=oqsp['frodo1344aes'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "x25519/eFrodoKEM-640-SHAKE", port=oqsp['x25519_frodo640shake'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "x25519/eFrodoKEM-640-AES", port=oqsp['x25519_frodo640aes'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "secp256r1/eFrodoKEM-640-SHAKE", port=oqsp['p256_frodo640shake'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "secp256r1/eFrodoKEM-640-AES", port=oqsp['p256_frodo640aes'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "secp384r1/eFrodoKEM-976-SHAKE", port=oqsp['p384_frodo976shake'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "secp384r1/eFrodoKEM-976-AES", port=oqsp['p384_frodo976aes'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "secp521r1/eFrodoKEM-1344-SHAKE", port=oqsp['p521_frodo1344shake'], ca=oqs_test_ca),
TestConfig("test.openquantumsafe.org", "secp521r1/eFrodoKEM-1344-AES", port=oqsp['p521_frodo1344aes'], ca=oqs_test_ca),
]
else:
logging.info("failed to pull OQS port assignment, skipping OQS...")
Expand Down

0 comments on commit 0c780c6

Please sign in to comment.