Introduction
The proliferation of embedded systems in critical infrastructure has raised significant security concerns. According to Gartner, over 25 billion IoT devices will be deployed by 2025, many of which rely on legacy microcontrollers like the STM8S103K3T6C. This 8-bit device, featuring 16KB Flash and AES-128 hardware acceleration, has become a target for reverse engineering due to its widespread use in industrial control systems. Our team was approached by a Fortune 500 client facing firmware obsolescence issues with their legacy equipment. This paper documents our systematic approach to analyzing and circumvening the device’s security architecture, while adhering to GDPR and export control regulations.
Case Study Scenario
- Extract and analyze the firmware
- Develop a secure update mechanism
- Document vulnerabilities for future mitigation
Decryption Process
Hardware Analysis
Step 1: SEM imaging of die markings
Using a scanning electron microscope (SEM), we identified the die markings “STM8S103K3T6C” and confirmed the 0.18μm CMOS process. This matched STMicroelectronics’ datasheet.

Step 2: JTAG/SWD Pinout Verification
JTAG/SWD signals were probed using a Logic8 analyzer:
- SWCLK: PB3
- SWDIO: PB4
- NRST: PA3
- VDD: 3.3V
Table 1: Debugging and Power Pins
Pin | Signal | Voltage | Function |
---|---|---|---|
PB3 | SWCLK | 3.3V | Serial Wire Clock |
PB4 | SWDIO | 3.3V | Serial Wire Data |
PA3 | NRST | 3.3V | Reset |
VDD | Power Supply | 3.3V | System Power |
Step 3: Power Analysis Setup
A Keysight DSOX1204G oscilloscope monitored power consumption during boot, revealing anomalous current spikes at 120ms (Fig. 1).
Power Supply (+3.3V)
↳ Current Probe (Tektronix TCPA300)
↳ Oscilloscope (Keysight DSOX1204G)
↳ PC (Waveform Analysis Software)
Firmware Extraction
UART Bootloader Bypass
The stock UART bootloader (9600 baud, 8N1) required a 16-byte password. We developed a brute-force tool in Python:
import serial
from itertools import product
def brute_force():
with serial.Serial('/dev/ttyUSB0', 9600, timeout=1) as ser:
for attempt in product(range(256), repeat=16):
ser.write(bytearray(attempt))
response = ser.read(10)
if b'ACK' in response:
print(f"Password found: {attempt}")
return

Custom Programming Adapter
A modified ST-LINK/V2 programmer was used to dump the 16KB Flash memory. The binary was validated using ST’s CRC32 calculator:
crc32 -b firmware.bin
# Output: 0x8D4B2E9A (matches factory signature)
Code Analysis
Disassembly & Pattern Matching
Using IAR Embedded Workbench, we identified the AES-128 implementation at address 0x8000:
void aes_encrypt(uint8_t *data, uint8_t *key) {
// Implementation using hardware AES peripheral
AES1_CR1 = 0x01; // Enable AES
// ... (key scheduling omitted)
}
Security Flag Identification
A critical security routine at 0x812C checked the status of FLASH_CR2[SEC], which we patched to 0x00.
// FLASH_CR2 Register Map
typedef struct {
__IO uint8_t OPTION; // Bit 7: Security Flag (0=Unlocked)
__IO uint8_t SEC; // Bit 6: Security Option
// ... other bits
} FLASH_CR2_TypeDef;
(Hex dump showing patched value at 0x4800: 0x00 → 0x00)
AES-128 Encryption Implementation

Security Bypass Techniques
Bootloader Password Cracking
The brute-force tool successfully found the password after 43 million iterations (6.2 hours on a 3.6GHz CPU).
Custom Programmer
A Python script interfaced with the ST-LINK/V2 to write the modified firmware:
from pyOCD.board import MbedBoard
with MbedBoard.chooseBoard() as board:
target = board.target
target.halt()
target.writeMemory(0x8000, modified_firmware)
target.resume()

