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

New approach for discrete logarithm keys #3210

Merged
merged 1 commit into from
Mar 6, 2023
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
20 changes: 20 additions & 0 deletions doc/migration_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -352,3 +352,23 @@ desired hash is not compatible with the algorithm.
In previous versions, various APIs required that the application specify the
hash function to be used. In most cases this can now be omitted (passing an
empty string) and a suitable default will be chosen.

Discrete Logarithm Key Changes
--------------------------------

Keys based on the discrete logarithm problem no longer derive from the
DL_Scheme_PrivateKey and DL_Scheme_PublicKey classes; these classes
have been removed.

Functions to access DL algorithm interal fields (such as the integer value of
the private key using ``get_x``) have been removed. If you need access to this
information you can use the new ``get_int_field`` function.

The constructors of the DL scheme private keys have changed. Previously, loading
and creating a key used the same constructor, namely one taking arguments
``(DL_Group, RandomNumberGenerator&, BigInt x = 0)`` and then the behavior of
the constructor depend on if ``x`` was zero (in which case a new key was
created) or otherwise if ``x`` was non-zero then it was taken as the private
key. Now there are two constructors, one taking a random number generator and a
group, which generates a new key, and a second taking a group and an integer,
which loads an existing key.
17 changes: 7 additions & 10 deletions src/lib/ffi/ffi_pkey_algs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
#include <botan/internal/ffi_rng.h>
#include <botan/internal/ffi_mp.h>

#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
#include <botan/ecc_key.h>
#if defined(BOTAN_HAS_DL_GROUP)
#include <botan/dl_group.h>
#endif

#if defined(BOTAN_HAS_DL_PUBLIC_KEY_FAMILY)
#include <botan/dl_algo.h>
#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
#include <botan/ecc_key.h>
#endif

#if defined(BOTAN_HAS_RSA)
Expand Down Expand Up @@ -346,9 +346,8 @@ int botan_privkey_load_dsa(botan_privkey_t* key,
*key = nullptr;

return ffi_guard_thunk(__func__, [=]() -> int {
Botan::Null_RNG null_rng;
Botan::DL_Group group(safe_get(p), safe_get(q), safe_get(g));
auto dsa = std::make_unique<Botan::DSA_PrivateKey>(null_rng, group, safe_get(x));
auto dsa = std::make_unique<Botan::DSA_PrivateKey>(group, safe_get(x));
*key = new botan_privkey_struct(std::move(dsa));
return BOTAN_FFI_SUCCESS;
});
Expand Down Expand Up @@ -502,9 +501,8 @@ int botan_privkey_load_elgamal(botan_privkey_t* key,
#if defined(BOTAN_HAS_ELGAMAL)
*key = nullptr;
return ffi_guard_thunk(__func__, [=]() -> int {
Botan::Null_RNG null_rng;
Botan::DL_Group group(safe_get(p), safe_get(g));
auto elg = std::make_unique<Botan::ElGamal_PrivateKey>(null_rng, group, safe_get(x));
auto elg = std::make_unique<Botan::ElGamal_PrivateKey>(group, safe_get(x));
*key = new botan_privkey_struct(std::move(elg));
return BOTAN_FFI_SUCCESS;
});
Expand All @@ -527,9 +525,8 @@ int botan_privkey_load_dh(botan_privkey_t* key,
#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
*key = nullptr;
return ffi_guard_thunk(__func__, [=]() -> int {
Botan::Null_RNG null_rng;
Botan::DL_Group group(safe_get(p), safe_get(g));
auto dh = std::make_unique<Botan::DH_PrivateKey>(null_rng, group, safe_get(x));
auto dh = std::make_unique<Botan::DH_PrivateKey>(group, safe_get(x));
*key = new botan_privkey_struct(std::move(dh));
return BOTAN_FFI_SUCCESS;
});
Expand Down
148 changes: 87 additions & 61 deletions src/lib/pubkey/dh/dh.cpp
Original file line number Diff line number Diff line change
@@ -1,84 +1,106 @@
/*
* Diffie-Hellman
* (C) 1999-2007,2016,2019 Jack Lloyd
* (C) 1999-2007,2016,2019,2023 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/dh.h>
#include <botan/internal/dl_scheme.h>
#include <botan/internal/pk_ops_impl.h>
#include <botan/internal/monty_exp.h>
#include <botan/internal/blinding.h>

namespace Botan {

/*
* DH_PublicKey Constructor
*/
DH_PublicKey::DH_PublicKey(const DL_Group& grp, const BigInt& y1)
DH_PublicKey::DH_PublicKey(const AlgorithmIdentifier& alg_id,
const std::vector<uint8_t>& key_bits)
{
m_group = grp;
m_y = y1;
m_public_key = std::make_shared<DL_PublicKey>(alg_id, key_bits, DL_Group_Format::ANSI_X9_42);
}

DH_PublicKey::DH_PublicKey(const DL_Group& group, const BigInt& y)
{
m_public_key = std::make_shared<DL_PublicKey>(group, y);
}

/*
* Return the public value for key agreement
*/
std::vector<uint8_t> DH_PublicKey::public_value() const
{
return unlock(BigInt::encode_1363(m_y, group_p().bytes()));
return m_public_key->public_key_as_bytes();
}

/*
* Create a DH private key
*/
DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng,
const DL_Group& grp,
const BigInt& x_arg)
size_t DH_PublicKey::estimated_strength() const
{
return m_public_key->estimated_strength();
}

size_t DH_PublicKey::key_length() const
{
m_group = grp;
return m_public_key->p_bits();
}

if(x_arg == 0)
{
const size_t exp_bits = grp.exponent_bits();
m_x.randomize(rng, exp_bits);
m_y = m_group.power_g_p(m_x, exp_bits);
}
else
{
m_x = x_arg;
const BigInt& DH_PublicKey::get_int_field(const std::string& field) const
{
return m_public_key->get_int_field(algo_name(), field);
}

if(m_y == 0)
m_y = m_group.power_g_p(m_x, grp.p_bits());
}
AlgorithmIdentifier DH_PublicKey::algorithm_identifier() const
{
return AlgorithmIdentifier(
object_identifier(),
m_public_key->group().DER_encode(DL_Group_Format::ANSI_X9_42));
}

std::vector<uint8_t> DH_PublicKey::public_key_bits() const
{
return m_public_key->DER_encode();
}

bool DH_PublicKey::check_key(RandomNumberGenerator& rng, bool strong) const
{
return m_public_key->check_key(rng, strong);
}

DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng,
const DL_Group& group)
{
m_private_key = std::make_shared<DL_PrivateKey>(group, rng);
m_public_key = m_private_key->public_key();
}

DH_PrivateKey::DH_PrivateKey(const DL_Group& group,
const BigInt& x)
{
m_private_key = std::make_shared<DL_PrivateKey>(group, x);
m_public_key = m_private_key->public_key();
}

/*
* Load a DH private key
*/
DH_PrivateKey::DH_PrivateKey(const AlgorithmIdentifier& alg_id,
const secure_vector<uint8_t>& key_bits) :
DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group_Format::ANSI_X9_42)
const secure_vector<uint8_t>& key_bits)
{
if(m_y.is_zero())
{
m_y = m_group.power_g_p(m_x, m_group.p_bits());
}
m_private_key = std::make_shared<DL_PrivateKey>(alg_id, key_bits, DL_Group_Format::ANSI_X9_42);
m_public_key = m_private_key->public_key();
}

