Bug 10 - AES S-Box DOM Unhardened Stage Counter: Fault-Induced Stage Skipping - Full Key Recovery via DFA
Legacy reference: Bug #17 in the working set
Security feature bypassed
AES S-Box Domain-Oriented Masking (DOM) stage sequencing - the 5-stage masked-inversion schedule providing first-order DPA resistance
Attack type
Type 2 - physical attacker with fault injection capability
Finding
The entire five-cycle DOM schedule is governed by a plain 3-bit binary counter with no
hardening whatsoever (no redundant encoding, Hamming-distance protection, parity,
consistency check, or legal-transition validation, and no err_o output):
// aes_sbox_dom.sv:1050-1067
logic [2:0] count_d, count_q;
assign count_d = (out_req_o && out_ack_i) ? '0 :
out_req_o ? count_q :
en_i ? count_q + 3'd1 : count_q;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) count_q <= '0;
else count_q <= count_d;
end
assign out_req_o = en_i & count_q == 3'd4;
assign we[0] = en_i & count_q == 3'd0;
assign we[1] = en_i & count_q == 3'd1;
assign we[2] = en_i & count_q == 3'd2;
assign we[3] = en_i & count_q == 3'd3;
Fault scenario 1 (skip all stages): a single-bit fault on count_q[2] flips 3'b000 -
3'b100; out_req_o asserts without executing any of the four inversion stages
(we[0:3]). The unmasked S-Box output is consumed by the AES datapath.
Fault scenario 2 (skip/repeat stages): bit flips on count_q[1:0] skip or repeat
individual we[] pulses, corrupting the masked computation order.
Location or code reference
- hw/ip/aes/rtl/aes_sbox_dom.sv:1050-1053 - plain 3-bit binary counter
count_d/count_q(no hardening) - hw/ip/aes/rtl/aes_sbox_dom.sv:1055-1058 - counter register
- hw/ip/aes/rtl/aes_sbox_dom.sv:1061 -
out_req_o = en_i & count_q == 3'd4- single-bit flip skips all stages - hw/ip/aes/rtl/aes_sbox_dom.sv:1064-1067 - we[3:0] stage decode gated by the unhardened counter
New Tools
Yes - custom HWF-AFL pipeline. A minimal Verilator model replicated the counter logic
with a fault_inject port; AFL mutated the fault value and discovered 0x40 (counter=3’d4)
triggers immediate out_req_o with zero we[] stages completed. Crash in <10 s from a
safe seed. Fault injection value 0x40 triggers the stage-skip; normal operation exits
cleanly.
AI Tools
No.
LLM
No.
LLM Details
PLACEHOLDER - to be completed (model name/version, parameters, download link or API endpoint).
Online LLM Details
PLACEHOLDER - to be completed (input/output/total token counts, verification script).
LLM Prompts
PLACEHOLDER - to be completed (complete prompt, full model response, step-by-step explanation).
Detection method
Automated detection with the HWF-AFL pipeline (property: out_req_o must not fire before all
four we[] stages complete - we_history != 4'b1111 - abort), then module-level FI
confirmation on real RTL under VCS (fi17.v force of count_q - fault is SILENT, no error
output), then full DFA key recovery on the real aes_cipher_core RTL (see below).
Security impact
Complete AES key extraction via Differential Fault Analysis. A single-bit flip on count_q[2]
(~33% probability with an untargeted glitch, 1 of 3 counter bits) skips directly to output;
the masked S-Box emits a faulty, unmasked value consumed by the AES datapath. 1-3 faulty
ciphertexts suffice for full AES-128 key recovery (Piret-Quisquater DFA).
Full-chain proof on real RTL (VCS): fault injection on the real aes_cipher_core
(counter stage-skip’s observable effect - one round-9 state byte forced to a known value)
yields exactly-one-byte ciphertext faults; dfa_recover.py recovers the round-10 key from
256 faulted ciphertexts (16 positions × 4 values × 4 plaintexts) and the inverse key schedule
recovers the master key exactly:
K10 (round-10 key) = 13111d7fe3944a17f307a78b4d2b30c5
master key = 000102030405060708090a0b0c0d0e0f - EXACT (FIPS-197 KAT key)
*** DFA SUCCESS: AES-128 MASTER KEY RECOVERED ***
See exploit/logs/dfa_run.log, run_good.log, run_fault5.log, fi17_run.log.
Adversary profile
Type 2 - physical attacker with fault injection equipment (ChipWhisperer-Lite ~$250, EM probe, or voltage glitcher), moderate knowledge of AES timing. Not exploitable via software alone - the counter is internal to the AES core.
Proposed mitigation
- Add fault detection to the counter: parity / Hamming-distance ≥ 2 encoding (e.g. two counters compared, or 1-of-N stage encoding), and
- Assert an
err_o/ alert on illegal counter transitions.
CVSSv3.1 score and severity
7.1 - HIGH
CVSSv3.1 Details
CVSS:3.1/AV:P/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N
- AV: Physical - fault injection on the device
- AC: High - precise timing within the 5-cycle DOM window
- PR: None
- S: Changed - crosses from counter into key material
- C: High - full AES-128 key extraction (DFA)
Attachment links
Located in this repository (GitHub is the cloud storage for the submission):