Skip to content

libsodium: add harnesses for KEM, ipcrypt, HKDF, SHA-3/XOF, pwhash, stream, secretstream, etc.#73

Open
tc-agent wants to merge 2 commits into
masterfrom
libsodium-expand-harness-coverage
Open

libsodium: add harnesses for KEM, ipcrypt, HKDF, SHA-3/XOF, pwhash, stream, secretstream, etc.#73
tc-agent wants to merge 2 commits into
masterfrom
libsodium-expand-harness-coverage

Conversation

@tc-agent

Copy link
Copy Markdown
Owner

Summary

Expands the libsodium fuzzing surface with 13 new harnesses and broadens the
existing crypto_box, crypto_secretbox, and crypto_sign harnesses to exercise
their non-_easy APIs. The existing surface only covered ~8 primitives
(AEAD, box, secretbox, generichash, kdf, kx, sign, secret_key_auth);
substantial primitive families had no harness at all.

Fuzz Introspector baseline

https://introspector.oss-fuzz.com/project-profile?project=libsodium
(report dated 2026-05-19): runtime line coverage 51.89% (5524/10646),
static reachability 24.64%, function coverage 46.00%, fuzzer count 8.

https://storage.googleapis.com/oss-fuzz-coverage/libsodium/reports/20260519/linux/src/libsodium/src/libsodium/report.html
shows several whole subdirectories at very low coverage that no existing
harness reached, e.g. crypto_pwhash/ 1.45% (Argon2 / scrypt entirely
untouched), crypto_box/ 0.00%, crypto_stream/ 31.34%,
crypto_kdf/ 35.29%, sodium/ 27.46%.

New harnesses (13)

  • crypto_pwhash_fuzzer - Argon2id/Argon2i/scrypt one-shot, _str + _str_verify
    • _str_needs_rehash round-trip, plus attacker-controlled _str_verify to
      drive the encoded-string parser. Uses MIN ops/mem.
  • crypto_stream_fuzzer - XSalsa20, Salsa20{,/12,/8}, ChaCha20, ChaCha20-IETF,
    XChaCha20 XOR round-trip with offset variant.
  • crypto_shorthash_fuzzer - SipHash-2-4, SipHashx-2-4.
  • crypto_onetimeauth_fuzzer - Poly1305 one-shot vs streaming equivalence +
    flipped-tag verify rejection.
  • crypto_scalarmult_fuzzer - X25519/Ed25519/Ristretto255 base/non-base scalar
    mult, point validation, _from_uniform, scalar reduce/negate/invert, ed25519
    add/sub - all on attacker-controlled bytes.
  • crypto_secretstream_fuzzer - xchacha20poly1305 secretstream end-to-end
    push/pull with TAG_MESSAGE / TAG_PUSH / TAG_REKEY / TAG_FINAL mix.
  • crypto_box_seal_fuzzer - sealed box round-trip + attacker-controlled bytes
    through seal_open.
  • sodium_utils_fuzzer - sodium_pad/_unpad, sodium_bin2hex/_hex2bin,
    sodium_bin2base64/_base642bin (all 4 variants), sodium_compare/_increment/
    _add/_sub/_is_zero, sodium_ip2bin.
  • crypto_hkdf_fuzzer - HKDF-SHA256/HKDF-SHA512 one-shot extract+expand and
    the streaming _extract_init/_update/_final form.
  • crypto_kem_fuzzer - ML-KEM-768 (FIPS 203) and X-Wing; keypair,
    _enc/_enc_deterministic, _dec, plus attacker-controlled ciphertext through
    _dec to exercise the implicit-rejection branch.
  • crypto_ipcrypt_fuzzer - ipcrypt deterministic/ND/NDX/PFX round-trip.
  • crypto_box_xchacha_fuzzer - curve25519-xchacha20poly1305 box +
    xchacha20poly1305 secretbox round-trip + sealed-box variant.
  • crypto_xof_fuzzer - SHA3-256/512, SHAKE-128/256, TurboSHAKE-128/256
    one-shot vs streaming equivalence.
  • crypto_auth_hmac_fuzzer - HMAC-SHA256/SHA512/SHA512-256 streaming under
    multiple key-length classes plus flipped-tag verify rejection.

All new harnesses gate on a selector byte from the fuzzer input so the same
input shape exercises several primitives, and they round-trip / cross-check
where applicable so libfuzzer sees a useful signal beyond "does not crash".

