As of August 2020 the site you are on (wiki.newae.com) is deprecated, and content is now at rtfm.newae.com.

Changes

Jump to: navigation, search

Making Scripts

7,538 bytes added, 19:13, 10 April 2018
Updated scripts and added stm32 scripts
This script is an example of using the <code>chipwhisperer</code> module for capturing traces during AES encryption. <b>Make sure to have the correct firmware loaded on the target.</b> These traces are then saved and loaded later for analysis.
==== XMEGA Target ====
<syntaxhighlight lang=python>
from __future__ import division, print_function
# program the target
xmega programmer = XMEGAProgrammer()xmegaprogrammer.setUSBInterface(scope.scopetype.dev.xmega)= scopexmegaprogrammer._logging = Nonexmegaprogrammer.find()xmegaprogrammer.erase()glitch_simple_firmware_dir aes_firmware_dir = os.path.join(FIRMWARE_DIR, 'simpleserial-aes')glitch_simple_hex aes_hex = os.path.join(glitch_simple_firmware_diraes_firmware_dir, r"simpleserial-aes-CW303.hex")xmegaprogrammer.program(glitch_simple_hexaes_hex, memtype="flash", verify=True)xmegaprogrammer.close()
ktp = AcqKeyTextPattern_Basic(target=target)
keys = []
N = 50 # Number of traces
target.init()
for i in tqdm(range(N), desc='Capturing traces'):
# run aux stuff that should come before trace here
 
key, text = ktp.newPair() # manual creation of a key, text pair can be substituted here
textin.append(text)
keys.append(key)
 
target.reinit()
 
target.setModeEncrypt() # only does something for targets that support it
target.loadEncryptionKey(key)
target.loadInput(text)
 
# run aux stuff that should run before the scope arms here
 
scope.arm()
 
# run aux stuff that should run after the scope arms here
 
target.go()
timeout = 50
# wait for target to finish
while target.isDone() is False and timeout:
timeout -= 1
time.sleep(0.01)
 
try:
ret = scope.capture()
if ret:
print('Timeout happened during acquisition')
except IOError as e:
print('IOError: %s' % str(e))
 
# run aux stuff that should happen after trace here
_ = target.readOutput() # clears the response from the serial port
traces.append(scope.getLastTrace())
trace_array = np.asarray(traces) # if you prefer to work with numpy array for number crunching
textin_array = np.asarray(textin)
known_keys = np.asarray(keys) # for fixed key, these keys are all the same
 
now = datetime.now()
fmt_string = '{:02}{:02}_{}.npy'
trace_file_path = fmt_string.format(now.hour, now.minute, "traces")
textin_file_path = fmt_string.format(now.hour, now.minute, "textins")
keys_file_path = fmt_string.format(now.hour, now.minute, "keys")
 
print('Saving results to {},{} and {}...'.format(trace_file_path, textin_file_path, keys_file_path), end='')
# save to a files for later processing
np.save(trace_file_path, trace_array)
np.save(textin_file_path, textin_array)
np.save(keys_file_path, known_keys)
print('Done')
 
# uncomment plt.show() to show an example trace
plt.plot(traces[0])
#plt.show()
 
# cleanup the connection to the target and scope
scope.dis()
target.dis()
</syntaxhighlight>
 
==== STM32F3 Target ====
<syntaxhighlight lang=python>
from __future__ import division, print_function
 
import time
import os
 
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime
from tqdm import tqdm
 
import chipwhisperer as cw
from chipwhisperer.capture.acq_patterns.basic import AcqKeyTextPattern_Basic
from chipwhisperer.tests.tools_for_tests import FIRMWARE_DIR
from chipwhisperer.capture.api.programmers import STM32FProgrammer
 
scope = cw.scope()
target = cw.target(scope)
 
# setup scope parameters
scope.gain.gain = 45
scope.adc.samples = 5000
scope.adc.offset = 0
scope.adc.basic_mode = "rising_edge"
scope.clock.clkgen_freq = 7370000
scope.clock.adc_src = "clkgen_x4"
scope.trigger.triggers = "tio4"
scope.io.tio1 = "serial_rx"
scope.io.tio2 = "serial_tx"
scope.io.hs2 = "clkgen"
 
