LCOV - code coverage report
Current view: top level - src/test/fuzz - crypto_diff_fuzz_chacha20.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 2 212 0.9 %
Date: 2024-01-03 14:57:27 Functions: 1 11 9.1 %
Branches: 2 60 3.3 %

           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 <test/fuzz/FuzzedDataProvider.h>
       7                 :            : #include <test/fuzz/fuzz.h>
       8                 :            : #include <test/fuzz/util.h>
       9                 :            : 
      10                 :            : #include <cstdint>
      11                 :            : #include <vector>
      12                 :            : 
      13                 :            : /*
      14                 :            : From https://cr.yp.to/chacha.html
      15                 :            : chacha-merged.c version 20080118
      16                 :            : D. J. Bernstein
      17                 :            : Public domain.
      18                 :            : */
      19                 :            : 
      20                 :            : typedef unsigned int u32;
      21                 :            : typedef unsigned char u8;
      22                 :            : 
      23                 :            : #define U8C(v) (v##U)
      24                 :            : #define U32C(v) (v##U)
      25                 :            : 
      26                 :            : #define U8V(v) ((u8)(v)&U8C(0xFF))
      27                 :            : #define U32V(v) ((u32)(v)&U32C(0xFFFFFFFF))
      28                 :            : 
      29                 :            : #define ROTL32(v, n) (U32V((v) << (n)) | ((v) >> (32 - (n))))
      30                 :          2 : 
      31                 :            : #define U8TO32_LITTLE(p)                                              \
      32                 :            :     (((u32)((p)[0])) | ((u32)((p)[1]) << 8) | ((u32)((p)[2]) << 16) | \
      33                 :            :      ((u32)((p)[3]) << 24))
      34                 :            : 
      35                 :            : #define U32TO8_LITTLE(p, v)      \
      36                 :            :     do {                         \
      37                 :            :         (p)[0] = U8V((v));       \
      38                 :            :         (p)[1] = U8V((v) >> 8);  \
      39                 :            :         (p)[2] = U8V((v) >> 16); \
      40                 :            :         (p)[3] = U8V((v) >> 24); \
      41                 :            :     } while (0)
      42                 :            : 
      43                 :            : /* ------------------------------------------------------------------------- */
      44                 :            : /* Data structures */
      45                 :            : 
      46                 :            : typedef struct
      47                 :            : {
      48                 :            :     u32 input[16];
      49                 :            : } ECRYPT_ctx;
      50                 :            : 
      51                 :            : /* ------------------------------------------------------------------------- */
      52                 :            : /* Mandatory functions */
      53                 :            : 
      54                 :            : void ECRYPT_keysetup(
      55                 :            :     ECRYPT_ctx* ctx,
      56                 :            :     const u8* key,
      57                 :            :     u32 keysize, /* Key size in bits. */
      58                 :            :     u32 ivsize); /* IV size in bits. */
      59                 :            : 
      60                 :            : void ECRYPT_ivsetup(
      61                 :            :     ECRYPT_ctx* ctx,
      62                 :            :     const u8* iv);
      63                 :            : 
      64                 :            : void ECRYPT_encrypt_bytes(
      65                 :            :     ECRYPT_ctx* ctx,
      66                 :            :     const u8* plaintext,
      67                 :            :     u8* ciphertext,
      68                 :            :     u32 msglen); /* Message length in bytes. */
      69                 :            : 
      70                 :            : /* ------------------------------------------------------------------------- */
      71                 :            : 
      72                 :            : /* Optional features */
      73                 :            : 
      74                 :            : void ECRYPT_keystream_bytes(
      75                 :            :     ECRYPT_ctx* ctx,
      76                 :            :     u8* keystream,
      77                 :            :     u32 length); /* Length of keystream in bytes. */
      78                 :            : 
      79                 :            : /* ------------------------------------------------------------------------- */
      80                 :            : 
      81                 :            : #define ROTATE(v, c) (ROTL32(v, c))
      82                 :            : #define XOR(v, w) ((v) ^ (w))
      83                 :            : #define PLUS(v, w) (U32V((v) + (w)))
      84                 :            : #define PLUSONE(v) (PLUS((v), 1))
      85                 :            : 
      86                 :            : #define QUARTERROUND(a, b, c, d) \
      87                 :            :     a = PLUS(a, b); d = ROTATE(XOR(d, a), 16);   \
      88                 :            :     c = PLUS(c, d); b = ROTATE(XOR(b, c), 12);   \
      89                 :            :     a = PLUS(a, b); d = ROTATE(XOR(d, a), 8);    \
      90                 :            :     c = PLUS(c, d); b = ROTATE(XOR(b, c), 7);
      91                 :            : 
      92                 :            : static const char sigma[] = "expand 32-byte k";
      93                 :            : static const char tau[] = "expand 16-byte k";
      94                 :            : 
      95                 :          0 : void ECRYPT_keysetup(ECRYPT_ctx* x, const u8* k, u32 kbits, u32 ivbits)
      96                 :            : {
      97                 :            :     const char* constants;
      98                 :            : 
      99                 :          0 :     x->input[4] = U8TO32_LITTLE(k + 0);
     100                 :          0 :     x->input[5] = U8TO32_LITTLE(k + 4);
     101                 :          0 :     x->input[6] = U8TO32_LITTLE(k + 8);
     102                 :          0 :     x->input[7] = U8TO32_LITTLE(k + 12);
     103         [ #  # ]:          0 :     if (kbits == 256) { /* recommended */
     104                 :          0 :         k += 16;
     105                 :          0 :         constants = sigma;
     106                 :          0 :     } else { /* kbits == 128 */
     107                 :          0 :         constants = tau;
     108                 :            :     }
     109                 :          0 :     x->input[8] = U8TO32_LITTLE(k + 0);
     110                 :          0 :     x->input[9] = U8TO32_LITTLE(k + 4);
     111                 :          0 :     x->input[10] = U8TO32_LITTLE(k + 8);
     112                 :          0 :     x->input[11] = U8TO32_LITTLE(k + 12);
     113                 :          0 :     x->input[0] = U8TO32_LITTLE(constants + 0);
     114                 :          0 :     x->input[1] = U8TO32_LITTLE(constants + 4);
     115                 :          0 :     x->input[2] = U8TO32_LITTLE(constants + 8);
     116                 :          0 :     x->input[3] = U8TO32_LITTLE(constants + 12);
     117                 :          0 : }
     118                 :            : 
     119                 :          0 : void ECRYPT_ivsetup(ECRYPT_ctx* x, const u8* iv)
     120                 :            : {
     121                 :          0 :     x->input[12] = 0;
     122                 :          0 :     x->input[13] = 0;
     123                 :          0 :     x->input[14] = U8TO32_LITTLE(iv + 0);
     124                 :          0 :     x->input[15] = U8TO32_LITTLE(iv + 4);
     125                 :          0 : }
     126                 :            : 
     127                 :          0 : void ECRYPT_encrypt_bytes(ECRYPT_ctx* x, const u8* m, u8* c, u32 bytes)
     128                 :            : {
     129                 :            :     u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
     130                 :            :     u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
     131                 :          0 :     u8* ctarget = nullptr;
     132                 :            :     u8 tmp[64];
     133                 :            :     uint32_t i;
     134                 :            : 
     135         [ #  # ]:          0 :     if (!bytes) return;
     136                 :            : 
     137                 :          0 :     j0 = x->input[0];
     138                 :          0 :     j1 = x->input[1];
     139                 :          0 :     j2 = x->input[2];
     140                 :          0 :     j3 = x->input[3];
     141                 :          0 :     j4 = x->input[4];
     142                 :          0 :     j5 = x->input[5];
     143                 :          0 :     j6 = x->input[6];
     144                 :          0 :     j7 = x->input[7];
     145                 :          0 :     j8 = x->input[8];
     146                 :          0 :     j9 = x->input[9];
     147                 :          0 :     j10 = x->input[10];
     148                 :          0 :     j11 = x->input[11];
     149                 :          0 :     j12 = x->input[12];
     150                 :          0 :     j13 = x->input[13];
     151                 :          0 :     j14 = x->input[14];
     152                 :          0 :     j15 = x->input[15];
     153                 :            : 
     154                 :          0 :     for (;;) {
     155         [ #  # ]:          0 :         if (bytes < 64) {
     156         [ #  # ]:          0 :             for (i = 0; i < bytes; ++i)
     157                 :          0 :                 tmp[i] = m[i];
     158                 :          0 :             m = tmp;
     159                 :          0 :             ctarget = c;
     160                 :          0 :             c = tmp;
     161                 :          0 :         }
     162                 :          0 :         x0 = j0;
     163                 :          0 :         x1 = j1;
     164                 :          0 :         x2 = j2;
     165                 :          0 :         x3 = j3;
     166                 :          0 :         x4 = j4;
     167                 :          0 :         x5 = j5;
     168                 :          0 :         x6 = j6;
     169                 :          0 :         x7 = j7;
     170                 :          0 :         x8 = j8;
     171                 :          0 :         x9 = j9;
     172                 :          0 :         x10 = j10;
     173                 :          0 :         x11 = j11;
     174                 :          0 :         x12 = j12;
     175                 :          0 :         x13 = j13;
     176                 :          0 :         x14 = j14;
     177                 :          0 :         x15 = j15;
     178         [ #  # ]:          0 :         for (i = 20; i > 0; i -= 2) {
     179                 :          0 :             QUARTERROUND(x0, x4, x8, x12)
     180                 :          0 :             QUARTERROUND(x1, x5, x9, x13)
     181                 :          0 :             QUARTERROUND(x2, x6, x10, x14)
     182                 :          0 :             QUARTERROUND(x3, x7, x11, x15)
     183                 :          0 :             QUARTERROUND(x0, x5, x10, x15)
     184                 :          0 :             QUARTERROUND(x1, x6, x11, x12)
     185                 :          0 :             QUARTERROUND(x2, x7, x8, x13)
     186                 :          0 :             QUARTERROUND(x3, x4, x9, x14)
     187                 :          0 :         }
     188                 :          0 :         x0 = PLUS(x0, j0);
     189                 :          0 :         x1 = PLUS(x1, j1);
     190                 :          0 :         x2 = PLUS(x2, j2);
     191                 :          0 :         x3 = PLUS(x3, j3);
     192                 :          0 :         x4 = PLUS(x4, j4);
     193                 :          0 :         x5 = PLUS(x5, j5);
     194                 :          0 :         x6 = PLUS(x6, j6);
     195                 :          0 :         x7 = PLUS(x7, j7);
     196                 :          0 :         x8 = PLUS(x8, j8);
     197                 :          0 :         x9 = PLUS(x9, j9);
     198                 :          0 :         x10 = PLUS(x10, j10);
     199                 :          0 :         x11 = PLUS(x11, j11);
     200                 :          0 :         x12 = PLUS(x12, j12);
     201                 :          0 :         x13 = PLUS(x13, j13);
     202                 :          0 :         x14 = PLUS(x14, j14);
     203                 :          0 :         x15 = PLUS(x15, j15);
     204                 :            : 
     205                 :          0 :         x0 = XOR(x0, U8TO32_LITTLE(m + 0));
     206                 :          0 :         x1 = XOR(x1, U8TO32_LITTLE(m + 4));
     207                 :          0 :         x2 = XOR(x2, U8TO32_LITTLE(m + 8));
     208                 :          0 :         x3 = XOR(x3, U8TO32_LITTLE(m + 12));
     209                 :          0 :         x4 = XOR(x4, U8TO32_LITTLE(m + 16));
     210                 :          0 :         x5 = XOR(x5, U8TO32_LITTLE(m + 20));
     211                 :          0 :         x6 = XOR(x6, U8TO32_LITTLE(m + 24));
     212                 :          0 :         x7 = XOR(x7, U8TO32_LITTLE(m + 28));
     213                 :          0 :         x8 = XOR(x8, U8TO32_LITTLE(m + 32));
     214                 :          0 :         x9 = XOR(x9, U8TO32_LITTLE(m + 36));
     215                 :          0 :         x10 = XOR(x10, U8TO32_LITTLE(m + 40));
     216                 :          0 :         x11 = XOR(x11, U8TO32_LITTLE(m + 44));
     217                 :          0 :         x12 = XOR(x12, U8TO32_LITTLE(m + 48));
     218                 :          0 :         x13 = XOR(x13, U8TO32_LITTLE(m + 52));
     219                 :          0 :         x14 = XOR(x14, U8TO32_LITTLE(m + 56));
     220                 :          0 :         x15 = XOR(x15, U8TO32_LITTLE(m + 60));
     221                 :            : 
     222                 :          0 :         j12 = PLUSONE(j12);
     223         [ #  # ]:          0 :         if (!j12) {
     224                 :          0 :             j13 = PLUSONE(j13);
     225                 :            :             /* stopping at 2^70 bytes per nonce is user's responsibility */
     226                 :          0 :         }
     227                 :            : 
     228                 :          0 :         U32TO8_LITTLE(c + 0, x0);
     229                 :          0 :         U32TO8_LITTLE(c + 4, x1);
     230                 :          0 :         U32TO8_LITTLE(c + 8, x2);
     231                 :          0 :         U32TO8_LITTLE(c + 12, x3);
     232                 :          0 :         U32TO8_LITTLE(c + 16, x4);
     233                 :          0 :         U32TO8_LITTLE(c + 20, x5);
     234                 :          0 :         U32TO8_LITTLE(c + 24, x6);
     235                 :          0 :         U32TO8_LITTLE(c + 28, x7);
     236                 :          0 :         U32TO8_LITTLE(c + 32, x8);
     237                 :          0 :         U32TO8_LITTLE(c + 36, x9);
     238                 :          0 :         U32TO8_LITTLE(c + 40, x10);
     239                 :          0 :         U32TO8_LITTLE(c + 44, x11);
     240                 :          0 :         U32TO8_LITTLE(c + 48, x12);
     241                 :          0 :         U32TO8_LITTLE(c + 52, x13);
     242                 :          0 :         U32TO8_LITTLE(c + 56, x14);
     243                 :          0 :         U32TO8_LITTLE(c + 60, x15);
     244                 :            : 
     245         [ #  # ]:          0 :         if (bytes <= 64) {
     246         [ #  # ]:          0 :             if (bytes < 64) {
     247         [ #  # ]:          0 :                 for (i = 0; i < bytes; ++i)
     248                 :          0 :                     ctarget[i] = c[i];
     249                 :          0 :             }
     250                 :          0 :             x->input[12] = j12;
     251                 :          0 :             x->input[13] = j13;
     252                 :          0 :             return;
     253                 :            :         }
     254                 :          0 :         bytes -= 64;
     255                 :          0 :         c += 64;
     256                 :          0 :         m += 64;
     257                 :            :     }
     258                 :          0 : }
     259                 :            : 
     260                 :          0 : void ECRYPT_keystream_bytes(ECRYPT_ctx* x, u8* stream, u32 bytes)
     261                 :            : {
     262                 :            :     u32 i;
     263         [ #  # ]:          0 :     for (i = 0; i < bytes; ++i)
     264                 :          0 :         stream[i] = 0;
     265                 :          0 :     ECRYPT_encrypt_bytes(x, stream, stream, bytes);
     266                 :          0 : }
     267                 :            : 
     268 [ +  - ][ +  - ]:          6 : FUZZ_TARGET(crypto_diff_fuzz_chacha20)
     269                 :            : {
     270                 :          0 :     FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
     271                 :            : 
     272                 :            :     ECRYPT_ctx ctx;
     273                 :            : 
     274                 :          0 :     const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32);
     275                 :          0 :     ChaCha20 chacha20{MakeByteSpan(key)};
     276                 :          0 :     ECRYPT_keysetup(&ctx, key.data(), key.size() * 8, 0);
     277                 :            : 
     278                 :            :     // ECRYPT_keysetup() doesn't set the counter and nonce to 0 while SetKey() does
     279                 :            :     static const uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
     280                 :          0 :     ChaCha20::Nonce96 nonce{0, 0};
     281                 :          0 :     uint32_t counter{0};
     282                 :          0 :     ECRYPT_ivsetup(&ctx, iv);
     283                 :            : 
     284 [ #  # ][ #  # ]:          0 :     LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 3000) {
                 [ #  # ]
     285         [ #  # ]:          0 :         CallOneOf(
     286                 :            :             fuzzed_data_provider,
     287                 :          0 :             [&] {
     288                 :          0 :                 const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32);
     289                 :          0 :                 chacha20.SetKey(MakeByteSpan(key));
     290                 :          0 :                 nonce = {0, 0};
     291                 :          0 :                 counter = 0;
     292                 :          0 :                 ECRYPT_keysetup(&ctx, key.data(), key.size() * 8, 0);
     293                 :            :                 // ECRYPT_keysetup() doesn't set the counter and nonce to 0 while SetKey() does
     294                 :          0 :                 uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
     295                 :          0 :                 ECRYPT_ivsetup(&ctx, iv);
     296                 :          0 :             },
     297                 :          0 :             [&] {
     298                 :          0 :                 uint32_t iv_prefix = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
     299                 :          0 :                 uint64_t iv = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
     300                 :          0 :                 nonce = {iv_prefix, iv};
     301                 :          0 :                 counter = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
     302                 :          0 :                 chacha20.Seek(nonce, counter);
     303                 :          0 :                 ctx.input[12] = counter;
     304                 :          0 :                 ctx.input[13] = iv_prefix;
     305                 :          0 :                 ctx.input[14] = iv;
     306                 :          0 :                 ctx.input[15] = iv >> 32;
     307                 :          0 :             },
     308                 :          0 :             [&] {
     309                 :          0 :                 uint32_t integralInRange = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096);
     310         [ #  # ]:          0 :                 std::vector<uint8_t> output(integralInRange);
     311                 :          0 :                 chacha20.Keystream(MakeWritableByteSpan(output));
     312         [ #  # ]:          0 :                 std::vector<uint8_t> djb_output(integralInRange);
     313                 :          0 :                 ECRYPT_keystream_bytes(&ctx, djb_output.data(), djb_output.size());
     314 [ #  # ][ #  # ]:          0 :                 assert(output == djb_output);
     315                 :            :                 // DJB's version seeks forward to a multiple of 64 bytes after every operation. Correct for that.
     316                 :          0 :                 uint32_t old_counter = counter;
     317                 :          0 :                 counter += (integralInRange + 63) >> 6;
     318         [ #  # ]:          0 :                 if (counter < old_counter) ++nonce.first;
     319         [ #  # ]:          0 :                 if (integralInRange & 63) {
     320                 :          0 :                     chacha20.Seek(nonce, counter);
     321                 :          0 :                 }
     322         [ #  # ]:          0 :                 assert(counter == ctx.input[12]);
     323                 :          0 :             },
     324                 :          0 :             [&] {
     325                 :          0 :                 uint32_t integralInRange = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096);
     326         [ #  # ]:          0 :                 std::vector<uint8_t> output(integralInRange);
     327                 :          0 :                 const std::vector<uint8_t> input = ConsumeFixedLengthByteVector(fuzzed_data_provider, output.size());
     328                 :          0 :                 chacha20.Crypt(MakeByteSpan(input), MakeWritableByteSpan(output));
     329         [ #  # ]:          0 :                 std::vector<uint8_t> djb_output(integralInRange);
     330                 :          0 :                 ECRYPT_encrypt_bytes(&ctx, input.data(), djb_output.data(), input.size());
     331 [ #  # ][ #  # ]:          0 :                 assert(output == djb_output);
     332                 :            :                 // DJB's version seeks forward to a multiple of 64 bytes after every operation. Correct for that.
     333                 :          0 :                 uint32_t old_counter = counter;
     334                 :          0 :                 counter += (integralInRange + 63) >> 6;
     335         [ #  # ]:          0 :                 if (counter < old_counter) ++nonce.first;
     336         [ #  # ]:          0 :                 if (integralInRange & 63) {
     337                 :          0 :                     chacha20.Seek(nonce, counter);
     338                 :          0 :                 }
     339         [ #  # ]:          0 :                 assert(counter == ctx.input[12]);
     340                 :          0 :             });
     341                 :          0 :     }
     342                 :          0 : }

Generated by: LCOV version 1.14