std::unique_ptr<Public_Key> DH_PrivateKey::public_key() const
{
return std::make_unique<DH_PublicKey>(get_group(), get_y());
return std::unique_ptr<DH_PublicKey>(new DH_PublicKey(m_public_key));
}

/*
* Return the public value for key agreement
*/
std::vector<uint8_t> DH_PrivateKey::public_value() const
{
return DH_PublicKey::public_value();
}

secure_vector<uint8_t> DH_PrivateKey::private_key_bits() const
{
return m_private_key->DER_encode();
}

const BigInt& DH_PrivateKey::get_int_field(const std::string& field) const
{
return m_private_key->get_int_field(algo_name(), field);
}

namespace {

/**
Expand All @@ -88,32 +110,36 @@ class DH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF
{
public:

DH_KA_Operation(const DH_PrivateKey& key, const std::string& kdf, RandomNumberGenerator& rng) :
DH_KA_Operation(std::shared_ptr<const DL_PrivateKey> key,
const std::string& kdf,
RandomNumberGenerator& rng) :
PK_Ops::Key_Agreement_with_KDF(kdf),
m_p(key.group_p()),
m_x(key.get_x()),
m_x_bits(m_x.bits()),
m_monty_p(key.get_group().monty_params_p()),
m_blinder(m_p,
m_key(key),
m_blinder(key->group().get_p(),
rng,
[](const BigInt& k) { return k; },
[this](const BigInt& k) { return powermod_x_p(inverse_mod(k, m_p)); })
[this](const BigInt& k)
{
const BigInt inv_k = inverse_mod(k, group().get_p());
return powermod_x_p(inv_k);
})
{}

size_t agreed_value_size() const override { return m_p.bytes(); }
size_t agreed_value_size() const override { return group().p_bytes(); }

secure_vector<uint8_t> raw_agree(const uint8_t w[], size_t w_len) override;
private:
const DL_Group& group() const
{
return m_key->group();
}

BigInt powermod_x_p(const BigInt& v) const
{
const size_t powm_window = 4;
auto powm_v_p = monty_precompute(m_monty_p, v, powm_window);
return monty_execute(*powm_v_p, m_x, m_x_bits);
return group().power_b_p(v, m_key->private_key());
}

const BigInt& m_p;
const BigInt& m_x;
const size_t m_x_bits;
std::shared_ptr<const DL_PrivateKey> m_key;
std::shared_ptr<const Montgomery_Params> m_monty_p;
Blinder m_blinder;
};
Expand All @@ -122,14 +148,14 @@ secure_vector<uint8_t> DH_KA_Operation::raw_agree(const uint8_t w[], size_t w_le
{
BigInt v = BigInt::decode(w, w_len);

if(v <= 1 || v >= m_p - 1)
if(v <= 1 || v >= group().get_p())
throw Invalid_Argument("DH agreement - invalid key provided");

v = m_blinder.blind(v);
v = powermod_x_p(v);
v = m_blinder.unblind(v);

return BigInt::encode_1363(v, m_p.bytes());
return BigInt::encode_1363(v, group().p_bytes());
}

}
Expand All @@ -140,7 +166,7 @@ DH_PrivateKey::create_key_agreement_op(RandomNumberGenerator& rng,
const std::string& provider) const
{
if(provider == "base" || provider.empty())
return std::make_unique<DH_KA_Operation>(*this, params, rng);
return std::make_unique<DH_KA_Operation>(this->m_private_key, params, rng);
throw Provider_Not_Found(algo_name(), provider);
}

Expand Down
Loading