Coverage Report

Created: 2021-02-21 07:20

/src/botan/src/lib/pubkey/eckcdsa/eckcdsa.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* ECKCDSA (ISO/IEC 14888-3:2006/Cor.2:2009)
3
* (C) 2016 René Korthaus, Sirrix AG
4
* (C) 2018 Jack Lloyd
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8
9
#include <botan/eckcdsa.h>
10
#include <botan/internal/pk_ops_impl.h>
11
#include <botan/internal/point_mul.h>
12
#include <botan/internal/keypair.h>
13
#include <botan/reducer.h>
14
#include <botan/internal/emsa.h>
15
#include <botan/hash.h>
16
#include <botan/rng.h>
17
18
namespace Botan {
19
20
std::unique_ptr<Public_Key> ECKCDSA_PrivateKey::public_key() const
21
0
   {
22
0
   return std::unique_ptr<Public_Key>(new ECKCDSA_PublicKey(domain(), public_point()));
23
0
   }
24
25
bool ECKCDSA_PrivateKey::check_key(RandomNumberGenerator& rng,
26
                                 bool strong) const
27
0
   {
28
0
   if(!public_point().on_the_curve())
29
0
      {
30
0
      return false;
31
0
      }
32
33
0
   if(!strong)
34
0
      {
35
0
      return true;
36
0
      }
37
38
0
   return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)");
39
0
   }
40
41
namespace {
42
43
/**
44
* ECKCDSA signature operation
45
*/
46
class ECKCDSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA
47
   {
48
   public:
49
50
      ECKCDSA_Signature_Operation(const ECKCDSA_PrivateKey& eckcdsa,
51
                                const std::string& emsa) :
52
         PK_Ops::Signature_with_EMSA(emsa),
53
         m_group(eckcdsa.domain()),
54
         m_x(eckcdsa.private_value()),
55
         m_prefix()
56
0
         {
57
0
         const BigInt public_point_x = eckcdsa.public_point().get_affine_x();
58
0
         const BigInt public_point_y = eckcdsa.public_point().get_affine_y();
59
60
0
         m_prefix.resize(public_point_x.bytes() + public_point_y.bytes());
61
0
         public_point_x.binary_encode(m_prefix.data());
62
0
         public_point_y.binary_encode(&m_prefix[public_point_x.bytes()]);
63
0
         m_prefix.resize(HashFunction::create(hash_for_signature())->hash_block_size()); // use only the "hash input block size" leftmost bits
64
0
         }
65
66
      secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len,
67
                                      RandomNumberGenerator& rng) override;
68
69
0
      size_t signature_length() const override { return 2*m_group.get_order_bytes(); }
70
0
      size_t max_input_bits() const override { return m_group.get_order_bits(); }
71
72
0
      bool has_prefix() override { return true; }
73
0
      secure_vector<uint8_t> message_prefix() const override { return m_prefix; }
74
75
   private:
76
      const EC_Group m_group;
77
      const BigInt& m_x;
78
      secure_vector<uint8_t> m_prefix;
79
      std::vector<BigInt> m_ws;
80
   };
81
82
secure_vector<uint8_t>
83
ECKCDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t,
84
                                     RandomNumberGenerator& rng)
85
0
   {
86
0
   const BigInt k = m_group.random_scalar(rng);
87
0
   const BigInt k_times_P_x = m_group.blinded_base_point_multiply_x(k, rng, m_ws);
88
89
0
   secure_vector<uint8_t> to_be_hashed(k_times_P_x.bytes());
90
0
   k_times_P_x.binary_encode(to_be_hashed.data());
91
92
0
   std::unique_ptr<EMSA> emsa = this->clone_emsa();
93
0
   emsa->update(to_be_hashed.data(), to_be_hashed.size());
94
0
   secure_vector<uint8_t> c = emsa->raw_data();
95
0
   c = emsa->encoding_of(c, max_input_bits(), rng);
96
97
0
   const BigInt r(c.data(), c.size());
98
99
0
   xor_buf(c, msg, c.size());
100
0
   BigInt w(c.data(), c.size());
101
0
   w = m_group.mod_order(w);
102
103
0
   const BigInt s = m_group.multiply_mod_order(m_x, k - w);
104
0
   if(s.is_zero())
105
0
      throw Internal_Error("During ECKCDSA signature generation created zero s");
106
107
0
   secure_vector<uint8_t> output = BigInt::encode_1363(r, c.size());
108
0
   output += BigInt::encode_1363(s, m_group.get_order_bytes());
109
0
   return output;
110
0
   }
