16#define QUARTERROUND(a,b,c,d) \
17 a += b; d = std::rotl(d ^ a, 16); \
18 c += d; b = std::rotl(b ^ c, 12); \
19 a += b; d = std::rotl(d ^ a, 8); \
20 c += d; b = std::rotl(b ^ c, 7);
22#define REPEAT10(a) do { {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; } while(0)
26 assert(key.size() == KEYLEN);
30 input[3] =
ReadLE32(key.data() + 12);
31 input[4] =
ReadLE32(key.data() + 16);
32 input[5] =
ReadLE32(key.data() + 20);
33 input[6] =
ReadLE32(key.data() + 24);
34 input[7] =
ReadLE32(key.data() + 28);
53 input[8] = block_counter;
54 input[9] =
nonce.first;
55 input[10] =
nonce.second;
56 input[11] =
nonce.second >> 32;
61 std::byte* c = output.data();
62 size_t blocks = output.size() / BLOCKLEN;
63 assert(blocks * BLOCKLEN == output.size());
65 uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
66 uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
162 assert(in_bytes.size() == out_bytes.size());
163 const std::byte*
m = in_bytes.data();
164 std::byte* c = out_bytes.data();
165 size_t blocks = out_bytes.size() / BLOCKLEN;
166 assert(blocks * BLOCKLEN == out_bytes.size());
168 uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
169 uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
283 if (
out.empty())
return;
285 unsigned reuse = std::min<size_t>(m_bufleft,
out.size());
286 std::copy(m_buffer.end() - m_bufleft, m_buffer.end() - m_bufleft + reuse,
out.begin());
290 if (
out.size() >= m_aligned.BLOCKLEN) {
291 size_t blocks =
out.size() / m_aligned.BLOCKLEN;
292 m_aligned.Keystream(
out.first(blocks * m_aligned.BLOCKLEN));
293 out =
out.subspan(blocks * m_aligned.BLOCKLEN);
296 m_aligned.Keystream(m_buffer);
297 std::copy(m_buffer.begin(), m_buffer.begin() +
out.size(),
out.begin());
298 m_bufleft = m_aligned.BLOCKLEN -
out.size();
302void ChaCha20::Crypt(std::span<const std::byte> input, std::span<std::byte> output)
noexcept
304 assert(input.size() == output.size());
306 if (!input.size())
return;
308 unsigned reuse = std::min<size_t>(m_bufleft, input.size());
309 for (
unsigned i = 0; i < reuse; i++) {
310 output[i] = input[i] ^ m_buffer[m_aligned.BLOCKLEN - m_bufleft + i];
313 output = output.subspan(reuse);
314 input = input.subspan(reuse);
316 if (input.size() >= m_aligned.BLOCKLEN) {
317 size_t blocks = input.size() / m_aligned.BLOCKLEN;
318 m_aligned.Crypt(input.first(blocks * m_aligned.BLOCKLEN), output.first(blocks * m_aligned.BLOCKLEN));
319 output = output.subspan(blocks * m_aligned.BLOCKLEN);
320 input = input.subspan(blocks * m_aligned.BLOCKLEN);
322 if (!input.empty()) {
323 m_aligned.Keystream(m_buffer);
324 for (
unsigned i = 0; i < input.size(); i++) {
325 output[i] = input[i] ^ m_buffer[i];
327 m_bufleft = m_aligned.BLOCKLEN - input.size();
338 m_aligned.SetKey(key);
344 m_chacha20(key), m_rekey_interval(rekey_interval)
346 assert(key.size() == KEYLEN);
351 assert(input.size() == output.size());
354 m_chacha20.Crypt(input, output);
357 if (++m_chunk_counter == m_rekey_interval) {
359 std::byte new_key[KEYLEN];
360 m_chacha20.Keystream(new_key);
362 m_chacha20.SetKey(new_key);
367 m_chacha20.Seek({0, ++m_rekey_counter}, 0);
void Keystream(std::span< std::byte > out) noexcept
outputs the keystream into out, whose length must be a multiple of BLOCKLEN.
void Crypt(std::span< const std::byte > input, std::span< std::byte > output) noexcept
en/deciphers the message <input> and write the result into <output>
ChaCha20Aligned() noexcept=delete
For safety, disallow initialization without key.
std::pair< uint32_t, uint64_t > Nonce96
Type for 96-bit nonces used by the Set function below.
void Seek(Nonce96 nonce, uint32_t block_counter) noexcept
Set the 96-bit nonce and 32-bit block counter.
void SetKey(std::span< const std::byte > key) noexcept
Set 32-byte key, and seek to nonce 0 and block position 0.
~ChaCha20Aligned()
Destructor to clean up private memory.
void SetKey(std::span< const std::byte > key) noexcept
Set 32-byte key, and seek to nonce 0 and block position 0.
std::array< std::byte, ChaCha20Aligned::BLOCKLEN > m_buffer
~ChaCha20()
Destructor to clean up private memory.
void Keystream(std::span< std::byte > out) noexcept
outputs the keystream to out.
void Crypt(std::span< const std::byte > in_bytes, std::span< std::byte > out_bytes) noexcept
en/deciphers the message <in_bytes> and write the result into <out_bytes>
FSChaCha20(const FSChaCha20 &)=delete
void Crypt(std::span< const std::byte > input, std::span< std::byte > output) noexcept
Encrypt or decrypt a chunk.
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
#define QUARTERROUND(a, b, c, d)
void WriteLE32(B *ptr, uint32_t x)
uint32_t ReadLE32(const B *ptr)