Skip to content

fix(crypto): seed the IV generator from OS entropy, not the wall clock - #142

Merged
gburd merged 3 commits into
masterfrom
fix/iv-entropy
Sep 6, 2026
Merged

fix(crypto): seed the IV generator from OS entropy, not the wall clock#142
gburd merged 3 commits into
masterfrom
fix/iv-entropy

Conversation

@gburd

@gburd gburd commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator

Deferred security item from the 2026-08 review. Encryption IV unpredictability was weak: the Mersenne Twister behind __db_generate_iv was seeded from __os_gettime() hashed wall-clock seconds, so an attacker who knows roughly when the environment was created can narrow the IV stream. (AES-CBC mode and IV uniqueness were already correct — only unpredictability was at issue.)

The fix

  • New src/os/os_csprng.c__os_csprng() fills a buffer from the OS CSPRNG: getrandom(2) where available, else arc4random_buf(3), else /dev/urandom through the os layer. It returns an error rather than silently degrading.
  • configure: probe getrandom, arc4random_buf, sys/random.h; db_int.in includes <sys/random.h> when present. Registered in srcfiles.in, dist/Makefile.in, dist/meson.build (POSIX only — Windows keeps its own path and the historical fallback).
  • mt19937db.c: seed from __os_csprng(), falling back to the hashed clock only if the OS has no entropy source, so encryption still functions there.

Also fixes a latent tooling breakage found while doing this

Our SSI work put category-9 message IDs (4573/4574) into src/common/db_err.c, which is message category 0 (range 1–500). dist/s_message_id therefore computed a next-ID of 4575, exceeded category 0's max, and reported RANGE FULL — silently blocking any new DB_STR in src/os, src/common, src/crypto, src/hmac or src/fileops. Reassigned those two to 0211/0212 (the DB_SNAPSHOT_CONFLICT/DB_SNAPSHOT_UNSAFE strings themselves are unchanged) and gave os_csprng 0213. s_message_id now runs clean.

This is the same root-cause class as #140: SSI touched a shared convention without auditing it.

Verified

Probes detected (HAVE_GETRANDOM, HAVE_SYS_RANDOM_H, HAVE_ARC4RANDOM_BUF); build clean; a direct check confirms two __os_csprng draws differ and are non-zero; sec001, sec002 (encryption) and test001 btree/hash pass.

Deferred security item from the 2026-08 review: encryption IV *unpredictability*
was weak. The Mersenne Twister behind __db_generate_iv was seeded from
__os_gettime() hashed wall-clock SECONDS, so an attacker who knows roughly when
the environment was created can narrow the IV stream. (AES-CBC mode and IV
uniqueness were already correct; only unpredictability was at issue.)

- New src/os/os_csprng.c: __os_csprng() fills a buffer from the OS CSPRNG --
  getrandom(2) where available, else arc4random_buf(3), else /dev/urandom via
  the os layer. Returns an error rather than silently degrading.
- configure.ac: probe getrandom, arc4random_buf, and sys/random.h; db_int.in
  includes <sys/random.h> when present. Registered in srcfiles.in, Makefile.in
  and dist/meson.build (POSIX only; Windows keeps its own path and the historical
  fallback).
- mt19937db.c: seed from __os_csprng(); fall back to the hashed clock ONLY if the
  OS has no entropy source, so encryption still functions there.

Also fixes a latent tooling breakage found while doing this: our SSI work put
category-9 message ids (4573/4574) into src/common/db_err.c, which lives in
message category 0 (range 1-500). dist/s_message_id therefore computed a next-id
of 4575, exceeded category 0's max, and reported RANGE FULL -- blocking any new
DB_STR in src/os, src/common, src/crypto, src/hmac or src/fileops. Reassigned
those two to 0211/0212 (DB_SNAPSHOT_CONFLICT / DB_SNAPSHOT_UNSAFE strings are
unchanged) and gave os_csprng 0213. s_message_id now runs clean.

Verified: probes detected (HAVE_GETRANDOM, HAVE_SYS_RANDOM_H,
HAVE_ARC4RANDOM_BUF); build clean; a direct check shows two __os_csprng draws
differ and are non-zero; sec001, sec002 (encryption) and test001 btree/hash pass.
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

ABI diff produced no report (build skipped or no base tag).


Advisory: libabigail/nm is the authoritative binary-ABI check; Coccinelle is complementary source-level early warning. See dist/cocci/README.md.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

Coccinelle convention checks

No new violations. ✅

Resolved since baseline (2) -- update dist/cocci/baseline.txt to lock these in.
rule_mutex_unbalanced|MUTEX_UNBALANCED|src/crypto/mersenne/mt19937db.c|return (ret);
rule_mutex_unbalanced|MUTEX_UNBALANCED|src/mp/mp_register.c|return (ret);

My first version of the /dev/urandom fallback used a raw `int fd` with
__os_open/__os_read/__os_closehandle, but this OS layer takes an opaque DB_FH *
(__os_open's last arg is DB_FH **, __os_read takes DB_FH * and size_t *nr).
That broke 26 CI jobs (macOS, clang, Windows, nix, meson).

Why my local check missed it: HAVE_GETRANDOM is defined on this host, so the
fallback branch was preprocessed out and never compiled -- I validated only the
configuration that skips the buggy code.

Now compiled AND run in all three configurations: getrandom, arc4random_buf, and
the urandom fallback (0 errors, 0 warnings each); clang and --disable-cryptography
builds clean; two draws differ in both the default and the forced-fallback build.
Windows compiles mt19937db.c (which now calls __os_csprng) but had no
implementation, so the DLL link failed with LNK2019: unresolved external symbol
__os_csprng referenced in function __db_genrand. I had registered os_csprng.c
only in the POSIX build registries; Windows keeps its sources in the VS project
files, not dist/srcfiles.in.

src/os_windows/os_csprng.c uses RtlGenRandom (SystemFunction036 via advapi32)
rather than BCryptGenRandom: no provider handle, available since XP, and no new
bcrypt.lib dependency. Registered in VS10/db.vcxproj and db_small.vcxproj.

POSIX build re-verified clean; message ids stay in category 0's range
(0213 POSIX / 0214 Windows) and s_message_id runs clean.
@gburd
gburd merged commit 3bdf8cd into master Sep 6, 2026
49 of 52 checks passed
@gburd
gburd deleted the fix/iv-entropy branch September 6, 2026 20:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant