16 constexpr
static inline uint32_t
rotl32(uint32_t v,
int c) {
return (v << c) | (v >> (32 - c)); }
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); 24 #define REPEAT10(a) do { {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; } while(0) 28 assert(key.size() == KEYLEN);
55 input[8] = block_counter;
56 input[9] =
nonce.first;
57 input[10] =
nonce.second;
58 input[11] =
nonce.second >> 32;
63 unsigned char* c =
UCharCast(output.data());
64 size_t blocks = output.size() / BLOCKLEN;
65 assert(blocks * BLOCKLEN == output.size());
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;
164 assert(in_bytes.size() == out_bytes.size());
165 const unsigned char*
m =
UCharCast(in_bytes.data());
166 unsigned char* c =
UCharCast(out_bytes.data());
167 size_t blocks = out_bytes.size() / BLOCKLEN;
168 assert(blocks * BLOCKLEN == out_bytes.size());
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;
285 if (
out.empty())
return;
287 unsigned reuse = std::min<size_t>(m_bufleft,
out.size());
288 std::copy(m_buffer.end() - m_bufleft, m_buffer.end() - m_bufleft + reuse,
out.begin());
292 if (
out.size() >= m_aligned.BLOCKLEN) {
293 size_t blocks =
out.size() / m_aligned.BLOCKLEN;
294 m_aligned.Keystream(
out.first(blocks * m_aligned.BLOCKLEN));
295 out =
out.subspan(blocks * m_aligned.BLOCKLEN);
298 m_aligned.Keystream(m_buffer);
299 std::copy(m_buffer.begin(), m_buffer.begin() +
out.size(),
out.begin());
300 m_bufleft = m_aligned.BLOCKLEN -
out.size();
306 assert(input.size() == output.size());
308 if (!input.size())
return;
310 unsigned reuse = std::min<size_t>(m_bufleft, input.size());
311 for (
unsigned i = 0; i < reuse; i++) {
312 output[i] = input[i] ^ m_buffer[m_aligned.BLOCKLEN - m_bufleft + i];
315 output = output.subspan(reuse);
316 input = input.subspan(reuse);
318 if (input.size() >= m_aligned.BLOCKLEN) {
319 size_t blocks = input.size() / m_aligned.BLOCKLEN;
320 m_aligned.Crypt(input.first(blocks * m_aligned.BLOCKLEN), output.first(blocks * m_aligned.BLOCKLEN));
321 output = output.subspan(blocks * m_aligned.BLOCKLEN);
322 input = input.subspan(blocks * m_aligned.BLOCKLEN);
324 if (!input.empty()) {
325 m_aligned.Keystream(m_buffer);
326 for (
unsigned i = 0; i < input.size(); i++) {
327 output[i] = input[i] ^ m_buffer[i];
329 m_bufleft = m_aligned.BLOCKLEN - input.size();
340 m_aligned.SetKey(key);
346 m_chacha20(key), m_rekey_interval(rekey_interval)
348 assert(key.size() == KEYLEN);
353 assert(input.size() == output.size());
356 m_chacha20.Crypt(input, output);
359 if (++m_chunk_counter == m_rekey_interval) {
361 std::byte new_key[KEYLEN];
362 m_chacha20.Keystream(new_key);
364 m_chacha20.SetKey(new_key);
369 m_chacha20.Seek({0, ++m_rekey_counter}, 0);
~ChaCha20()
Destructor to clean up private memory.
void Keystream(Span< std::byte > out) noexcept
outputs the keystream to out.
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
void SetKey(Span< const std::byte > key) noexcept
Set 32-byte key, and seek to nonce 0 and block position 0.
void Seek(Nonce96 nonce, uint32_t block_counter) noexcept
Set the 96-bit nonce and 32-bit block counter.
static void WriteLE32(unsigned char *ptr, uint32_t x)
~ChaCha20Aligned()
Destructor to clean up private memory.
#define QUARTERROUND(a, b, c, d)
void Crypt(Span< const std::byte > input, Span< std::byte > output) noexcept
Encrypt or decrypt a chunk.
static constexpr uint32_t rotl32(uint32_t v, int c)
ChaCha20Aligned() noexcept=delete
For safety, disallow initialization without key.
std::array< std::byte, ChaCha20Aligned::BLOCKLEN > m_buffer
std::pair< uint32_t, uint64_t > Nonce96
Type for 96-bit nonces used by the Set function below.
void Crypt(Span< const std::byte > in_bytes, Span< std::byte > out_bytes) noexcept
en/deciphers the message <in_bytes> and write the result into <out_bytes>
void Crypt(Span< const std::byte > input, Span< std::byte > output) noexcept
en/deciphers the message <input> and write the result into <output>
static uint32_t ReadLE32(const unsigned char *ptr)
unsigned char * UCharCast(char *c)
void Keystream(Span< std::byte > out) noexcept
outputs the keystream into out, whose length must be a multiple of BLOCKLEN.
void SetKey(Span< const std::byte > key) noexcept
Set 32-byte key, and seek to nonce 0 and block position 0.
FSChaCha20(const FSChaCha20 &)=delete