コンテンツにスキップ

ChipWhisperer Cheat Sheet

Overview

ChipWhisperer is the leading open-source hardware security platform for performing side-channel attacks (power analysis, electromagnetic analysis) and fault injection (voltage glitching, clock glitching) against embedded systems. Developed by NewAE Technology, it enables security researchers to measure the power consumption of cryptographic operations and extract secret keys, or inject precise voltage glitches to bypass security checks and dump protected firmware. ChipWhisperer democratizes hardware security testing that previously required equipment costing tens of thousands of dollars.

The platform consists of hardware capture/glitch boards (ChipWhisperer-Lite, ChipWhisperer-Husky, ChipWhisperer-Pro) and a comprehensive Python framework (chipwhisperer package) with Jupyter notebook tutorials. It supports attacks against AES, RSA, ECC, and other cryptographic implementations, as well as fault attacks to bypass secure boot, extract keys from locked microcontrollers, and break authentication mechanisms. ChipWhisperer is widely used in academic research, security certifications (Common Criteria, FIPS), and penetration testing of IoT devices, smart cards, and embedded systems.

Installation

Python Package

# Install ChipWhisperer Python package
pip install chipwhisperer

# Install with Jupyter notebook support
pip install chipwhisperer[notebooks]

# Install from source (latest)
git clone https://github.com/newaetech/chipwhisperer.git
cd chipwhisperer
pip install -e .
pip install -r requirements.txt

# Install Jupyter notebooks
cd chipwhisperer/jupyter
pip install -r requirements.txt

USB Permissions (Linux)

# Add udev rules
sudo cp hardware/chipwhisperer/50-newae.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules
sudo udevadm trigger

# Add user to dialout group
sudo usermod -aG dialout $USER
sudo usermod -aG plugdev $USER

Jupyter Notebooks

# Launch tutorial notebooks
cd chipwhisperer/jupyter
jupyter notebook

# Navigate to:
# courses/sca101/ - Side Channel Analysis 101
# courses/fault101/ - Fault Injection 101
# courses/sca201/ - Advanced SCA

Hardware Setup

Supported Hardware

BoardCaptureGlitchChannelsSample Rate
ChipWhisperer-LiteYesYes1105 MS/s
ChipWhisperer-HuskyYesYes1200 MS/s
ChipWhisperer-ProYesYes1105 MS/s
PhyWhisperer-USBNoUSB--
ChipWhisperer-NanoYesYes120 MS/s

Target Boards

TargetDescription
CW308 UFO BoardUniversal target platform
CW308T-STM32FSTM32F0/F1/F3/F4 targets
CW308T-XMEGAAtmel XMEGA target
CW308T-K82FNXP Kinetis K82F target
CW308T-EFM32Silicon Labs EFM32 target
CW312 Bergen BoardMulti-target board
CW305 Artix FPGAFPGA target for crypto

Connection Setup

import chipwhisperer as cw

# Connect to ChipWhisperer-Lite
scope = cw.scope()

# Connect to specific board
scope = cw.scope(scope_type=cw.scopes.OpenADC)

# Connect to target
target = cw.target(scope, cw.targets.SimpleSerial)

# Program target firmware
cw.program_target(scope, cw.programmers.STM32FProgrammer,
                   "simpleserial-aes-CWLITEARM.hex")

Power Analysis Attacks

Simple Power Analysis (SPA)

import chipwhisperer as cw
import numpy as np

# Setup
scope = cw.scope()
target = cw.target(scope)

# Configure capture
scope.default_setup()
scope.adc.samples = 5000
scope.adc.offset = 0

# Capture single trace
scope.arm()
target.simpleserial_write('p', bytearray(16))  # Send plaintext
scope.capture()
trace = scope.get_last_trace()
response = target.simpleserial_read('r', 16)

# Plot trace
import matplotlib.pyplot as plt
plt.plot(trace)
plt.title("Power Trace during AES Encryption")
plt.xlabel("Sample")
plt.ylabel("Power")
plt.show()

Correlation Power Analysis (CPA)

import chipwhisperer as cw
import chipwhisperer.analyzer as cwa
import numpy as np