Modifications to existing harnesses

  • crypto_box_fuzzer: also exercises the zero-prepad crypto_box/_open API and
    the precomputed _beforenm/_easy_afternm path. The _easy variants delegate
    around box_curve25519xsalsa20poly1305.c, so the previous harness left it
    uncovered.
  • secretbox_easy_fuzzer: also calls _detached and the zero-prepad
    crypto_secretbox/_open API to reach crypto_secretbox.c and
    secretbox_xsalsa20poly1305.c.
  • crypto_sign_fuzzer: adds Ed25519ph streaming sign+verify, the combined
    crypto_sign/crypto_sign_open API, and the pk_to_curve25519/sk_to_curve25519/
    sk_to_seed/sk_to_pk conversions.

Local coverage

After 5 minutes of fuzz_for_pr per harness:

  • accumulated-corpus measurement: 71.39% line coverage (12426/17405)
    • +19.50pp over the 51.89% Fuzz Introspector baseline
  • cold-start single 5-minute run: 64.74% (11280/17424) - +12.85pp

Largest per-subdirectory deltas vs baseline (accumulated corpus):

subdir baseline local delta
crypto_pwhash/ 1.45% 49.65% +48.20pp
crypto_kem/ n/a 89.78% new
crypto_xof/ n/a 83.19% new
crypto_secretstream/ n/a 81.07% new
crypto_shorthash/ n/a 90.91% new
crypto_ipcrypt/ n/a 46.75% new
crypto_kdf/ 35.29% 64.97% +29.68pp
crypto_secretbox/ 48.65% 69.67% +21.02pp
crypto_core/ 51.93% 91.42% +39.49pp
crypto_box/ 0.00% 62.20% +62.20pp

The remaining gap is largely CPU-dispatch siblings linked into the static
library that never execute on this CPU (e.g.
argon2-fill-block-{ref,ssse3,avx512f}.c - only the AVX2 variant runs;
chacha20_ref.c, softaes.c, crypto_ipcrypt/ipcrypt_soft.c, poly1305_donna64.h,
pwhash_scryptsalsa208sha256_nosse.c, blake2b-compress-{ref,ssse3}.c).

@github-actions

Copy link
Copy Markdown

Fuzzing Coverage Report

Tested: project libsodium · base 766921e → head 715723d · 300s total fuzz budget · updated 2026-05-28 07:57 UTC · workflow run

OSS-Fuzz: Fuzz Introspector · build status

Metric Before After Delta
Static reachability 30.7% (190/618) 48.3% (566/1173) +17.5%
Line coverage 52.5% (5604/10674) 72.2% (12648/17525) +125.7%
Branch coverage 22.6% (954/4227) 43.3% (2725/6299) +185.6%
Function coverage 46.8% (312/667) 59.4% (747/1258) +139.4%

Per-harness

Harness Lines before Lines after Δ
crypto_aead_fuzzer 27.6% (2562/9274) 27.6% (2562/9274) +0.0%
crypto_auth_hmac_fuzzer 0% 9.7% (836/8641) new
crypto_box_fuzzer 25.8% (2257/8735) 27.1% (2373/8768) +5.1%
crypto_box_seal_fuzzer 0% 27.6% (2436/8824) new
crypto_box_xchacha_fuzzer 0% 27.9% (2424/8693) new
crypto_generichash_fuzzer 6.4% (520/8181) 6.4% (520/8181) +0.0%
crypto_hkdf_fuzzer 0% 9.5% (826/8738) new
crypto_ipcrypt_fuzzer 0% 11.0% (978/8889) new
crypto_kdf_fuzzer 5.7% (466/8181) 5.7% (466/8181) +0.0%
crypto_kem_fuzzer 0% 22.2% (2061/9298) new
crypto_kx_fuzzer 14.8% (1228/8280) 14.8% (1228/8280) +0.0%
crypto_onetimeauth_fuzzer 0% 13.3% (1086/8175) new
crypto_pwhash_fuzzer 0% 20.4% (2131/10462) new
crypto_scalarmult_fuzzer 0% 32.1% (2747/8552) new
crypto_secretstream_fuzzer 0% 16.8% (1422/8459) new
crypto_shorthash_fuzzer 0% 5.1% (424/8259) new
crypto_sign_fuzzer 27.1% (2333/8600) 28.8% (2491/8640) +6.8%
crypto_stream_fuzzer 0% 9.7% (843/8688) new
crypto_xof_fuzzer 0% 10.8% (956/8875) new
secret_key_auth_fuzzer 7.8% (653/8407) 7.8% (653/8407) +0.0%
secretbox_easy_fuzzer 16.1% (1360/8432) 17.0% (1439/8461) +5.8%
sodium_utils_fuzzer 0% 11.2% (974/8709) new

Δ = (after − before) / before, to accommodate that denominators may change. "new" when before is 0; "deleted" when after is 0.

@tc-agent
tc-agent force-pushed the master branch 3 times, most recently from af7f9a7 to 806b281 Compare May 28, 2026 18:05
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