16constexpr static inline uint32_t
rotl32(uint32_t v,
int c) {
17 return (v << c) | (v >> (32 - c));
20#define QUARTERROUND(a, b, c, d) \
23 d = rotl32(d ^ a, 16); \
25 b = rotl32(b ^ c, 12); \
27 d = rotl32(d ^ a, 8); \
29 b = rotl32(b ^ c, 7); \
49 assert(key.size() == KEYLEN);
73 input[8] = block_counter;
74 input[9] = nonce.first;
75 input[10] = nonce.second;
76 input[11] = nonce.second >> 32;
81 size_t blocks = output.size() / BLOCKLEN;
82 assert(blocks * BLOCKLEN == output.size());
84 uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14,
86 uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
180 assert(in_bytes.size() == out_bytes.size());
181 const uint8_t *m =
UCharCast(in_bytes.data());
182 uint8_t *c =
UCharCast(out_bytes.data());
183 size_t blocks = out_bytes.size() / BLOCKLEN;
184 assert(blocks * BLOCKLEN == out_bytes.size());
186 uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14,
188 uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
303 unsigned reuse = std::min<size_t>(m_bufleft, out.size());
304 std::copy(m_buffer.end() - m_bufleft,
305 m_buffer.end() - m_bufleft + reuse, out.begin());
307 out = out.subspan(reuse);
309 if (out.size() >= m_aligned.BLOCKLEN) {
310 size_t blocks = out.size() / m_aligned.BLOCKLEN;
311 m_aligned.Keystream(out.first(blocks * m_aligned.BLOCKLEN));
312 out = out.subspan(blocks * m_aligned.BLOCKLEN);
315 m_aligned.Keystream(m_buffer);
316 std::copy(m_buffer.begin(), m_buffer.begin() + out.size(), out.begin());
317 m_bufleft = m_aligned.BLOCKLEN - out.size();
323 assert(input.size() == output.size());
329 unsigned reuse = std::min<size_t>(m_bufleft, input.size());
330 for (
unsigned i = 0; i < reuse; i++) {
331 output[i] = input[i] ^ m_buffer[m_aligned.BLOCKLEN - m_bufleft + i];
334 output = output.subspan(reuse);
335 input = input.subspan(reuse);
337 if (input.size() >= m_aligned.BLOCKLEN) {
338 size_t blocks = input.size() / m_aligned.BLOCKLEN;
339 m_aligned.Crypt(input.first(blocks * m_aligned.BLOCKLEN),
340 output.first(blocks * m_aligned.BLOCKLEN));
341 output = output.subspan(blocks * m_aligned.BLOCKLEN);
342 input = input.subspan(blocks * m_aligned.BLOCKLEN);
344 if (!input.empty()) {
345 m_aligned.Keystream(m_buffer);
346 for (
unsigned i = 0; i < input.size(); i++) {
347 output[i] = input[i] ^ m_buffer[i];
349 m_bufleft = m_aligned.BLOCKLEN - input.size();
358 m_aligned.SetKey(key);
364 uint32_t rekey_interval) noexcept
365 : m_chacha20(key), m_rekey_interval(rekey_interval) {
368 assert(key.size() == KEYLEN);
373 assert(input.size() == output.size());
376 m_chacha20.Crypt(input, output);
379 if (++m_chunk_counter == m_rekey_interval) {
381 std::byte new_key[KEYLEN];
382 m_chacha20.Keystream(new_key);
384 m_chacha20.SetKey(new_key);
389 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 KEYLEN-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.
A Span is an object that can refer to a contiguous sequence of objects.
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
static constexpr uint32_t rotl32(uint32_t v, int c)
#define QUARTERROUND(a, b, c, d)
static void WriteLE32(uint8_t *ptr, uint32_t x)
static uint32_t ReadLE32(const uint8_t *ptr)
uint8_t * UCharCast(char *c)