# Setup
scope = cw.scope()
target = cw.target(scope)
scope.default_setup()
scope.adc.samples = 5000

# Collect traces
num_traces = 2000
project = cw.create_project("aes_cpa")

for i in range(num_traces):
    key = bytearray(16)  # Fixed key
    text = cw.ktp.get_next_plaintext()

    trace = cw.capture_trace(scope, target, text, key)
    if trace:
        project.traces.append(trace)

project.save()

# Run CPA attack
attack = cwa.cpa(project)
attack.set_leak_model(cwa.leakage_models.sbox_output)

# Process results
results = attack.run()

# Get recovered key
recovered_key = attack.get_results().best_key()
print(f"Recovered key: {recovered_key.hex()}")

# Plot correlation
plot_data = attack.get_statistics()
plt.plot(plot_data.correlation[0])
plt.title("CPA Correlation - Key Byte 0")
plt.show()

Template Attack

# Build profiling traces (known key)
profiling_project = cw.create_project("profiling")
for i in range(5000):
    text = cw.ktp.get_next_plaintext()
    trace = cw.capture_trace(scope, target, text, known_key)
    if trace:
        profiling_project.traces.append(trace)

# Build templates
template_attack = cwa.profiling.TemplateAttack(profiling_project)
template_attack.generate_templates()

# Attack with unknown key
attack_project = cw.create_project("attack")
for i in range(50):  # Very few traces needed
    text = cw.ktp.get_next_plaintext()
    trace = cw.capture_trace(scope, target, text, unknown_key)
    if trace:
        attack_project.traces.append(trace)

# Recover key
results = template_attack.attack(attack_project)
print(f"Key: {results.best_key().hex()}")

Fault Injection

Voltage Glitching

import chipwhisperer as cw

scope = cw.scope()
target = cw.target(scope)

# Configure glitch module
scope.glitch.clk_src = "clkgen"
scope.glitch.output = "enable_only"
scope.glitch.trigger_src = "ext_single"

# Glitch parameters
scope.glitch.width = 10.0       # Glitch width (% of clock period)
scope.glitch.offset = 10.0      # Offset from trigger
scope.glitch.repeat = 1         # Number of glitch pulses
scope.glitch.ext_offset = 100   # External trigger offset (clock cycles)

# Voltage glitch settings
scope.io.glitch_hp = True       # High-power MOSFET
scope.io.glitch_lp = False      # Low-power MOSFET

# Arm and trigger
scope.arm()
target.simpleserial_write('p', bytearray(16))
scope.capture()

# Check if glitch was successful
response = target.simpleserial_read('r', 16, timeout=100)

Glitch Sweep (Finding Parameters)

import chipwhisperer as cw
import chipwhisperer.common.results.glitch as glitch

scope = cw.scope()
target = cw.target(scope)

# Configure glitch
scope.glitch.clk_src = "clkgen"
scope.glitch.output = "enable_only"
scope.glitch.trigger_src = "ext_single"

# Sweep parameters
gc = glitch.GlitchController(groups=["success", "reset", "normal"])

gc.set_range("width", 1, 50)
gc.set_range("offset", 1, 50)
gc.set_range("ext_offset", 0, 500)

for glitch_settings in gc.glitch_values():
    scope.glitch.width = glitch_settings[0]
    scope.glitch.offset = glitch_settings[1]
    scope.glitch.ext_offset = glitch_settings[2]

    # Reset target
    target.flush()
    scope.arm()

    # Trigger operation
    target.simpleserial_write('p', bytearray(16))

    ret = scope.capture()
    if ret:
        gc.add("reset", glitch_settings)
        continue

    response = target.simpleserial_read('r', 16, timeout=50)

    if response is None:
        gc.add("reset", glitch_settings)
    elif check_success(response):
        gc.add("success", glitch_settings)
        print(f"SUCCESS: width={glitch_settings[0]}, offset={glitch_settings[1]}")
    else:
        gc.add("normal", glitch_settings)

# Plot results
gc.display_stats()

Clock Glitching

# Configure clock glitch (insert extra clock edges)
scope.glitch.clk_src = "clkgen"
scope.glitch.output = "clock_xor"  # XOR with target clock
scope.glitch.trigger_src = "ext_single"

