LCOV - code coverage report
Current view: top level - src/crypto - chacha20.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 119 267 44.6 %
Date: 2023-11-06 23:13:05 Functions: 8 13 61.5 %
Branches: 371 808 45.9 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (c) 2017-2022 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                 :            : // Based on the public domain implementation 'merged' by D. J. Bernstein
       6                 :            : // See https://cr.yp.to/chacha.html.
       7                 :            : 
       8                 :            : #include <crypto/common.h>
       9                 :            : #include <crypto/chacha20.h>
      10                 :            : #include <support/cleanse.h>
      11                 :            : #include <span.h>
      12                 :            : 
      13                 :            : #include <algorithm>
      14                 :            : #include <string.h>
      15                 :            : 
      16                 :     678720 : constexpr static inline uint32_t rotl32(uint32_t v, int c) { return (v << c) | (v >> (32 - c)); }
      17                 :            : 
      18                 :            : #define QUARTERROUND(a,b,c,d) \
      19                 :            :   a += b; d = rotl32(d ^ a, 16); \
      20                 :            :   c += d; b = rotl32(b ^ c, 12); \
      21                 :            :   a += b; d = rotl32(d ^ a, 8); \
      22                 :            :   c += d; b = rotl32(b ^ c, 7);
      23                 :            : 
      24                 :            : #define REPEAT10(a) do { {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; } while(0)
      25                 :            : 
      26                 :       4882 : void ChaCha20Aligned::SetKey(Span<const std::byte> key) noexcept
      27                 :            : {
      28         [ +  - ]:       4882 :     assert(key.size() == KEYLEN);
      29 [ +  - ][ +  - ]:       4882 :     input[0] = ReadLE32(UCharCast(key.data() + 0));
      30 [ +  - ][ +  - ]:       4882 :     input[1] = ReadLE32(UCharCast(key.data() + 4));
      31 [ +  - ][ +  - ]:       4882 :     input[2] = ReadLE32(UCharCast(key.data() + 8));
      32 [ +  - ][ +  - ]:       4882 :     input[3] = ReadLE32(UCharCast(key.data() + 12));
      33 [ +  - ][ +  - ]:       4882 :     input[4] = ReadLE32(UCharCast(key.data() + 16));
      34 [ +  - ][ +  - ]:       4882 :     input[5] = ReadLE32(UCharCast(key.data() + 20));
      35 [ +  - ][ +  - ]:       4882 :     input[6] = ReadLE32(UCharCast(key.data() + 24));
      36 [ +  - ][ +  - ]:       4882 :     input[7] = ReadLE32(UCharCast(key.data() + 28));
      37                 :       4882 :     input[8] = 0;
      38                 :       4882 :     input[9] = 0;
      39                 :       4882 :     input[10] = 0;
      40                 :       4882 :     input[11] = 0;
      41                 :       4882 : }
      42                 :            : 
      43                 :       2777 : ChaCha20Aligned::~ChaCha20Aligned()
      44                 :            : {
      45         [ +  - ]:       2777 :     memory_cleanse(input, sizeof(input));
      46                 :       2777 : }
      47                 :            : 
      48                 :       2777 : ChaCha20Aligned::ChaCha20Aligned(Span<const std::byte> key) noexcept
      49                 :            : {
      50                 :       2777 :     SetKey(key);
      51                 :       2777 : }
      52                 :            : 
      53                 :          0 : void ChaCha20Aligned::Seek(Nonce96 nonce, uint32_t block_counter) noexcept
      54                 :            : {
      55                 :          0 :     input[8] = block_counter;
      56                 :          0 :     input[9] = nonce.first;
      57                 :          0 :     input[10] = nonce.second;
      58                 :          0 :     input[11] = nonce.second >> 32;
      59                 :          0 : }
      60                 :            : 
      61                 :       2121 : inline void ChaCha20Aligned::Keystream(Span<std::byte> output) noexcept
      62                 :            : {
      63         [ +  - ]:       2121 :     unsigned char* c = UCharCast(output.data());
      64                 :       2121 :     size_t blocks = output.size() / BLOCKLEN;
      65         [ +  - ]:       2121 :     assert(blocks * BLOCKLEN == output.size());
      66                 :            : 
      67                 :            :     uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
      68                 :            :     uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
      69                 :            : 
      70         [ +  - ]:       2121 :     if (!blocks) return;
      71                 :            : 
      72                 :       2121 :     j4 = input[0];
      73                 :       2121 :     j5 = input[1];
      74                 :       2121 :     j6 = input[2];
      75                 :       2121 :     j7 = input[3];
      76                 :       2121 :     j8 = input[4];
      77                 :       2121 :     j9 = input[5];
      78                 :       2121 :     j10 = input[6];
      79                 :       2121 :     j11 = input[7];
      80                 :       2121 :     j12 = input[8];
      81                 :       2121 :     j13 = input[9];
      82                 :       2121 :     j14 = input[10];
      83                 :       2121 :     j15 = input[11];
      84                 :            : 
      85                 :       2121 :     for (;;) {
      86                 :       2121 :         x0 = 0x61707865;
      87                 :       2121 :         x1 = 0x3320646e;
      88                 :       2121 :         x2 = 0x79622d32;
      89                 :       2121 :         x3 = 0x6b206574;
      90                 :       2121 :         x4 = j4;
      91                 :       2121 :         x5 = j5;
      92                 :       2121 :         x6 = j6;
      93                 :       2121 :         x7 = j7;
      94                 :       2121 :         x8 = j8;
      95                 :       2121 :         x9 = j9;
      96                 :       2121 :         x10 = j10;
      97                 :       2121 :         x11 = j11;
      98                 :       2121 :         x12 = j12;
      99                 :       2121 :         x13 = j13;
     100                 :       2121 :         x14 = j14;
     101                 :       2121 :         x15 = j15;
     102                 :            : 
     103                 :            :         // The 20 inner ChaCha20 rounds are unrolled here for performance.
     104 [ +  - ][ +  - ]:       2121 :         REPEAT10(
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     105                 :            :             QUARTERROUND( x0, x4, x8,x12);
     106                 :            :             QUARTERROUND( x1, x5, x9,x13);
     107                 :            :             QUARTERROUND( x2, x6,x10,x14);
     108                 :            :             QUARTERROUND( x3, x7,x11,x15);
     109                 :            :             QUARTERROUND( x0, x5,x10,x15);
     110                 :            :             QUARTERROUND( x1, x6,x11,x12);
     111                 :            :             QUARTERROUND( x2, x7, x8,x13);
     112                 :            :             QUARTERROUND( x3, x4, x9,x14);
     113                 :            :         );
     114                 :            : 
     115                 :       2121 :         x0 += 0x61707865;
     116                 :       2121 :         x1 += 0x3320646e;
     117                 :       2121 :         x2 += 0x79622d32;
     118                 :       2121 :         x3 += 0x6b206574;
     119                 :       2121 :         x4 += j4;
     120                 :       2121 :         x5 += j5;
     121                 :       2121 :         x6 += j6;
     122                 :       2121 :         x7 += j7;
     123                 :       2121 :         x8 += j8;
     124                 :       2121 :         x9 += j9;
     125                 :       2121 :         x10 += j10;
     126                 :       2121 :         x11 += j11;
     127                 :       2121 :         x12 += j12;
     128                 :       2121 :         x13 += j13;
     129                 :       2121 :         x14 += j14;
     130                 :       2121 :         x15 += j15;
     131                 :            : 
     132                 :       2121 :         ++j12;
     133         [ -  + ]:       2121 :         if (!j12) ++j13;
     134                 :            : 
     135         [ +  - ]:       2121 :         WriteLE32(c + 0, x0);
     136         [ +  - ]:       2121 :         WriteLE32(c + 4, x1);
     137         [ +  - ]:       2121 :         WriteLE32(c + 8, x2);
     138         [ +  - ]:       2121 :         WriteLE32(c + 12, x3);
     139         [ +  - ]:       2121 :         WriteLE32(c + 16, x4);
     140         [ +  - ]:       2121 :         WriteLE32(c + 20, x5);
     141         [ +  - ]:       2121 :         WriteLE32(c + 24, x6);
     142         [ +  - ]:       2121 :         WriteLE32(c + 28, x7);
     143         [ +  - ]:       2121 :         WriteLE32(c + 32, x8);
     144         [ +  - ]:       2121 :         WriteLE32(c + 36, x9);
     145         [ +  - ]:       2121 :         WriteLE32(c + 40, x10);
     146         [ +  - ]:       2121 :         WriteLE32(c + 44, x11);
     147         [ +  - ]:       2121 :         WriteLE32(c + 48, x12);
     148         [ +  - ]:       2121 :         WriteLE32(c + 52, x13);
     149         [ +  - ]:       2121 :         WriteLE32(c + 56, x14);
     150         [ +  - ]:       2121 :         WriteLE32(c + 60, x15);
     151                 :            : 
     152         [ -  + ]:       2121 :         if (blocks == 1) {
     153                 :       2121 :             input[8] = j12;
     154                 :       2121 :             input[9] = j13;
     155                 :       2121 :             return;
     156                 :            :         }
     157                 :          0 :         blocks -= 1;
     158                 :          0 :         c += BLOCKLEN;
     159                 :            :     }
     160                 :       2121 : }
     161                 :            : 
     162                 :          0 : inline void ChaCha20Aligned::Crypt(Span<const std::byte> in_bytes, Span<std::byte> out_bytes) noexcept
     163                 :            : {
     164         [ #  # ]:          0 :     assert(in_bytes.size() == out_bytes.size());
     165                 :          0 :     const unsigned char* m = UCharCast(in_bytes.data());
     166                 :          0 :     unsigned char* c = UCharCast(out_bytes.data());
     167                 :          0 :     size_t blocks = out_bytes.size() / BLOCKLEN;
     168         [ #  # ]:          0 :     assert(blocks * BLOCKLEN == out_bytes.size());
     169                 :            : 
     170                 :            :     uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
     171                 :            :     uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
     172                 :            : 
     173         [ #  # ]:          0 :     if (!blocks) return;
     174                 :            : 
     175                 :          0 :     j4 = input[0];
     176                 :          0 :     j5 = input[1];
     177                 :          0 :     j6 = input[2];
     178                 :          0 :     j7 = input[3];
     179                 :          0 :     j8 = input[4];
     180                 :          0 :     j9 = input[5];
     181                 :          0 :     j10 = input[6];
     182                 :          0 :     j11 = input[7];
     183                 :          0 :     j12 = input[8];
     184                 :          0 :     j13 = input[9];
     185                 :          0 :     j14 = input[10];
     186                 :          0 :     j15 = input[11];
     187                 :            : 
     188                 :          0 :     for (;;) {
     189                 :          0 :         x0 = 0x61707865;
     190                 :          0 :         x1 = 0x3320646e;
     191                 :          0 :         x2 = 0x79622d32;
     192                 :          0 :         x3 = 0x6b206574;
     193                 :          0 :         x4 = j4;
     194                 :          0 :         x5 = j5;
     195                 :          0 :         x6 = j6;
     196                 :          0 :         x7 = j7;
     197                 :          0 :         x8 = j8;
     198                 :          0 :         x9 = j9;
     199                 :          0 :         x10 = j10;
     200                 :          0 :         x11 = j11;
     201                 :          0 :         x12 = j12;
     202                 :          0 :         x13 = j13;
     203                 :          0 :         x14 = j14;
     204                 :          0 :         x15 = j15;
     205                 :            : 
     206                 :            :         // The 20 inner ChaCha20 rounds are unrolled here for performance.
     207                 :          0 :         REPEAT10(
     208                 :            :             QUARTERROUND( x0, x4, x8,x12);
     209                 :            :             QUARTERROUND( x1, x5, x9,x13);
     210                 :            :             QUARTERROUND( x2, x6,x10,x14);
     211                 :            :             QUARTERROUND( x3, x7,x11,x15);
     212                 :            :             QUARTERROUND( x0, x5,x10,x15);
     213                 :            :             QUARTERROUND( x1, x6,x11,x12);
     214                 :            :             QUARTERROUND( x2, x7, x8,x13);
     215                 :            :             QUARTERROUND( x3, x4, x9,x14);
     216                 :            :         );
     217                 :            : 
     218                 :          0 :         x0 += 0x61707865;
     219                 :          0 :         x1 += 0x3320646e;
     220                 :          0 :         x2 += 0x79622d32;
     221                 :          0 :         x3 += 0x6b206574;
     222                 :          0 :         x4 += j4;
     223                 :          0 :         x5 += j5;
     224                 :          0 :         x6 += j6;
     225                 :          0 :         x7 += j7;
     226                 :          0 :         x8 += j8;
     227                 :          0 :         x9 += j9;
     228                 :          0 :         x10 += j10;
     229                 :          0 :         x11 += j11;
     230                 :          0 :         x12 += j12;
     231                 :          0 :         x13 += j13;
     232                 :          0 :         x14 += j14;
     233                 :          0 :         x15 += j15;
     234                 :            : 
     235         [ #  # ]:          0 :         x0 ^= ReadLE32(m + 0);
     236         [ #  # ]:          0 :         x1 ^= ReadLE32(m + 4);
     237         [ #  # ]:          0 :         x2 ^= ReadLE32(m + 8);
     238         [ #  # ]:          0 :         x3 ^= ReadLE32(m + 12);
     239         [ #  # ]:          0 :         x4 ^= ReadLE32(m + 16);
     240         [ #  # ]:          0 :         x5 ^= ReadLE32(m + 20);
     241         [ #  # ]:          0 :         x6 ^= ReadLE32(m + 24);
     242         [ #  # ]:          0 :         x7 ^= ReadLE32(m + 28);
     243         [ #  # ]:          0 :         x8 ^= ReadLE32(m + 32);
     244         [ #  # ]:          0 :         x9 ^= ReadLE32(m + 36);
     245         [ #  # ]:          0 :         x10 ^= ReadLE32(m + 40);
     246         [ #  # ]:          0 :         x11 ^= ReadLE32(m + 44);
     247         [ #  # ]:          0 :         x12 ^= ReadLE32(m + 48);
     248         [ #  # ]:          0 :         x13 ^= ReadLE32(m + 52);
     249         [ #  # ]:          0 :         x14 ^= ReadLE32(m + 56);
     250         [ #  # ]:          0 :         x15 ^= ReadLE32(m + 60);
     251                 :            : 
     252                 :          0 :         ++j12;
     253         [ #  # ]:          0 :         if (!j12) ++j13;
     254                 :            : 
     255                 :          0 :         WriteLE32(c + 0, x0);
     256                 :          0 :         WriteLE32(c + 4, x1);
     257                 :          0 :         WriteLE32(c + 8, x2);
     258                 :          0 :         WriteLE32(c + 12, x3);
     259                 :          0 :         WriteLE32(c + 16, x4);
     260                 :          0 :         WriteLE32(c + 20, x5);
     261                 :          0 :         WriteLE32(c + 24, x6);
     262                 :          0 :         WriteLE32(c + 28, x7);
     263                 :          0 :         WriteLE32(c + 32, x8);
     264                 :          0 :         WriteLE32(c + 36, x9);
     265                 :          0 :         WriteLE32(c + 40, x10);
     266                 :          0 :         WriteLE32(c + 44, x11);
     267                 :          0 :         WriteLE32(c + 48, x12);
     268                 :          0 :         WriteLE32(c + 52, x13);
     269                 :          0 :         WriteLE32(c + 56, x14);
     270                 :          0 :         WriteLE32(c + 60, x15);
     271                 :            : 
     272         [ #  # ]:          0 :         if (blocks == 1) {
     273                 :          0 :             input[8] = j12;
     274                 :          0 :             input[9] = j13;
     275                 :          0 :             return;
     276                 :            :         }
     277                 :          0 :         blocks -= 1;
     278                 :          0 :         c += BLOCKLEN;
     279                 :          0 :         m += BLOCKLEN;
     280                 :            :     }
     281                 :          0 : }
     282                 :            : 
     283                 :       2232 : void ChaCha20::Keystream(Span<std::byte> out) noexcept
     284                 :            : {
     285         [ +  - ]:       2232 :     if (out.empty()) return;
     286         [ +  + ]:       2232 :     if (m_bufleft) {
     287         [ +  - ]:        111 :         unsigned reuse = std::min<size_t>(m_bufleft, out.size());
     288         [ +  - ]:        111 :         std::copy(m_buffer.end() - m_bufleft, m_buffer.end() - m_bufleft + reuse, out.begin());
     289                 :        111 :         m_bufleft -= reuse;
     290                 :        111 :         out = out.subspan(reuse);
     291                 :        111 :     }
     292         [ +  - ]:       2232 :     if (out.size() >= m_aligned.BLOCKLEN) {
     293                 :          0 :         size_t blocks = out.size() / m_aligned.BLOCKLEN;
     294                 :          0 :         m_aligned.Keystream(out.first(blocks * m_aligned.BLOCKLEN));
     295                 :          0 :         out = out.subspan(blocks * m_aligned.BLOCKLEN);
     296                 :          0 :     }
     297         [ +  + ]:       2232 :     if (!out.empty()) {
     298         [ +  - ]:       2121 :         m_aligned.Keystream(m_buffer);
     299         [ +  - ]:       2121 :         std::copy(m_buffer.begin(), m_buffer.begin() + out.size(), out.begin());
     300                 :       2121 :         m_bufleft = m_aligned.BLOCKLEN - out.size();
     301                 :       2121 :     }
     302                 :       2232 : }
     303                 :            : 
     304                 :          0 : void ChaCha20::Crypt(Span<const std::byte> input, Span<std::byte> output) noexcept
     305                 :            : {
     306         [ #  # ]:          0 :     assert(input.size() == output.size());
     307                 :            : 
     308         [ #  # ]:          0 :     if (!input.size()) return;
     309         [ #  # ]:          0 :     if (m_bufleft) {
     310         [ #  # ]:          0 :         unsigned reuse = std::min<size_t>(m_bufleft, input.size());
     311         [ #  # ]:          0 :         for (unsigned i = 0; i < reuse; i++) {
     312                 :          0 :             output[i] = input[i] ^ m_buffer[m_aligned.BLOCKLEN - m_bufleft + i];
     313                 :          0 :         }
     314                 :          0 :         m_bufleft -= reuse;
     315                 :          0 :         output = output.subspan(reuse);
     316                 :          0 :         input = input.subspan(reuse);
     317                 :          0 :     }
     318         [ #  # ]:          0 :     if (input.size() >= m_aligned.BLOCKLEN) {
     319                 :          0 :         size_t blocks = input.size() / m_aligned.BLOCKLEN;
     320                 :          0 :         m_aligned.Crypt(input.first(blocks * m_aligned.BLOCKLEN), output.first(blocks * m_aligned.BLOCKLEN));
     321                 :          0 :         output = output.subspan(blocks * m_aligned.BLOCKLEN);
     322                 :          0 :         input = input.subspan(blocks * m_aligned.BLOCKLEN);
     323                 :          0 :     }
     324         [ #  # ]:          0 :     if (!input.empty()) {
     325         [ #  # ]:          0 :         m_aligned.Keystream(m_buffer);
     326         [ #  # ]:          0 :         for (unsigned i = 0; i < input.size(); i++) {
     327                 :          0 :             output[i] = input[i] ^ m_buffer[i];
     328                 :          0 :         }
     329                 :          0 :         m_bufleft = m_aligned.BLOCKLEN - input.size();
     330                 :          0 :     }
     331                 :          0 : }
     332                 :            : 
     333                 :       2777 : ChaCha20::~ChaCha20()
     334                 :            : {
     335         [ +  - ]:       2777 :     memory_cleanse(m_buffer.data(), m_buffer.size());
     336                 :       2777 : }
     337                 :            : 
     338                 :       2105 : void ChaCha20::SetKey(Span<const std::byte> key) noexcept
     339                 :            : {
     340                 :       2105 :     m_aligned.SetKey(key);
     341                 :       2105 :     m_bufleft = 0;
     342         [ +  - ]:       2105 :     memory_cleanse(m_buffer.data(), m_buffer.size());
     343                 :       2105 : }
     344                 :            : 
     345                 :          0 : FSChaCha20::FSChaCha20(Span<const std::byte> key, uint32_t rekey_interval) noexcept :
     346                 :          0 :     m_chacha20(key), m_rekey_interval(rekey_interval)
     347                 :            : {
     348         [ #  # ]:          0 :     assert(key.size() == KEYLEN);
     349                 :          0 : }
     350                 :            : 
     351                 :          0 : void FSChaCha20::Crypt(Span<const std::byte> input, Span<std::byte> output) noexcept
     352                 :            : {
     353         [ #  # ]:          0 :     assert(input.size() == output.size());
     354                 :            : 
     355                 :            :     // Invoke internal stream cipher for actual encryption/decryption.
     356                 :          0 :     m_chacha20.Crypt(input, output);
     357                 :            : 
     358                 :            :     // Rekey after m_rekey_interval encryptions/decryptions.
     359         [ #  # ]:          0 :     if (++m_chunk_counter == m_rekey_interval) {
     360                 :            :         // Get new key from the stream cipher.
     361                 :            :         std::byte new_key[KEYLEN];
     362                 :          0 :         m_chacha20.Keystream(new_key);
     363                 :            :         // Update its key.
     364                 :          0 :         m_chacha20.SetKey(new_key);
     365                 :            :         // Wipe the key (a copy remains inside m_chacha20, where it'll be wiped on the next rekey
     366                 :            :         // or on destruction).
     367         [ #  # ]:          0 :         memory_cleanse(new_key, sizeof(new_key));
     368                 :            :         // Set the nonce for the new section of output.
     369         [ #  # ]:          0 :         m_chacha20.Seek({0, ++m_rekey_counter}, 0);
     370                 :            :         // Reset the chunk counter.
     371                 :          0 :         m_chunk_counter = 0;
     372                 :          0 :     }
     373                 :          0 : }

Generated by: LCOV version 1.14