/src/cryptofuzz/modules/bitcoin/module.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "module.h" |
2 | | #include <cryptofuzz/util.h> |
3 | | #include <cryptofuzz/repository.h> |
4 | | #include <fuzzing/datasource/id.hpp> |
5 | | #include <memory> |
6 | | |
7 | | #include "crypto/sha1.cpp" |
8 | | #include "crypto/sha256.cpp" |
9 | | #include "crypto/sha512.cpp" |
10 | | #include "crypto/sha3.cpp" |
11 | | #include "crypto/ripemd160.cpp" |
12 | | |
13 | | #include "crypto/hmac_sha256.cpp" |
14 | | #include "crypto/hmac_sha512.cpp" |
15 | | |
16 | | #include "crypto/hkdf_sha256_32.cpp" |
17 | | |
18 | | #include "crypto/aes.cpp" |
19 | | #include "crypto/chacha20.cpp" |
20 | | #include "crypto/poly1305.cpp" |
21 | | #include "crypto/chacha_poly_aead.cpp" |
22 | | |
23 | | #include "crypto/siphash.cpp" |
24 | | |
25 | | #include "uint256.cpp" |
26 | | #include "arith_uint256.cpp" |
27 | | |
28 | | #include "cleanse.cpp" |
29 | | #include "util/strencodings.cpp" |
30 | | |
31 | | namespace cryptofuzz { |
32 | | namespace module { |
33 | | |
34 | | Bitcoin::Bitcoin(void) : |
35 | 6 | Module("Bitcoin") { } |
36 | | |
37 | | namespace Bitcoin_detail { |
38 | | |
39 | | template <class Alg> |
40 | 118k | void digest_write(std::shared_ptr<Alg> alg, const uint8_t* data, const size_t size) { |
41 | 118k | alg->Write(data, size); |
42 | 118k | } void cryptofuzz::module::Bitcoin_detail::digest_write<CSHA1>(std::__1::shared_ptr<CSHA1>, unsigned char const*, unsigned long) Line | Count | Source | 40 | 27.2k | void digest_write(std::shared_ptr<Alg> alg, const uint8_t* data, const size_t size) { | 41 | 27.2k | alg->Write(data, size); | 42 | 27.2k | } |
void cryptofuzz::module::Bitcoin_detail::digest_write<CSHA256>(std::__1::shared_ptr<CSHA256>, unsigned char const*, unsigned long) Line | Count | Source | 40 | 20.5k | void digest_write(std::shared_ptr<Alg> alg, const uint8_t* data, const size_t size) { | 41 | 20.5k | alg->Write(data, size); | 42 | 20.5k | } |
void cryptofuzz::module::Bitcoin_detail::digest_write<CSHA512>(std::__1::shared_ptr<CSHA512>, unsigned char const*, unsigned long) Line | Count | Source | 40 | 26.0k | void digest_write(std::shared_ptr<Alg> alg, const uint8_t* data, const size_t size) { | 41 | 26.0k | alg->Write(data, size); | 42 | 26.0k | } |
void cryptofuzz::module::Bitcoin_detail::digest_write<CRIPEMD160>(std::__1::shared_ptr<CRIPEMD160>, unsigned char const*, unsigned long) Line | Count | Source | 40 | 44.5k | void digest_write(std::shared_ptr<Alg> alg, const uint8_t* data, const size_t size) { | 41 | 44.5k | alg->Write(data, size); | 42 | 44.5k | } |
|
43 | | |
44 | | template <> |
45 | 15.6k | void digest_write(std::shared_ptr<SHA3_256> alg, const uint8_t* data, const size_t size) { |
46 | 15.6k | alg->Write({data, size}); |
47 | 15.6k | } |
48 | | |
49 | | template <class Alg> |
50 | 1.46k | std::optional<component::Digest> digest(operation::Digest& op, Datasource& ds) { |
51 | 1.46k | std::optional<component::Digest> ret = std::nullopt; |
52 | | |
53 | 1.46k | size_t numResets = 0; |
54 | 1.46k | util::Multipart parts; |
55 | 1.46k | std::shared_ptr<Alg> alg = nullptr; |
56 | | |
57 | | /* Initialize */ |
58 | 1.46k | { |
59 | 1.46k | parts = util::ToParts(ds, op.cleartext); |
60 | 1.46k | alg = std::make_shared<Alg>(); |
61 | 1.46k | } |
62 | | |
63 | 1.84k | again: |
64 | | |
65 | | /* Process */ |
66 | 134k | for (const auto& part : parts) { |
67 | 134k | digest_write(alg, part.first, part.second); |
68 | 134k | try { |
69 | 134k | if ( numResets < 5 && ds.Get<bool>() ) { |
70 | 386 | alg->Reset(); |
71 | 386 | numResets++; |
72 | 386 | goto again; |
73 | 386 | } |
74 | 134k | } catch ( fuzzing::datasource::Datasource::OutOfData ) { |
75 | 133k | } |
76 | 134k | } |
77 | | |
78 | | /* Finalize */ |
79 | 1.46k | { |
80 | 1.46k | uint8_t out[Alg::OUTPUT_SIZE]; |
81 | 1.46k | alg->Finalize(out); |
82 | 1.46k | ret = component::Digest(out, Alg::OUTPUT_SIZE); |
83 | 1.46k | } |
84 | | |
85 | 1.46k | return ret; |
86 | 1.84k | } std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::digest<CSHA1>(cryptofuzz::operation::Digest&, fuzzing::datasource::Datasource&) Line | Count | Source | 50 | 320 | std::optional<component::Digest> digest(operation::Digest& op, Datasource& ds) { | 51 | 320 | std::optional<component::Digest> ret = std::nullopt; | 52 | | | 53 | 320 | size_t numResets = 0; | 54 | 320 | util::Multipart parts; | 55 | 320 | std::shared_ptr<Alg> alg = nullptr; | 56 | | | 57 | | /* Initialize */ | 58 | 320 | { | 59 | 320 | parts = util::ToParts(ds, op.cleartext); | 60 | 320 | alg = std::make_shared<Alg>(); | 61 | 320 | } | 62 | | | 63 | 402 | again: | 64 | | | 65 | | /* Process */ | 66 | 27.2k | for (const auto& part : parts) { | 67 | 27.2k | digest_write(alg, part.first, part.second); | 68 | 27.2k | try { | 69 | 27.2k | if ( numResets < 5 && ds.Get<bool>() ) { | 70 | 82 | alg->Reset(); | 71 | 82 | numResets++; | 72 | 82 | goto again; | 73 | 82 | } | 74 | 27.2k | } catch ( fuzzing::datasource::Datasource::OutOfData ) { | 75 | 27.1k | } | 76 | 27.2k | } | 77 | | | 78 | | /* Finalize */ | 79 | 320 | { | 80 | 320 | uint8_t out[Alg::OUTPUT_SIZE]; | 81 | 320 | alg->Finalize(out); | 82 | 320 | ret = component::Digest(out, Alg::OUTPUT_SIZE); | 83 | 320 | } | 84 | | | 85 | 320 | return ret; | 86 | 402 | } |
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::digest<CSHA256>(cryptofuzz::operation::Digest&, fuzzing::datasource::Datasource&) Line | Count | Source | 50 | 244 | std::optional<component::Digest> digest(operation::Digest& op, Datasource& ds) { | 51 | 244 | std::optional<component::Digest> ret = std::nullopt; | 52 | | | 53 | 244 | size_t numResets = 0; | 54 | 244 | util::Multipart parts; | 55 | 244 | std::shared_ptr<Alg> alg = nullptr; | 56 | | | 57 | | /* Initialize */ | 58 | 244 | { | 59 | 244 | parts = util::ToParts(ds, op.cleartext); | 60 | 244 | alg = std::make_shared<Alg>(); | 61 | 244 | } | 62 | | | 63 | 313 | again: | 64 | | | 65 | | /* Process */ | 66 | 20.5k | for (const auto& part : parts) { | 67 | 20.5k | digest_write(alg, part.first, part.second); | 68 | 20.5k | try { | 69 | 20.5k | if ( numResets < 5 && ds.Get<bool>() ) { | 70 | 69 | alg->Reset(); | 71 | 69 | numResets++; | 72 | 69 | goto again; | 73 | 69 | } | 74 | 20.5k | } catch ( fuzzing::datasource::Datasource::OutOfData ) { | 75 | 20.4k | } | 76 | 20.5k | } | 77 | | | 78 | | /* Finalize */ | 79 | 244 | { | 80 | 244 | uint8_t out[Alg::OUTPUT_SIZE]; | 81 | 244 | alg->Finalize(out); | 82 | 244 | ret = component::Digest(out, Alg::OUTPUT_SIZE); | 83 | 244 | } | 84 | | | 85 | 244 | return ret; | 86 | 313 | } |
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::digest<CSHA512>(cryptofuzz::operation::Digest&, fuzzing::datasource::Datasource&) Line | Count | Source | 50 | 252 | std::optional<component::Digest> digest(operation::Digest& op, Datasource& ds) { | 51 | 252 | std::optional<component::Digest> ret = std::nullopt; | 52 | | | 53 | 252 | size_t numResets = 0; | 54 | 252 | util::Multipart parts; | 55 | 252 | std::shared_ptr<Alg> alg = nullptr; | 56 | | | 57 | | /* Initialize */ | 58 | 252 | { | 59 | 252 | parts = util::ToParts(ds, op.cleartext); | 60 | 252 | alg = std::make_shared<Alg>(); | 61 | 252 | } | 62 | | | 63 | 333 | again: | 64 | | | 65 | | /* Process */ | 66 | 26.0k | for (const auto& part : parts) { | 67 | 26.0k | digest_write(alg, part.first, part.second); | 68 | 26.0k | try { | 69 | 26.0k | if ( numResets < 5 && ds.Get<bool>() ) { | 70 | 81 | alg->Reset(); | 71 | 81 | numResets++; | 72 | 81 | goto again; | 73 | 81 | } | 74 | 26.0k | } catch ( fuzzing::datasource::Datasource::OutOfData ) { | 75 | 25.9k | } | 76 | 26.0k | } | 77 | | | 78 | | /* Finalize */ | 79 | 252 | { | 80 | 252 | uint8_t out[Alg::OUTPUT_SIZE]; | 81 | 252 | alg->Finalize(out); | 82 | 252 | ret = component::Digest(out, Alg::OUTPUT_SIZE); | 83 | 252 | } | 84 | | | 85 | 252 | return ret; | 86 | 333 | } |
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::digest<CRIPEMD160>(cryptofuzz::operation::Digest&, fuzzing::datasource::Datasource&) Line | Count | Source | 50 | 335 | std::optional<component::Digest> digest(operation::Digest& op, Datasource& ds) { | 51 | 335 | std::optional<component::Digest> ret = std::nullopt; | 52 | | | 53 | 335 | size_t numResets = 0; | 54 | 335 | util::Multipart parts; | 55 | 335 | std::shared_ptr<Alg> alg = nullptr; | 56 | | | 57 | | /* Initialize */ | 58 | 335 | { | 59 | 335 | parts = util::ToParts(ds, op.cleartext); | 60 | 335 | alg = std::make_shared<Alg>(); | 61 | 335 | } | 62 | | | 63 | 404 | again: | 64 | | | 65 | | /* Process */ | 66 | 44.5k | for (const auto& part : parts) { | 67 | 44.5k | digest_write(alg, part.first, part.second); | 68 | 44.5k | try { | 69 | 44.5k | if ( numResets < 5 && ds.Get<bool>() ) { | 70 | 69 | alg->Reset(); | 71 | 69 | numResets++; | 72 | 69 | goto again; | 73 | 69 | } | 74 | 44.5k | } catch ( fuzzing::datasource::Datasource::OutOfData ) { | 75 | 44.4k | } | 76 | 44.5k | } | 77 | | | 78 | | /* Finalize */ | 79 | 335 | { | 80 | 335 | uint8_t out[Alg::OUTPUT_SIZE]; | 81 | 335 | alg->Finalize(out); | 82 | 335 | ret = component::Digest(out, Alg::OUTPUT_SIZE); | 83 | 335 | } | 84 | | | 85 | 335 | return ret; | 86 | 404 | } |
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::digest<SHA3_256>(cryptofuzz::operation::Digest&, fuzzing::datasource::Datasource&) Line | Count | Source | 50 | 310 | std::optional<component::Digest> digest(operation::Digest& op, Datasource& ds) { | 51 | 310 | std::optional<component::Digest> ret = std::nullopt; | 52 | | | 53 | 310 | size_t numResets = 0; | 54 | 310 | util::Multipart parts; | 55 | 310 | std::shared_ptr<Alg> alg = nullptr; | 56 | | | 57 | | /* Initialize */ | 58 | 310 | { | 59 | 310 | parts = util::ToParts(ds, op.cleartext); | 60 | 310 | alg = std::make_shared<Alg>(); | 61 | 310 | } | 62 | | | 63 | 395 | again: | 64 | | | 65 | | /* Process */ | 66 | 15.6k | for (const auto& part : parts) { | 67 | 15.6k | digest_write(alg, part.first, part.second); | 68 | 15.6k | try { | 69 | 15.6k | if ( numResets < 5 && ds.Get<bool>() ) { | 70 | 85 | alg->Reset(); | 71 | 85 | numResets++; | 72 | 85 | goto again; | 73 | 85 | } | 74 | 15.6k | } catch ( fuzzing::datasource::Datasource::OutOfData ) { | 75 | 15.5k | } | 76 | 15.6k | } | 77 | | | 78 | | /* Finalize */ | 79 | 310 | { | 80 | 310 | uint8_t out[Alg::OUTPUT_SIZE]; | 81 | 310 | alg->Finalize(out); | 82 | 310 | ret = component::Digest(out, Alg::OUTPUT_SIZE); | 83 | 310 | } | 84 | | | 85 | 310 | return ret; | 86 | 395 | } |
|
87 | | |
88 | | } /* namespace Bitcoin_detail */ |
89 | | |
90 | 1.48k | std::optional<component::Digest> Bitcoin::OpDigest(operation::Digest& op) { |
91 | 1.48k | std::optional<component::Digest> ret = std::nullopt; |
92 | | |
93 | 1.48k | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
94 | | |
95 | 1.48k | switch ( op.digestType.Get() ) { |
96 | 320 | case CF_DIGEST("SHA1"): |
97 | 320 | return Bitcoin_detail::digest<CSHA1>(op, ds); |
98 | 244 | case CF_DIGEST("SHA256"): |
99 | 244 | return Bitcoin_detail::digest<CSHA256>(op, ds); |
100 | 252 | case CF_DIGEST("SHA512"): |
101 | 252 | return Bitcoin_detail::digest<CSHA512>(op, ds); |
102 | 335 | case CF_DIGEST("RIPEMD160"): |
103 | 335 | return Bitcoin_detail::digest<CRIPEMD160>(op, ds); |
104 | 310 | case CF_DIGEST("SHA3-256"): |
105 | 310 | return Bitcoin_detail::digest<SHA3_256>(op, ds); |
106 | 1.48k | } |
107 | | |
108 | 27 | return ret; |
109 | 1.48k | } |
110 | | |
111 | | namespace Bitcoin_detail { |
112 | | |
113 | | template <class Alg> |
114 | 528 | std::optional<component::MAC> hmac(operation::HMAC& op, Datasource& ds) { |
115 | 528 | std::optional<component::MAC> ret = std::nullopt; |
116 | | |
117 | 528 | util::Multipart parts; |
118 | 528 | std::unique_ptr<Alg> alg = nullptr; |
119 | | |
120 | | /* Initialize */ |
121 | 528 | { |
122 | 528 | parts = util::ToParts(ds, op.cleartext); |
123 | 528 | alg = std::make_unique<Alg>(op.cipher.key.GetPtr(), op.cipher.key.GetSize()); |
124 | 528 | } |
125 | | |
126 | | /* Process */ |
127 | 34.2k | for (const auto& part : parts) { |
128 | 34.2k | alg->Write(part.first, part.second); |
129 | 34.2k | } |
130 | | |
131 | | /* Finalize */ |
132 | 528 | { |
133 | 528 | uint8_t out[Alg::OUTPUT_SIZE]; |
134 | 528 | alg->Finalize(out); |
135 | 528 | ret = component::MAC(out, Alg::OUTPUT_SIZE); |
136 | 528 | } |
137 | | |
138 | 528 | return ret; |
139 | 528 | } std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::hmac<CHMAC_SHA256>(cryptofuzz::operation::HMAC&, fuzzing::datasource::Datasource&) Line | Count | Source | 114 | 245 | std::optional<component::MAC> hmac(operation::HMAC& op, Datasource& ds) { | 115 | 245 | std::optional<component::MAC> ret = std::nullopt; | 116 | | | 117 | 245 | util::Multipart parts; | 118 | 245 | std::unique_ptr<Alg> alg = nullptr; | 119 | | | 120 | | /* Initialize */ | 121 | 245 | { | 122 | 245 | parts = util::ToParts(ds, op.cleartext); | 123 | 245 | alg = std::make_unique<Alg>(op.cipher.key.GetPtr(), op.cipher.key.GetSize()); | 124 | 245 | } | 125 | | | 126 | | /* Process */ | 127 | 17.7k | for (const auto& part : parts) { | 128 | 17.7k | alg->Write(part.first, part.second); | 129 | 17.7k | } | 130 | | | 131 | | /* Finalize */ | 132 | 245 | { | 133 | 245 | uint8_t out[Alg::OUTPUT_SIZE]; | 134 | 245 | alg->Finalize(out); | 135 | 245 | ret = component::MAC(out, Alg::OUTPUT_SIZE); | 136 | 245 | } | 137 | | | 138 | 245 | return ret; | 139 | 245 | } |
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::hmac<CHMAC_SHA512>(cryptofuzz::operation::HMAC&, fuzzing::datasource::Datasource&) Line | Count | Source | 114 | 283 | std::optional<component::MAC> hmac(operation::HMAC& op, Datasource& ds) { | 115 | 283 | std::optional<component::MAC> ret = std::nullopt; | 116 | | | 117 | 283 | util::Multipart parts; | 118 | 283 | std::unique_ptr<Alg> alg = nullptr; | 119 | | | 120 | | /* Initialize */ | 121 | 283 | { | 122 | 283 | parts = util::ToParts(ds, op.cleartext); | 123 | 283 | alg = std::make_unique<Alg>(op.cipher.key.GetPtr(), op.cipher.key.GetSize()); | 124 | 283 | } | 125 | | | 126 | | /* Process */ | 127 | 16.5k | for (const auto& part : parts) { | 128 | 16.5k | alg->Write(part.first, part.second); | 129 | 16.5k | } | 130 | | | 131 | | /* Finalize */ | 132 | 283 | { | 133 | 283 | uint8_t out[Alg::OUTPUT_SIZE]; | 134 | 283 | alg->Finalize(out); | 135 | 283 | ret = component::MAC(out, Alg::OUTPUT_SIZE); | 136 | 283 | } | 137 | | | 138 | 283 | return ret; | 139 | 283 | } |
|
140 | | |
141 | | } /* namespace Bitcoin_detail */ |
142 | | |
143 | | namespace Bitcoin_detail { |
144 | 202 | static std::optional<component::Digest> SipHash64(operation::HMAC& op, Datasource& ds) { |
145 | 202 | std::optional<component::Digest> ret = std::nullopt; |
146 | | |
147 | 202 | util::Multipart parts; |
148 | 202 | std::unique_ptr<CSipHasher> alg = nullptr; |
149 | | |
150 | | /* Initialize */ |
151 | 202 | { |
152 | 202 | if ( op.cipher.key.GetSize() != 16 ) { |
153 | 29 | return ret; |
154 | 29 | } |
155 | | |
156 | 173 | uint64_t key[2]; |
157 | 173 | memcpy(&key[0], op.cipher.key.GetPtr(), 8); |
158 | 173 | memcpy(&key[1], op.cipher.key.GetPtr() + 8, 8); |
159 | | |
160 | 173 | if ( op.cleartext.GetSize() == 32 || op.cleartext.GetSize() == 36 ) { |
161 | 5 | bool oneShot = false; |
162 | 5 | try { |
163 | 5 | oneShot = ds.Get<bool>(); |
164 | 5 | } catch ( ... ) { } |
165 | | |
166 | 5 | if ( oneShot == true ) { |
167 | 3 | uint64_t out; |
168 | | |
169 | 3 | if ( op.cleartext.GetSize() == 32 ) { |
170 | 1 | out = SipHashUint256(key[0], key[1], uint256(op.cleartext.Get())); |
171 | 2 | } else if ( op.cleartext.GetSize() == 36 ) { |
172 | 2 | uint8_t in[32]; |
173 | 2 | uint32_t extra; |
174 | | |
175 | 2 | memcpy(in, op.cleartext.GetPtr(), sizeof(in)); |
176 | 2 | memcpy(&extra, op.cleartext.GetPtr() + 32, sizeof(extra)); |
177 | | |
178 | 2 | out = SipHashUint256Extra( |
179 | 2 | key[0], |
180 | 2 | key[1], |
181 | 2 | uint256(std::vector<uint8_t>(in, in + sizeof(in))), |
182 | 2 | extra); |
183 | 2 | } else { |
184 | 0 | abort(); |
185 | 0 | } |
186 | | |
187 | 3 | ret = component::Digest((const uint8_t*)&out, sizeof(out)); |
188 | | |
189 | 3 | return ret; |
190 | 3 | } |
191 | 5 | } |
192 | | |
193 | 170 | alg = std::make_unique<CSipHasher>(key[0], key[1]); |
194 | | |
195 | | //if ( op.cleartext.GetSize() > 0 && (op.cleartext.GetSize() % 8) == 0 && ds.Get<bool>() == true ) { |
196 | 170 | if ( (op.cleartext.GetSize() % 8) == 0 && ds.Get<bool>() == true ) { |
197 | 5.07k | for (size_t i = 0; i < op.cleartext.GetSize(); i += 8) { |
198 | 5.04k | uint64_t v; |
199 | 5.04k | memcpy(&v, op.cleartext.GetPtr() + i, sizeof(v)); |
200 | 5.04k | alg->Write(v); |
201 | 5.04k | } |
202 | | |
203 | 28 | const auto out = alg->Finalize(); |
204 | 28 | ret = component::Digest((const uint8_t*)&out, sizeof(out)); |
205 | | |
206 | 28 | return ret; |
207 | 28 | } |
208 | | |
209 | | |
210 | 142 | parts = util::ToParts(ds, op.cleartext); |
211 | 142 | } |
212 | | |
213 | | /* Process */ |
214 | 0 | { |
215 | 12.0k | for (const auto& part : parts) { |
216 | 12.0k | alg->Write(part.first, part.second); |
217 | 12.0k | } |
218 | 142 | } |
219 | | |
220 | | /* Finalize */ |
221 | 142 | { |
222 | 142 | const auto out = alg->Finalize(); |
223 | 142 | ret = component::Digest((const uint8_t*)&out, sizeof(out)); |
224 | 142 | } |
225 | | |
226 | 142 | return ret; |
227 | 170 | } |
228 | | } |
229 | | |
230 | 842 | std::optional<component::MAC> Bitcoin::OpHMAC(operation::HMAC& op) { |
231 | 842 | std::optional<component::MAC> ret = std::nullopt; |
232 | | |
233 | 842 | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
234 | | |
235 | 842 | switch ( op.digestType.Get() ) { |
236 | 245 | case CF_DIGEST("SHA256"): |
237 | 245 | return Bitcoin_detail::hmac<CHMAC_SHA256>(op, ds); |
238 | 283 | case CF_DIGEST("SHA512"): |
239 | 283 | return Bitcoin_detail::hmac<CHMAC_SHA512>(op, ds); |
240 | 202 | case CF_DIGEST("SIPHASH64"): |
241 | 202 | return Bitcoin_detail::SipHash64(op, ds); |
242 | 842 | } |
243 | | |
244 | 112 | return ret; |
245 | 842 | } |
246 | | |
247 | | namespace Bitcoin_detail { |
248 | | template <class T> |
249 | 696 | std::optional<T> chacha20(const Buffer& key, const Buffer& iv, const Buffer& in) { |
250 | 696 | std::optional<T> ret = std::nullopt; |
251 | | |
252 | 696 | if ( key.GetSize() != 16 && key.GetSize() != 32 ) { |
253 | 135 | return ret; |
254 | 135 | } |
255 | 561 | if ( iv.GetSize() != 8 ) { |
256 | 255 | return std::nullopt; |
257 | 255 | } |
258 | | |
259 | 306 | uint64_t iv_uint64_t; |
260 | | |
261 | 306 | ChaCha20 cc20(key.GetPtr(), key.GetSize()); |
262 | | |
263 | 306 | memcpy(&iv_uint64_t, iv.GetPtr(), sizeof(iv_uint64_t)); |
264 | 306 | cc20.SetIV(iv_uint64_t); |
265 | | |
266 | 306 | uint8_t* out = util::malloc(in.GetSize()); |
267 | | |
268 | 306 | CF_NORET(cc20.Crypt(in.GetPtr(), out, in.GetSize())); |
269 | | |
270 | 306 | ret = T(Buffer(out, in.GetSize())); |
271 | 306 | util::free(out); |
272 | | |
273 | 306 | return ret; |
274 | 561 | } std::__1::optional<cryptofuzz::component::Ciphertext> cryptofuzz::module::Bitcoin_detail::chacha20<cryptofuzz::component::Ciphertext>(cryptofuzz::Buffer const&, cryptofuzz::Buffer const&, cryptofuzz::Buffer const&) Line | Count | Source | 249 | 318 | std::optional<T> chacha20(const Buffer& key, const Buffer& iv, const Buffer& in) { | 250 | 318 | std::optional<T> ret = std::nullopt; | 251 | | | 252 | 318 | if ( key.GetSize() != 16 && key.GetSize() != 32 ) { | 253 | 63 | return ret; | 254 | 63 | } | 255 | 255 | if ( iv.GetSize() != 8 ) { | 256 | 142 | return std::nullopt; | 257 | 142 | } | 258 | | | 259 | 113 | uint64_t iv_uint64_t; | 260 | | | 261 | 113 | ChaCha20 cc20(key.GetPtr(), key.GetSize()); | 262 | | | 263 | 113 | memcpy(&iv_uint64_t, iv.GetPtr(), sizeof(iv_uint64_t)); | 264 | 113 | cc20.SetIV(iv_uint64_t); | 265 | | | 266 | 113 | uint8_t* out = util::malloc(in.GetSize()); | 267 | | | 268 | 113 | CF_NORET(cc20.Crypt(in.GetPtr(), out, in.GetSize())); | 269 | | | 270 | 113 | ret = T(Buffer(out, in.GetSize())); | 271 | 113 | util::free(out); | 272 | | | 273 | 113 | return ret; | 274 | 255 | } |
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::chacha20<cryptofuzz::Buffer>(cryptofuzz::Buffer const&, cryptofuzz::Buffer const&, cryptofuzz::Buffer const&) Line | Count | Source | 249 | 378 | std::optional<T> chacha20(const Buffer& key, const Buffer& iv, const Buffer& in) { | 250 | 378 | std::optional<T> ret = std::nullopt; | 251 | | | 252 | 378 | if ( key.GetSize() != 16 && key.GetSize() != 32 ) { | 253 | 72 | return ret; | 254 | 72 | } | 255 | 306 | if ( iv.GetSize() != 8 ) { | 256 | 113 | return std::nullopt; | 257 | 113 | } | 258 | | | 259 | 193 | uint64_t iv_uint64_t; | 260 | | | 261 | 193 | ChaCha20 cc20(key.GetPtr(), key.GetSize()); | 262 | | | 263 | 193 | memcpy(&iv_uint64_t, iv.GetPtr(), sizeof(iv_uint64_t)); | 264 | 193 | cc20.SetIV(iv_uint64_t); | 265 | | | 266 | 193 | uint8_t* out = util::malloc(in.GetSize()); | 267 | | | 268 | 193 | CF_NORET(cc20.Crypt(in.GetPtr(), out, in.GetSize())); | 269 | | | 270 | 193 | ret = T(Buffer(out, in.GetSize())); | 271 | 193 | util::free(out); | 272 | | | 273 | 193 | return ret; | 274 | 306 | } |
|
275 | | |
276 | 0 | std::optional<component::Ciphertext> chacha20_poly1305(const operation::SymmetricEncrypt& op) { |
277 | 0 | std::optional<component::Ciphertext> ret = std::nullopt; |
278 | |
|
279 | 0 | if ( op.cipher.key.GetSize() != CHACHA20_POLY1305_AEAD_KEY_LEN ) { |
280 | 0 | return ret; |
281 | 0 | } |
282 | | |
283 | 0 | if ( op.aad == std::nullopt || op.aad->GetSize() != CHACHA20_POLY1305_AEAD_KEY_LEN ) { |
284 | 0 | return ret; |
285 | 0 | } |
286 | | |
287 | 0 | if ( op.tagSize == std::nullopt || *op.tagSize != POLY1305_TAGLEN ) { |
288 | 0 | return ret; |
289 | 0 | } |
290 | | |
291 | 0 | if ( op.cipher.iv.GetSize() != 12 ) { |
292 | 0 | return ret; |
293 | 0 | } |
294 | | |
295 | 0 | uint64_t seqnr_payload, seqnr_aad; |
296 | 0 | memcpy(&seqnr_payload, op.cipher.iv.GetPtr(), sizeof(seqnr_payload)); |
297 | 0 | memcpy(&seqnr_aad, op.cipher.iv.GetPtr() + sizeof(seqnr_payload), sizeof(seqnr_aad)); |
298 | |
|
299 | 0 | uint8_t* out = util::malloc(op.ciphertextSize); |
300 | |
|
301 | 0 | ChaCha20Poly1305AEAD aead(op.cipher.key.GetPtr(), op.cipher.key.GetSize(), op.aad->GetPtr(), op.aad->GetSize()); |
302 | |
|
303 | 0 | CF_CHECK_TRUE(aead.Crypt(seqnr_payload, seqnr_aad, 0, out, op.ciphertextSize, op.cleartext.GetPtr(), op.cleartext.GetSize(), true)); |
304 | |
|
305 | 0 | CF_ASSERT(op.ciphertextSize >= op.cleartext.GetSize() + POLY1305_TAGLEN, "ChaCha20Poly1305AEAD succeeded with invalid output size"); |
306 | |
|
307 | 0 | ret = component::Ciphertext( |
308 | 0 | Buffer(out, op.cleartext.GetSize()), |
309 | 0 | Buffer(out + op.cleartext.GetSize(), POLY1305_TAGLEN)); |
310 | |
|
311 | 0 | end: |
312 | 0 | util::free(out); |
313 | |
|
314 | 0 | return ret; |
315 | 0 | } |
316 | | |
317 | 0 | std::optional<component::Cleartext> chacha20_poly1305(const operation::SymmetricDecrypt& op) { |
318 | 0 | std::optional<component::Cleartext> ret = std::nullopt; |
319 | |
|
320 | 0 | if ( op.cipher.key.GetSize() != CHACHA20_POLY1305_AEAD_KEY_LEN ) { |
321 | 0 | return ret; |
322 | 0 | } |
323 | | |
324 | 0 | if ( op.aad == std::nullopt || op.aad->GetSize() != CHACHA20_POLY1305_AEAD_KEY_LEN ) { |
325 | 0 | return ret; |
326 | 0 | } |
327 | | |
328 | 0 | if ( op.tag == std::nullopt || op.tag->GetSize() != POLY1305_TAGLEN ) { |
329 | 0 | return ret; |
330 | 0 | } |
331 | | |
332 | 0 | if ( op.cipher.iv.GetSize() != 12 ) { |
333 | 0 | return ret; |
334 | 0 | } |
335 | | |
336 | 0 | uint8_t* out = util::malloc(op.cleartextSize); |
337 | |
|
338 | 0 | ChaCha20Poly1305AEAD aead(op.cipher.key.GetPtr(), op.cipher.key.GetSize(), op.aad->GetPtr(), op.aad->GetSize()); |
339 | |
|
340 | 0 | const auto in = util::Append(op.ciphertext.Get(), op.tag->Get()); |
341 | 0 | CF_CHECK_TRUE(aead.Crypt(0, 0, 0, out, op.cleartextSize, in.data(), in.size(), false)); |
342 | |
|
343 | 0 | CF_ASSERT(op.cleartextSize >= op.ciphertext.GetSize(), "ChaCha20Poly1305AEAD succeeded with invalid output size"); |
344 | |
|
345 | 0 | ret = component::Cleartext(Buffer(out, op.ciphertext.GetSize())); |
346 | |
|
347 | 0 | end: |
348 | 0 | util::free(out); |
349 | |
|
350 | 0 | return ret; |
351 | 0 | } |
352 | | |
353 | 152 | std::optional<component::Ciphertext> aes_256_cbc(const operation::SymmetricEncrypt& op) { |
354 | 152 | std::optional<component::Ciphertext> ret = std::nullopt; |
355 | | |
356 | 152 | std::unique_ptr<AES256CBCEncrypt> aes = nullptr; |
357 | 152 | uint8_t* out = util::malloc(op.cleartext.GetSize() + AES_BLOCKSIZE); |
358 | 152 | int numWritten; |
359 | | |
360 | | /* Initialize */ |
361 | 152 | { |
362 | 152 | CF_CHECK_EQ(op.cipher.key.GetSize(), AES256_KEYSIZE); |
363 | 101 | CF_CHECK_EQ(op.cipher.iv.GetSize(), AES_BLOCKSIZE); |
364 | 90 | aes = std::make_unique<AES256CBCEncrypt>(op.cipher.key.GetPtr(), op.cipher.iv.GetPtr(), true); |
365 | 90 | } |
366 | | |
367 | | /* Process */ |
368 | 0 | { |
369 | 90 | CF_CHECK_GT(numWritten = aes->Encrypt(op.cleartext.GetPtr(), op.cleartext.GetSize(), out), 0); |
370 | 87 | } |
371 | | |
372 | | /* Finalize */ |
373 | 0 | { |
374 | 87 | ret = component::Ciphertext(Buffer(out, numWritten)); |
375 | 87 | } |
376 | | |
377 | 152 | end: |
378 | 152 | util::free(out); |
379 | | |
380 | 152 | return ret; |
381 | 87 | } |
382 | | |
383 | 197 | std::optional<component::Cleartext> aes_256_cbc(const operation::SymmetricDecrypt& op) { |
384 | 197 | std::optional<component::Cleartext> ret = std::nullopt; |
385 | | |
386 | 197 | std::unique_ptr<AES256CBCDecrypt> aes = nullptr; |
387 | 197 | uint8_t* out = util::malloc(op.ciphertext.GetSize()); |
388 | 197 | int numWritten; |
389 | | |
390 | | /* Initialize */ |
391 | 197 | { |
392 | 197 | CF_CHECK_EQ(op.cipher.cipherType.Get(), CF_CIPHER("AES_256_CBC")); |
393 | 197 | CF_CHECK_EQ(op.cipher.key.GetSize(), AES256_KEYSIZE); |
394 | 127 | CF_CHECK_EQ(op.cipher.iv.GetSize(), AES_BLOCKSIZE); |
395 | 110 | aes = std::make_unique<AES256CBCDecrypt>(op.cipher.key.GetPtr(), op.cipher.iv.GetPtr(), true); |
396 | 110 | } |
397 | | |
398 | | /* Process */ |
399 | 0 | { |
400 | 110 | CF_CHECK_GT(numWritten = aes->Decrypt(op.ciphertext.GetPtr(), op.ciphertext.GetSize(), out), 0); |
401 | 87 | } |
402 | | |
403 | | /* Finalize */ |
404 | 0 | { |
405 | 87 | ret = component::Cleartext(out, numWritten); |
406 | 87 | } |
407 | | |
408 | 197 | end: |
409 | 197 | util::free(out); |
410 | | |
411 | 197 | return ret; |
412 | 87 | } |
413 | | |
414 | | } /* namespace Bitcoin_detail */ |
415 | | |
416 | 470 | std::optional<component::Ciphertext> Bitcoin::OpSymmetricEncrypt(operation::SymmetricEncrypt& op) { |
417 | 470 | if ( op.cipher.cipherType.Is(CF_CIPHER("CHACHA20")) ) { |
418 | 318 | return Bitcoin_detail::chacha20<component::Ciphertext>(op.cipher.key, op.cipher.iv, op.cleartext); |
419 | 318 | } else if ( op.cipher.cipherType.Is(CF_CIPHER("CHACHA20_POLY1305")) ) { |
420 | 0 | return Bitcoin_detail::chacha20_poly1305(op); |
421 | 152 | } else if ( op.cipher.cipherType.Is(CF_CIPHER("AES_256_CBC")) ) { |
422 | 152 | return Bitcoin_detail::aes_256_cbc(op); |
423 | 152 | } |
424 | | |
425 | 0 | return std::nullopt; |
426 | | |
427 | 470 | } |
428 | | |
429 | 575 | std::optional<component::Cleartext> Bitcoin::OpSymmetricDecrypt(operation::SymmetricDecrypt& op) { |
430 | 575 | if ( op.cipher.cipherType.Is(CF_CIPHER("CHACHA20")) ) { |
431 | 378 | return Bitcoin_detail::chacha20<component::Cleartext>(op.cipher.key, op.cipher.iv, op.ciphertext); |
432 | 378 | } else if ( op.cipher.cipherType.Is(CF_CIPHER("CHACHA20_POLY1305")) ) { |
433 | 0 | return Bitcoin_detail::chacha20_poly1305(op); |
434 | 197 | } else if ( op.cipher.cipherType.Is(CF_CIPHER("AES_256_CBC")) ) { |
435 | 197 | return Bitcoin_detail::aes_256_cbc(op); |
436 | 197 | } |
437 | | |
438 | 0 | return std::nullopt; |
439 | 575 | } |
440 | | |
441 | 613 | std::optional<component::Key> Bitcoin::OpKDF_HKDF(operation::KDF_HKDF& op) { |
442 | 613 | if ( !op.digestType.Is(CF_DIGEST("SHA256")) ) { |
443 | 485 | return std::nullopt; |
444 | 485 | } |
445 | | |
446 | 128 | if ( op.keySize != 32 ) { |
447 | 125 | return std::nullopt; |
448 | 125 | } |
449 | | |
450 | 3 | if ( op.info.GetSize() > 128 ) { |
451 | 2 | return std::nullopt; |
452 | 2 | } |
453 | | |
454 | 1 | uint8_t out[32]; |
455 | | |
456 | 1 | CHKDF_HMAC_SHA256_L32 hkdf( |
457 | 1 | op.password.GetPtr(), op.password.GetSize(), |
458 | 1 | op.salt.AsString()); |
459 | | |
460 | 1 | CF_NORET(hkdf.Expand32(op.info.AsString(), out)); |
461 | | |
462 | 1 | return component::Key(out, sizeof(out)); |
463 | 3 | } |
464 | | |
465 | | namespace Bitcoin_detail { |
466 | | class Bignum { |
467 | | private: |
468 | | Datasource& ds; |
469 | | arith_uint256 bn; |
470 | | public: |
471 | | Bignum(Datasource& ds) : |
472 | 9.48k | ds(ds) { |
473 | 9.48k | } |
474 | 21.3k | arith_uint256& Ref(void) { |
475 | 21.3k | { |
476 | 21.3k | bool convert = false; |
477 | 21.3k | try { |
478 | 21.3k | convert = ds.Get<bool>(); |
479 | 21.3k | } catch ( fuzzing::datasource::Datasource::OutOfData ) { } |
480 | | |
481 | 21.3k | if ( convert ) { |
482 | 8.22k | bn = UintToArith256(ArithToUint256(bn)); |
483 | 8.22k | } |
484 | 21.3k | } |
485 | | |
486 | 21.3k | { |
487 | 21.3k | bool getDouble = false; |
488 | 21.3k | try { |
489 | 21.3k | getDouble = ds.Get<bool>(); |
490 | 21.3k | } catch ( fuzzing::datasource::Datasource::OutOfData ) { } |
491 | | |
492 | 21.3k | if ( getDouble ) { |
493 | 7.62k | const auto d = bn.getdouble(); |
494 | 7.62k | (void)d; |
495 | 7.62k | } |
496 | 21.3k | } |
497 | | |
498 | 21.3k | return bn; |
499 | 21.3k | } |
500 | | }; |
501 | | } |
502 | | |
503 | | namespace Bitcoin_detail { |
504 | 2.55k | bool UseParamTwice(fuzzing::datasource::Datasource& ds, const arith_uint256& A, const arith_uint256& B) { |
505 | 2.55k | if ( A != B ) { |
506 | 2.45k | return false; |
507 | 2.45k | } |
508 | | |
509 | 94 | try { |
510 | 94 | return ds.Get<bool>(); |
511 | 94 | } catch ( fuzzing::datasource::Base::OutOfData ) { |
512 | 30 | } |
513 | | |
514 | 30 | return false; |
515 | 94 | } |
516 | | |
517 | 3.16k | uint8_t GetMod3(fuzzing::datasource::Datasource& ds) { |
518 | 3.16k | try { |
519 | 3.16k | return ds.Get<uint8_t>() % 3; |
520 | 3.16k | } catch ( fuzzing::datasource::Base::OutOfData ) { |
521 | 601 | } |
522 | | |
523 | 601 | return 0; |
524 | 3.16k | } |
525 | | } /* namespace Bitcoin_detail */ |
526 | | |
527 | | |
528 | 3.16k | std::optional<component::Bignum> Bitcoin::OpBignumCalc(operation::BignumCalc& op) { |
529 | 3.16k | #define PREPARE_RESULT() {resultIdx = Bitcoin_detail::GetMod3(ds);} |
530 | 3.16k | #define RESULT_REF() (resultIdx == 0 ? result : (resultIdx == 1 ? &a : &b)) |
531 | 7.37k | #define RESULT() ((resultIdx == 0 ? result : (resultIdx == 1 ? a : b)).Ref()) |
532 | 3.16k | #define PARAM_B() ((Bitcoin_detail::UseParamTwice(ds, a.Ref(), b.Ref()) ? a : b).Ref()) |
533 | | |
534 | 3.16k | if ( op.modulo == std::nullopt ) { |
535 | 0 | return std::nullopt; |
536 | 0 | } |
537 | | |
538 | 3.16k | if ( op.modulo->ToTrimmedString() != "115792089237316195423570985008687907853269984665640564039457584007913129639936" ) { |
539 | 0 | return std::nullopt; |
540 | 0 | } |
541 | | |
542 | 3.16k | Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize()); |
543 | 3.16k | std::optional<component::Bignum> ret = std::nullopt; |
544 | | |
545 | 3.16k | Bitcoin_detail::Bignum result(ds), a(ds), b(ds); |
546 | | |
547 | 3.16k | a.Ref().SetHex(util::DecToHex(op.bn0.ToTrimmedString())); |
548 | 3.16k | b.Ref().SetHex(util::DecToHex(op.bn1.ToTrimmedString())); |
549 | | |
550 | 3.16k | uint8_t resultIdx; |
551 | | |
552 | 3.16k | PREPARE_RESULT(); |
553 | | |
554 | 3.16k | switch ( op.calcOp.Get() ) { |
555 | 99 | case CF_CALCOP("Add(A,B)"): |
556 | 99 | RESULT() = a.Ref() + PARAM_B(); |
557 | 99 | break; |
558 | 298 | case CF_CALCOP("Sub(A,B)"): |
559 | 298 | RESULT() = a.Ref() - PARAM_B(); |
560 | 298 | break; |
561 | 333 | case CF_CALCOP("Mul(A,B)"): |
562 | 333 | RESULT() = a.Ref() * PARAM_B(); |
563 | 333 | break; |
564 | 429 | case CF_CALCOP("Div(A,B)"): |
565 | 429 | CF_CHECK_NE(PARAM_B(), 0); |
566 | 413 | RESULT() = a.Ref() / PARAM_B(); |
567 | 413 | break; |
568 | 159 | case CF_CALCOP("IsEq(A,B)"): |
569 | 159 | RESULT() = a.Ref() == PARAM_B(); |
570 | 159 | break; |
571 | 176 | case CF_CALCOP("IsGt(A,B)"): |
572 | 176 | RESULT() = a.Ref() > PARAM_B(); |
573 | 176 | break; |
574 | 149 | case CF_CALCOP("IsGte(A,B)"): |
575 | 149 | RESULT() = a.Ref() >= PARAM_B(); |
576 | 149 | break; |
577 | 176 | case CF_CALCOP("IsLt(A,B)"): |
578 | 176 | RESULT() = a.Ref() < PARAM_B(); |
579 | 176 | break; |
580 | 189 | case CF_CALCOP("IsLte(A,B)"): |
581 | 189 | RESULT() = a.Ref() <= PARAM_B(); |
582 | 189 | break; |
583 | 44 | case CF_CALCOP("IsOdd(A)"): |
584 | 44 | RESULT() = a.Ref() & 1; |
585 | 44 | break; |
586 | 65 | case CF_CALCOP("Set(A)"): |
587 | 65 | RESULT() = a.Ref(); |
588 | 65 | break; |
589 | 42 | case CF_CALCOP("And(A,B)"): |
590 | 42 | RESULT() = a.Ref() & PARAM_B(); |
591 | 42 | break; |
592 | 50 | case CF_CALCOP("Or(A,B)"): |
593 | 50 | RESULT() = a.Ref() | PARAM_B(); |
594 | 50 | break; |
595 | 37 | case CF_CALCOP("Xor(A,B)"): |
596 | 37 | RESULT() = a.Ref() ^ PARAM_B(); |
597 | 37 | break; |
598 | 227 | case CF_CALCOP("NumBits(A)"): |
599 | 227 | RESULT() = a.Ref().bits(); |
600 | 227 | break; |
601 | 690 | default: |
602 | 690 | goto end; |
603 | 3.16k | } |
604 | | |
605 | 2.45k | ret = util::HexToDec(RESULT().GetHex()); |
606 | | |
607 | 3.16k | end: |
608 | 3.16k | return ret; |
609 | | |
610 | 2.45k | #undef PREPARE_RESULT |
611 | 2.45k | #undef RESULT_PTR |
612 | 2.45k | #undef RESULT |
613 | 2.45k | #undef PARAM_B |
614 | 2.45k | } |
615 | | |
616 | 3.16k | bool Bitcoin::SupportsModularBignumCalc(void) const { |
617 | 3.16k | return true; |
618 | 3.16k | } |
619 | | |
620 | | } /* namespace module */ |
621 | | } /* namespace cryptofuzz */ |