LCOV - code coverage report
Current view: top level - src/test/fuzz - crypto_chacha20.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 100.0 % 78 78
Test Date: 2024-12-04 04:00:22 Functions: 100.0 % 14 14
Branches: 69.0 % 42 29

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

Generated by: LCOV version 2.0-1