1 /*
2 * Diffie-Hellman
3 * (C) 1999-2007,2016,2019 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/dh.h>
9 #include <botan/internal/pk_ops_impl.h>
10 #include <botan/internal/monty_exp.h>
11 #include <botan/blinding.h>
12 
13 namespace Botan {
14 
15 /*
16 * DH_PublicKey Constructor
17 */
DH_PublicKey(const DL_Group & grp,const BigInt & y1)18 DH_PublicKey::DH_PublicKey(const DL_Group& grp, const BigInt& y1)
19    {
20    m_group = grp;
21    m_y = y1;
22    }
23 
24 /*
25 * Return the public value for key agreement
26 */
public_value() const27 std::vector<uint8_t> DH_PublicKey::public_value() const
28    {
29    return unlock(BigInt::encode_1363(m_y, group_p().bytes()));
30    }
31 
32 /*
33 * Create a DH private key
34 */
DH_PrivateKey(RandomNumberGenerator & rng,const DL_Group & grp,const BigInt & x_arg)35 DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng,
36                              const DL_Group& grp,
37                              const BigInt& x_arg)
38    {
39    m_group = grp;
40 
41    if(x_arg == 0)
42       {
43       const size_t exp_bits = grp.exponent_bits();
44       m_x.randomize(rng, exp_bits);
45       m_y = m_group.power_g_p(m_x, exp_bits);
46       }
47    else
48       {
49       m_x = x_arg;
50 
51       if(m_y == 0)
52          m_y = m_group.power_g_p(m_x, grp.p_bits());
53       }
54    }
55 
56 /*
57 * Load a DH private key
58 */
DH_PrivateKey(const AlgorithmIdentifier & alg_id,const secure_vector<uint8_t> & key_bits)59 DH_PrivateKey::DH_PrivateKey(const AlgorithmIdentifier& alg_id,
60                              const secure_vector<uint8_t>& key_bits) :
61    DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_42)
62    {
63    if(m_y.is_zero())
64       {
65       m_y = m_group.power_g_p(m_x, m_group.p_bits());
66       }
67    }
68 
69 /*
70 * Return the public value for key agreement
71 */
public_value() const72 std::vector<uint8_t> DH_PrivateKey::public_value() const
73    {
74    return DH_PublicKey::public_value();
75    }
76 
77 namespace {
78 
79 /**
80 * DH operation
81 */
82 class DH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF
83    {
84    public:
85 
DH_KA_Operation(const DH_PrivateKey & key,const std::string & kdf,RandomNumberGenerator & rng)86       DH_KA_Operation(const DH_PrivateKey& key, const std::string& kdf, RandomNumberGenerator& rng) :
87          PK_Ops::Key_Agreement_with_KDF(kdf),
88          m_p(key.group_p()),
89          m_x(key.get_x()),
90          m_x_bits(m_x.bits()),
91          m_monty_p(key.get_group().monty_params_p()),
92          m_blinder(m_p,
93                    rng,
94                    [](const BigInt& k) { return k; },
__anonda5249140302(const BigInt& k) 95                    [this](const BigInt& k) { return powermod_x_p(inverse_mod(k, m_p)); })
96          {}
97 
agreed_value_size() const98       size_t agreed_value_size() const override { return m_p.bytes(); }
99 
100       secure_vector<uint8_t> raw_agree(const uint8_t w[], size_t w_len) override;
101    private:
powermod_x_p(const BigInt & v) const102       BigInt powermod_x_p(const BigInt& v) const
103          {
104          const size_t powm_window = 4;
105          auto powm_v_p = monty_precompute(m_monty_p, v, powm_window);
106          return monty_execute(*powm_v_p, m_x, m_x_bits);
107          }
108 
109       const BigInt& m_p;
110       const BigInt& m_x;
111       const size_t m_x_bits;
112       std::shared_ptr<const Montgomery_Params> m_monty_p;
113       Blinder m_blinder;
114    };
115 
raw_agree(const uint8_t w[],size_t w_len)116 secure_vector<uint8_t> DH_KA_Operation::raw_agree(const uint8_t w[], size_t w_len)
117    {
118    BigInt v = BigInt::decode(w, w_len);
119 
120    if(v <= 1 || v >= m_p - 1)
121       throw Invalid_Argument("DH agreement - invalid key provided");
122 
123    v = m_blinder.blind(v);
124    v = powermod_x_p(v);
125    v = m_blinder.unblind(v);
126 
127    return BigInt::encode_1363(v, m_p.bytes());
128    }
129 
130 }
131 
132 std::unique_ptr<PK_Ops::Key_Agreement>
create_key_agreement_op(RandomNumberGenerator & rng,const std::string & params,const std::string & provider) const133 DH_PrivateKey::create_key_agreement_op(RandomNumberGenerator& rng,
134                                        const std::string& params,
135                                        const std::string& provider) const
136    {
137    if(provider == "base" || provider.empty())
138       return std::unique_ptr<PK_Ops::Key_Agreement>(new DH_KA_Operation(*this, params, rng));
139    throw Provider_Not_Found(algo_name(), provider);
140    }
141 
142 }
143