/src/cryptofuzz/modules/wolfcrypt/ecdsa_448.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "ecdsa_448.h" |
2 | | #include "module_internal.h" |
3 | | #include "shared.h" |
4 | | #include "bn_ops.h" |
5 | | #include <cryptofuzz/util.h> |
6 | | |
7 | | extern "C" { |
8 | | #include <wolfssl/options.h> |
9 | | #include <wolfssl/wolfcrypt/curve448.h> |
10 | | #include <wolfssl/wolfcrypt/ed448.h> |
11 | | } |
12 | | |
13 | | namespace cryptofuzz { |
14 | | namespace module { |
15 | | namespace wolfCrypt_detail { |
16 | | |
17 | | #if defined(CRYPTOFUZZ_WOLFCRYPT_ALLOCATION_FAILURES) |
18 | | extern bool haveAllocFailure; |
19 | | #endif |
20 | | |
21 | 0 | static bool ed448LoadPrivateKey(ed448_key& key, component::Bignum priv, Datasource& ds) { |
22 | 0 | bool ret = false; |
23 | |
|
24 | 0 | uint8_t priv_bytes[ED448_KEY_SIZE]; |
25 | |
|
26 | 0 | CF_CHECK_EQ(wolfCrypt_bignum::Bignum::ToBin(ds, priv, priv_bytes, sizeof(priv_bytes)), true); |
27 | 0 | CF_CHECK_EQ(wc_ed448_import_private_only(priv_bytes, sizeof(priv_bytes), &key), 0); |
28 | |
|
29 | 0 | ret = true; |
30 | 0 | end: |
31 | 0 | return ret; |
32 | 0 | } |
33 | | |
34 | 0 | static std::optional<std::vector<uint8_t>> ed448GetPublicKeyAsVector(ed448_key& key) { |
35 | 0 | std::optional<std::vector<uint8_t>> ret = std::nullopt; |
36 | 0 | uint8_t pub_bytes[ED448_PUB_KEY_SIZE]; |
37 | |
|
38 | 0 | WC_CHECK_EQ(wc_ed448_make_public(&key, pub_bytes, sizeof(pub_bytes)), MP_OKAY); |
39 | |
|
40 | 0 | ret = std::vector<uint8_t>(pub_bytes, pub_bytes + sizeof(pub_bytes)); |
41 | 0 | end: |
42 | 0 | return ret; |
43 | 0 | } |
44 | | |
45 | 0 | static std::optional<component::ECC_PublicKey> ed448GetPublicKey(ed448_key& key, Datasource& ds) { |
46 | 0 | std::optional<component::ECC_PublicKey> ret = std::nullopt; |
47 | 0 | std::optional<std::vector<uint8_t>> pubv = std::nullopt; |
48 | 0 | std::optional<component::Bignum> pub = std::nullopt; |
49 | |
|
50 | 0 | CF_CHECK_NE(pubv = ed448GetPublicKeyAsVector(key), std::nullopt); |
51 | 0 | CF_CHECK_NE(pub = wolfCrypt_bignum::Bignum::BinToBignum(ds, pubv->data(), pubv->size()), std::nullopt); |
52 | |
|
53 | 0 | ret = {pub->ToString(), "0"}; |
54 | |
|
55 | 0 | end: |
56 | 0 | return ret; |
57 | 0 | } |
58 | | |
59 | 0 | static bool ed448DerivePublicKey(ed448_key& key) { |
60 | 0 | std::optional<std::vector<uint8_t>> pubv = std::nullopt; |
61 | 0 | bool ret = false; |
62 | |
|
63 | 0 | CF_CHECK_NE(pubv = ed448GetPublicKeyAsVector(key), std::nullopt); |
64 | 0 | memcpy(key.p, pubv->data(), ED448_PUB_KEY_SIZE); |
65 | 0 | key.pubKeySet = 1; |
66 | |
|
67 | 0 | ret = true; |
68 | |
|
69 | 0 | end: |
70 | 0 | return ret; |
71 | 0 | } |
72 | | |
73 | 0 | static bool ed448LoadPublicKey(ed448_key& key, component::Bignum pub, Datasource& ds, const bool mustSucceed = false) { |
74 | 0 | bool ret = false; |
75 | |
|
76 | 0 | uint8_t pub_bytes[ED448_PUB_KEY_SIZE]; |
77 | 0 | CF_CHECK_EQ(wolfCrypt_bignum::Bignum::ToBin(ds, pub, pub_bytes, sizeof(pub_bytes), mustSucceed), true); |
78 | 0 | CF_CHECK_EQ(wc_ed448_import_public(pub_bytes, sizeof(pub_bytes), &key), 0); |
79 | |
|
80 | 0 | ret = true; |
81 | 0 | end: |
82 | 0 | return ret; |
83 | 0 | } |
84 | | |
85 | 0 | std::optional<component::ECC_PublicKey> OpECC_PrivateToPublic_Curve448(operation::ECC_PrivateToPublic& op) { |
86 | 0 | std::optional<component::ECC_PublicKey> ret = std::nullopt; |
87 | 0 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
88 | 0 | wolfCrypt_detail::SetGlobalDs(&ds); |
89 | |
|
90 | 0 | static const uint8_t basepoint[CURVE448_KEY_SIZE] = {5}; |
91 | |
|
92 | 0 | std::optional<std::vector<uint8_t>> priv_bytes = std::nullopt; |
93 | 0 | uint8_t pub_bytes[CURVE448_PUB_KEY_SIZE]; |
94 | | |
95 | | /* Load private key */ |
96 | 0 | { |
97 | 0 | priv_bytes = util::DecToBin(op.priv.ToTrimmedString(), CURVE448_KEY_SIZE); |
98 | 0 | CF_CHECK_NE(priv_bytes, std::nullopt); |
99 | |
|
100 | 0 | priv_bytes->data()[0] &= 0xFC; |
101 | 0 | priv_bytes->data()[55] |= 0x80; static_assert(55 < CURVE448_KEY_SIZE); |
102 | 0 | } |
103 | | |
104 | | /* Convert to public key */ |
105 | 0 | { |
106 | 0 | CF_CHECK_EQ(curve448(pub_bytes, priv_bytes->data(), basepoint), MP_OKAY); |
107 | 0 | } |
108 | | |
109 | | /* Convert public key */ |
110 | 0 | { |
111 | 0 | ret = { util::BinToDec(pub_bytes, sizeof(pub_bytes)), "0" }; |
112 | 0 | } |
113 | |
|
114 | 0 | end: |
115 | 0 | wolfCrypt_detail::UnsetGlobalDs(); |
116 | 0 | return ret; |
117 | 0 | } |
118 | | |
119 | 0 | std::optional<component::ECC_PublicKey> OpECC_PrivateToPublic_Ed448(operation::ECC_PrivateToPublic& op) { |
120 | 0 | std::optional<component::ECC_PublicKey> ret = std::nullopt; |
121 | 0 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
122 | 0 | wolfCrypt_detail::SetGlobalDs(&ds); |
123 | |
|
124 | 0 | uint8_t pub_bytes[ED448_PUB_KEY_SIZE]; |
125 | |
|
126 | 0 | ed448_key key; |
127 | 0 | bool e448_key_inited = false; |
128 | |
|
129 | 0 | WC_CHECK_EQ(wc_ed448_init(&key), 0); |
130 | 0 | e448_key_inited = true; |
131 | | |
132 | | /* Load private key */ |
133 | 0 | { |
134 | 0 | const auto priv_bytes = util::DecToBin(op.priv.ToTrimmedString(), ED448_KEY_SIZE); |
135 | 0 | CF_CHECK_NE(priv_bytes, std::nullopt); |
136 | |
|
137 | 0 | WC_CHECK_EQ(wc_ed448_import_private_only(priv_bytes->data(), priv_bytes->size(), &key), 0); |
138 | 0 | } |
139 | | |
140 | | /* Convert to public key */ |
141 | 0 | { |
142 | 0 | WC_CHECK_EQ(wc_ed448_make_public(&key, pub_bytes, sizeof(pub_bytes)), MP_OKAY); |
143 | 0 | } |
144 | | |
145 | | /* Convert public key */ |
146 | 0 | { |
147 | 0 | ret = { util::BinToDec(pub_bytes, sizeof(pub_bytes)), "0" }; |
148 | 0 | } |
149 | |
|
150 | 0 | end: |
151 | 0 | if ( e448_key_inited == true ) { |
152 | 0 | wc_ed448_free(&key); |
153 | 0 | } |
154 | |
|
155 | 0 | wolfCrypt_detail::UnsetGlobalDs(); |
156 | 0 | return ret; |
157 | 0 | } |
158 | | |
159 | 0 | std::optional<bool> OpECC_ValidatePubkey_Ed448(operation::ECC_ValidatePubkey& op) { |
160 | 0 | std::optional<bool> ret = std::nullopt; |
161 | 0 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
162 | 0 | wolfCrypt_detail::SetGlobalDs(&ds); |
163 | |
|
164 | 0 | ed448_key key; |
165 | 0 | bool e448_key_inited = false; |
166 | |
|
167 | 0 | WC_CHECK_EQ(wc_ed448_init(&key), 0); |
168 | 0 | e448_key_inited = true; |
169 | |
|
170 | 0 | CF_CHECK_EQ(ed448LoadPublicKey(key, op.pub.first, ds), true); |
171 | |
|
172 | 0 | haveAllocFailure = false; |
173 | 0 | ret = wc_ed448_check_key(&key) == 0; |
174 | 0 | if ( *ret == false && haveAllocFailure == true ) { |
175 | 0 | ret = std::nullopt; |
176 | 0 | } |
177 | |
|
178 | 0 | end: |
179 | 0 | if ( e448_key_inited == true ) { |
180 | 0 | wc_ed448_free(&key); |
181 | 0 | } |
182 | |
|
183 | 0 | wolfCrypt_detail::UnsetGlobalDs(); |
184 | 0 | return ret; |
185 | 0 | } |
186 | | |
187 | 0 | std::optional<bool> OpECC_ValidatePubkey_Curve448(operation::ECC_ValidatePubkey& op) { |
188 | 0 | std::optional<bool> ret = std::nullopt; |
189 | 0 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
190 | 0 | wolfCrypt_detail::SetGlobalDs(&ds); |
191 | |
|
192 | 0 | wolfCrypt_bignum::Bignum pub(ds); |
193 | 0 | uint8_t pub_bytes[CURVE448_KEY_SIZE]; |
194 | |
|
195 | 0 | CF_CHECK_EQ(pub.Set(op.pub.first.ToString(ds)), true); |
196 | 0 | CF_CHECK_TRUE(pub.ToBin(pub_bytes, sizeof(pub_bytes))); |
197 | |
|
198 | 0 | haveAllocFailure = false; |
199 | 0 | ret = wc_curve448_check_public(pub_bytes, sizeof(pub_bytes), EC448_BIG_ENDIAN) == 0; |
200 | 0 | if ( *ret == false && haveAllocFailure == true ) { |
201 | 0 | ret = std::nullopt; |
202 | 0 | } |
203 | |
|
204 | 0 | end: |
205 | |
|
206 | 0 | wolfCrypt_detail::UnsetGlobalDs(); |
207 | 0 | return ret; |
208 | 0 | } |
209 | | |
210 | 0 | std::optional<component::ECDSA_Signature> OpECDSA_Sign_ed448(operation::ECDSA_Sign& op) { |
211 | 0 | std::optional<component::ECDSA_Signature> ret = std::nullopt; |
212 | 0 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
213 | 0 | wolfCrypt_detail::SetGlobalDs(&ds); |
214 | |
|
215 | 0 | ed448_key key; |
216 | 0 | bool e448_key_inited = false; |
217 | 0 | uint8_t sig[ED448_SIG_SIZE]; |
218 | 0 | word32 sigSz = sizeof(sig); |
219 | |
|
220 | 0 | WC_CHECK_EQ(wc_ed448_init(&key), 0); |
221 | 0 | e448_key_inited = true; |
222 | |
|
223 | 0 | CF_CHECK_EQ(wolfCrypt_detail::ed448LoadPrivateKey(key, op.priv, ds), true); |
224 | 0 | CF_CHECK_EQ(wolfCrypt_detail::ed448DerivePublicKey(key), true); |
225 | | |
226 | | /* Sign message */ |
227 | 0 | WC_CHECK_EQ(wc_ed448_sign_msg(op.cleartext.GetPtr(), op.cleartext.GetSize(), sig, &sigSz, &key, nullptr, 0), MP_OKAY); |
228 | 0 | CF_CHECK_EQ(sigSz, ED448_SIG_SIZE); |
229 | 0 | static_assert(ED448_SIG_SIZE % 2 == 0); |
230 | |
|
231 | 0 | { |
232 | 0 | std::optional<component::BignumPair> ret_sig; |
233 | 0 | std::optional<component::BignumPair> ret_pub; |
234 | |
|
235 | 0 | CF_CHECK_NE(ret_sig = wolfCrypt_bignum::Bignum::BinToBignumPair(ds, sig, ED448_SIG_SIZE), std::nullopt); |
236 | 0 | CF_CHECK_NE(ret_pub = wolfCrypt_detail::ed448GetPublicKey(key, ds), std::nullopt); |
237 | |
|
238 | 0 | ret = component::ECDSA_Signature(*ret_sig, *ret_pub); |
239 | 0 | } |
240 | | |
241 | 0 | end: |
242 | 0 | if ( e448_key_inited == true ) { |
243 | 0 | wc_ed448_free(&key); |
244 | 0 | } |
245 | |
|
246 | 0 | wolfCrypt_detail::UnsetGlobalDs(); |
247 | 0 | return ret; |
248 | 0 | } |
249 | | |
250 | 0 | std::optional<bool> OpECDSA_Verify_ed448(operation::ECDSA_Verify& op) { |
251 | 0 | std::optional<bool> ret = std::nullopt; |
252 | 0 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
253 | 0 | wolfCrypt_detail::SetGlobalDs(&ds); |
254 | |
|
255 | 0 | ed448_key key; |
256 | 0 | bool e448_key_inited = false; |
257 | 0 | uint8_t ed448sig[ED448_SIG_SIZE]; |
258 | 0 | int verify; |
259 | 0 | bool oneShot = true; |
260 | 0 | bool haveEmptyPart = false; |
261 | |
|
262 | 0 | haveAllocFailure = false; |
263 | 0 | ret = false; |
264 | |
|
265 | 0 | WC_CHECK_EQ(wc_ed448_init(&key), 0); |
266 | 0 | e448_key_inited = true; |
267 | |
|
268 | 0 | CF_CHECK_EQ(ed448LoadPublicKey(key, op.signature.pub.first, ds, true), true); |
269 | 0 | CF_CHECK_EQ(wolfCrypt_bignum::Bignum::ToBin(ds, op.signature.signature, ed448sig, sizeof(ed448sig), true), true); |
270 | |
|
271 | 0 | #if defined(WOLFSSL_ED25519_STREAMING_VERIFY) |
272 | 0 | try { oneShot = ds.Get<bool>(); } catch ( ... ) { } |
273 | 0 | #endif |
274 | |
|
275 | 0 | if ( oneShot == true ) { |
276 | 0 | WC_CHECK_EQ(wc_ed448_verify_msg(ed448sig, sizeof(ed448sig), op.cleartext.GetPtr(), op.cleartext.GetSize(), &verify, &key, nullptr, 0), 0); |
277 | 0 | } else { |
278 | | #if !defined(WOLFSSL_ED25519_STREAMING_VERIFY) |
279 | | CF_UNREACHABLE(); |
280 | | #else |
281 | 0 | const auto parts = util::ToParts(ds, op.cleartext); |
282 | |
|
283 | 0 | WC_CHECK_EQ(wc_ed448_verify_msg_init(ed448sig, sizeof(ed448sig), &key, (byte)Ed448, nullptr, 0), 0); |
284 | |
|
285 | 0 | for (const auto& part : parts) { |
286 | 0 | if ( part.second == 0 ) { |
287 | 0 | haveEmptyPart = true; |
288 | 0 | } |
289 | 0 | WC_CHECK_EQ(wc_ed448_verify_msg_update(part.first, part.second, &key), 0); |
290 | 0 | } |
291 | | |
292 | 0 | WC_CHECK_EQ(wc_ed448_verify_msg_final(ed448sig, sizeof(ed448sig), &verify, &key), 0); |
293 | 0 | #endif |
294 | 0 | } |
295 | | |
296 | 0 | ret = verify ? true : false; |
297 | |
|
298 | 0 | end: |
299 | 0 | if ( e448_key_inited == true ) { |
300 | 0 | wc_ed448_free(&key); |
301 | 0 | } |
302 | |
|
303 | 0 | wolfCrypt_detail::UnsetGlobalDs(); |
304 | |
|
305 | 0 | if ( ret && *ret == false ) { |
306 | 0 | if ( haveAllocFailure ) { |
307 | 0 | ret = std::nullopt; |
308 | 0 | } else if ( haveEmptyPart ) { |
309 | 0 | ret = std::nullopt; |
310 | 0 | } else if ( op.cleartext.IsZero() ) { |
311 | 0 | ret = std::nullopt; |
312 | 0 | } |
313 | |
|
314 | 0 | } |
315 | 0 | return ret; |
316 | 0 | } |
317 | | |
318 | | } /* namespace wolfCrypt_detail */ |
319 | | } /* namespace module */ |
320 | | } /* namespace cryptofuzz */ |