/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 | | |
11 | | #include <botan/reducer.h> |
12 | | #include <botan/internal/keypair.h> |
13 | | #include <botan/internal/pk_ops_impl.h> |
14 | | #include <botan/internal/point_mul.h> |
15 | | |
16 | | namespace Botan { |
17 | | |
18 | 0 | std::unique_ptr<Public_Key> ECGDSA_PrivateKey::public_key() const { |
19 | 0 | return std::make_unique<ECGDSA_PublicKey>(domain(), public_point()); |
20 | 0 | } |
21 | | |
22 | 0 | bool ECGDSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const { |
23 | 0 | if(!EC_PrivateKey::check_key(rng, strong)) { |
24 | 0 | return false; |
25 | 0 | } |
26 | | |
27 | 0 | if(!strong) { |
28 | 0 | return true; |
29 | 0 | } |
30 | | |
31 | 0 | return KeyPair::signature_consistency_check(rng, *this, "SHA-256"); |
32 | 0 | } |
33 | | |
34 | | namespace { |
35 | | |
36 | | /** |
37 | | * ECGDSA signature operation |
38 | | */ |
39 | | class ECGDSA_Signature_Operation final : public PK_Ops::Signature_with_Hash { |
40 | | public: |
41 | | ECGDSA_Signature_Operation(const ECGDSA_PrivateKey& ecgdsa, std::string_view emsa) : |
42 | 168 | PK_Ops::Signature_with_Hash(emsa), m_group(ecgdsa.domain()), m_x(ecgdsa.private_value()) {} |
43 | | |
44 | | secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) override; |
45 | | |
46 | 0 | size_t signature_length() const override { return 2 * m_group.get_order_bytes(); } |
47 | | |
48 | | AlgorithmIdentifier algorithm_identifier() const override; |
49 | | |
50 | | private: |
51 | | const EC_Group m_group; |
52 | | const BigInt m_x; |
53 | | std::vector<BigInt> m_ws; |
54 | | }; |
55 | | |
56 | 0 | AlgorithmIdentifier ECGDSA_Signature_Operation::algorithm_identifier() const { |
57 | 0 | const std::string full_name = "ECGDSA/" + hash_function(); |
58 | 0 | const OID oid = OID::from_string(full_name); |
59 | 0 | return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM); |
60 | 0 | } |
61 | | |
62 | | secure_vector<uint8_t> ECGDSA_Signature_Operation::raw_sign(const uint8_t msg[], |
63 | | size_t msg_len, |
64 | 168 | RandomNumberGenerator& rng) { |
65 | 168 | const BigInt m = BigInt::from_bytes_with_max_bits(msg, msg_len, m_group.get_order_bits()); |
66 | | |
67 | 168 | const BigInt k = m_group.random_scalar(rng); |
68 | | |
69 | 168 | const BigInt r = m_group.mod_order(m_group.blinded_base_point_multiply_x(k, rng, m_ws)); |
70 | | |
71 | 168 | const BigInt kr = m_group.multiply_mod_order(k, r); |
72 | | |
73 | 168 | const BigInt s = m_group.multiply_mod_order(m_x, kr - m); |
74 | | |
75 | | // With overwhelming probability, a bug rather than actual zero r/s |
76 | 168 | if(r.is_zero() || s.is_zero()) { |
77 | 2 | throw Internal_Error("During ECGDSA signature generated zero r/s"); |
78 | 2 | } |
79 | | |
80 | 166 | return BigInt::encode_fixed_length_int_pair(r, s, m_group.get_order_bytes()); |
81 | 168 | } |
82 | | |
83 | | /** |
84 | | * ECGDSA verification operation |
85 | | */ |
86 | | class ECGDSA_Verification_Operation final : public PK_Ops::Verification_with_Hash { |
87 | | public: |
88 | | ECGDSA_Verification_Operation(const ECGDSA_PublicKey& ecgdsa, std::string_view padding) : |
89 | | PK_Ops::Verification_with_Hash(padding), |
90 | | m_group(ecgdsa.domain()), |
91 | 221 | m_gy_mul(m_group.get_base_point(), ecgdsa.public_point()) {} |
92 | | |
93 | | ECGDSA_Verification_Operation(const ECGDSA_PublicKey& ecgdsa, const AlgorithmIdentifier& alg_id) : |
94 | | PK_Ops::Verification_with_Hash(alg_id, "ECGDSA"), |
95 | | m_group(ecgdsa.domain()), |
96 | 0 | m_gy_mul(m_group.get_base_point(), ecgdsa.public_point()) {} |
97 | | |
98 | | bool verify(const uint8_t msg[], size_t msg_len, const uint8_t sig[], size_t sig_len) override; |
99 | | |
100 | | private: |
101 | | const EC_Group m_group; |
102 | | const EC_Point_Multi_Point_Precompute m_gy_mul; |
103 | | }; |
104 | | |
105 | 221 | bool ECGDSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len, const uint8_t sig[], size_t sig_len) { |
106 | 221 | if(sig_len != m_group.get_order_bytes() * 2) { |
107 | 0 | return false; |
108 | 0 | } |
109 | | |
110 | 221 | const BigInt e = BigInt::from_bytes_with_max_bits(msg, msg_len, m_group.get_order_bits()); |
111 | | |
112 | 221 | const BigInt r(sig, sig_len / 2); |
113 | 221 | const BigInt s(sig + sig_len / 2, sig_len / 2); |
114 | | |
115 | 221 | if(r <= 0 || r >= m_group.get_order() || s <= 0 || s >= m_group.get_order()) { |
116 | 78 | return false; |
117 | 78 | } |
118 | | |
119 | 143 | const BigInt w = m_group.inverse_mod_order(r); |
120 | | |
121 | 143 | const BigInt u1 = m_group.multiply_mod_order(e, w); |
122 | 143 | const BigInt u2 = m_group.multiply_mod_order(s, w); |
123 | 143 | const EC_Point R = m_gy_mul.multi_exp(u1, u2); |
124 | | |
125 | 143 | if(R.is_zero()) { |
126 | 75 | return false; |
127 | 75 | } |
128 | | |
129 | 68 | const BigInt v = m_group.mod_order(R.get_affine_x()); |
130 | 68 | return (v == r); |
131 | 143 | } |
132 | | |
133 | | } // namespace |
134 | | |
135 | 0 | std::unique_ptr<Private_Key> ECGDSA_PublicKey::generate_another(RandomNumberGenerator& rng) const { |
136 | 0 | return std::make_unique<ECGDSA_PrivateKey>(rng, domain()); |
137 | 0 | } |
138 | | |
139 | | std::unique_ptr<PK_Ops::Verification> ECGDSA_PublicKey::create_verification_op(std::string_view params, |
140 | 221 | std::string_view provider) const { |
141 | 221 | if(provider == "base" || provider.empty()) { |
142 | 221 | return std::make_unique<ECGDSA_Verification_Operation>(*this, params); |
143 | 221 | } |
144 | 0 | throw Provider_Not_Found(algo_name(), provider); |
145 | 221 | } |
146 | | |
147 | | std::unique_ptr<PK_Ops::Verification> ECGDSA_PublicKey::create_x509_verification_op( |
148 | 0 | const AlgorithmIdentifier& signature_algorithm, std::string_view provider) const { |
149 | 0 | if(provider == "base" || provider.empty()) { |
150 | 0 | return std::make_unique<ECGDSA_Verification_Operation>(*this, signature_algorithm); |
151 | 0 | } |
152 | | |
153 | 0 | throw Provider_Not_Found(algo_name(), provider); |
154 | 0 | } |
155 | | |
156 | | std::unique_ptr<PK_Ops::Signature> ECGDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/, |
157 | | std::string_view params, |
158 | 168 | std::string_view provider) const { |
159 | 168 | if(provider == "base" || provider.empty()) { |
160 | 168 | return std::make_unique<ECGDSA_Signature_Operation>(*this, params); |
161 | 168 | } |
162 | 0 | throw Provider_Not_Found(algo_name(), provider); |
163 | 168 | } |
164 | | |
165 | | } // namespace Botan |