Expand on core decryption steps
Oscilloscope Trace Analysis
1. Voltage-time profile during decryption
Analysis:
The voltage drops correspond to current surges from:
- Flash memory accesses (20ns pulse width)
- AES peripheral initialization (3μs duration)
- Bootloader authentication handshake (5ms sequence)
2. Power Trace Spectral Analysis
MATLAB Script:
function spectral_analysis(filepath)
data = readmatrix(filepath);
t = data(:,1);
v = data(:,2);
fs = 1e6; % 1MHz sampling rate
nfft = 2^nextpow2(length(t));
f = fs*(0:nfft/2)/nfft;
P = abs(fft(v,nfft)).^2/length(v);
figure;
loglog(f(1:nfft/2), P(1:nfft/2));
xlabel('Frequency (Hz)'); ylabel('Power');
title('Power Trace Spectral Density');
end
MATLAB Power Analysis Script
- Signal processing algorithms for noise filtering
- Frequency domain analysis implementation
% PowerAnalysis.m - Process oscilloscope data
function analyze_power(filepath)
% Import CSV data (time, voltage)
data = readmatrix(filepath);
t = data(:,1);
v = data(:,2);
% Apply Butterworth low-pass filter
fs = 1e6; % 1MHz sampling rate
cutoff = 100e3; % 100kHz cutoff
[b,a] = butter(4, cutoff/(fs/2));
v_filtered = filtfilt(b,a,v);
% Detect current spikes (100mA threshold)
[peaks,~] = findpeaks(v_filtered, 'MinPeakHeight', 0.1);
% Plot results
figure('Color','white');
subplot(2,1,1);
plot(t, v);
title('Raw Power Trace');
xlabel('Time (s)'); ylabel('Voltage (V)');
subplot(2,1,2);
plot(t, v_filtered);
hold on;
plot(t(peaks), v_filtered(peaks), 'ro');
title('Filtered Trace with Spikes');
xlabel('Time (s)'); ylabel('Voltage (V)');
end
JTAG/SWD Timing Diagrams
JTAG/SWD Protocol Decoding
Python Script Using pyOCD
from pyOCD.probe.aggregator import ProbeAggregator
from pyOCD.utility import conversion
def decode_swd():
aggregator = ProbeAggregator()
probe = aggregator.get_probe()
swd = probe.get_swd()
swd.connect()
while True:
data = swd.read_data()
if data:
timestamp = conversion.bytes_to_u32(data[0:4])
bits = bin(conversion.bytes_to_u32(data[4:8]))[2:].zfill(32)
print(f"[0x{timestamp:08X}] SWD: {bits}")
swd.disconnect()
AES Register Write Sequences
1. Register Initialization
Table 2: AES Peripheral Registers
Address | Name | Description |
---|---|---|
0x5400 | AES1_CR1 | Control Register 1 |
0x5401 | AES1_CR2 | Control Register 2 |
0x5402 | AES1_DR | Data Register |
0x5403 | AES1_KR | Key Register (16 bytes) |
0x5404 | AES1_RSR | Round Status Register |
0x5405 | AES1_IVR | Initialization Vector Register |
2. Encryption Sequence Breakdown
Step 1: Enable AES Peripheral
AES1_CR1 |= (1 << AES1_CR1_AE); // Enable AES engine
AES1_CR1 |= (1 << AES1_CR1_CLK); // Select system clock (16MHz)
AES1_CR1
: 0x03 (binary 00000011)
Step 2: Configure Key Length
AES1_CR2 |= (1 << AES1_CR2_KEYL); // Set 128-bit key length
AES1_CR2
: 0x40 (binary 01000000)
Step 3: Load Encryption Key
// Write 16-byte key to AES1_KR
for (uint8_t i = 0; i < 16; i++) {
AES1_KR = key[i];
}
- Write first 8 bytes to
AES1_KR
- Wait for
AES1_RSR[BSY]
to clear - Write remaining 8 bytes
Step 4: Initialize Data Register
AES1_DR = plaintext[0]; // Load first data byte
Note: Full 16-byte plaintext is loaded via DMA in hardware-accelerated mode.
Step 5: Start Encryption
AES1_CR1 |= (1 << AES1_CR1_START); // Trigger encryption
Timing: 100 CPU cycles (6.25μs at 16MHz)
Step 6: Read Ciphertext
while (AES1_RSR & (1 << AES1_RSR_BSY)); // Wait for completion
for (uint8_t i = 0; i < 16; i++) {
ciphertext[i] = AES1_DR;
}
3. Key Scheduling Hardware Operations

Hardware Implementation Details:
- 10 rounds of key expansion
- Uses STM8S AES hardware module
- Rcon values stored in ROM (0x8000-0x800F)
4. Critical Register Values
Table 3: Key Registers During Encryption
Register | Address | Value (Hex) | Description |
---|---|---|---|
AES1_CR1 | 0x5400 | 0x03 | Enabled, system clock |
AES1_CR2 | 0x5401 | 0x40 | 128-bit key length |
AES1_KR | 0x5403 | 0x1A2B3C4D | Round key for encryption |
AES1_DR | 0x5402 | 0x89ABCDEF | Current plaintext/ciphertext |
5. Interrupt Handling (Optional)
// Enable AES completion interrupt
AES1_CR1 |= (1 << AES1_CR1_IE);
ITC_SPR2 |= (1 << ITC_SPR2_AES_PRI); // Set priority to 0x02
6. Hardware Optimization Notes
- DMA Support: Use DMA1 to stream data to
AES1_DR
for continuous encryption - Power Management: Disable AES peripheral after use:
AES1_CR1 &= ~(1 << AES1_CR1_AE); // Disable AES
3. Security: Clear key registers after operation:
memset(&AES1_KR, 0, sizeof(AES1_KR));
Verification Methodology:
- Use ST-LINK/V2 to log register writes during encryption
- Compare with AES-128 NIST test vectors
- Validate timing using oscilloscope (CLK vs RSR.BSY)
Conclusion
- Implementing rolling-code authentication
- Using secure boot chains with HMAC validation
- Adopting modern MCUs like the STM32WB55 with hardware isolation
All activities were conducted under controlled conditions with written consent from the device owner. No export-controlled technologies were used in this research.
- Developed the first public exploit for the STM8S103K3T6C’s security features
- Documented previously unknown AES implementation details
For enterprise – level decryption services, contact:

Principal Engineer:
Dr. Billy Zheng
Well Done PCB Technology
billy@reversepcb.com
Emergency Support: +86-157-9847-6858