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

Update draft 06 #2287

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Prev Previous commit
Next Next commit
Update PQC to draft-05
require Botan 3.6.0 for PQC
switch to final NIST PQC standards
update KMAC Key Combiner
  • Loading branch information
TJ-91 committed Nov 11, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 22cfa7632c63e0b9a2235dd2b22b6f330af964d2
5 changes: 1 addition & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -82,10 +82,7 @@ tristate_feature_auto(ENABLE_RIPEMD160 "Enable RIPEMD-160 hash support.")
option(ENABLE_CRYPTO_REFRESH "Enable crypto-refresh support (v6)")
option(ENABLE_PQC "Enable PQC support")

# Note: The following two flags are only temporary and will be removed once POC is in a stable state
if (DEFINED ENABLE_PQC_MLKEM_IPD)
add_definitions(-DENABLE_PQC_MLKEM_IPD)
endif()
# Note: The following flag is only temporary and will be removed once POC is in a stable state
if (DEFINED ENABLE_PQC_DBG_LOG)
add_definitions(-DENABLE_PQC_DBG_LOG)
endif()
17 changes: 11 additions & 6 deletions src/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -31,12 +31,17 @@ find_package(ZLIB REQUIRED)

# required packages
find_package(JSON-C 0.11 REQUIRED)
if (CRYPTO_BACKEND_BOTAN3)
find_package(Botan 3.0.0 REQUIRED)
elseif (CRYPTO_BACKEND_BOTAN)
find_package(Botan 2.14.0 REQUIRED)
if(BOTAN_VERSION VERSION_GREATER_EQUAL 3.0.0)
set(CRYPTO_BACKEND_BOTAN3 1)
if(ENABLE_PQC)
find_package(Botan 3.6.0 REQUIRED)
set(CRYPTO_BACKEND_BOTAN3 1)
else()
if (CRYPTO_BACKEND_BOTAN3)
find_package(Botan 3.0.0 REQUIRED)
elseif (CRYPTO_BACKEND_BOTAN)
find_package(Botan 2.14.0 REQUIRED)
if(BOTAN_VERSION VERSION_GREATER_EQUAL 3.0.0)
set(CRYPTO_BACKEND_BOTAN3 1)
endif()
endif()
endif()
if (CRYPTO_BACKEND_OPENSSL)
4 changes: 2 additions & 2 deletions src/lib/crypto/dilithium.cpp
Original file line number Diff line number Diff line change
@@ -32,9 +32,9 @@ namespace {
Botan::DilithiumMode
rnp_dilithium_param_to_botan_dimension(dilithium_parameter_e mode)
{
Botan::DilithiumMode result = Botan::DilithiumMode::Dilithium8x7;
Botan::DilithiumMode result = Botan::DilithiumMode::ML_DSA_8x7;
if (mode == dilithium_parameter_e::dilithium_L3) {
result = Botan::DilithiumMode::Dilithium6x5;
result = Botan::DilithiumMode::ML_DSA_6x5;
}
return result;
}
17 changes: 5 additions & 12 deletions src/lib/crypto/dilithium_common.cpp
Original file line number Diff line number Diff line change
@@ -58,17 +58,10 @@ pgp_dilithium_private_key_t::pgp_dilithium_private_key_t(
}

size_t
dilithium_privkey_size(dilithium_parameter_e parameter)
dilithium_privkey_size()
{
switch (parameter) {
case dilithium_L3:
return 4000;
case dilithium_L5:
return 4864;
default:
RNP_LOG("invalid parameter given");
throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS);
}
/* seed format */
return 32;
}

