Interleave stream encryption and Poly1305 on cache-sized chunks

This commit is contained in:
Frank Denis
2026-07-12 19:49:37 +02:00
parent f17fa784e0
commit 7014b204b6
3 changed files with 78 additions and 10 deletions
@@ -17,6 +17,8 @@
static const unsigned char _pad0[16] = { 0 };
#define STREAM_POLY1305_CHUNK 131072
int
crypto_aead_chacha20poly1305_encrypt_detached(unsigned char *c,
unsigned char *mac,
@@ -42,9 +44,22 @@ crypto_aead_chacha20poly1305_encrypt_detached(unsigned char *c,
STORE64_LE(slen, (uint64_t) adlen);
crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen);
crypto_stream_chacha20_xor_ic(c, m, mlen, npub, 1U, k);
{
unsigned long long off = 0U;
uint64_t ic = 1U;
crypto_onetimeauth_poly1305_update(&state, c, mlen);
COMPILER_ASSERT(STREAM_POLY1305_CHUNK % 64U == 0U);
while (off < mlen) {
unsigned long long cl = mlen - off;
if (cl > STREAM_POLY1305_CHUNK) {
cl = STREAM_POLY1305_CHUNK;
}
crypto_stream_chacha20_xor_ic(c + off, m + off, cl, npub, ic, k);
crypto_onetimeauth_poly1305_update(&state, c + off, cl);
off += cl;
ic += cl / 64U;
}
}
STORE64_LE(slen, (uint64_t) mlen);
crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen);
@@ -112,9 +127,22 @@ crypto_aead_chacha20poly1305_ietf_encrypt_detached(unsigned char *c,
crypto_onetimeauth_poly1305_update(&state, ad, adlen);
crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - adlen) & 0xf);
crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, npub, 1U, k);
{
unsigned long long off = 0U;
uint32_t ic = 1U;
crypto_onetimeauth_poly1305_update(&state, c, mlen);
while (off < mlen) {
unsigned long long cl = mlen - off;
if (cl > STREAM_POLY1305_CHUNK) {
cl = STREAM_POLY1305_CHUNK;
}
crypto_stream_chacha20_ietf_xor_ic(c + off, m + off, cl,
npub, ic, k);
crypto_onetimeauth_poly1305_update(&state, c + off, cl);
off += cl;
ic += (uint32_t) (cl / 64U);
}
}
crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - mlen) & 0xf);
STORE64_LE(slen, (uint64_t) adlen);
@@ -19,6 +19,8 @@
static const unsigned char _pad0[16] = { 0 };
#define STREAM_POLY1305_CHUNK 131072
static int
_encrypt_detached(unsigned char *c,
unsigned char *mac,
@@ -43,9 +45,31 @@ _encrypt_detached(unsigned char *c,
crypto_onetimeauth_poly1305_update(&state, ad, adlen);
crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - adlen) & 0xf);
crypto_stream_chacha20_ietf_ext_xor_ic(c, m, mlen, npub, 1U, k);
{
unsigned long long off = 0U;
uint32_t ic = 1U;
/*
* The ietf_ext counter is 32-bit and overflows into the IV past
* ~256 GiB, which a chunk restart cannot reproduce, so oversized
* messages make a single pass instead.
*/
unsigned long long chunk = mlen <= 64ULL * (0xffffffffULL - 1ULL)
? STREAM_POLY1305_CHUNK
: mlen;
crypto_onetimeauth_poly1305_update(&state, c, mlen);
COMPILER_ASSERT(STREAM_POLY1305_CHUNK % 64U == 0U);
while (off < mlen) {
unsigned long long cl = mlen - off;
if (cl > chunk) {
cl = chunk;
}
crypto_stream_chacha20_ietf_ext_xor_ic(c + off, m + off, cl,
npub, ic, k);
crypto_onetimeauth_poly1305_update(&state, c + off, cl);
off += cl;
ic += (uint32_t) (cl / 64U);
}
}
crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - mlen) & 0xf);
STORE64_LE(slen, (uint64_t) adlen);
@@ -13,6 +13,8 @@
#include "private/common.h"
#include "utils.h"
#define STREAM_POLY1305_CHUNK 131072
int
crypto_secretbox_detached(unsigned char *c, unsigned char *mac,
const unsigned char *m,
@@ -60,13 +62,27 @@ crypto_secretbox_detached(unsigned char *c, unsigned char *mac,
c[i] = block0[crypto_secretbox_ZEROBYTES + i];
}
sodium_memzero(block0, sizeof block0);
if (mlen > mlen0) {
crypto_stream_salsa20_xor_ic(c + mlen0, m + mlen0, mlen - mlen0,
n + 16, 1U, subkey);
crypto_onetimeauth_poly1305_update(&state, c, mlen0);
{
unsigned long long off = mlen0;
uint64_t ic = 1U;
COMPILER_ASSERT(STREAM_POLY1305_CHUNK % 64U == 0U);
while (off < mlen) {
unsigned long long cl = mlen - off;
if (cl > STREAM_POLY1305_CHUNK) {
cl = STREAM_POLY1305_CHUNK;
}
crypto_stream_salsa20_xor_ic(c + off, m + off, cl,
n + 16, ic, subkey);
crypto_onetimeauth_poly1305_update(&state, c + off, cl);
off += cl;
ic += cl / 64U;
}
}
sodium_memzero(subkey, sizeof subkey);
crypto_onetimeauth_poly1305_update(&state, c, mlen);
crypto_onetimeauth_poly1305_final(&state, mac);
sodium_memzero(&state, sizeof state);