scope.glitch.width = 49.0       # ~50% duty cycle glitch
scope.glitch.offset = 0.0
scope.glitch.ext_offset = 200   # 200 clock cycles after trigger
scope.glitch.repeat = 1

Configuration

Scope Settings

# Clock configuration
scope.clock.clkgen_freq = 7370000  # 7.37 MHz
scope.clock.adc_src = "clkgen_x4"  # 29.48 MS/s

# ADC configuration
scope.adc.samples = 5000
scope.adc.offset = 0
scope.adc.basic_mode = "rising_edge"
scope.adc.timeout = 2

# Trigger configuration
scope.trigger.triggers = "tio4"   # Trigger source
scope.io.tio1 = "serial_rx"
scope.io.tio2 = "serial_tx"
scope.io.hs2 = "clkgen"          # Output clock to target

# Target voltage
scope.io.target_pwr = True        # Enable 3.3V to target

Capture Settings for Different Targets

# AES on ARM Cortex-M (STM32)
scope.adc.samples = 5000
scope.clock.clkgen_freq = 7.37e6
scope.adc.offset = 0

# AES on XMEGA
scope.adc.samples = 3000
scope.clock.clkgen_freq = 7.37e6

# RSA (much longer operation)
scope.adc.samples = 24400
scope.clock.clkgen_freq = 7.37e6

# ECC
scope.adc.samples = 20000

Advanced Usage

Electromagnetic Analysis (EMA)

# Use H-field probe instead of shunt resistor
# Connect EM probe to scope input

scope.adc.preamp_gain = 40  # Increase gain for EM
scope.adc.samples = 10000

# Capture and analyze same as power analysis
# but with EM probe positioned over target IC

Preprocessing

from chipwhisperer.analyzer.preprocessing import resync_dtw, filter_type

# Resynchronize traces (remove jitter)
resync = resync_dtw.ResyncDTW(project)
resync.ref_trace = 0
resync.radius = 5
resync_project = resync.preprocess()

# Low-pass filter
filtered = filter_type.FilterType(project)
filtered.filter_type = "low"
filtered.cutoff = 0.1
filtered_project = filtered.preprocess()

Test Vector Leakage Assessment (TVLA)

# Fixed vs Random t-test (detect leakage)
from chipwhisperer.analyzer import tvla

# Collect fixed key traces
fixed_traces = []
random_traces = []

for i in range(5000):
    if i % 2 == 0:
        text = fixed_plaintext
    else:
        text = random_plaintext()

    trace = cw.capture_trace(scope, target, text, key)
    if i % 2 == 0:
        fixed_traces.append(trace.wave)
    else:
        random_traces.append(trace.wave)

# Calculate t-statistic
t_val = tvla.t_test(np.array(fixed_traces), np.array(random_traces))

# Plot: |t| > 4.5 indicates leakage
plt.plot(np.abs(t_val))
plt.axhline(y=4.5, color='r', linestyle='--')
plt.title("TVLA t-test")
plt.show()

Troubleshooting

IssueSolution
Device not foundCheck USB cable, install udev rules
Noisy tracesShorten probe wires, add decoupling caps
No triggerVerify trigger pin, check scope.trigger config
Glitch has no effectAdjust width/offset, verify glitch output
Target resets during glitchReduce glitch width/repeat, check power supply
CPA attack failsNeed more traces, check alignment, verify model
Traces misalignedUse resync preprocessing, check clock stability
Firmware programming failsVerify programmer type, check connections

Diagnostic Commands

# Check scope connection
scope = cw.scope()
print(scope)
print(f"FW Version: {scope.fw_version}")
print(f"SAM FW: {scope.sam_fw_version}")

# Check target connection
target = cw.target(scope)
target.flush()
target.simpleserial_write('v', b'')  # Get version
print(target.simpleserial_read('v', 100))

# Verify clock
print(f"Clock freq: {scope.clock.clkgen_freq}")
print(f"ADC freq: {scope.clock.adc_freq}")

# Check glitch module
print(f"Glitch width: {scope.glitch.width}")
print(f"Glitch offset: {scope.glitch.offset}")

# Disconnect cleanly
scope.dis()
target.dis()