Folder | Description |
---|---|
papers | Scripts and instructions to reproduce results from published papers |
cryptolib | Crypto frameworks (programs under test) |
↳common | Shared DATA files that coordinate all phases of DATA |
data-gui | Graphical user interface (GUI) as git submodule |
pin | Root directory of the Intel Pin DBI framework |
pintool | DATA's Pintool extension to generate address traces |
analysis | DATA's Python analysis scripts |
↳leakage_models | Input transformations (leakage models) for leakage classification (phase 3) |
DATA is actively tested on Ubuntu 20.04 LTS.
However, it should run at least on the following 64-bit x86 Linux systems too:
- Ubuntu 19.04
- Ubuntu 18.10
- Ubuntu 16.04
- Debian 9.8
- Debian 9.4
- Debian 8.3
Tested python versions:
- Python 3.7
- Python 3.5
DATA needs setarch
in order to disable ASLR. Since Docker has issues
with setarch
, DATA cannot be run inside Docker.
On Debian/Ubuntu, the following packages are required to run DATA:
sudo apt-get install coreutils util-linux bash sed grep wget tar mawk time build-essential git python3 python3-setuptools python3-dev python3-virtualenv gcc-multilib
Build and install DATA by executing
make
make install
This creates a file data.sh
in your HOME directory which needs to
be sourced in order to activate DATA.
If you encounter a compile-time error related to setuptools, setting the following environment variable can help:
export SETUPTOOLS_USE_DISTUTILS=stdlib
- Delete the DATA_ROOT directory listed in
~/data.sh
- Remove
data.sh
from your HOME directory via
rm ~/data.sh
To run DATA on an existing library framework, follow these steps:
- Enable data
source ~/data.sh
- Choose a crypto framework to analyze and navigate into its folder
cd cryptolib/openssl
- Choose a result directory by setting the
RESULTDIR
variableexport RESULTDIR=/tmp/DATA_results
- List available algorithms by invoking the framework script
./symmetric.sh -l
- Choose an algorithm of the list, and analyze it
./symmetric.sh --phase1 -p -e --gui des-ecb 64
To test your own library, have a look at this template and read the next sections.
Usage of DATA requires several interacting components. The analyst writes a framework script representing a program or library to test. The framework script is invoked from the command line and in turn invokes DATA. All results are collected in a single result directory.
DATA is centered around a so-called framework script responsible for
providing a wrapper for the program to test. It needs to provide a few
bash
callback functions interfacing with the program to test. In
particular, the callback functions are responsible for:
- building the program to test into an executable file
- generating cryptographic keys or other necessary input files
- invoking the executable
Also, the framework script embeds DATA with an easy-to-use command-line interface called DATA CLI.
DATA provides an easy-to-use command-line interface (CLI). The most important flags are:
--phase1
Run the first phase and produceresult_phase1.pickle
--phase2
Run the second phase produceresult_phase2.pickle
--phase3
Run the third phase and produceresult_phase3.pickle
-p
Run the analysis on all available CPU cores in parallel-e
Export framework files for the DATA GUI--gui
Open the DATA GUI to visualize the latest analysis results-h
Print the help
-
Preparation: When invoking DATA CLI, it first compiles the library under test. To do so, it invokes the
cb_prepare_framework
callback specified in the framework script. -
**Phase 1 key generation (
-g
flag): ** DATA generates random cryptographic keys for later analysis. To do so, it invokes thecb_genkey
callback specified in the framework script. In addition, the script specifies the number of generated keys viaPHASE1_TRACES
. Keys are named.key
in the result directory. -
Phase 1 trace recording (
-d
flag): DATA records full-length address traces with Pintool. To do so, it invokes the callbackscb_pre_run
,cb_run_command
andcb_post_run
specified in the framework script. Each execution of the program under test uses one of the previously generated keys. Traces are named.trace
in the result directory. -
Phase 1 difference detection (
-ad
flag): The DATA analysis script compares the full-length address traces pairwise to find control-flow and data differences. If a program under test yields no differences, the analysis is stopped and phases 2 and 3 are skipped. If differences occur, the results are stored inresult_phase1.pickle
. In addition, all leaking code locations are stored inleaks.bin
for phase 2 and 3. -
Phase 2 trace recording (
-ns
flag): DATA records reduced address traces for one random-key set and multiple fixed-key sets with Pintool. For the random set, a random key is generated for each trace, as with phase 1. For the fixed sets, the program under test is executed repeatedly with the same secret input.PHASE2_TRACES
specifies the number of traces per set.PHASE2_CONSTKEYS
specifies the number of fixed-key sets. Thus, in total(PHASE2_CONSTKEYS+1)*PHASE2_TRACES
traces are recorded. For every trace, the Pintool only monitors the instructions and memory loads listed inleaks.bin
. This significantly reduces the instrumentation time and the trace sizes. All traces and keys are stored in thegen_*
sub-directories within the result directory. -
Phase 2 leakage detection (
-an
flag): The DATA analysis script iterates over all differences from phase 1 and compares the observed addresses in the fixed and random trace sets. If the addresses do not have a similar distribution in both sets, the corresponding difference is flagged as an information leak. The results are stored inresult_phase2.pickle
in the result directory. -
Phase 3 trace recording (
-sp
flag): DATA records reduced address traces with Pintool, as with phase 2. The number of traces is specified viaPHASE3_TRACES
. To reduce computation time, traces and keys from phase 2 can be partially reused (-u
flag). All traces and keys are stored in thespe_*
sub-directories within the result directory. -
Phase 3 leakage classification (
-as
flag): The DATA analysis script iterates over all leaks from phase 2 (or from phase 1 ifPHASE3_SKIP_PHASE2
is set) and tests them against a leakage model specified viaSPECIFIC_LEAKAGE_CALLBACK
. Available leakage models are listed in leakage models. The results are stored inresult_phase3_<leakage-model>.pickle
in the result directory. -
Finalization (
-i
flag): Depending on which previous phases were run, this option causes DATA to collect all results into a singleresult_final.pickle
file. Moreover, as all statistical tests are already run, this option strips unneeded trace information from the pickle file. -
Framework export (
-e
flag): This option compresses all necessary framework files needed for the DATA GUI into a singleframework.zip
archive. In particular, this archive contains disassembler dumps and source code (if available) of all code which exhibits phase one differences. Thus, the DATA GUI can be run on a different computer by giving it theframework.zip
archive, alongisde the.pickle
report to analyze. -
DATA GUI (
--gui
flag): This option runs the DATA GUI directly from the DATA CLI on the last result pickle. It requires a framework export first.
DATA comes with a standalone graphical user interface (GUI) to
visualize leakage results. You can launch the GUI either via the DATA
CLI, or by running datagui
directly on the command line.
The GUI asks for the result_*.pickle
as well as the exported
framework.zip
, which are both in the result directory. For more
information about the GUI check out the
README.
The following sections contain usage recommendations that help improve your experience with DATA.
-
Custom Wrappers: Sometimes, the program under test does not ship as binary. In this case, you need to develop a custom wrapper invoking the program, e.g. parametrized via the command line. When developing such a custom wrapper, avoid leakage in your wrapper code.
-
Debug Compile: Make sure to compile your program under test with debug information (gcc
-g
flag). DATA GUI will then be able to display source code, alongside discovered leakage. -
Framework Script: Have a look at this template as a starting point for your own framework script. DATA tries to reduce non-determinism by disabling ASLR and clearing all environment variables. If your program under test requires certain environment variables, write them into
${ENVFILE}
(see openssl/asymmetric.sh as example). Use the--dry
flag to test your script with extended output. -
Reduce Non-Determinism: In your framework script or custom wrapper, it is recommended to set all non-secret or unrelated program inputs to fixed values. This reduces noise in the address traces of phase one and reveals leaks faster. If an input can't be fixed, DATA will filter out its effects in phase two and free. Simply record more traces in this case. The same holds for non-deterministic program behavior, which is for instance introduced by side-channel countermeasures that randomize code or data accesses. Any non-deterministic behavior with no relation to the secret will be filtered at the expense of increasing the number of traces.
The DATA CLI currently offers two options for improved analysis speed:
-
Parallel execution (
-p
flag): DATA performs various analysis steps in parallel via separate sub-processes. The number of sub-processes is limited by the number of processor cores available to the script. Make sure that sufficient system resources are available, as parallel execution might cause significant system load! -
Trace reuse (
-u
flag): This option forces DATA to reuse all random traces from phase 2 for the third phase. If phase three still requires more traces, DATA will automatically record the missing traces.
The number of traces in each phase can be configured in the framework script of each tested program via the following environment variables:
Variable | Description |
---|---|
PHASE1_TRACES |
number of keys / traces to generate in phase 1 |
PHASE2_FIXEDKEYS |
number of phase 2 repetitions (fixed key sets) |
PHASE2_TRACES |
number of traces to generate per repetition in phase 2 |
PHASE3_TRACES |
number of traces to generate in phase 3 |
Always make sure that PHASE1_TRACES
is larger or equal than
PHASE2_FIXEDKEYS
. Since it is not possible to provide reasonable
measurement numbers that hold for arbitrary programs under test, we
recommend to start with the default numbers that are pre-configured.
Increase PHASE1_TRACES
as long as new differences appear. Once the
number of differences settles, increase PHASE2_TRACES
as long as the
leakage statistics contain untested differences. Increase
PHASE2_FIXEDKEYS
if there seem to be leaks among the dropped
differences. Finally, increase PHASE3_TRACES
to reveal faint
relations in the specific leakage tests. Note that increasing
NTRACE_DIFF
requires new measurements for phases 2 and 3, if the
additional traces in phase 1 reveal new differences.
This section is only relevant for more advanced analysis. In addition
to the .pickle
result files, the analysis
script stores all results in readable XML
reports. They show where differences and leaks occur, and give more
details about generic and specific leakage tests than the DATA GUI. The
XML reports can be found in each analysis directory as:
result_phase1.xml
result_phase2.xml
result_phase3_<leakage-model>.xml
result_final.xml
All generated reports have the same basic structure:
<Report>
<CallHierarchy>
...
</CallHierarchy>
<LibHierarchy>
...
</LibHierarchy>
<Report>
The CallHierarchy lists differences and leaks according to the call graph. Every function call in the execution creates a new context to which differences and leaks can be attributed. The following is an example of a function call during DES encryption in OpenSSL:
<context>
CALL 7ffff6374872(+179872)[733]: PEM_read_bio(T)@/PATH/libcrypto.so.1.1
TO 7ffff634c570(+151570)[250]: EVP_DecodeUpdate(T)@/PATH/libcrypto.so.1.1
</context>
The snippet reports that there was a call in PEM_read_bio()
to
EVP_DecodeUpdate()
. For each code location, the report prints a set
of properties:
Property | Description |
---|---|
7ffff6374872 |
absolute (virtual) address |
(+179872) |
relative address offset in the binary |
[733] |
symbol size, if known (otherwise ? is printed) |
PEM_read_bio |
symbol name, if known (otherwise ? is printed) |
(T) |
symbol type, taken from nm --defined-only <binary> |
/PATH/libcrypto.so.1.1 |
the absolute binary path |
In the <CallHierarchy>
element, control-flow and data differences or
leaks are always attributed to a context. They are printed before the
return of the call, which is indicated by </context>
, as shown:
<context>
CALL ...
TO ...
<dataleaks>
...
</dataleaks>
<cfleaks>
...
</cfleaks>
</context>
Individual differences and leaks are each presented with a separate entry. The following leak appears during DES encryption:
<dataleaks>
<leak>
7ffff62ea2e9(+1782e9)[1f]: OPENSSL_hexchar2int(T)@/PATH/libcrypto.so.1.1
7ffff6391a60: 36
7ffff6391a61: 48
7ffff6391a62: 12
...
<result status='leak' type='generic,specific'>
<generic result='leak' source='H_pos' kuiper='0.866667' significance='0.438291' confidence='0.999900'/>
<generic result='leak' source='H_addr' kuiper='0.192708' significance='0.112697' confidence='0.999900'/>
...
<specific result='leak' source='M_pos' leakagemodel='sym_byte_value' property='2' address='7ffff6391a96' rdc='0.4166' significance='0.4123' confidence='0.999900'/>
<specific result='leak' source='M_addr' leakagemodel='sym_byte_value' property='2' address='7ffff6391a96' rdc='0.4577' significance='0.4123' confidence='0.999900'/>
...
</result>
<MIN>
7ffff6391a60(+21fa60)[37]: CSWTCH.22(r)@/PATH/libcrypto.so.1.1
</MIN>
<MAX>
7ffff6391a96(+21fa96)[37]: CSWTCH.22(r)@/PATH/libcrypto.so.1.1
</MAX>
</leak>
</dataleaks>
The location of the leak is reported similar to a function call. In the
example, the instruction at address 7ffff62ea2e9(+1782e9)
in function
OPENSSL_hexchar2int()
in the libcrypto.so.1.1
library causes a data
leak. In the analyzed traces, this instruction accesses address
7ffff6391a60
36 times, address 7ffff6391a61
48 times, and so on. We
refer to these accesses as evidences of the leak. The <MIN>
and
<MAX>
elements show the smallest and largest evidences, and thereby
give the range of the leak. The location of these evidences is reported
similar to function calls. In this example, the leaking instruction
accesses a compiler-generated lookup table named CSWTCH.22
.
The conclusions of the generic and specific leakage tests are given in
the <result>
element. The result status can be difference, leak,
or dropped. Leaks are either generic, specific or both. Generic
leaks are reported as follows:
Attribute | Description |
---|---|
result |
test result, leak or none (if result is insignificant) |
source |
leakage source, H_pos or H_addr |
kuiper |
Kuiper test statistic |
significance |
significance threshold for the test statistic |
confidence |
probability with which test results are truly significant |
The leakage source H_pos states that the total number of evidences leaks information about the secret input. In contrast, H_addr states that the number of accesses per address leaks. If the Kuiper statistic is above the significance threshold, the result is set to leak. The confidence level states the probability of this result being a true positive. Specific leaks are reported similarly, although more information about the leakage model is provided:
Attribute | Description |
---|---|
result |
test result, leak or none (if result is insignificant) |
source |
leakage source, M_pos or M_addr |
leakagemodel |
leakage model, as loaded from the analysis directory |
property |
part or property of the input that exhibits a relation to the accessed address |
address |
accessed address that exhibits a relation to the secret input |
rdc |
RDC test statistic |
significance |
significance threshold for the test statistic |
confidence |
probability with which test results are truly significant |
M_pos and M_addr are two matrices that are used in the specific
leakage test. These matrices are built individually for each leak. For
every address that is accessed at a leak, a row is added to the
matrices. In M_pos, the columns contain the positions at which an
address is accessed. For example, if a leaking instruction performs
three memory loads, the possible positions are 0
, 1
, and 2
. If
there is no access for an address, -1
is entered. If an address is
accessed multiple times, the median of the positions is entered. In
M_addr, the columns contain how often an address has been accessed.
If there is no access for an address, 0
is entered.
The specific leakage test compares each row in M_pos and M_addr
with the output of the leakage model. Depending on the model, there can
be multiple properties of one input. For example, if individual bytes
of a 64-bit DES key are compared to the rows in M_pos and M_addr,
there are in total 8
properties (bytes 0
to 7
) that may be
reported for a leak.
If the test result is significant for a leak, the reported address reveals the part or property of the input that is specified by the leakage model. For instance, if the Hamming weight model shows significant relations, then an adversary can obtain the Hamming weight of the input from the leak. Again, the confidence level states the probability with which this relation is truly significant.
The LibHierarchy takes the same differences and leaks as contained in the CallHierarchy and splits them according to functions and corresponding binaries. For the data leak discussed in the previous section, the LibHierarchy representation looks as follows:
<Lib>
/PATH/libcrypto.so.1.1 7ffff6172000-7ffff6619e97 (dynamic)
<Function>
7ffff62ea2d0(+1782d0)[1f]: OPENSSL_hexchar2int(T)@/PATH/libcrypto.so.1.1
<dataleaks>
<leak>
7ffff62ea2e9(+1782e9)[1f]: OPENSSL_hexchar2int(T)@/PATH/libcrypto.so.1.1
...
</leak>
</dataleaks>
</Function>
</Lib>
Next to the absolute path of the binary, the range
7ffff6172000-7ffff6619e97
denotes the location at which the binary
was mapped in the virtual address space. If the binary was dynamically
loaded, a (dynamic)
flag is added. Instead of contexts, the
LibHierarchy contains <Function>
elements to which differences and
leaks are attributed. Each element contains the absolute and relative
location of the function as well as its symbol size, name, and type (if
available). Leaks are then reported identically to the CallHierarchy.
At the end of the <CallHierarchy>
and each library in
<LibHierarchy>
there is a summary of all reported differences and
leaks in so-called <LeakStats>
. It is structured as follows:
<LeakStats>
<Differences>
...
</Differences>
<Leaks>
<Generic>
...
</Generic>
<Specific>
...
</Specific>
</Leaks>
</LeakStats>
The summary is split into two parts: <Differences>
and <Leaks>
. The
<Differences>
element looks as follows:
<Differences>
cflow: 164
cflow-drop: 12
cflow-notest: 5
data: 349
data-drop: 39
data-notest: 15
</Differences>
The exemplary results show that 164
control-flow differences have
been detected in phase 1, out of which 12
have been discarded in
phase 2. 5
differences have not been tested, because there weren't
enough traces to perform the generic leakage test in phase 2.
Similarly, out of 349
data differences, 39
were discarded and 15
weren't tested at all. We recommend to increase the number of
measurements as long as differences show up untested in the leakage
statistics (see Usage Tips).
The <Leaks>
element provides generic and specific leakage test
results from phases 2 and 3, respectively. Each element in <Leaks>
distinguishes between data and control-flow results:
<Leaks>
<Generic>
cflow: 147
data: 297
</Generic>
<Specific>
leakage-model: dsa_privkey_hw
cflow: 6
data: 24
</Specific>
</Leaks>
The <Generic>
element shows that 147
control-flow differences have
been flagged as information leaks. This correspond to the previous
numbers, since 164
differences - 12
discarded ones - 5
untested
ones = 147
leaks. Similarly, 295
data leaks have been found among
349
differences, of which 39
have been discarded and 15
have not
been tested.
The <Specific>
element shows that 6
control-flow and 24
data
leaks exhibit significant relations to the Hamming weight of the secret
input, a DSA private key in this example. Since multiple leakage models
can be tested, reports can contain multiple <Specific>
result
elements.