size_t
@@ -90,9 +83,9 @@ dilithium_signature_size(dilithium_parameter_e parameter)
{
switch (parameter) {
case dilithium_L3:
return 3293;
return 3309;
case dilithium_L5:
return 4595;
return 4627;
default:
RNP_LOG("invalid parameter given");
throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS);
2 changes: 1 addition & 1 deletion src/lib/crypto/dilithium_common.h
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@

#include "dilithium.h"

size_t dilithium_privkey_size(dilithium_parameter_e parameter);
size_t dilithium_privkey_size();
size_t dilithium_pubkey_size(dilithium_parameter_e parameter);
size_t dilithium_signature_size(dilithium_parameter_e parameter);

6 changes: 2 additions & 4 deletions src/lib/crypto/dilithium_exdsa_composite.cpp
Original file line number Diff line number Diff line change
@@ -257,8 +257,7 @@ pgp_dilithium_exdsa_composite_private_key_t::pgp_dilithium_exdsa_composite_priva
: pk_alg_(pk_alg)
{
if (exdsa_curve_privkey_size(pk_alg_to_curve_id(pk_alg)) != exdsa_key_encoded.size() ||
dilithium_privkey_size(pk_alg_to_dilithium_id(pk_alg)) !=
dilithium_key_encoded.size()) {
dilithium_privkey_size() != dilithium_key_encoded.size()) {
RNP_LOG("exdsa or mldsa key length mismatch");
throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS);
}
@@ -273,9 +272,8 @@ pgp_dilithium_exdsa_composite_private_key_t::pgp_dilithium_exdsa_composite_priva
size_t
pgp_dilithium_exdsa_composite_private_key_t::encoded_size(pgp_pubkey_alg_t pk_alg)
{
dilithium_parameter_e dilithium_param = pk_alg_to_dilithium_id(pk_alg);
pgp_curve_t curve = pk_alg_to_curve_id(pk_alg);
return exdsa_curve_privkey_size(curve) + dilithium_privkey_size(dilithium_param);
return exdsa_curve_privkey_size(curve) + dilithium_privkey_size();
}

void
77 changes: 28 additions & 49 deletions src/lib/crypto/kmac.cpp
Original file line number Diff line number Diff line change
@@ -59,66 +59,45 @@ KMAC256::domSeparation() const
}

std::vector<uint8_t>
KMAC256::customizationString() const
{
return customizationString_;
}

std::vector<uint8_t>
KMAC256::counter() const
KMAC256::Input_X(const std::vector<uint8_t> &ecc_ciphertext,
const std::vector<uint8_t> &kyber_ciphertext,
const std::vector<uint8_t> &ecc_pub,
const std::vector<uint8_t> &kyber_pub,
pgp_pubkey_alg_t alg_id)
{
return counter_;
}
std::vector<uint8_t> res;

/*
// Input:
// algID - the algorithm ID encoded as octet

fixedInfo = algID
*/
std::vector<uint8_t>
KMAC256::fixedInfo(pgp_pubkey_alg_t alg_id)
{
std::vector<uint8_t> result;
result.push_back(static_cast<uint8_t>(alg_id));
return result;
#if defined(ENABLE_PQC_DBG_LOG)
RNP_LOG_NO_POS_INFO("KMAC256 Key_K: ");
RNP_LOG_U8VEC(" - eccCipherText: %s", ecc_ciphertext);
RNP_LOG_U8VEC(" - mlkemCipherText: %s", kyber_ciphertext);
RNP_LOG_U8VEC(" - ecdhPublicKey: %s", ecc_pub);
RNP_LOG_U8VEC(" - mlkemPublicKey: %s", kyber_pub);
RNP_LOG(" - algId : %d", alg_id);
#endif
res.insert(res.end(), ecc_ciphertext.begin(), ecc_ciphertext.end());
res.insert(res.end(), ecc_pub.begin(), ecc_pub.end());
res.insert(res.end(), kyber_ciphertext.begin(), kyber_ciphertext.end());
res.insert(res.end(), kyber_pub.begin(), kyber_pub.end());
res.push_back(static_cast<uint8_t>(alg_id));
return res;
}

