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 211 0.9 %
Date: 2023-09-26 12:08:55 Functions: 2 11 18.2 %

          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           2 : 
      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           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           4 : 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