| 266 | } |
| 267 | |
| 268 | FUZZ_TARGET(crypto_diff_fuzz_chacha20) |
| 269 | { |
| 270 | FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; |
| 271 | |
| 272 | ChaCha20 chacha20; |
| 273 | ECRYPT_ctx ctx; |
| 274 | // D. J. Bernstein doesn't initialise ctx to 0 while Bitcoin Core initialises chacha20 to 0 in the constructor |
| 275 | for (int i = 0; i < 16; i++) { |
| 276 | ctx.input[i] = 0; |
| 277 | } |
| 278 | |
| 279 | if (fuzzed_data_provider.ConsumeBool()) { |
| 280 | const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32)); |
| 281 | chacha20 = ChaCha20{key.data(), key.size()}; |
| 282 | ECRYPT_keysetup(&ctx, key.data(), key.size() * 8, 0); |
| 283 | // ECRYPT_keysetup() doesn't set the counter and nonce to 0 while SetKey() does |
| 284 | uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0}; |
| 285 | ECRYPT_ivsetup(&ctx, iv); |
| 286 | } |
| 287 | |
| 288 | LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 3000) { |
| 289 | CallOneOf( |
| 290 | fuzzed_data_provider, |
| 291 | [&] { |
| 292 | const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32)); |
| 293 | chacha20.SetKey(key.data(), key.size()); |
| 294 | ECRYPT_keysetup(&ctx, key.data(), key.size() * 8, 0); |
| 295 | // ECRYPT_keysetup() doesn't set the counter and nonce to 0 while SetKey() does |
| 296 | uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0}; |
| 297 | ECRYPT_ivsetup(&ctx, iv); |
| 298 | }, |
| 299 | [&] { |
| 300 | uint64_t iv = fuzzed_data_provider.ConsumeIntegral<uint64_t>(); |
| 301 | chacha20.SetIV(iv); |
| 302 | ctx.input[14] = iv; |
| 303 | ctx.input[15] = iv >> 32; |
| 304 | }, |
| 305 | [&] { |
| 306 | uint64_t counter = fuzzed_data_provider.ConsumeIntegral<uint64_t>(); |
| 307 | chacha20.Seek(counter); |
| 308 | ctx.input[12] = counter; |
| 309 | ctx.input[13] = counter >> 32; |
| 310 | }, |
| 311 | [&] { |
| 312 | uint32_t integralInRange = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096); |
| 313 | std::vector<uint8_t> output(integralInRange); |
| 314 | chacha20.Keystream(output.data(), output.size()); |
| 315 | std::vector<uint8_t> djb_output(integralInRange); |
| 316 | ECRYPT_keystream_bytes(&ctx, djb_output.data(), djb_output.size()); |
| 317 | assert(output == djb_output); |
| 318 | }, |
| 319 | [&] { |
| 320 | uint32_t integralInRange = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096); |
| 321 | std::vector<uint8_t> output(integralInRange); |
| 322 | const std::vector<uint8_t> input = ConsumeFixedLengthByteVector(fuzzed_data_provider, output.size()); |
| 323 | chacha20.Crypt(input.data(), output.data(), input.size()); |
| 324 | std::vector<uint8_t> djb_output(integralInRange); |
| 325 | ECRYPT_encrypt_bytes(&ctx, input.data(), djb_output.data(), input.size()); |
nothing calls this directly
no test coverage detected