std::vector<uint8_t>
KMAC256::encData(const std::vector<uint8_t> &ecc_key_share,
const std::vector<uint8_t> &ecc_ciphertext,
const std::vector<uint8_t> &kyber_key_share,
const std::vector<uint8_t> &kyber_ciphertext,
pgp_pubkey_alg_t alg_id)
KMAC256::Key_K(const std::vector<uint8_t> &ecc_key_share,
const std::vector<uint8_t> &kyber_key_share)
{
std::vector<uint8_t> enc_data;
std::vector<uint8_t> counter_vec = counter();
std::vector<uint8_t> fixedInfo_vec = fixedInfo(alg_id);

/* draft-wussler-openpgp-pqc-02:
std::vector<uint8_t> res;

eccKemData = eccKeyShare || eccCipherText
kyberKemData = kyberKeyShare || kyberCipherText
encData = counter || eccKemData || kyberKemData || fixedInfo
*/
#if defined(ENABLE_PQC_DBG_LOG)
RNP_LOG_NO_POS_INFO("KMAC256 encData: ");
RNP_LOG_U8VEC(" - counter: %s", counter_vec);
RNP_LOG_NO_POS_INFO("KMAC256 Key_K: ");
RNP_LOG_U8VEC(" - eccKeyShare: %s", ecc_key_share);
RNP_LOG_U8VEC(" - eccCipherText: %s", ecc_ciphertext);
RNP_LOG_U8VEC(" - kyberKeyShare: %s", kyber_key_share);
RNP_LOG_U8VEC(" - kyberCipherText: %s", kyber_ciphertext);
RNP_LOG_U8VEC(" - fixedInfo: %s", fixedInfo_vec);
RNP_LOG_U8VEC(" - mlkemKeyShare: %s", kyber_key_share);
#endif

enc_data.insert(enc_data.end(), counter_vec.begin(), counter_vec.end());
enc_data.insert(enc_data.end(), ecc_key_share.begin(), ecc_key_share.end());
enc_data.insert(enc_data.end(), ecc_ciphertext.begin(), ecc_ciphertext.end());
enc_data.insert(enc_data.end(), kyber_key_share.begin(), kyber_key_share.end());
enc_data.insert(enc_data.end(), kyber_ciphertext.begin(), kyber_ciphertext.end());
enc_data.insert(enc_data.end(), fixedInfo_vec.begin(), fixedInfo_vec.end());

return enc_data;
res.insert(res.end(), ecc_key_share.begin(), ecc_key_share.end());
res.insert(res.end(), kyber_key_share.begin(), kyber_key_share.end());
return res;
}

