- 🐛 Fix AES-GCM producing wrong ciphertext on
dart2wasmfor messages of
about 1 MiB or larger
(#28). The block counter is
stored in aUint8List
view over another buffer, and dart2wasm skips the modulo-256 truncation when
such a view is assigned an out-of-range value, socounter[i]++let the carry
bleed into the neighbouring byte. From the first 32-bit carry onward the
keystream desynchronised, silently breaking interoperability with every other
platform (and with other AES-GCM implementations). All stored counter bytes
are now masked explicitly. - ✅ The
inc32counter behaviour is now pinned against raw AES-ECB at every
byte-carry boundary, plus an end-to-end check across the 1 MiB boundary, and
thedart2wasmsuite runs on every push instead of only at release time. - ✅ New cross-cutting
test/counter_boundary_test.dartasserts counter
continuity — blockjof a run started at counterCequals block0of a
run started atC + j— for AES/Twofish/Blowfish CTR, ChaCha20 (32- and
64-bit counters), XChaCha20, Salsa20 and XSalsa20. Because the starting
counter is an input, this reaches the 32- and 64-bit carries that no
achievable message length could walk to, alongside a 1 MiB run per cipher. - Improve the benchmark harness (
benchmark/_base.dart): it now reports the
median per-iteration time sampled across ~25ms batches instead of the
arithmetic mean, making results robust against GC pauses and keeping each
batch well above the coarsened web timer resolution. Benchmark tooling only;
no library code or output is affected.
Full Changelog: v0.7.1...v0.7.2