17#define QUARTERROUND(a,b,c,d) \
18 a += b; d = std::rotl(d ^ a, 16); \
19 c += d; b = std::rotl(b ^ c, 12); \
20 a += b; d = std::rotl(d ^ a, 8); \
21 c += d; b = std::rotl(b ^ c, 7);
23#define REPEAT10(a) do { {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; } while(0)
27 assert(key.size() == KEYLEN);
54 input[8] = block_counter;
55 input[9] =
nonce.first;
56 input[10] =
nonce.second;
57 input[11] =
nonce.second >> 32;
62 unsigned char* c =
UCharCast(output.data());
63 size_t blocks = output.size() / BLOCKLEN;
64 assert(blocks * BLOCKLEN == output.size());
66 uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
67 uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
163 assert(in_bytes.size() == out_bytes.size());
164 const unsigned char*
m =
UCharCast(in_bytes.data());
165 unsigned char* c =
UCharCast(out_bytes.data());
166 size_t blocks = out_bytes.size() / BLOCKLEN;
167 assert(blocks * BLOCKLEN == out_bytes.size());
169 uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
170 uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
284 if (
out.empty())
return;
286 unsigned reuse = std::min<size_t>(m_bufleft,
out.size());
287 std::copy(m_buffer.end() - m_bufleft, m_buffer.end() - m_bufleft + reuse,
out.begin());
291 if (
out.size() >= m_aligned.BLOCKLEN) {
292 size_t blocks =
out.size() / m_aligned.BLOCKLEN;
293 m_aligned.Keystream(
out.first(blocks * m_aligned.BLOCKLEN));
294 out =
out.subspan(blocks * m_aligned.BLOCKLEN);
297 m_aligned.Keystream(m_buffer);
298 std::copy(m_buffer.begin(), m_buffer.begin() +
out.size(),
out.begin());
299 m_bufleft = m_aligned.BLOCKLEN -
out.size();
305 assert(input.size() == output.size());
307 if (!input.size())
return;
309 unsigned reuse = std::min<size_t>(m_bufleft, input.size());
310 for (
unsigned i = 0; i < reuse; i++) {
311 output[i] = input[i] ^ m_buffer[m_aligned.BLOCKLEN - m_bufleft + i];
314 output = output.subspan(reuse);
315 input = input.subspan(reuse);
317 if (input.size() >= m_aligned.BLOCKLEN) {
318 size_t blocks = input.size() / m_aligned.BLOCKLEN;
319 m_aligned.Crypt(input.first(blocks * m_aligned.BLOCKLEN), output.first(blocks * m_aligned.BLOCKLEN));
320 output = output.subspan(blocks * m_aligned.BLOCKLEN);
321 input = input.subspan(blocks * m_aligned.BLOCKLEN);
323 if (!input.empty()) {
324 m_aligned.Keystream(m_buffer);
325 for (
unsigned i = 0; i < input.size(); i++) {
326 output[i] = input[i] ^ m_buffer[i];
328 m_bufleft = m_aligned.BLOCKLEN - input.size();
339 m_aligned.SetKey(key);
345 m_chacha20(key), m_rekey_interval(rekey_interval)
347 assert(key.size() == KEYLEN);
352 assert(input.size() == output.size());
355 m_chacha20.Crypt(input, output);
358 if (++m_chunk_counter == m_rekey_interval) {
360 std::byte new_key[KEYLEN];
361 m_chacha20.Keystream(new_key);
363 m_chacha20.SetKey(new_key);
368 m_chacha20.Seek({0, ++m_rekey_counter}, 0);
void Keystream(Span< std::byte > out) noexcept
outputs the keystream into out, whose length must be a multiple of BLOCKLEN.
void Crypt(Span< const std::byte > input, 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 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.
~ChaCha20Aligned()
Destructor to clean up private memory.
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>
std::array< std::byte, ChaCha20Aligned::BLOCKLEN > m_buffer
void Keystream(Span< std::byte > out) noexcept
outputs the keystream to out.
~ChaCha20()
Destructor to clean up private memory.
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
void Crypt(Span< const std::byte > input, 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)
static uint32_t ReadLE32(const unsigned char *ptr)
static void WriteLE32(unsigned char *ptr, uint32_t x)
unsigned char * UCharCast(char *c)