mirror of
https://github.com/itzmeanjan/ml-kem.git
synced 2026-01-09 15:47:55 -05:00
Don't allow requesting arbitrary length *shared secret* using SHAKE256 KDF
See section 1.3 of https://doi.org/10.6028/NIST.FIPS.203.ipd (draft standard of Kyber) Signed-off-by: Anjan Roy <hello@itzmeanjan.in>
This commit is contained in:
@@ -51,6 +51,7 @@ keygen(std::span<const uint8_t, 32> d, // used in CPA-PKE
|
||||
hasher.absorb(pubkey);
|
||||
hasher.finalize();
|
||||
hasher.digest(_seckey2);
|
||||
hasher.reset();
|
||||
}
|
||||
|
||||
// Given (k * 12 * 32 + 32) -bytes public key and 32 -bytes seed ( used for
|
||||
@@ -74,10 +75,11 @@ keygen(std::span<const uint8_t, 32> d, // used in CPA-PKE
|
||||
// https://github.com/pq-crystals/kyber.git. It also helps in properly
|
||||
// benchmarking underlying KEM's encapsulation implementation.
|
||||
template<size_t k, size_t eta1, size_t eta2, size_t du, size_t dv>
|
||||
static inline shake256::shake256_t
|
||||
static inline void
|
||||
encapsulate(std::span<const uint8_t, 32> m,
|
||||
std::span<const uint8_t, kyber_utils::get_kem_public_key_len(k)> pubkey,
|
||||
std::span<uint8_t, kyber_utils::get_kem_cipher_len(k, du, dv)> cipher)
|
||||
std::span<uint8_t, kyber_utils::get_kem_cipher_len(k, du, dv)> cipher,
|
||||
std::span<uint8_t, 32> shared_secret)
|
||||
requires(kyber_params::check_encap_params(k, eta1, eta2, du, dv))
|
||||
{
|
||||
std::array<uint8_t, 64> g_in{};
|
||||
@@ -125,7 +127,8 @@ encapsulate(std::span<const uint8_t, 32> m,
|
||||
shake256::shake256_t xof256;
|
||||
xof256.absorb(_kdf_in);
|
||||
xof256.finalize();
|
||||
return xof256;
|
||||
xof256.squeeze(shared_secret);
|
||||
xof256.reset();
|
||||
}
|
||||
|
||||
// Given (k * 24 * 32 + 96) -bytes secret key and (k * du * 32 + dv * 32) -bytes
|
||||
@@ -143,8 +146,10 @@ encapsulate(std::span<const uint8_t, 32> m,
|
||||
// See algorithm 9 defined in Kyber specification
|
||||
// https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
|
||||
template<size_t k, size_t eta1, size_t eta2, size_t du, size_t dv>
|
||||
static inline shake256::shake256_t
|
||||
decapsulate(std::span<const uint8_t, kyber_utils::get_kem_secret_key_len(k)> seckey, std::span<const uint8_t, kyber_utils::get_kem_cipher_len(k, du, dv)> cipher)
|
||||
static inline void
|
||||
decapsulate(std::span<const uint8_t, kyber_utils::get_kem_secret_key_len(k)> seckey,
|
||||
std::span<const uint8_t, kyber_utils::get_kem_cipher_len(k, du, dv)> cipher,
|
||||
std::span<uint8_t, 32> shared_secret)
|
||||
requires(kyber_params::check_decap_params(k, eta1, eta2, du, dv))
|
||||
{
|
||||
constexpr size_t sklen = k * 12 * 32;
|
||||
@@ -201,7 +206,8 @@ decapsulate(std::span<const uint8_t, kyber_utils::get_kem_secret_key_len(k)> sec
|
||||
shake256::shake256_t xof256;
|
||||
xof256.absorb(_kdf_in);
|
||||
xof256.finalize();
|
||||
return xof256;
|
||||
xof256.squeeze(shared_secret);
|
||||
xof256.reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ constexpr size_t SKEY_LEN = kyber_utils::get_kem_secret_key_len(k);
|
||||
// = 1568 -bytes Kyber1024 cipher text length
|
||||
constexpr size_t CIPHER_LEN = kyber_utils::get_kem_cipher_len(k, du, dv);
|
||||
|
||||
// = 32 -bytes Kyber1024 fixed size shared secret byte length
|
||||
constexpr size_t SHARED_SECRET_LEN = 32;
|
||||
|
||||
// Computes a new Kyber1024 KEM keypair s.t. public key is 1568 -bytes and
|
||||
// secret key is 3168 -bytes, given 32 -bytes seed d ( used in CPA-PKE ) and 32
|
||||
// -bytes seed z ( used in CCA-KEM ).
|
||||
@@ -40,10 +43,13 @@ keygen(std::span<const uint8_t, 32> d, std::span<const uint8_t, 32> z, std::span
|
||||
// at same SHAKE256 XOF backed KDF.
|
||||
//
|
||||
// Returned KDF can be used for deriving shared key of arbitrary bytes length.
|
||||
inline shake256::shake256_t
|
||||
encapsulate(std::span<const uint8_t, 32> m, std::span<const uint8_t, PKEY_LEN> pubkey, std::span<uint8_t, CIPHER_LEN> cipher)
|
||||
inline void
|
||||
encapsulate(std::span<const uint8_t, 32> m,
|
||||
std::span<const uint8_t, PKEY_LEN> pubkey,
|
||||
std::span<uint8_t, CIPHER_LEN> cipher,
|
||||
std::span<uint8_t, SHARED_SECRET_LEN> shared_secret)
|
||||
{
|
||||
return kem::encapsulate<k, η1, η2, du, dv>(m, pubkey, cipher);
|
||||
kem::encapsulate<k, η1, η2, du, dv>(m, pubkey, cipher, shared_secret);
|
||||
}
|
||||
|
||||
// Given a Kyber1024 KEM secret key ( of 3168 -bytes ) and a cipher text of 1568
|
||||
@@ -52,10 +58,10 @@ encapsulate(std::span<const uint8_t, 32> m, std::span<const uint8_t, PKEY_LEN> p
|
||||
// derivation function).
|
||||
//
|
||||
// Returned KDF can be used for deriving shared key of arbitrary bytes length.
|
||||
inline shake256::shake256_t
|
||||
decapsulate(std::span<const uint8_t, SKEY_LEN> seckey, std::span<const uint8_t, CIPHER_LEN> cipher)
|
||||
inline void
|
||||
decapsulate(std::span<const uint8_t, SKEY_LEN> seckey, std::span<const uint8_t, CIPHER_LEN> cipher, std::span<uint8_t, SHARED_SECRET_LEN> shared_secret)
|
||||
{
|
||||
return kem::decapsulate<k, η1, η2, du, dv>(seckey, cipher);
|
||||
kem::decapsulate<k, η1, η2, du, dv>(seckey, cipher, shared_secret);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ constexpr size_t SKEY_LEN = kyber_utils::get_kem_secret_key_len(k);
|
||||
// = 768 -bytes Kyber512 cipher text length
|
||||
constexpr size_t CIPHER_LEN = kyber_utils::get_kem_cipher_len(k, du, dv);
|
||||
|
||||
// = 32 -bytes Kyber512 fixed size shared secret byte length
|
||||
constexpr size_t SHARED_SECRET_LEN = 32;
|
||||
|
||||
// Computes a new Kyber512 KEM keypair s.t. public key is 800 -bytes and secret
|
||||
// key is 1632 -bytes, given 32 -bytes seed d ( used in CPA-PKE ) and 32 -bytes
|
||||
// seed z ( used in CCA-KEM ).
|
||||
@@ -40,10 +43,13 @@ keygen(std::span<const uint8_t, 32> d, std::span<const uint8_t, 32> z, std::span
|
||||
// SHAKE256 XOF backed KDF.
|
||||
//
|
||||
// Returned KDF can be used for deriving shared key of arbitrary bytes length.
|
||||
inline shake256::shake256_t
|
||||
encapsulate(std::span<const uint8_t, 32> m, std::span<const uint8_t, PKEY_LEN> pubkey, std::span<uint8_t, CIPHER_LEN> cipher)
|
||||
inline void
|
||||
encapsulate(std::span<const uint8_t, 32> m,
|
||||
std::span<const uint8_t, PKEY_LEN> pubkey,
|
||||
std::span<uint8_t, CIPHER_LEN> cipher,
|
||||
std::span<uint8_t, SHARED_SECRET_LEN> shared_secret)
|
||||
{
|
||||
return kem::encapsulate<k, η1, η2, du, dv>(m, pubkey, cipher);
|
||||
kem::encapsulate<k, η1, η2, du, dv>(m, pubkey, cipher, shared_secret);
|
||||
}
|
||||
|
||||
// Given a Kyber512 KEM secret key ( of 1632 -bytes ) and a cipher text of 768
|
||||
@@ -52,10 +58,10 @@ encapsulate(std::span<const uint8_t, 32> m, std::span<const uint8_t, PKEY_LEN> p
|
||||
// derivation function).
|
||||
//
|
||||
// Returned KDF can be used for deriving shared key of arbitrary bytes length.
|
||||
inline shake256::shake256_t
|
||||
decapsulate(std::span<const uint8_t, SKEY_LEN> seckey, std::span<const uint8_t, CIPHER_LEN> cipher)
|
||||
inline void
|
||||
decapsulate(std::span<const uint8_t, SKEY_LEN> seckey, std::span<const uint8_t, CIPHER_LEN> cipher, std::span<uint8_t, SHARED_SECRET_LEN> shared_secret)
|
||||
{
|
||||
return kem::decapsulate<k, η1, η2, du, dv>(seckey, cipher);
|
||||
kem::decapsulate<k, η1, η2, du, dv>(seckey, cipher, shared_secret);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ constexpr size_t SKEY_LEN = kyber_utils::get_kem_secret_key_len(k);
|
||||
// = 1088 -bytes Kyber768 cipher text length
|
||||
constexpr size_t CIPHER_LEN = kyber_utils::get_kem_cipher_len(k, du, dv);
|
||||
|
||||
// = 32 -bytes Kyber768 fixed size shared secret byte length
|
||||
constexpr size_t SHARED_SECRET_LEN = 32;
|
||||
|
||||
// Computes a new Kyber768 KEM keypair s.t. public key is 1184 -bytes and secret
|
||||
// key is 2400 -bytes, given 32 -bytes seed d ( used in CPA-PKE ) and 32 -bytes
|
||||
// seed z ( used in CCA-KEM ).
|
||||
@@ -39,10 +42,13 @@ keygen(std::span<const uint8_t, 32> d, std::span<const uint8_t, 32> z, std::span
|
||||
// at same SHAKE256 XOF backed KDF.
|
||||
//
|
||||
// Returned KDF can be used for deriving shared key of arbitrary bytes length.
|
||||
inline shake256::shake256_t
|
||||
encapsulate(std::span<const uint8_t, 32> m, std::span<const uint8_t, PKEY_LEN> pubkey, std::span<uint8_t, CIPHER_LEN> cipher)
|
||||
inline void
|
||||
encapsulate(std::span<const uint8_t, 32> m,
|
||||
std::span<const uint8_t, PKEY_LEN> pubkey,
|
||||
std::span<uint8_t, CIPHER_LEN> cipher,
|
||||
std::span<uint8_t, SHARED_SECRET_LEN> shared_secret)
|
||||
{
|
||||
return kem::encapsulate<k, η1, η2, du, dv>(m, pubkey, cipher);
|
||||
kem::encapsulate<k, η1, η2, du, dv>(m, pubkey, cipher, shared_secret);
|
||||
}
|
||||
|
||||
// Given a Kyber768 KEM secret key ( of 2400 -bytes ) and a cipher text of 1088
|
||||
@@ -51,10 +57,10 @@ encapsulate(std::span<const uint8_t, 32> m, std::span<const uint8_t, PKEY_LEN> p
|
||||
// derivation function).
|
||||
//
|
||||
// Returned KDF can be used for deriving shared key of arbitrary bytes length.
|
||||
inline shake256::shake256_t
|
||||
decapsulate(std::span<const uint8_t, SKEY_LEN> seckey, std::span<const uint8_t, CIPHER_LEN> cipher)
|
||||
inline void
|
||||
decapsulate(std::span<const uint8_t, SKEY_LEN> seckey, std::span<const uint8_t, CIPHER_LEN> cipher, std::span<uint8_t, SHARED_SECRET_LEN> shared_secret)
|
||||
{
|
||||
return kem::decapsulate<k, η1, η2, du, dv>(seckey, cipher);
|
||||
kem::decapsulate<k, η1, η2, du, dv>(seckey, cipher, shared_secret);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user