KMAC256::~KMAC256()
40 changes: 16 additions & 24 deletions src/lib/crypto/kmac.hpp
Original file line number Diff line number Diff line change
@@ -35,38 +35,28 @@
namespace rnp {
class KMAC256 {
/* KDF for PQC key combiner according to
* https://datatracker.ietf.org/doc/html/draft-wussler-openpgp-pqc-02 */
* https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-pqc-05 */

protected:
/* The value of domSeparation is the UTF-8 encoding of the string
"OpenPGPCompositeKeyDerivationFunction" and MUST be the following octet sequence:

domSeparation := 4F 70 65 6E 50 47 50 43 6F 6D 70 6F 73 69 74 65
4B 65 79 44 65 72 69 76 61 74 69 6F 6E 46 75 6E
63 74 69 6F 6E
/*
// domSep – the UTF-8 encoding of the string "OpenPGPCompositeKDFv1"
//
// domSep given in hexadecimal encoding := 4F 70 65 6E 50 47 50 43 6F 6D 70
// 6F 73 69 74 65 4B 44 46 76 31

*/
const std::vector<uint8_t> domSeparation_ = std::vector<uint8_t>(
{0x4F, 0x70, 0x65, 0x6E, 0x50, 0x47, 0x50, 0x43, 0x6F, 0x6D, 0x70, 0x6F, 0x73,
0x69, 0x74, 0x65, 0x4B, 0x65, 0x79, 0x44, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74,
0x69, 0x6F, 0x6E, 0x46, 0x75, 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E});

/* customizationString := 4B 44 46 */
const std::vector<uint8_t> customizationString_ = std::vector<uint8_t>({0x4B, 0x44, 0x46});

/* counter - a 4 byte counter set to the value 1 */
const std::vector<uint8_t> counter_ = std::vector<uint8_t>({0x00, 0x00, 0x00, 0x01});
const std::vector<uint8_t> domSeparation_ =
std::vector<uint8_t>({0x4F, 0x70, 0x65, 0x6E, 0x50, 0x47, 0x50, 0x43, 0x6F, 0x6D, 0x70,
0x6F, 0x73, 0x69, 0x74, 0x65, 0x4B, 0x44, 0x46, 0x76, 0x31});

std::vector<uint8_t> domSeparation() const;
std::vector<uint8_t> customizationString() const;
std::vector<uint8_t> counter() const;
std::vector<uint8_t> fixedInfo(pgp_pubkey_alg_t alg_id);
std::vector<uint8_t> encData(const std::vector<uint8_t> &ecc_key_share,
const std::vector<uint8_t> &ecc_ciphertext,
const std::vector<uint8_t> &kyber_key_share,
std::vector<uint8_t> Input_X(const std::vector<uint8_t> &ecc_ciphertext,
const std::vector<uint8_t> &kyber_ciphertext,
const std::vector<uint8_t> &ecc_pub,
const std::vector<uint8_t> &kyber_pub,
pgp_pubkey_alg_t alg_id);

std::vector<uint8_t> Key_K(const std::vector<uint8_t> &ecc_key_share,
const std::vector<uint8_t> &kyber_key_share);
KMAC256(){};

public:
@@ -75,8 +65,10 @@ class KMAC256 {
/* KMAC interface for OpenPGP PQC composite algorithms */
virtual void compute(const std::vector<uint8_t> &ecc_key_share,
const std::vector<uint8_t> &ecc_key_ciphertext,
const std::vector<uint8_t> &ecc_pub,
const std::vector<uint8_t> &kyber_key_share,
const std::vector<uint8_t> &kyber_ciphertext,
const std::vector<uint8_t> &kyber_pub,
const pgp_pubkey_alg_t alg_id,
std::vector<uint8_t> & out) = 0;

16 changes: 8 additions & 8 deletions src/lib/crypto/kmac_botan.cpp
Original file line number Diff line number Diff line change
@@ -47,28 +47,28 @@ KMAC256_Botan::create()
void
KMAC256_Botan::compute(const std::vector<uint8_t> &ecc_key_share,
const std::vector<uint8_t> &ecc_ciphertext,
const std::vector<uint8_t> &ecc_pub,
const std::vector<uint8_t> &kyber_key_share,
const std::vector<uint8_t> &kyber_ciphertext,
const std::vector<uint8_t> &kyber_pub,
const pgp_pubkey_alg_t alg_id,
std::vector<uint8_t> & out)
{
auto kmac = Botan::MessageAuthenticationCode::create_or_throw("KMAC-256(256)");

/* the mapping between the KEM Combiner and the MAC interface is:
* key <> domSeparation
* nonce <> customizationString
* message <> encData
* key <> Key_K (key shares)
* nonce <> domSeparation
* message <> Input_X (ciphertexts, pubkeys, alg_id)
*/

#if defined(ENABLE_PQC_DBG_LOG)
RNP_LOG_U8VEC("KMAC256 domSeparation: %s", domSeparation());
RNP_LOG_U8VEC("KMAC256 customizationString: %s", customizationString());
#endif

kmac->set_key(domSeparation());
kmac->start(customizationString()); // set nonce
kmac->update(
encData(ecc_key_share, ecc_ciphertext, kyber_key_share, kyber_ciphertext, alg_id));
kmac->set_key(Key_K(ecc_key_share, kyber_key_share));
kmac->start(domSeparation()); // set nonce
kmac->update(Input_X(ecc_ciphertext, kyber_ciphertext, ecc_pub, kyber_pub, alg_id));
out = kmac->final_stdvec();

#if defined(ENABLE_PQC_DBG_LOG)
2 changes: 2 additions & 0 deletions src/lib/crypto/kmac_botan.hpp
Original file line number Diff line number Diff line change
@@ -43,8 +43,10 @@ class KMAC256_Botan : public KMAC256 {

void compute(const std::vector<uint8_t> &ecc_key_share,
const std::vector<uint8_t> &ecc_ciphertext,
const std::vector<uint8_t> &ecc_pub,
const std::vector<uint8_t> &kyber_key_share,
const std::vector<uint8_t> &kyber_ciphertext,
const std::vector<uint8_t> &kyber_pub,
const pgp_pubkey_alg_t alg_id,
std::vector<uint8_t> & out) override;
};
28 changes: 8 additions & 20 deletions src/lib/crypto/kyber.cpp
Original file line number Diff line number Diff line change
@@ -33,27 +33,17 @@ namespace {
Botan::KyberMode
rnp_kyber_param_to_botan_kyber_mode(kyber_parameter_e mode)
{
#if defined(BOTAN_HAS_ML_KEM_INITIAL_PUBLIC_DRAFT) && defined(ENABLE_PQC_MLKEM_IPD)
Botan::KyberMode result = Botan::KyberMode::ML_KEM_1024_ipd;
Botan::KyberMode result = Botan::KyberMode::ML_KEM_1024;
if (mode == kyber_768) {
result = Botan::KyberMode::ML_KEM_768_ipd;
result = Botan::KyberMode::ML_KEM_768;
}
#else
Botan::KyberMode result = Botan::KyberMode::Kyber1024;
if (mode == kyber_768) {
result = Botan::KyberMode::Kyber768;
}
#endif
return result;
}

uint32_t
key_share_size_from_kyber_param(kyber_parameter_e param)
kyber_key_share_size()
{
if (param == kyber_768) {
return 24;
}
return 32; // kyber_1024
return 32;
}
} // namespace

@@ -63,6 +53,7 @@ kyber_generate_keypair(rnp::RNG *rng, kyber_parameter_e kyber_param)
Botan::Kyber_PrivateKey kyber_priv(*rng->obj(),
rnp_kyber_param_to_botan_kyber_mode(kyber_param));

/* returns the two 32-byte values d and z of ML-KEM.KeyGen() */
Botan::secure_vector<uint8_t> encoded_private_key = kyber_priv.private_key_bits();
std::unique_ptr<Botan::Public_Key> kyber_pub = kyber_priv.public_key();

@@ -98,10 +89,7 @@ pgp_kyber_public_key_t::encapsulate(rnp::RNG *rng) const
Botan::secure_vector<uint8_t> encap_key; // this has to go over the wire
Botan::secure_vector<uint8_t> data_encryption_key; // this is the key used for
// encryption of the payload data
kem_enc.encrypt(encap_key,
data_encryption_key,
*rng->obj(),
key_share_size_from_kyber_param(kyber_mode_));
kem_enc.encrypt(encap_key, data_encryption_key, *rng->obj(), kyber_key_share_size());
kyber_encap_result_t result;
result.ciphertext.insert(
result.ciphertext.end(), encap_key.data(), encap_key.data() + encap_key.size());
@@ -119,8 +107,8 @@ pgp_kyber_private_key_t::decapsulate(rnp::RNG * rng,
assert(is_initialized_);
auto decoded_kyber_priv = botan_key();
Botan::PK_KEM_Decryptor kem_dec(decoded_kyber_priv, *rng->obj(), "Raw", "base");
Botan::secure_vector<uint8_t> dec_shared_key = kem_dec.decrypt(
ciphertext, ciphertext_len, key_share_size_from_kyber_param(kyber_mode_));
Botan::secure_vector<uint8_t> dec_shared_key =
kem_dec.decrypt(ciphertext, ciphertext_len, kyber_key_share_size());
return std::vector<uint8_t>(dec_shared_key.data(),
dec_shared_key.data() + dec_shared_key.size());
}
Loading