# program the target
programmer = STM32FProgrammer()
programmer.scope = scope
programmer._logging = None
programmer.open()
programmer.find()
programmer.erase()
aes_firmware_dir = os.path.join(FIRMWARE_DIR, 'simpleserial-aes')
aes_hex = os.path.join(aes_firmware_dir, r"simpleserial-aes-CW308_STM32F3.hex")
programmer.program(aes_hex, memtype="flash", verify=True)
programmer.close()
 
ktp = AcqKeyTextPattern_Basic(target=target)
 
traces = []
textin = []
keys = []
N = 50 # Number of traces
target.init()
for i in tqdm(range(N), desc='Capturing traces'):
# run aux stuff that should come before trace here
# run aux stuff that should happen after trace here
_ = target.readOutput() # throw out the target response
traces.append(scope.getLastTrace())
trace_array = np.asarray(traces) # if you prefer to work with numpy array for number crunching
=== Exploring glitches ===
This script shows an example of using the ChipWhisperer tool for performing clock glitch attacks on a target executing code. This script has similar functionality of the glitch explorer in the GUI but exposes more the insides of the ChipWhisperer tool. This script varies the offset and the width percentage of the clock glitch applied to the target during code execution. More details about clock glitching can be found in [[Tutorial_A2_Introduction_to_Glitch_Attacks_(including_Glitch_Explorer) | Tutorial A2]]
==== XMEGA Target ====
<syntaxhighlight lang=python>
from __future__ import print_function, division
import os
from collections import namedtuple
import csv
import numpy as np
from chipwhisperer.tests.tools_for_tests import FIRMWARE_DIR
from chipwhisperer.capture.api.programmers import XMEGAProgrammer
#from scripting_utils import GlitchResultsDisplay
logging.basicConfig(level=logging.WARN)
scope = cw.scope()
target = cw.target(scope)
 
# program the XMEGA with the built hex file
xmega = XMEGAProgrammer()
xmega.setUSBInterface(scope.scopetype.dev.xmega)
xmega._logging = None
xmega.find()
xmega.erase()
glitch_simple_firmware_dir = os.path.join(FIRMWARE_DIR, 'glitch-simple')
glitch_simple_hex = os.path.join(glitch_simple_firmware_dir, r"glitchsimple-CW303.hex")
xmega.program(glitch_simple_hex, memtype="flash", verify=True)
xmega.close()
# setup parameters needed for glitch the XMEGA
target.go_cmd = ""
target.key_cmd = ""
 
