zupt/AUDIT.md
Cristian Cezar Moisés 5bb280eb25 feat: add Jasmin assembly integration for crypto acceleration
- Integrated `zupt_mac_verify_ct` in `zupt_decrypt_buffer()` to replace C XOR loop for HMAC-SHA256
- Integrated `zupt_ct_select_32` in `zupt_mlkem768_decaps()` to replace C `cmov()` for FO transformation
- Added `include/zupt_jasmin.h` with extern declarations and ABI docs
- Added `#ifdef ZUPT_USE_JASMIN` guards with clean C fallbacks in `zupt_crypto.c` and `zupt_mlkem.c`
- Makefile now auto-detects `jasmin/*.s`, assembles and links with `-DZUPT_USE_JASMIN`

Closes #3
2026-03-28 23:03:04 -03:00

7.7 KiB
Raw Blame History

Security Audit — Zupt v1.5.0

Date: March 28, 2026 Author: Cristian Cezar Moisés Audit type: Self-audit with formal verification (Jasmin) and NIST/RFC test vectors Status: No independent third-party audit performed


1. Cryptographic Test Vector Verification

All primitives tested against published reference vectors:

Primitive Standard Vectors Status
SHA-256 FIPS 180-4 3 (empty, "abc", 448-bit) PASS
HMAC-SHA256 RFC 4231 2 (TC2: "Jefe", TC3: 20×0xAA) PASS
SHA3-256 FIPS 202 2 (empty, "abc") PASS
SHAKE-128 FIPS 202 1 (empty, 128-bit output) PASS
X25519 RFC 7748 §5.2 2 (both test vectors) PASS
ML-KEM-768 FIPS 203 2 (5-trial roundtrip + implicit rejection) PASS
XXH64 xxHash spec 1 (empty string, seed=0) PASS
Total 13 13/13 PASS

Reproduction: make test-vectors && ./test_vectors


2. Functional Test Results

Suite Tests Result What It Covers
Regression 16 16/16 PASS All codecs, modes, encryption, edge cases, corruption detection
Multi-threaded 14 14/14 PASS N=1/2/4/8 threads, large files, 1000 files, MT+encryption
Post-quantum 10 10/10 PASS Keygen, PQ encrypt/decrypt, wrong key, password compat, PQ+MT, 2MB
Quick smoke 9 9/9 PASS Normal, solid, encrypted, wrong pw, MT, fast, store, PQ, integrity
NIST vectors 13 13/13 PASS See table above
Total 62 62/62 PASS

Reproduction: make test-all


3. Memory Safety

Tool Command Result
AddressSanitizer make test-asan Zero errors
UndefinedBehaviorSanitizer Built with -fsanitize=address,undefined Zero errors
All code paths tested Normal + solid + encrypted + PQ + MT Clean

Reproduction:

make test-asan
./zupt_asan compress /tmp/t.zupt /path/to/data/
./zupt_asan extract -o /tmp/out/ /tmp/t.zupt
./zupt_asan keygen -o /tmp/k.key
./zupt_asan compress --pq /tmp/pub.key /tmp/pq.zupt /path/to/data/
./zupt_asan extract --pq /tmp/k.key -o /tmp/pqout/ /tmp/pq.zupt

4. Compiler Warning Audit

Compiler Flags Warnings
GCC 13.x -Wall -Wextra -Wpedantic -O2 -std=c11 Zero
Clang 18.x -Wall -Wextra -Wpedantic -O2 -std=c11 Zero

5. Constant-Time Analysis

Function Location CT Method Jasmin Verified? Risk Level
HMAC comparison zupt_crypto.c:252 4×u64 XOR accumulation Yeszupt_mac_verify_ct linked None (Jasmin proven)
ML-KEM FO select zupt_mlkem.c:593 4×u64 masked select Yeszupt_ct_select_32 linked None (Jasmin proven)
ML-KEM NTT butterfly zupt_mlkem.c Montgomery reduction (branchless) No Low
ML-KEM CBD sampling zupt_mlkem.c Bitwise operations only No Low
X25519 fe_cswap zupt_x25519.c:95 Masked XOR swap No (limb mismatch) Low (C is branchless)
X25519 Montgomery ladder zupt_x25519.c:243 Fixed 255 iterations No Low
AES-256 encrypt zupt_aes256.c:59 Table-based S-box No HIGH on shared HW
SHA-256 zupt_sha256.c Table-based constants No Low (not secret-indexed)
Keccak-f[1600] zupt_keccak.c Bitwise XOR/ROT only No None
Key wipe zupt_crypto.c explicit_bzero / volatile No Low

