/src/botan/src/lib/pubkey/ecc_key/ecc_key.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * ECC Key implemenation |
3 | | * (C) 2007 Manuel Hartl, FlexSecure GmbH |
4 | | * Falko Strenzke, FlexSecure GmbH |
5 | | * 2008-2010 Jack Lloyd |
6 | | * |
7 | | * Botan is released under the Simplified BSD License (see license.txt) |
8 | | */ |
9 | | |
10 | | #include <botan/ecc_key.h> |
11 | | #include <botan/numthry.h> |
12 | | #include <botan/der_enc.h> |
13 | | #include <botan/ber_dec.h> |
14 | | #include <botan/secmem.h> |
15 | | #include <botan/point_gfp.h> |
16 | | #include <botan/internal/workfactor.h> |
17 | | |
18 | | namespace Botan { |
19 | | |
20 | | size_t EC_PublicKey::key_length() const |
21 | 0 | { |
22 | 0 | return domain().get_p_bits(); |
23 | 0 | } |
24 | | |
25 | | size_t EC_PublicKey::estimated_strength() const |
26 | 0 | { |
27 | 0 | return ecp_work_factor(key_length()); |
28 | 0 | } |
29 | | |
30 | | namespace { |
31 | | |
32 | | EC_Group_Encoding default_encoding_for(EC_Group& group) |
33 | 20.2k | { |
34 | 20.2k | if(group.get_curve_oid().empty()) |
35 | 239 | return EC_Group_Encoding::Explicit; |
36 | 20.0k | else |
37 | 20.0k | return EC_Group_Encoding::NamedCurve; |
38 | 20.2k | } |
39 | | |
40 | | } |
41 | | |
42 | | EC_PublicKey::EC_PublicKey(const EC_Group& dom_par, |
43 | | const PointGFp& pub_point) : |
44 | | m_domain_params(dom_par), |
45 | | m_public_key(pub_point), |
46 | | m_domain_encoding(default_encoding_for(m_domain_params)) |
47 | 0 | { |
48 | | #if 0 |
49 | | if(domain().get_curve() != public_point().get_curve()) |
50 | | throw Invalid_Argument("EC_PublicKey: curve mismatch in constructor"); |
51 | | #endif |
52 | 0 | } |
53 | | |
54 | | EC_PublicKey::EC_PublicKey(const AlgorithmIdentifier& alg_id, |
55 | | const std::vector<uint8_t>& key_bits) : |
56 | | m_domain_params{EC_Group(alg_id.get_parameters())}, |
57 | | m_public_key{domain().OS2ECP(key_bits)}, |
58 | | m_domain_encoding(default_encoding_for(m_domain_params)) |
59 | 1.88k | { |
60 | 1.88k | } |
61 | | |
62 | | bool EC_PublicKey::check_key(RandomNumberGenerator& rng, |
63 | | bool) const |
64 | 0 | { |
65 | 0 | return m_domain_params.verify_group(rng) && |
66 | 0 | m_domain_params.verify_public_element(public_point()); |
67 | 0 | } |
68 | | |
69 | | |
70 | | AlgorithmIdentifier EC_PublicKey::algorithm_identifier() const |
71 | 0 | { |
72 | 0 | return AlgorithmIdentifier(get_oid(), DER_domain()); |
73 | 0 | } |
74 | | |
75 | | std::vector<uint8_t> EC_PublicKey::public_key_bits() const |
76 | 0 | { |
77 | 0 | return public_point().encode(point_encoding()); |
78 | 0 | } |
79 | | |
80 | | void EC_PublicKey::set_point_encoding(PointGFp::Compression_Type enc) |
81 | 0 | { |
82 | 0 | if(enc != PointGFp::COMPRESSED && |
83 | 0 | enc != PointGFp::UNCOMPRESSED && |
84 | 0 | enc != PointGFp::HYBRID) |
85 | 0 | throw Invalid_Argument("Invalid point encoding for EC_PublicKey"); |
86 | | |
87 | 0 | m_point_encoding = enc; |
88 | 0 | } |
89 | | |
90 | | void EC_PublicKey::set_parameter_encoding(EC_Group_Encoding form) |
91 | 0 | { |
92 | 0 | if(form == EC_Group_Encoding::NamedCurve && m_domain_params.get_curve_oid().empty()) |
93 | 0 | throw Invalid_Argument("Cannot used NamedCurve encoding for a curve without an OID"); |
94 | | |
95 | 0 | m_domain_encoding = form; |
96 | 0 | } |
97 | | |
98 | | const BigInt& EC_PrivateKey::private_value() const |
99 | 15.1k | { |
100 | 15.1k | if(m_private_key == 0) |
101 | 0 | throw Invalid_State("EC_PrivateKey::private_value - uninitialized"); |
102 | | |
103 | 15.1k | return m_private_key; |
104 | 15.1k | } |
105 | | |
106 | | /** |
107 | | * EC_PrivateKey constructor |
108 | | */ |
109 | | EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng, |
110 | | const EC_Group& ec_group, |
111 | | const BigInt& x, |
112 | | bool with_modular_inverse) |
113 | 17.4k | { |
114 | 17.4k | m_domain_params = ec_group; |
115 | 17.4k | m_domain_encoding = default_encoding_for(m_domain_params); |
116 | | |
117 | 17.4k | if(x == 0) |
118 | 17.4k | { |
119 | 17.4k | m_private_key = ec_group.random_scalar(rng); |
120 | 17.4k | } |
121 | 0 | else |
122 | 0 | { |
123 | 0 | m_private_key = x; |
124 | 0 | } |
125 | | |
126 | 17.4k | std::vector<BigInt> ws; |
127 | | |
128 | 17.4k | if(with_modular_inverse) |
129 | 0 | { |
130 | | // ECKCDSA |
131 | 0 | m_public_key = domain().blinded_base_point_multiply( |
132 | 0 | m_domain_params.inverse_mod_order(m_private_key), rng, ws); |
133 | 0 | } |
134 | 17.4k | else |
135 | 17.4k | { |
136 | 17.4k | m_public_key = domain().blinded_base_point_multiply(m_private_key, rng, ws); |
137 | 17.4k | } |
138 | | |
139 | 17.4k | BOTAN_ASSERT(m_public_key.on_the_curve(), |
140 | 17.4k | "Generated public key point was on the curve"); |
141 | 17.4k | } |
142 | | |
143 | | secure_vector<uint8_t> EC_PrivateKey::private_key_bits() const |
144 | 0 | { |
145 | 0 | return DER_Encoder() |
146 | 0 | .start_sequence() |
147 | 0 | .encode(static_cast<size_t>(1)) |
148 | 0 | .encode(BigInt::encode_1363(m_private_key, m_private_key.bytes()), ASN1_Type::OctetString) |
149 | 0 | .start_explicit_context_specific(1) |
150 | 0 | .encode(m_public_key.encode(PointGFp::Compression_Type::UNCOMPRESSED), ASN1_Type::BitString) |
151 | 0 | .end_cons() |
152 | 0 | .end_cons() |
153 | 0 | .get_contents(); |
154 | 0 | } |
155 | | |
156 | | EC_PrivateKey::EC_PrivateKey(const AlgorithmIdentifier& alg_id, |
157 | | const secure_vector<uint8_t>& key_bits, |
158 | | bool with_modular_inverse) |
159 | 2.55k | { |
160 | 2.55k | m_domain_params = EC_Group(alg_id.get_parameters()); |
161 | 2.55k | m_domain_encoding = default_encoding_for(m_domain_params); |
162 | | |
163 | 2.55k | OID key_parameters; |
164 | 2.55k | secure_vector<uint8_t> public_key_bits; |
165 | | |
166 | 2.55k | BER_Decoder(key_bits) |
167 | 2.55k | .start_sequence() |
168 | 2.55k | .decode_and_check<size_t>(1, "Unknown version code for ECC key") |
169 | 2.55k | .decode_octet_string_bigint(m_private_key) |
170 | 2.55k | .decode_optional(key_parameters, ASN1_Type(0), ASN1_Class::ExplicitContextSpecific) |
171 | 2.55k | .decode_optional_string(public_key_bits, ASN1_Type::BitString, 1, ASN1_Class::ExplicitContextSpecific) |
172 | 2.55k | .end_cons(); |
173 | | |
174 | 2.55k | if(public_key_bits.empty()) |
175 | 422 | { |
176 | 422 | if(with_modular_inverse) |
177 | 0 | { |
178 | | // ECKCDSA |
179 | 0 | m_public_key = domain().get_base_point() * m_domain_params.inverse_mod_order(m_private_key); |
180 | 0 | } |
181 | 422 | else |
182 | 422 | { |
183 | 422 | m_public_key = domain().get_base_point() * m_private_key; |
184 | 422 | } |
185 | | |
186 | 422 | BOTAN_ASSERT(m_public_key.on_the_curve(), |
187 | 422 | "Public point derived from loaded key was on the curve"); |
188 | 422 | } |
189 | 2.13k | else |
190 | 2.13k | { |
191 | 2.13k | m_public_key = domain().OS2ECP(public_key_bits); |
192 | | // OS2ECP verifies that the point is on the curve |
193 | 2.13k | } |
194 | 2.55k | } |
195 | | |
196 | | } |