Add TRNG attack files
This commit is contained in:
parent
c71df79b32
commit
1901ad680d
5 changed files with 7562 additions and 0 deletions
BIN
TRNG_attack/TRNG_impl.bit
Normal file
BIN
TRNG_attack/TRNG_impl.bit
Normal file
Binary file not shown.
27
TRNG_attack/attack_student.py
Normal file
27
TRNG_attack/attack_student.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
import numpy as np
|
||||
|
||||
TRNG_PAIR_CNT = 64
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# reading info file - length of trace, sampling frequency (not necessary to know in our case), random value generated by the TRNG
|
||||
with open("data_info.txt", "r") as fin:
|
||||
tracelen = int(fin.readline())
|
||||
fs = int(fin.readline())
|
||||
trng_val = fin.readline()
|
||||
|
||||
traces = np.fromfile("data.bin", dtype='uint8') # reading traces for individual ROs
|
||||
traces = np.reshape(traces, (traces.size//tracelen, tracelen)) # reshape of matrix, each row contains the trace for one RO
|
||||
|
||||
traces_bin = ??? # conversion of waveforms to rectangles - everything below threshold is 0, otherwise 1 (they are boolean values actually)
|
||||
rising_edges = np.logical_not(???) & ??? # finding rising edges, each rising edge is represented by True
|
||||
|
||||
cnt = np.count_nonzero(???, axis=1) # count the number of rising edges in rows
|
||||
# cnt is now a 1D vector
|
||||
cnt = cnt.reshape(TRNG_PAIR_CNT,2).min(axis=1) # Reshape of the count array into matrix, where each row contains 2 values - the number of rising edges for two ROs in a pair. Then we select the smaller value.
|
||||
|
||||
cnt_sel = cnt & ?x???? # select only the two least significant bits
|
||||
|
||||
estimate = ''.join([np.binary_repr(x, width=2) for x in cnt_sel]) # binary representation of the values (the last 2 bits) and joining them into one string
|
||||
print('{0:0>32x}'.format(int(estimate, 2)))
|
||||
print(trng_val) # from data_info, output of the RNG in FPGA
|
87
TRNG_attack/measurement.py
Normal file
87
TRNG_attack/measurement.py
Normal file
|
@ -0,0 +1,87 @@
|
|||
import oscilloscope
|
||||
import serial
|
||||
import serial.tools.list_ports
|
||||
from time import sleep
|
||||
|
||||
SAMPLE_FREQ = 625*10**6
|
||||
|
||||
RO_CNT = 64
|
||||
TRNG_PAIR_CNT = 64
|
||||
|
||||
def list_resources(resources: list, resource_name: str):
|
||||
if not resources:
|
||||
print('no', resource_name, 'available')
|
||||
else:
|
||||
print('available', resource_name + ':')
|
||||
for resource_id in range(len(resources)):
|
||||
print('[', resource_id, '] ', resources[resource_id])
|
||||
|
||||
def list_scopes():
|
||||
found_oscilloscopes = oscilloscope.get_oscilloscopes()
|
||||
list_resources(found_oscilloscopes, 'oscilloscopes')
|
||||
|
||||
def channel_meas(scope, n):
|
||||
scope.command_check(":WAVeform:SOURce", 'CHANnel{}'.format(n))
|
||||
trace = scope.query_binary(':WAVeform:DATA?')
|
||||
return trace
|
||||
|
||||
|
||||
# Infinite test run
|
||||
# The cycle iterates over all ROs. Can be interrupted by pressing CTRL-C
|
||||
def run(fpga_comm):
|
||||
print ("Infinite run, press CTRL-C to break.")
|
||||
try:
|
||||
i = 0
|
||||
while True:
|
||||
fpga_comm.write(bytes([i,i]))
|
||||
i = (i + 1) % RO_CNT
|
||||
sleep(1)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
|
||||
def trng_read(scope, fpga_comm):
|
||||
|
||||
with open('data_info.txt', "w") as finfo, open ('data.bin', "wb") as fdata:
|
||||
|
||||
for i in range(TRNG_PAIR_CNT):
|
||||
print('--------------------------MEAS {}-------------------------------'.format(i))
|
||||
scope.write(':SINGle')
|
||||
sleep(0.1)
|
||||
fpga_comm.write(bytes([i,i]))
|
||||
trace1 = channel_meas(scope, 1)
|
||||
trace2 = channel_meas(scope, 2)
|
||||
if i == 0:
|
||||
tracelength = scope.query(':WAVeform:POINts?')
|
||||
fs = scope.query(':ACQuire:SRATe?')
|
||||
print(tracelength, file = finfo)
|
||||
print(int(float(fs)), file = finfo)
|
||||
fdata.write(trace1)
|
||||
fdata.write(trace2)
|
||||
|
||||
val = fpga_comm.read(16)
|
||||
print(val.hex())
|
||||
print(val.hex(), file = finfo)
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
list_scopes()
|
||||
ports = serial.tools.list_ports.comports()
|
||||
list_resources(ports, "COM")
|
||||
|
||||
# modify the device numbers in the following two lines:
|
||||
s = serial.Serial(ports[0].device, 923076)
|
||||
scope = oscilloscope.Oscilloscope(0)
|
||||
|
||||
# scope.setup_measurement()
|
||||
# scope.save_conf('scope_setup.conf')
|
||||
scope.load_conf('scope_setup.conf')
|
||||
sleep(2) # wait for the oscilloscope to process the setup
|
||||
|
||||
# test run -- only TRNG, no recording
|
||||
# run(s)
|
||||
|
||||
# measurement -- RESET the FPGA first! (USB disconnect+connect)
|
||||
# trng_read(scope, s)
|
101
TRNG_attack/oscilloscope.py
Normal file
101
TRNG_attack/oscilloscope.py
Normal file
|
@ -0,0 +1,101 @@
|
|||
import logging
|
||||
import pyvisa
|
||||
from pyvisa import constants
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.addHandler(logging.NullHandler())
|
||||
|
||||
|
||||
def get_oscilloscopes():
|
||||
rm = pyvisa.ResourceManager('@py')
|
||||
return rm.list_resources(query = '?*::INSTR')
|
||||
|
||||
|
||||
class Oscilloscope:
|
||||
def __init__(self, oscilloscope_id):
|
||||
rm = pyvisa.ResourceManager('@py')
|
||||
resources = rm.list_resources(query = '?*::INSTR')
|
||||
self.resource = rm.open_resource(
|
||||
resources[oscilloscope_id],
|
||||
read_termination = '\n',
|
||||
write_termination = '\n')
|
||||
self.resource.timeout = 20000
|
||||
logger.debug('timeout set to %dms', self.resource.timeout)
|
||||
self.resource.query_delay = 0.1
|
||||
logger.debug('query_delay set to %fs', self.resource.query_delay)
|
||||
# self.query = self.resource.query
|
||||
self.write('*CLS')
|
||||
print('connected to the oscilloscope with *IDN:',
|
||||
self.query('*IDN?'))
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
def close(self):
|
||||
logger.debug('closing oscilloscope...')
|
||||
self.resource.close()
|
||||
|
||||
def write(self, *args):
|
||||
logger.debug('%s', ', '.join(map(str, args)))
|
||||
return self.resource.write(*args)
|
||||
|
||||
def query(self, *args):
|
||||
logger.debug('%s...', ', '.join(map(str, args)))
|
||||
data = self.resource.query(*args)
|
||||
logger.debug('%s %s', args[0], data)
|
||||
return data
|
||||
|
||||
def command_binary(self, query, data: bytes):
|
||||
logger.debug('%s, len: %d', query, len(data))
|
||||
return self.resource.write_binary_values(
|
||||
query,
|
||||
data,
|
||||
datatype='B')
|
||||
|
||||
def query_binary(self, query):
|
||||
logger.debug('%s...', query)
|
||||
data = self.resource.query_binary_values(
|
||||
query,
|
||||
datatype='B',
|
||||
container = bytes)
|
||||
logger.debug('%s, len: %d', query, len(data))
|
||||
return data
|
||||
|
||||
def query_check(self, command):
|
||||
print(command, self.resource.query(command+'?'))
|
||||
|
||||
def command_check(self, command, value):
|
||||
data = self.resource.write(command + ' ' + value)
|
||||
self.query_check(command)
|
||||
return data
|
||||
|
||||
def save_conf(self, filename):
|
||||
logger.debug('to filename %s', filename)
|
||||
data = self.query_binary(':SYSTem:SETup?')
|
||||
out_file = open(filename, 'wb')
|
||||
len_written = out_file.write(data)
|
||||
out_file.close()
|
||||
logger.debug('read %d, written %d', len(data), len_written)
|
||||
return len(data) - len_written
|
||||
|
||||
def load_conf(self, filename):
|
||||
logger.debug('from filename %s', filename)
|
||||
in_file = open(filename, 'rb')
|
||||
data = in_file.read()
|
||||
len_written = self.command_binary(':SYSTem:SETup ', data)
|
||||
in_file.close()
|
||||
logger.debug('read %d, written %d', len(data), len_written)
|
||||
return len(data) - len_written
|
||||
|
||||
def setup_measurement(self):
|
||||
logger.debug('')
|
||||
self.command_check(":ACQuire:TYPE", "Normal")
|
||||
# self.command_check(":ACQuire:COUNt", "2")
|
||||
self.command_check(":TIMebase:MODE", "MAIN")
|
||||
self.command_check(":WAVeform:UNSigned", "1")
|
||||
self.command_check(":WAVeform:BYTeorder", "LSBFirst")
|
||||
self.command_check(":WAVeform:FORMat", "BYTE")
|
||||
self.command_check(":WAVeform:SOURce", "CHANnel1")
|
||||
self.command_check(":WAVeform:POINts:MODE", "RAW")
|
||||
self.command_check(":ACQuire:COMPlete", "100")
|
7347
TRNG_attack/scope_setup.conf
Normal file
7347
TRNG_attack/scope_setup.conf
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue