/src/botan/src/lib/pubkey/ecgdsa/ecgdsa.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * ECGDSA (BSI-TR-03111, version 2.0) |
3 | | * (C) 2016 René Korthaus |
4 | | * (C) 2018 Jack Lloyd |
5 | | * |
6 | | * Botan is released under the Simplified BSD License (see license.txt) |
7 | | */ |
8 | | |
9 | | #include <botan/ecgdsa.h> |
10 | | #include <botan/keypair.h> |
11 | | #include <botan/reducer.h> |
12 | | #include <botan/internal/pk_ops_impl.h> |
13 | | #include <botan/internal/point_mul.h> |
14 | | |
15 | | namespace Botan { |
16 | | |
17 | | bool ECGDSA_PrivateKey::check_key(RandomNumberGenerator& rng, |
18 | | bool strong) const |
19 | 0 | { |
20 | 0 | if(!public_point().on_the_curve()) |
21 | 0 | return false; |
22 | 0 | |
23 | 0 | if(!strong) |
24 | 0 | return true; |
25 | 0 | |
26 | 0 | return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)"); |
27 | 0 | } |
28 | | |
29 | | namespace { |
30 | | |
31 | | /** |
32 | | * ECGDSA signature operation |
33 | | */ |
34 | | class ECGDSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA |
35 | | { |
36 | | public: |
37 | | |
38 | | ECGDSA_Signature_Operation(const ECGDSA_PrivateKey& ecgdsa, |
39 | | const std::string& emsa) : |
40 | | PK_Ops::Signature_with_EMSA(emsa), |
41 | | m_group(ecgdsa.domain()), |
42 | | m_x(ecgdsa.private_value()) |
43 | 0 | { |
44 | 0 | } |
45 | | |
46 | | secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len, |
47 | | RandomNumberGenerator& rng) override; |
48 | | |
49 | 0 | size_t signature_length() const override { return 2*m_group.get_order_bytes(); } |
50 | | |
51 | 0 | size_t max_input_bits() const override { return m_group.get_order_bits(); } |
52 | | |
53 | | private: |
54 | | const EC_Group m_group; |
55 | | const BigInt& m_x; |
56 | | std::vector<BigInt> m_ws; |
57 | | }; |
58 | | |
59 | | secure_vector<uint8_t> |
60 | | ECGDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len, |
61 | | RandomNumberGenerator& rng) |
62 | 0 | { |
63 | 0 | const BigInt m(msg, msg_len, m_group.get_order_bits()); |
64 | 0 |
|
65 | 0 | const BigInt k = m_group.random_scalar(rng); |
66 | 0 |
|
67 | 0 | const BigInt r = m_group.mod_order( |
68 | 0 | m_group.blinded_base_point_multiply_x(k, rng, m_ws)); |
69 | 0 |
|
70 | 0 | const BigInt kr = m_group.multiply_mod_order(k, r); |
71 | 0 |
|
72 | 0 | const BigInt s = m_group.multiply_mod_order(m_x, kr - m); |
73 | 0 |
|
74 | 0 | // With overwhelming probability, a bug rather than actual zero r/s |
75 | 0 | if(r.is_zero() || s.is_zero()) |
76 | 0 | throw Internal_Error("During ECGDSA signature generated zero r/s"); |
77 | 0 | |
78 | 0 | return BigInt::encode_fixed_length_int_pair(r, s, m_group.get_order_bytes()); |
79 | 0 | } |
80 | | |
81 | | /** |
82 | | * ECGDSA verification operation |
83 | | */ |
84 | | class ECGDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA |
85 | | { |
86 | | public: |
87 | | |
88 | | ECGDSA_Verification_Operation(const ECGDSA_PublicKey& ecgdsa, |
89 | | const std::string& emsa) : |
90 | | PK_Ops::Verification_with_EMSA(emsa), |
91 | | m_group(ecgdsa.domain()), |
92 | | m_gy_mul(m_group.get_base_point(), ecgdsa.public_point()) |
93 | 0 | { |
94 | 0 | } |
95 | | |
96 | 0 | size_t max_input_bits() const override { return m_group.get_order_bits(); } |
97 | | |
98 | 0 | bool with_recovery() const override { return false; } |
99 | | |
100 | | bool verify(const uint8_t msg[], size_t msg_len, |
101 | | const uint8_t sig[], size_t sig_len) override; |
102 | | private: |
103 | | const EC_Group m_group; |
104 | | const PointGFp_Multi_Point_Precompute m_gy_mul; |
105 | | }; |
106 | | |
107 | | bool ECGDSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len, |
108 | | const uint8_t sig[], size_t sig_len) |
109 | 0 | { |
110 | 0 | if(sig_len != m_group.get_order_bytes() * 2) |
111 | 0 | return false; |
112 | 0 | |
113 | 0 | const BigInt e(msg, msg_len, m_group.get_order_bits()); |
114 | 0 |
|
115 | 0 | const BigInt r(sig, sig_len / 2); |
116 | 0 | const BigInt s(sig + sig_len / 2, sig_len / 2); |
117 | 0 |
|
118 | 0 | if(r <= 0 || r >= m_group.get_order() || s <= 0 || s >= m_group.get_order()) |
119 | 0 | return false; |
120 | 0 | |
121 | 0 | const BigInt w = m_group.inverse_mod_order(r); |
122 | 0 |
|
123 | 0 | const BigInt u1 = m_group.multiply_mod_order(e, w); |
124 | 0 | const BigInt u2 = m_group.multiply_mod_order(s, w); |
125 | 0 | const PointGFp R = m_gy_mul.multi_exp(u1, u2); |
126 | 0 |
|
127 | 0 | if(R.is_zero()) |
128 | 0 | return false; |
129 | 0 | |
130 | 0 | const BigInt v = m_group.mod_order(R.get_affine_x()); |
131 | 0 | return (v == r); |
132 | 0 | } |
133 | | |
134 | | } |
135 | | |
136 | | std::unique_ptr<PK_Ops::Verification> |
137 | | ECGDSA_PublicKey::create_verification_op(const std::string& params, |
138 | | const std::string& provider) const |
139 | 0 | { |
140 | 0 | if(provider == "base" || provider.empty()) |
141 | 0 | return std::unique_ptr<PK_Ops::Verification>(new ECGDSA_Verification_Operation(*this, params)); |
142 | 0 | throw Provider_Not_Found(algo_name(), provider); |
143 | 0 | } |
144 | | |
145 | | std::unique_ptr<PK_Ops::Signature> |
146 | | ECGDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, |
147 | | const std::string& params, |
148 | | const std::string& provider) const |
149 | 0 | { |
150 | 0 | if(provider == "base" || provider.empty()) |
151 | 0 | return std::unique_ptr<PK_Ops::Signature>(new ECGDSA_Signature_Operation(*this, params)); |
152 | 0 | throw Provider_Not_Found(algo_name(), provider); |
153 | 0 | } |
154 | | |
155 | | } |