lowrisc / ot-sca Goto Github PK
View Code? Open in Web Editor NEWSide-channel analysis setup for OpenTitan
License: Apache License 2.0
Side-channel analysis setup for OpenTitan
License: Apache License 2.0
Implement a mechanism to upload and download bitstreams and traces to/from gcp buckets. Additional requirements:
The variable to distinguish the board (CW310 vs. CW305) is currently just a string, but this should be an enum. See comment.
Our capture scripts still use the CW-Lite scope. We should switch to CW-Husky which has higher capture performance.
In the AES capture script the "aes_fvsr_key" config option is named "aes_fsvr_key".
Integrate TVLA testing for the AES core using ChipWhisperer's test suite as documented here: https://cwtvla.readthedocs.io/en/latest/
OT PR 19380 updated ecc384_serial.c
and p384_ecdsa_sca.s
to enable trace capturing with the latest setup.
Binaries should be updated.
Currently, the notes stored in the trace database need to be added in the Python script. In a future version of the capture script, the notes could be passed as an argument when executing the script or during the execution in the CLI.
With the PR #95, we can now load histograms and use them for general test. This is done automatically when a PR is created but it does not cover all functionality of the tvla.py script. We should also add an automatic test which gets power measurements, computes their t-values and compares with the expected values.
In addition there may be some other functionalities of the tvla.py script that may be tested. Maybe @vrozic, @vogelpi and @andreaskurth has some ideas?
All of us now have access to the Husky scope and we almost exclusively use Husky instead of CW-Lite due to the better ADC resolution, higher sampling frequency and higher capture rate (larger on-chip buffer). Therefore we should consider to deprecate the CW-Lite support to clean up the repository.
Please see #36 for context and newaetech/chipwhisperer#306 for what needs to be done.
Implement firmware bootstrap using the native target SPI interface, or the capture board SPI connection available in the target connector.
This removes the dependency on the SPI FTDI cable currently used to load the firmware on the device.
SPIFLASH_RAW_BUFFER_SIZE
(sw/device/boot_rom/spiflash_frame.h) increased from 1024
to 2048
lowRISC/opentitan#5068.
I took a quick look and unless I missed something this shouldn't break our workflow but we should increase the frame size for the sake of efficiency.
FYI @bilgiday
At the moment, measurement offset in capture configuration files is specified in samples.
It probably makes more sense to use clk cycles of the target as a unit of measurement.
We currently hold all traces in RAM after capture / during analysis and write to CW projects, i.e. numpy files. Larger trace amounts require sequential iterations through traces to reduce RAM consumption.
While writing the code for the otbn capture and helping debugging the otbn-batch mode, @wettermo and I stumbled across the following lines
Lines 175 to 187 in 111c140
Can someone explain to me, why self._scope.clock.clkgen_freq = 100000000
is hardcoded there? Is this just a leftover or is there a particular reason? I'd expected thatt, self._scope.clock.clkgen_freq = pll_frequency
like in
Line 130 in 111c140
While writing, I just discovered that @bilgiday had changed this behavior in cw/util/device.py
in f51c6ec
So, may I assume, we could change this also in the cw_segmented.py
, or is this a bad idea for some reason?
In python-requirements.txt
we do not specify the version of bokeh
. In one of the recent version, plot_width
was replaced by width
. (The changelog says it was removed in the docs in version 2.4, however I only encountered the problem with release 3.0.3 not in 2.4.3)
This causes some errors in
Line 17 in 7455181
When changing the parameter, I encountered bokeh.core.serialization.SerializationError: can't serialize <class 'range'>
which is also discussed in bokeh/bokeh#12313 (comment)
So, it looks like as there are more things to deal with when upgrading to 3.0.3.
What's the best way to fix this issue?
Pin the bokeh version or fix it and require a bokeh update?
Currently, only the path to the used binary is stored into the trace database. In a future version of the capture script, the binary itself could be stored in the database.
On the CW310, the detection whether a bitstream has been programmed previously doesn't work. The bitstream is always programmed which takes around 15 seconds due to the bigger FPGA.
This is to remind me to have a look at #109 (comment)
PR #82 added the corresponding target binaries to support the aes-fvsr-key-batch command. For most of us this seems to work just fine but I saw lots of errors like:
Fixed key: b'811e3731b0120a7842781e22b25cddf9'
Connected to ChipWhisperer (num_samples: 1200, num_samples_actual: 1200, num_segments_actual: 1)
Capturing: 16%|███▋ | 162/1000 [00:00<00:01, 492.97 traces/s]
Traceback (most recent call last):
File "./capture.py", line 771, in <module>
app()
...
File "./capture.py", line 502, in aes_fvsr_key_batch
capture_aes_fvsr_key_batch(
File "./capture.py", line 460, in capture_aes_fvsr_key_batch
check_ciphertext(ot, expected_last_ciphertext, 4)
File "./capture.py", line 221, in check_ciphertext
assert actual_last_ciphertext == expected_last_ciphertext[0:ciphertext_len], (
AssertionError: Incorrect encryption result!
actual: bytearray(b'^\xdc\xe8{')
expected: [ 85 154 226 3 30 12 31 147 54 197 151 35 4 134 80 98]
In words, there are sometimes mismatches between the expected and received ciphertexts. Sometimes, the failure occurs for the first batch, sometimes for a later batch, sometimes it doesn't occur at all. The failures seem to depend on timing (adding some sleep command on the Python side seem to help), Husky firmware (the latest firmware seems to be more affected), and maybe also USB connection setup (docking station, hub, laptop directly).
We should root cause and fix the problem. Otherwise we can't reliably do long running captures. Imagine we collect 10 Mio traces and get such a failure after 2 hours - all traces will be lost.
Riscure has made a trs library available here: https://github.com/Riscure/python-trsfile. Implement a script to interoperate with ChipWhisperer traces.
Currently, the device SW sets the trigger HI/LO and in HW this is AND-ed with the AES !IDLE signal. This generates tight trigger HI/LO envelopes around the AES computation. For the longer term, we need to change this behaviour and have the trigger purely controlled by SW. TODO: Change this and test.
Similar to AES, KMAC and SHA3 we should have a golden model running in parallel with the target to verify the produced signature on the host side.
As the old capture.py file is not working anymore due to the repo restructure, we need to implement the KMAC capture.
Please use capture_aes.py as a boilerplate.
Currently, we have configuration files in ci/
and also in capture/
. To simplify the repository, there only should be one location for the configs.
Currently starts generating plaintexts and keys directly from PRNG seed=0 (using Mersenne twister PRNG).
Is split into two phases - execute and generate next batch of keys and plaintext in memory.
Device-side could be improved:
sample_fixed
valuesample_fixed = 0
. This is easy when using a SW AES instead of PRNG.In #54 we added support for KMAC using pyXKCP, which uses some vendor c-sources. We did that, because at this point in time there was no good python kmac implementation available.
However, this adds some c-sources and some cffi scripting.
In the meantime, kmac128 and kmac256 were added to pycryptodome v3.12.0
Do we want to streamline our python flow? This has of course a very low priority, but could be a good first issue for some else.
Currently, data capture, target and analysis scripts are stored in the same directory. Consider a top level view similar to the following:
tree .
.
├── analysis (models, pre/post processing libraries)
├── attacks (mountable attacks)
├── capture (data capture)
│ ├── cw
│ └── picoscope
├── obj (access to precompiled bitstreams, etc, TBD)
├── targets (target boards)
│ └── cw305
├── tests (integration tests, and end-to-end testing)
└── utils (utility libraries, e.g. cw to trs conversion scripts)
At the moment, binaries built for the CW310 board from OpenTitan master don't seem to work. I am not 100% sure what the root cause for this is. I suspect the main issue is that we changed the clock frequency for the CW310 some time ago to speed up TLT (see this PR lowRISC/opentitan#19479 or specifically commit lowRISC/opentitan@162cdab).
As a temporary workaround, we can use the ot-sca_2023-07-15_dd8b709_cw310
tag on my fork as a base (this is when I last updated CW310 bitstreams and binary): https://github.com/vogelpi/opentitan/releases/tag/ot-sca_2023-07-15_dd8b709_cw310
As discussed with @vrozic , currently there is no CI job for testing the container. To ensure that future changes to the container infrastructure are working, adding a new CI job could be useful.
Test capture script #150 uncovered a problem with naming of some of the capture commands and arguments. At the moment we don't use consistent naming strategy, which makes it complicated to automate the testing. Since the repository is likely to be extended with newer tests, we should come up with a consistent naming strategy to make maintaining easier.
Tasks:
capture.py
and the test scripts.Now that #23 is merged and programming OpenTitan using SAM3U seems to be working we should consider removing FTDI related code and update the getting started doc.
As discussed in #115 and https://docs.google.com/document/d/1sZjASiUji_IT-t9jEFlK-kGc_Gw3mGfubNvpkM_IQT4/edit#heading=h.qd65x0y76b0e we should check the usage of key, text = ktp.next()
in cw/capture.py
Default behavior is that ktp.next()
returns const_key, random_plaintext
. This default behavior can be changed with ctx.obj.ktp.fixed_key = False
.
Afaik, we call ktp.next()[0]
only once per function and use only the first call of the iterator to assign a constant key. For random keys we use ktp.next()[1]
. Thus, I think we ware fine and can change the default behavior, but we should double check that and read the spec if the first call of the iterator still outputs a deterministic value. On the other hand, if we really rely on a constant non random value, we should use a constant and not a constant iterator.
After the latest changes in capture setups, we are experiencing problems when capturing using ChipWhisperer Husky.
Currently, I am not sure what is causing the problem, but these are the symptoms:
scope.capture_and_transfer_waves()
functions, and results in the USB error raiseUSBError raise__STATUS_TO_EXCEPTION_DICT.get(value, __USBError)(value) usb1.USBErrorIO: LIBUSB_ERROR_IO [-1]
ValueError: Unknown ChipWhisperer:
I will investigate this further to find a permanent fix, but a temporary workaround is to:
Huskies in the CI setup are always powered-on, so the CI should be stable for now.
Noticed this while working on #23 (should not be related). When I run simple_capture_traces.py
. If I send multiple commands, it sends a response for each one except for the first one.
We currently use Python random
host-side and an implementation of the same Mersenne twister on device side.
We could replace it by a SW implementation of AES to generate the data on-device.
Currently, we're sampling with 50 MHz and the target is running at ~5 MHz for ECDSA captures to keep a 10x oversampling ratio (some of this work is not yet in the repo). Above 50 MHz it seems the synchronization between multiple runs/segments is lost. We should re-investigate this with an updated Husky firmware.
When the simple capture script is mature enough, use as template to implement remaining capture commands.
Evaluate and consider implementation of the correlation-enhanced power analysis collision attack formulated here: https://eprint.iacr.org/2010/297.pdf
With #71 we have moved our TVLA code to the public repo. Besides adding new features, we have so far identified the following things to improve:
capture.py
) to simplify the handling of input arguments.Ray
(see ceca.py
).trace-file
. Currently we need to open project file even when we are using traces from the trace file.start_sample
and end_sample
)t_value
vs number of samples
graphs. Currently constant range is used.tvla_cfg_aes.yaml
should be added.mode
and general_test
are used to specify the type of test. This should be reworked to use only one argument with the value specifying either the general test or the type of the specific test.tmp/ttest.npy
containing the analysis results is generated if and only if cfg["input_file"]
is provided. This should be a separate option because it is not related to the input file.ttest-step.npy
to be saved whenever n_steps != 0, regardless of the other input parameterssave_to_disk_trace
and save_to_disk_leakage
tvla.py
cannot generate figures if data is loaded from histograms.tvla.py
cannot generate some figures if data is loaded from the new database format.Currently, traces generated in the CI need to be manually inspected. Ideally, an automated comparison of generated traces to a golden model is conducted.
Implement cycle-based config as shown in #203.
As the old capture.py file is not working anymore due to the repo restructure, we need to implement the OTBN capture.
Please use capture_aes.py as a boilerplate.
It seems the target is currently reset between capturing different traces or trace segments which leads to very low performance as the binary needs to be transferred over SPI for every segment. We should look into changing the capture setup to not require a reset of the target between segments.
We haven't been updating the Dockerfile for a while and it would be worth checking whether it's still working the the latest changes in ot-sca or if it needs updating.
As the old capture.py file is not working anymore due to the repo restructure, we need to implement the SHA3 capture.
Please use capture_aes.py as a boilerplate.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.