LCOV - code coverage report
Current view: top level - src/test/fuzz - crypto_chacha20.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 0.0 % 77 0
Test Date: 2024-08-28 04:44:32 Functions: 0.0 % 14 0
Branches: 0.0 % 42 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2020-2021 The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #include <crypto/chacha20.h>
       6                 :             : #include <random.h>
       7                 :             : #include <test/fuzz/FuzzedDataProvider.h>
       8                 :             : #include <test/fuzz/fuzz.h>
       9                 :             : #include <test/fuzz/util.h>
      10                 :             : 
      11                 :             : #include <array>
      12                 :             : #include <cstddef>
      13                 :             : #include <cstdint>
      14                 :             : #include <vector>
      15                 :             : 
      16         [ #  # ]:           0 : FUZZ_TARGET(crypto_chacha20)
      17                 :             : {
      18                 :           0 :     FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
      19                 :             : 
      20                 :           0 :     const auto key = ConsumeFixedLengthByteVector<std::byte>(fuzzed_data_provider, ChaCha20::KEYLEN);
      21                 :           0 :     ChaCha20 chacha20{key};
      22                 :             : 
      23   [ #  #  #  # ]:           0 :     LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
      24         [ #  # ]:           0 :         CallOneOf(
      25                 :             :             fuzzed_data_provider,
      26                 :           0 :             [&] {
      27                 :           0 :                 auto key = ConsumeFixedLengthByteVector<std::byte>(fuzzed_data_provider, ChaCha20::KEYLEN);
      28                 :           0 :                 chacha20.SetKey(key);
      29                 :           0 :             },
      30                 :           0 :             [&] {
      31                 :           0 :                 chacha20.Seek(
      32                 :             :                     {
      33                 :           0 :                         fuzzed_data_provider.ConsumeIntegral<uint32_t>(),
      34                 :           0 :                         fuzzed_data_provider.ConsumeIntegral<uint64_t>()
      35                 :             :                     }, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
      36                 :           0 :             },
      37                 :           0 :             [&] {
      38                 :           0 :                 std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
      39                 :           0 :                 chacha20.Keystream(MakeWritableByteSpan(output));
      40                 :           0 :             },
      41                 :           0 :             [&] {
      42                 :           0 :                 std::vector<std::byte> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
      43                 :           0 :                 const auto input = ConsumeFixedLengthByteVector<std::byte>(fuzzed_data_provider, output.size());
      44                 :           0 :                 chacha20.Crypt(input, output);
      45                 :           0 :             });
      46                 :             :     }
      47                 :           0 : }
      48                 :             : 
      49                 :             : namespace
      50                 :             : {
      51                 :             : 
      52                 :             : /** Fuzzer that invokes ChaCha20::Crypt() or ChaCha20::Keystream multiple times:
      53                 :             :     once for a large block at once, and then the same data in chunks, comparing
      54                 :             :     the outcome.
      55                 :             : 
      56                 :             :     If UseCrypt, seeded InsecureRandomContext output is used as input to Crypt().
      57                 :             :     If not, Keystream() is used directly, or sequences of 0x00 are encrypted.
      58                 :             : */
      59                 :             : template<bool UseCrypt>
      60                 :           0 : void ChaCha20SplitFuzz(FuzzedDataProvider& provider)
      61                 :             : {
      62                 :             :     // Determine key, iv, start position, length.
      63                 :           0 :     auto key_bytes = ConsumeFixedLengthByteVector<std::byte>(provider, ChaCha20::KEYLEN);
      64                 :           0 :     uint64_t iv = provider.ConsumeIntegral<uint64_t>();
      65                 :           0 :     uint32_t iv_prefix = provider.ConsumeIntegral<uint32_t>();
      66                 :           0 :     uint64_t total_bytes = provider.ConsumeIntegralInRange<uint64_t>(0, 1000000);
      67                 :             :     /* ~x = 2^BITS - 1 - x, so ~(total_bytes >> 6) is the maximal seek position. */
      68                 :           0 :     uint32_t seek = provider.ConsumeIntegralInRange<uint32_t>(0, ~(uint32_t)(total_bytes >> 6));
      69                 :             : 
      70                 :             :     // Initialize two ChaCha20 ciphers, with the same key/iv/position.
      71                 :           0 :     ChaCha20 crypt1(key_bytes);
      72                 :           0 :     ChaCha20 crypt2(key_bytes);
      73                 :           0 :     crypt1.Seek({iv_prefix, iv}, seek);
      74                 :           0 :     crypt2.Seek({iv_prefix, iv}, seek);
      75                 :             : 
      76                 :             :     // Construct vectors with data.
      77                 :           0 :     std::vector<std::byte> data1, data2;
      78         [ #  # ]:           0 :     data1.resize(total_bytes);
      79         [ #  # ]:           0 :     data2.resize(total_bytes);
      80                 :             : 
      81                 :             :     // If using Crypt(), initialize data1 and data2 with the same InsecureRandomContext based
      82                 :             :     // stream.
      83                 :             :     if constexpr (UseCrypt) {
      84                 :           0 :         InsecureRandomContext(provider.ConsumeIntegral<uint64_t>()).fillrand(data1);
      85                 :           0 :         std::copy(data1.begin(), data1.end(), data2.begin());
      86                 :             :     }
      87                 :             : 
      88                 :             :     // Whether UseCrypt is used or not, the two byte arrays must match.
      89         [ #  # ]:           0 :     assert(data1 == data2);
      90                 :             : 
      91                 :             :     // Encrypt data1, the whole array at once.
      92                 :             :     if constexpr (UseCrypt) {
      93                 :           0 :         crypt1.Crypt(data1, data1);
      94                 :             :     } else {
      95                 :           0 :         crypt1.Keystream(data1);
      96                 :             :     }
      97                 :             : 
      98                 :             :     // Encrypt data2, in at most 256 chunks.
      99                 :           0 :     uint64_t bytes2 = 0;
     100                 :           0 :     int iter = 0;
     101                 :             :     while (true) {
     102   [ #  #  #  # ]:           0 :         bool is_last = (iter == 255) || (bytes2 == total_bytes) || provider.ConsumeBool();
     103                 :           0 :         ++iter;
     104                 :             :         // Determine how many bytes to encrypt in this chunk: a fuzzer-determined
     105                 :             :         // amount for all but the last chunk (which processes all remaining bytes).
     106                 :           0 :         uint64_t now = is_last ? total_bytes - bytes2 :
     107                 :           0 :             provider.ConsumeIntegralInRange<uint64_t>(0, total_bytes - bytes2);
     108                 :             :         // For each chunk, consider using Crypt() even when UseCrypt is false.
     109                 :             :         // This tests that Keystream() has the same behavior as Crypt() applied
     110                 :             :         // to 0x00 input bytes.
     111         [ #  # ]:           0 :         if (UseCrypt || provider.ConsumeBool()) {
     112                 :           0 :             crypt2.Crypt(Span{data2}.subspan(bytes2, now), Span{data2}.subspan(bytes2, now));
     113                 :             :         } else {
     114                 :           0 :             crypt2.Keystream(Span{data2}.subspan(bytes2, now));
     115                 :             :         }
     116                 :           0 :         bytes2 += now;
     117         [ #  # ]:           0 :         if (is_last) break;
     118                 :             :     }
     119                 :             :     // We should have processed everything now.
     120         [ #  # ]:           0 :     assert(bytes2 == total_bytes);
     121                 :             :     // And the result should match.
     122         [ #  # ]:           0 :     assert(data1 == data2);
     123                 :           0 : }
     124                 :             : 
     125                 :             : } // namespace
     126                 :             : 
     127         [ #  # ]:           0 : FUZZ_TARGET(chacha20_split_crypt)
     128                 :             : {
     129                 :           0 :     FuzzedDataProvider provider{buffer.data(), buffer.size()};
     130                 :           0 :     ChaCha20SplitFuzz<true>(provider);
     131                 :           0 : }
     132                 :             : 
     133         [ #  # ]:           0 : FUZZ_TARGET(chacha20_split_keystream)
     134                 :             : {
     135                 :           0 :     FuzzedDataProvider provider{buffer.data(), buffer.size()};
     136                 :           0 :     ChaCha20SplitFuzz<false>(provider);
     137                 :           0 : }
     138                 :             : 
     139         [ #  # ]:           0 : FUZZ_TARGET(crypto_fschacha20)
     140                 :             : {
     141                 :           0 :     FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
     142                 :             : 
     143                 :           0 :     auto key = fuzzed_data_provider.ConsumeBytes<std::byte>(FSChaCha20::KEYLEN);
     144         [ #  # ]:           0 :     key.resize(FSChaCha20::KEYLEN);
     145                 :             : 
     146                 :           0 :     auto fsc20 = FSChaCha20{key, fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(1, 1024)};
     147                 :             : 
     148   [ #  #  #  # ]:           0 :     LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000)
     149                 :             :     {
     150         [ #  # ]:           0 :         auto input = fuzzed_data_provider.ConsumeBytes<std::byte>(fuzzed_data_provider.ConsumeIntegralInRange(0, 4096));
     151                 :           0 :         std::vector<std::byte> output;
     152         [ #  # ]:           0 :         output.resize(input.size());
     153                 :           0 :         fsc20.Crypt(input, output);
     154                 :           0 :     }
     155                 :           0 : }
        

Generated by: LCOV version 2.0-1