Multi-block CFB1 never advances input/outBuffer leaking plaintext and stale output as ciphertext for blocks > 1
Summary
In both rijndael_blockEncrypt MODE_CFB1 and rijndael_blockDecrypt MODE_CFB1 per-block outer loop for(i=numBlocks i>0 i--) never advances input or outBuffer pointers unlike every ECB/CBC branch (which all do input+=16 outBuffer+=16). For numBlocks>1 function re-operates on same first 16 bytes every iteration never touches outBuffer[16..16*numBlocks-1] yet returns 128*numBlocks claiming it produced that many bits. Encrypt leaves plaintext for blocks 2..n untouched in ciphertext output (confidentiality break). Decrypt re-reads input[0..15] each block leaves output[16..] uninitialised/stale. No in-tree kernel caller uses MODE_CFB1 (only test00.c) so latent. [VERIFIED pass2: reproduced - MODE_CFB1 blockEncrypt returns 256 bits while out 16-31 stays at sentinel, loop never advances, plaintext blocks 2-n leak as ciphertext; pointer-advance fix-validated both directions, latent no in-tree caller]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2369 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| env.txt | β | 412 B | view raw | |
| fix.diff | β | 579 B | view raw | |
| rig | β | 4.0 KB | β download | |
| run_fixed_kernel.log | β | 2.8 KB | view raw | |
| run_kernel_baseline.log | β | 172 B | view raw | |
| verdict.json | β | 2.1 KB | view raw | |
| fix.diff | β | 579 B | view raw |
Fix verification
not_testableConfirmed kernel references
Detail
Evidence (decisive lines)
session baseline (ct[16..31] = e7*16 sentinel INTACT, rc=256; decrypt stale) vs run_fixed_kernel.log (ct[16..31] = 40 24 d0 ..., decrypt changed), fix.diff
PoC changes
initial ECB KAT used raw key bytes where the legacy makeKey API wants ASCII hex keyMaterial - the FIPS vector now matches
Verified recommended fix
advance input/outBuffer per block in both CFB1 loops
Verdict
Real in-kernel rijndael KPI, MODE_CFB1, two blocks (inputLen=256 bits): rijndael_blockEncrypt returns 256 claiming two produced blocks while out[16..31] stays at its pre-planted sentinel - the per-block loop never advances input/outBuffer (every other mode in the same function does), so encrypting leaves plaintext blocks 2..n in the ciphertext output and decrypt leaves out[16..] stale; the inner loop also re-reads input[0..15] each outer pass. With the pointer advance both blocks are processed (ct[16..31] now ciphertext, decrypt writes through block 2). The ECB KAT control of the same KPI matches FIPS-197; the legacy CFB1 path has no in-tree caller (cryptosoft never selects MODE_CFB1) - latent correctness/assurance defect, confirmed as filed.
No comments yet.