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: 210 211 99.5 %
Date: 2023-10-05 15:40:34 Functions: 11 11 100.0 %
Branches: 47 64 73.4 %

           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         [ +  - ]:        173 : 
      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                 :            : 
      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                 :        253 : void ECRYPT_keysetup(ECRYPT_ctx* x, const u8* k, u32 kbits, u32 ivbits)
      96                 :            : {
      97                 :            :     const char* constants;
      98                 :            : 
      99                 :        253 :     x->input[4] = U8TO32_LITTLE(k + 0);
     100                 :        253 :     x->input[5] = U8TO32_LITTLE(k + 4);
     101                 :        253 :     x->input[6] = U8TO32_LITTLE(k + 8);
     102                 :        253 :     x->input[7] = U8TO32_LITTLE(k + 12);
     103         [ +  - ]:        253 :     if (kbits == 256) { /* recommended */
     104                 :        253 :         k += 16;
     105                 :        253 :         constants = sigma;
     106                 :        253 :     } else { /* kbits == 128 */
     107                 :          0 :         constants = tau;
     108                 :            :     }
     109                 :        253 :     x->input[8] = U8TO32_LITTLE(k + 0);
     110                 :        253 :     x->input[9] = U8TO32_LITTLE(k + 4);
     111                 :        253 :     x->input[10] = U8TO32_LITTLE(k + 8);
     112                 :        253 :     x->input[11] = U8TO32_LITTLE(k + 12);
     113                 :        253 :     x->input[0] = U8TO32_LITTLE(constants + 0);
     114                 :        253 :     x->input[1] = U8TO32_LITTLE(constants + 4);
     115                 :        253 :     x->input[2] = U8TO32_LITTLE(constants + 8);
     116                 :        253 :     x->input[3] = U8TO32_LITTLE(constants + 12);
     117                 :        253 : }
     118                 :            : 
     119                 :        253 : void ECRYPT_ivsetup(ECRYPT_ctx* x, const u8* iv)
     120                 :            : {
     121                 :        253 :     x->input[12] = 0;
     122                 :        253 :     x->input[13] = 0;
     123                 :        253 :     x->input[14] = U8TO32_LITTLE(iv + 0);
     124                 :        253 :     x->input[15] = U8TO32_LITTLE(iv + 4);
     125                 :        253 : }
     126                 :            : 
     127                 :       4379 : 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                 :       4379 :     u8* ctarget = nullptr;
     132                 :            :     u8 tmp[64];
     133                 :            :     uint32_t i;
     134                 :            : 
     135         [ +  + ]:       4379 :     if (!bytes) return;
     136                 :            : 
     137                 :       2723 :     j0 = x->input[0];
     138                 :       2723 :     j1 = x->input[1];
     139                 :       2723 :     j2 = x->input[2];
     140                 :       2723 :     j3 = x->input[3];
     141                 :       2723 :     j4 = x->input[4];
     142                 :       2723 :     j5 = x->input[5];
     143                 :       2723 :     j6 = x->input[6];
     144                 :       2723 :     j7 = x->input[7];
     145                 :       2723 :     j8 = x->input[8];
     146                 :       2723 :     j9 = x->input[9];
     147                 :       2723 :     j10 = x->input[10];
     148                 :       2723 :     j11 = x->input[11];
     149                 :       2723 :     j12 = x->input[12];
     150                 :       2723 :     j13 = x->input[13];
     151                 :       2723 :     j14 = x->input[14];
     152                 :       2723 :     j15 = x->input[15];
     153                 :            : 
     154                 :      78671 :     for (;;) {
     155         [ +  + ]:      78671 :         if (bytes < 64) {
     156         [ +  + ]:      80143 :             for (i = 0; i < bytes; ++i)
     157                 :      77508 :                 tmp[i] = m[i];
     158                 :       2635 :             m = tmp;
     159                 :       2635 :             ctarget = c;
     160                 :       2635 :             c = tmp;
     161                 :       2635 :         }
     162                 :      78671 :         x0 = j0;
     163                 :      78671 :         x1 = j1;
     164                 :      78671 :         x2 = j2;
     165                 :      78671 :         x3 = j3;
     166                 :      78671 :         x4 = j4;
     167                 :      78671 :         x5 = j5;
     168                 :      78671 :         x6 = j6;
     169                 :      78671 :         x7 = j7;
     170                 :      78671 :         x8 = j8;
     171                 :      78671 :         x9 = j9;
     172                 :      78671 :         x10 = j10;
     173                 :      78671 :         x11 = j11;
     174                 :      78671 :         x12 = j12;
     175                 :      78671 :         x13 = j13;
     176                 :      78671 :         x14 = j14;
     177                 :      78671 :         x15 = j15;
     178         [ +  + ]:     865381 :         for (i = 20; i > 0; i -= 2) {
     179                 :     786710 :             QUARTERROUND(x0, x4, x8, x12)
     180                 :     786710 :             QUARTERROUND(x1, x5, x9, x13)
     181                 :     786710 :             QUARTERROUND(x2, x6, x10, x14)
     182                 :     786710 :             QUARTERROUND(x3, x7, x11, x15)
     183                 :     786710 :             QUARTERROUND(x0, x5, x10, x15)
     184                 :     786710 :             QUARTERROUND(x1, x6, x11, x12)
     185                 :     786710 :             QUARTERROUND(x2, x7, x8, x13)
     186                 :     786710 :             QUARTERROUND(x3, x4, x9, x14)
     187                 :     786710 :         }
     188                 :      78671 :         x0 = PLUS(x0, j0);
     189                 :      78671 :         x1 = PLUS(x1, j1);
     190                 :      78671 :         x2 = PLUS(x2, j2);
     191                 :      78671 :         x3 = PLUS(x3, j3);
     192                 :      78671 :         x4 = PLUS(x4, j4);
     193                 :      78671 :         x5 = PLUS(x5, j5);
     194                 :      78671 :         x6 = PLUS(x6, j6);
     195                 :      78671 :         x7 = PLUS(x7, j7);
     196                 :      78671 :         x8 = PLUS(x8, j8);
     197                 :      78671 :         x9 = PLUS(x9, j9);
     198                 :      78671 :         x10 = PLUS(x10, j10);
     199                 :      78671 :         x11 = PLUS(x11, j11);
     200                 :      78671 :         x12 = PLUS(x12, j12);
     201                 :      78671 :         x13 = PLUS(x13, j13);
     202                 :      78671 :         x14 = PLUS(x14, j14);
     203                 :      78671 :         x15 = PLUS(x15, j15);
     204                 :            : 
     205                 :      78671 :         x0 = XOR(x0, U8TO32_LITTLE(m + 0));
     206                 :      78671 :         x1 = XOR(x1, U8TO32_LITTLE(m + 4));
     207                 :      78671 :         x2 = XOR(x2, U8TO32_LITTLE(m + 8));
     208                 :      78671 :         x3 = XOR(x3, U8TO32_LITTLE(m + 12));
     209                 :      78671 :         x4 = XOR(x4, U8TO32_LITTLE(m + 16));
     210                 :      78671 :         x5 = XOR(x5, U8TO32_LITTLE(m + 20));
     211                 :      78671 :         x6 = XOR(x6, U8TO32_LITTLE(m + 24));
     212                 :      78671 :         x7 = XOR(x7, U8TO32_LITTLE(m + 28));
     213                 :      78671 :         x8 = XOR(x8, U8TO32_LITTLE(m + 32));
     214                 :      78671 :         x9 = XOR(x9, U8TO32_LITTLE(m + 36));
     215                 :      78671 :         x10 = XOR(x10, U8TO32_LITTLE(m + 40));
     216                 :      78671 :         x11 = XOR(x11, U8TO32_LITTLE(m + 44));
     217                 :      78671 :         x12 = XOR(x12, U8TO32_LITTLE(m + 48));
     218                 :      78671 :         x13 = XOR(x13, U8TO32_LITTLE(m + 52));
     219                 :      78671 :         x14 = XOR(x14, U8TO32_LITTLE(m + 56));
     220                 :      78671 :         x15 = XOR(x15, U8TO32_LITTLE(m + 60));
     221                 :            : 
     222                 :      78671 :         j12 = PLUSONE(j12);
     223         [ +  + ]:      78671 :         if (!j12) {
     224                 :         14 :             j13 = PLUSONE(j13);
     225                 :            :             /* stopping at 2^70 bytes per nonce is user's responsibility */
     226                 :         14 :         }
     227                 :            : 
     228                 :      78671 :         U32TO8_LITTLE(c + 0, x0);
     229                 :      78671 :         U32TO8_LITTLE(c + 4, x1);
     230                 :      78671 :         U32TO8_LITTLE(c + 8, x2);
     231                 :      78671 :         U32TO8_LITTLE(c + 12, x3);
     232                 :      78671 :         U32TO8_LITTLE(c + 16, x4);
     233                 :      78671 :         U32TO8_LITTLE(c + 20, x5);
     234                 :      78671 :         U32TO8_LITTLE(c + 24, x6);
     235                 :      78671 :         U32TO8_LITTLE(c + 28, x7);
     236                 :      78671 :         U32TO8_LITTLE(c + 32, x8);
     237                 :      78671 :         U32TO8_LITTLE(c + 36, x9);
     238                 :      78671 :         U32TO8_LITTLE(c + 40, x10);
     239                 :      78671 :         U32TO8_LITTLE(c + 44, x11);
     240                 :      78671 :         U32TO8_LITTLE(c + 48, x12);
     241                 :      78671 :         U32TO8_LITTLE(c + 52, x13);
     242                 :      78671 :         U32TO8_LITTLE(c + 56, x14);
     243                 :      78671 :         U32TO8_LITTLE(c + 60, x15);
     244                 :            : 
     245         [ +  + ]:      78671 :         if (bytes <= 64) {
     246         [ +  + ]:       2723 :             if (bytes < 64) {
     247         [ +  + ]:      80143 :                 for (i = 0; i < bytes; ++i)
     248                 :      77508 :                     ctarget[i] = c[i];
     249                 :       2635 :             }
     250                 :       2723 :             x->input[12] = j12;
     251                 :       2723 :             x->input[13] = j13;
     252                 :       2723 :             return;
     253                 :            :         }
     254                 :      75948 :         bytes -= 64;
     255                 :      75948 :         c += 64;
     256                 :      75948 :         m += 64;
     257                 :            :     }
     258                 :       4379 : }
     259                 :            : 
     260                 :       2905 : void ECRYPT_keystream_bytes(ECRYPT_ctx* x, u8* stream, u32 bytes)
     261                 :            : {
     262                 :            :     u32 i;
     263         [ +  + ]:     980430 :     for (i = 0; i < bytes; ++i)
     264                 :     977525 :         stream[i] = 0;
     265                 :       2905 :     ECRYPT_encrypt_bytes(x, stream, stream, bytes);
     266                 :       2905 : }
     267                 :            : 
     268         [ -  + ]:        433 : FUZZ_TARGET(crypto_diff_fuzz_chacha20)
     269                 :            : {
     270                 :         87 :     FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
     271                 :            : 
     272                 :            :     ECRYPT_ctx ctx;
     273                 :            : 
     274                 :         87 :     const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32);
     275                 :         87 :     ChaCha20 chacha20{MakeByteSpan(key)};
     276                 :         87 :     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         [ +  - ]:         87 :     ChaCha20::Nonce96 nonce{0, 0};
     281                 :         87 :     uint32_t counter{0};
     282                 :         87 :     ECRYPT_ivsetup(&ctx, iv);
     283                 :            : 
     284   [ +  -  +  +  :       6320 :     LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 3000) {
                   +  + ]
     285         [ +  - ]:       6233 :         CallOneOf(
     286                 :            :             fuzzed_data_provider,
     287                 :       6399 :             [&] {
     288                 :        166 :                 const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32);
     289                 :        166 :                 chacha20.SetKey(MakeByteSpan(key));
     290         [ +  - ]:        166 :                 nonce = {0, 0};
     291                 :        166 :                 counter = 0;
     292                 :        166 :                 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                 :        166 :                 uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
     295                 :        166 :                 ECRYPT_ivsetup(&ctx, iv);
     296                 :        166 :             },
     297                 :       7921 :             [&] {
     298                 :       1688 :                 uint32_t iv_prefix = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
     299                 :       1688 :                 uint64_t iv = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
     300                 :       1688 :                 nonce = {iv_prefix, iv};
     301                 :       1688 :                 counter = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
     302                 :       1688 :                 chacha20.Seek(nonce, counter);
     303                 :       1688 :                 ctx.input[12] = counter;
     304                 :       1688 :                 ctx.input[13] = iv_prefix;
     305                 :       1688 :                 ctx.input[14] = iv;
     306                 :       1688 :                 ctx.input[15] = iv >> 32;
     307                 :       1688 :             },
     308                 :       9138 :             [&] {
     309                 :       2905 :                 uint32_t integralInRange = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096);
     310         [ +  - ]:       2905 :                 std::vector<uint8_t> output(integralInRange);
     311                 :       2905 :                 chacha20.Keystream(MakeWritableByteSpan(output));
     312         [ +  - ]:       2905 :                 std::vector<uint8_t> djb_output(integralInRange);
     313                 :       2905 :                 ECRYPT_keystream_bytes(&ctx, djb_output.data(), djb_output.size());
     314   [ +  -  +  - ]:       2905 :                 assert(output == djb_output);
     315                 :            :                 // DJB's version seeks forward to a multiple of 64 bytes after every operation. Correct for that.
     316                 :       2905 :                 uint32_t old_counter = counter;
     317                 :       2905 :                 counter += (integralInRange + 63) >> 6;
     318         [ +  + ]:       2905 :                 if (counter < old_counter) ++nonce.first;
     319         [ +  + ]:       2905 :                 if (integralInRange & 63) {
     320                 :       1300 :                     chacha20.Seek(nonce, counter);
     321                 :       1300 :                 }
     322         [ +  - ]:       2905 :                 assert(counter == ctx.input[12]);
     323                 :       2905 :             },
     324                 :       7707 :             [&] {
     325                 :       1474 :                 uint32_t integralInRange = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096);
     326         [ +  - ]:       1474 :                 std::vector<uint8_t> output(integralInRange);
     327                 :       1474 :                 const std::vector<uint8_t> input = ConsumeFixedLengthByteVector(fuzzed_data_provider, output.size());
     328                 :       1474 :                 chacha20.Crypt(MakeByteSpan(input), MakeWritableByteSpan(output));
     329         [ +  - ]:       1474 :                 std::vector<uint8_t> djb_output(integralInRange);
     330                 :       1474 :                 ECRYPT_encrypt_bytes(&ctx, input.data(), djb_output.data(), input.size());
     331   [ +  -  +  - ]:       1474 :                 assert(output == djb_output);
     332                 :            :                 // DJB's version seeks forward to a multiple of 64 bytes after every operation. Correct for that.
     333                 :       1474 :                 uint32_t old_counter = counter;
     334                 :       1474 :                 counter += (integralInRange + 63) >> 6;
     335         [ +  + ]:       1474 :                 if (counter < old_counter) ++nonce.first;
     336         [ +  + ]:       1474 :                 if (integralInRange & 63) {
     337                 :       1335 :                     chacha20.Seek(nonce, counter);
     338                 :       1335 :                 }
     339         [ +  - ]:       1474 :                 assert(counter == ctx.input[12]);
     340                 :       1474 :             });
     341                 :       6233 :     }
     342                 :         87 : }

Generated by: LCOV version 1.14