111
112
/**
113
* ECKCDSA verification operation
114
*/
115
class ECKCDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA
116
   {
117
   public:
118
119
      ECKCDSA_Verification_Operation(const ECKCDSA_PublicKey& eckcdsa,
120
                                   const std::string& emsa) :
121
         PK_Ops::Verification_with_EMSA(emsa),
122
         m_group(eckcdsa.domain()),
123
         m_gy_mul(m_group.get_base_point(), eckcdsa.public_point()),
124
         m_prefix()
125
0
         {
126
0
         const BigInt public_point_x = eckcdsa.public_point().get_affine_x();
127
0
         const BigInt public_point_y = eckcdsa.public_point().get_affine_y();
128
129
0
         m_prefix.resize(public_point_x.bytes() + public_point_y.bytes());
130
0
         public_point_x.binary_encode(&m_prefix[0]);
131
0
         public_point_y.binary_encode(&m_prefix[public_point_x.bytes()]);
132
0
         m_prefix.resize(HashFunction::create(hash_for_signature())->hash_block_size()); // use only the "hash input block size" leftmost bits
133
0
         }
134
135
0
      bool has_prefix() override { return true; }
136
0
      secure_vector<uint8_t> message_prefix() const override { return m_prefix; }
137
138
0
      size_t max_input_bits() const override { return m_group.get_order_bits(); }
139
140
0
      bool with_recovery() const override { return false; }
141
142
      bool verify(const uint8_t msg[], size_t msg_len,
143
                  const uint8_t sig[], size_t sig_len) override;
144
   private:
145
      const EC_Group m_group;
146
      const PointGFp_Multi_Point_Precompute m_gy_mul;
147
      secure_vector<uint8_t> m_prefix;
148
   };
149
150
bool ECKCDSA_Verification_Operation::verify(const uint8_t msg[], size_t,
151
                                           const uint8_t sig[], size_t sig_len)
152
0
   {
153
0
   const std::unique_ptr<HashFunction> hash = HashFunction::create(hash_for_signature());
154
   //calculate size of r
155
156
0
   const size_t order_bytes = m_group.get_order_bytes();
157
158
0
   const size_t size_r = std::min(hash -> output_length(), order_bytes);
159
0
   if(sig_len != size_r + order_bytes)
160
0
      {
161
0
      return false;
162
0
      }
163
164
0
   secure_vector<uint8_t> r(sig, sig + size_r);
165
166
   // check that 0 < s < q
167
0
   const BigInt s(sig + size_r, order_bytes);
168
169
0
   if(s <= 0 || s >= m_group.get_order())
170
0
      {
171
0
      return false;
172
0
      }
173
174
0
   secure_vector<uint8_t> r_xor_e(r);
175
0
   xor_buf(r_xor_e, msg, r.size());
176
0
   BigInt w(r_xor_e.data(), r_xor_e.size());
177
0
   w = m_group.mod_order(w);
178
179
0
   const PointGFp q = m_gy_mul.multi_exp(w, s);
180
0
   if(q.is_zero())
181
0
      return false;
182
0
   const BigInt q_x = q.get_affine_x();
183
0
   secure_vector<uint8_t> c(q_x.bytes());
184
0
   q_x.binary_encode(c.data());
185
0
   std::unique_ptr<EMSA> emsa = this->clone_emsa();
186
0
   emsa->update(c.data(), c.size());
187
0
   secure_vector<uint8_t> v = emsa->raw_data();
188
0
   Null_RNG rng;
189
0
   v = emsa->encoding_of(v, max_input_bits(), rng);
190
191
0
   return (v == r);
192
0
   }
193
194
}
195
196
std::unique_ptr<PK_Ops::Verification>
197
ECKCDSA_PublicKey::create_verification_op(const std::string& params,
198
                                         const std::string& provider) const
199
0
   {
200
0
   if(provider == "base" || provider.empty())
201
0
      return std::unique_ptr<PK_Ops::Verification>(new ECKCDSA_Verification_Operation(*this, params));
202
0
   throw Provider_Not_Found(algo_name(), provider);
203
0
   }
204
205
std::unique_ptr<PK_Ops::Signature>
206
ECKCDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
207
                                        const std::string& params,
208
                                        const std::string& provider) const
209
0
   {
210
0
   if(provider == "base" || provider.empty())
211
0
      return std::unique_ptr<PK_Ops::Signature>(new ECKCDSA_Signature_Operation(*this, params));
212
0
   throw Provider_Not_Found(algo_name(), provider);
213
0
   }
214
215
}