# program the XMEGA with the built hex file
programmer = XMEGAProgrammer()
programmer.scope = scope
programmer._logging = None
programmer.find()
programmer.erase()
glitch_simple_firmware_dir = os.path.join(FIRMWARE_DIR, 'glitch-simple')
glitch_simple_hex = os.path.join(glitch_simple_firmware_dir, r"glitchsimple-CW303.hex")
programmer.program(glitch_simple_hex, memtype="flash", verify=True)
programmer.close()
# format output table
headers = ['target output', 'width', 'offset', 'success']
#glitch_display = GlitchResultsDisplay(headers)
# set glitch parameters
# glitch cycle
scope.glitch.width = width_range.min
open('glitch_out.csv', 'w').close()
f = open('glitch_out.csv', 'ab')
writer = csv.writer(f)
target.init()
while scope.glitch.width < width_range.max:
scope.glitch.offset = offset_range.min
# call before trace things here
# resets flush the garbage from the computer's target for the next glitch cycleread buffer # similar to Check Signature button in GUI xmegatarget.find() xmegaser.closeflush()
# target.reinit()enters reset mode # call target functions here, setModeEncrypt.scope.io.pdic = 'low'
# run aux stuff that should run before the scope arms here
# run aux stuff that should run after the scope arms here
# targetexits reset mode scope.go()io.pdic = 'high' 
timeout = 50
# wait for target to finish
trace = scope.getLastTrace()
# read from the targets buffer
output = target.ser.read(target.output_len * 232, timeout=100010)
traces.append(trace)
outputs.append(output)
# for table display purposes
success = '1234' in repr(output) # check for glitch success (depends on targets active firmware)
glitch_display.add_data(data = [repr(output), scope.glitch.width, scope.glitch.offset, success] #glitch_display.add_data(data) writer.writerow(data)
# run aux stuff that should happen after trace here
scope.glitch.offset += offset_range.step
scope.glitch.width += width_range.step
f.close()
traces = np.asarray(traces)
# the rest of the data is available with the outputs, widths, and offsets lists
#glitch_display.display_table()
print('Done')
# clean up the connection to the scope and target
scope.dis()
target.dis()
</syntaxhighlight>
 
==== STM32F3 Target ====
<syntaxhighlight lang=python>
from __future__ import print_function, division
 
import time
import logging
import os
from collections import namedtuple
import csv
 
import numpy as np
 
import chipwhisperer as cw
from chipwhisperer.tests.tools_for_tests import FIRMWARE_DIR
from chipwhisperer.capture.api.programmers import STM32FProgrammer
from scripting_utils import GlitchResultsDisplay
 
logging.basicConfig(level=logging.WARN)
scope = cw.scope()
target = cw.target(scope)
 
# setup parameters needed for glitch the stm32f
scope.glitch.clk_src = 'clkgen'
 
scope.gain.gain = 45
scope.adc.samples = 5000
scope.adc.offset = 0
scope.adc.basic_mode = "rising_edge"
scope.clock.clkgen_freq = 7370000
scope.clock.adc_src = "clkgen_x4"
scope.trigger.triggers = "tio4"
scope.io.tio1 = "serial_rx"
scope.io.tio2 = "serial_tx"
scope.io.hs2 = "glitch"
 
target.go_cmd = ""
target.key_cmd = ""
 
# program the stm32f with the built hex file
programmer = STM32FProgrammer()
programmer.scope = scope
programmer._logging = None
programmer.open()
programmer.find()
programmer.erase()
glitch_simple_firmware_dir = os.path.join(FIRMWARE_DIR, 'glitch-simple')
glitch_simple_hex = os.path.join(glitch_simple_firmware_dir, r"glitchsimple-CW308_STM32F3.hex")
programmer.program(glitch_simple_hex, memtype="flash", verify=True)
programmer.close()
 
# format output table
headers = ['target output', 'width', 'offset', 'success']
glitch_display = GlitchResultsDisplay(headers)
 
# set glitch parameters
# trigger glitches with external trigger
scope.glitch.trigger_src = 'ext_single'
scope.glitch.repeat = 105
 
traces = []
outputs = []
widths = []
offsets = []
 
# named tuples to make it easier to change the scope of the test
Range = namedtuple('Range', ['min', 'max', 'step'])
width_range = Range(-40, 40, 0.39*5)
offset_range = Range(-40, 40, 0.39*5)
 
# glitch cycle
scope.glitch.width = width_range.min
open('glitch_out.csv', 'w').close()
f = open('glitch_out.csv', 'ab')
writer = csv.writer(f)
target.init()
while scope.glitch.width < width_range.max:
scope.glitch.offset = offset_range.min
while scope.glitch.offset < offset_range.max:
# call before trace things here
 
# flush the garbage from the computer's target read buffer
target.ser.flush()
 
# run aux stuff that should run before the scope arms here
 
# target enters reset state
scope.io.nrst = 'low'
 
scope.arm()
 
# run aux stuff that should run after the scope arms here
 
# target exits reset state and starts execution
scope.io.nrst = 'high'
 
timeout = 50
# wait for target to finish
while target.isDone() is False and timeout:
timeout -= 1
time.sleep(0.01)
 
try:
ret = scope.capture()
if ret:
logging.warning('Timeout happened during acquisition')
except IOError as e:
logging.error('IOError: %s' % str(e))
 
# get the results from the scope
trace = scope.getLastTrace()
# read from the targets buffer
output = target.ser.read(32, timeout=100)
traces.append(trace)
outputs.append(output)
widths.append(scope.glitch.width)
offsets.append(scope.glitch.width)
 
# for table display purposes
success = '1234' in repr(output) # check for glitch success (depends on targets active firmware)
data = [repr(output), scope.glitch.width, scope.glitch.offset, success]
glitch_display.add_data(data)
writer.writerow(data)
 
# run aux stuff that should happen after trace here
scope.glitch.offset += offset_range.step
scope.glitch.width += width_range.step
f.close()
traces = np.asarray(traces)
# the rest of the data is available with the outputs, widths, and offsets lists
glitch_display.displaydisplay_table()
print('Done')
</syntaxhighlight>

Navigation menu