Jasmin Assembly Verification

Two functions confirmed active in binary via nm:

0000000000014ae0 T zupt_mac_verify_ct    ← Jasmin assembly, CT proven
0000000000014b20 T zupt_ct_select_32     ← Jasmin assembly, CT proven

Assembly generated by jasminc 2026.03.0. Constant-time enforced by Jasmin type system: secret-typed variables cannot flow into branch conditions or memory indices.

Not Wired (with reason)

Function Issue Fallback
zupt_fe_cswap Jasmin: 4×u64 limbs, C: 5×u51 — incompatible C masked XOR (branchless)
zupt_aes256_blk Stack offset bug: rk.[1][rsp+1] not [rsp+16] C table-based AES

6. Key Material Lifecycle

Phase Method Verified
Generation OS CSPRNG: getrandom(2) / /dev/urandom / RtlGenRandom Hard fail if unavailable
Storage Stack-local arrays (no heap allocation for keys) ASAN verified
Usage Passed by const pointer to AES-CTR / HMAC No copies to heap
Wipe zupt_secure_wipe(): explicit_bzero (glibc 2.25+), SecureZeroMemory (Win), volatile fallback Compiler cannot optimize out
Scope exit Stack frame destroyed Keys were on stack

All intermediate buffers in PBKDF2, hybrid KEM, ML-KEM encaps/decaps, and X25519 wiped before return.


7. Nonce Security

Scheme: per_block_nonce = base_nonce XOR pad_le(block_seq, 8)

  • base_nonce: 128-bit random from CSPRNG, generated once per archive.
  • block_seq: monotonically increasing 0, 1, 2, ... per archive.
  • Uniqueness within archive: Guaranteed (distinct seq → distinct nonce).
  • Uniqueness across archives: 2^-128 collision probability per pair (birthday bound on random base).

8. Encrypt-then-MAC Ordering

Step Action Verified
1 Compute HMAC over nonce ‖ ciphertext HMAC input is nonce+ct, not plaintext
2 Verify HMAC before any decryption Code path: MAC check → early return if fail → decrypt only on success
3 Decrypt only authenticated data No plaintext produced from unauthenticated ciphertext

Prevents: Chosen-ciphertext attacks, padding oracles, ciphertext tampering.


9. Bugs Found and Fixed (v0.5.1 → v1.5.0)

Bug Severity Version Fixed Impact
Huffman Kraft-inequality violation Critical v0.5.1 Data corruption on specific inputs
Heap-buffer-overflow in LZ match finder Critical v0.5.1 Potential code execution
rand() CSPRNG fallback Critical v0.5.1 Predictable encryption keys
ML-KEM poly_basemul OOB Critical v1.0.0 Buffer overread in NTT
ML-KEM missing poly_tomont Critical v1.0.0 Public key in wrong domain
ML-KEM inverted FO cmov Critical v1.0.0 Always selected rejection key
ML-KEM inv_ntt wrong table High v1.0.0 NTT roundtrip failure
PQ nonce mismatch High v1.0.0 Encrypt/decrypt used different nonces
X25519 AA + a24*E formula High v1.1.0 Wrong curve, not interoperable
Dead match_cost() Low v1.1.0 Clang warning
const polyvec qualifier Low v1.1.0 Pedantic warnings
__int128 pedantic Low v1.1.0 Pedantic warning

10. Known Limitations

Limitation Impact Mitigation Status
Table-based AES (C fallback) Cache-timing on shared hardware Jasmin AES-NI path exists but has offset bug Open — fix .jazz source
Table-based SHA-256 Theoretical cache-timing Not used on secret-indexed data Accepted
PBKDF2 not quantum-safe Quantum password brute-force Use --pq mode Documented
No mlock() Keys swappable to disk Short key lifetime + zupt_secure_wipe Planned
No fuzzing performed Undiscovered bugs AFL++ setup in FUZZING.md Planned
No independent audit Self-assessed only Open source + Jasmin proofs Planned
X25519 Jasmin not linked C fallback for fe_cswap C is branchless but compiler-dependent Open — limb mismatch

© 2026 Cristian Cezar Moisés — MIT License