Skip to content

Commit d011ca5

Browse files
authored
Add Marvin toolkit container (#400)
This contains a Docker image which can be used for testing for the Marvin Attack: https://people.redhat.com/~hkario/marvin/
1 parent 4cb8aec commit d011ca5

4 files changed

Lines changed: 235 additions & 0 deletions

File tree

‎marvin-toolkit/Cargo.toml‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "rust-crypto"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
anyhow = "1"
8+
clap = { version = "4", features = ["derive"] }
9+
rsa = "0.9"
10+
11+
[patch.crates-io]
12+
rsa = { git = "https://github.com/RustCrypto/RSA", branch = "const-crypto-biguint" }
13+
crypto-bigint = { git = "https://github.com/RustCrypto/crypto-bigint", branch = "master" }

‎marvin-toolkit/Dockerfile‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
FROM python:3.12-bookworm
2+
3+
# Create non-root user
4+
RUN adduser rustcrypto --disabled-password --gecos ""
5+
6+
USER rustcrypto
7+
8+
# Install Rust
9+
RUN curl -sSf https://sh.rustup.rs | sh -s -- -y
10+
ENV PATH="/home/rustcrypto/.cargo/bin:${PATH}"
11+
12+
# Clone the marvin-toolkit repository
13+
RUN cd $HOME \
14+
&& git clone https://github.com/tomato42/marvin-toolkit.git \
15+
&& cd marvin-toolkit \
16+
&& chmod +x *.sh \
17+
&& ./step0.sh
18+
WORKDIR "/home/rustcrypto/marvin-toolkit"
19+
20+
# Generating private keys, ciphertexts, building RustCrypto/RSA, should all be done at runtime
21+
COPY --chmod=777 entrypoint.sh ./entrypoint.sh
22+
23+
ENTRYPOINT ["./entrypoint.sh"]

‎marvin-toolkit/README.md‎

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Marvin tool-kit integration
2+
This document describes the procedure for replicating the analysis for the Marvin attack. This analysis is best done on a container for reproducibility.
3+
4+
**TL;DR**:
5+
```bash
6+
# Build the image
7+
docker build -t marvin:latest .
8+
9+
# Create the output directory and allow container to write to it
10+
mkdir -p outputs
11+
chmod a+rw outputs
12+
13+
# Run the analysis
14+
docker run -d --rm \
15+
--name marvin \
16+
-v $(pwd)/outputs:/home/rustcrypto/marvin-toolkit/outputs \
17+
-v $(pwd)/Cargo.toml:/home/rustcrypto/marvin-toolkit/example/rust-crypto/Cargo.toml \
18+
marvin:latest
19+
20+
# Use "docker logs -f marvin" to read live output
21+
22+
# Read the output
23+
cat outputs/results/report.txt
24+
```
25+
26+
## Adjusting analysis parameters
27+
For more help on the options pass in the `-h` flag in the `docker run` command:
28+
29+
```
30+
docker run ... marvin:latest -h
31+
```
32+
33+
There are two main parameters of the analysis: RSA key size and the number of repetitions during ciphertext generation.
34+
35+
RSA key size is specified through `-s <1024|2048|4096>`. The number of repetition is specified through `-n <num>`. A larger repetition number will increase the confidence of the analysis, but will make the analysis take longer. The default key size is 2048 and the default repetition count is 100,000.
36+
37+
```bash
38+
# Run analysis for RSA 4096 with 1 million repetition
39+
docker run -d --rm \
40+
--name marvin \
41+
marvin:latest -s 4096 -n 1000000
42+
```
43+
44+
## Extracting keys, ciphertexts, and analysis results (WIP)
45+
After the analysis is done, the generate keys, ciphertexts, and the analysis outputs are all copied into the directory `/home/rustcrypto/marvin-toolkit/outputs`. To extract and preserve these artifacts, mount a volume into this directory, such as using a bind mount:
46+
47+
```bash
48+
mkdir -p outputs
49+
chmod a+rw outputs
50+
51+
# Mount
52+
docker run -d --rm --name "marvin" \
53+
-v $(pwd)/outputs:/home/rustcrypto/marvin-toolkit/outputs \
54+
marvin:latest
55+
```
56+
57+
## Compile test harness with custom `Cargo.toml`
58+
The test harness is compiled at container run-time, so a custom `Cargo.toml` can be passed into the container at runtime to compile the test harness using custom versions of `RustCrypto/RSA` and/or `RustCrypto/crypto-bigint`:
59+
60+
```bash
61+
docker run -d --rm --name "marvin" \
62+
-v $(pwd)/Cargo.toml:/home/rustcrypto/marvin-toolkit/example/rust-crypto/Cargo.toml \
63+
marvin:latest
64+
```
65+
66+
If no `Cargo.toml` is specified, the default one will use `rsa = 0.9`

‎marvin-toolkit/entrypoint.sh‎

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#!/bin/bash
2+
3+
# Build the test harness
4+
cd example/rust-crypto
5+
cargo update --quiet
6+
cargo build --profile release --quiet
7+
cd ~/marvin-toolkit
8+
9+
# Parse CLI inputs to $size and $repeat
10+
size=2048
11+
repeat=100000
12+
13+
# Function to display help message
14+
display_help() {
15+
echo "Usage: $0 [-s SIZE] [-n NUMBER] [-h]"
16+
echo " -s SIZE Set the RSA key size (1024, 2048, or 4096; default: 2048)"
17+
echo " -n NUMBER Set the repeat number (integer; default: 100000)"
18+
echo " -h Display this help message"
19+
}
20+
21+
# Parse command-line arguments using getopts
22+
while getopts ":s:n:h" opt; do
23+
case $opt in
24+
s)
25+
size=$OPTARG
26+
if [[ ! "$size" =~ ^(1024|2048|4096)$ ]]; then
27+
echo "Error: Invalid size. Please choose 1024, 2048, or 4096."
28+
exit 1
29+
fi
30+
;;
31+
n)
32+
repeat=$OPTARG
33+
if ! [[ "$repeat" =~ ^[0-9]+$ ]]; then
34+
echo "Error: Invalid number. Please specify a valid integer."
35+
exit 1
36+
fi
37+
;;
38+
h)
39+
display_help
40+
exit 0
41+
;;
42+
\?)
43+
echo "Error: Invalid option -$OPTARG"
44+
display_help
45+
exit 1
46+
;;
47+
:)
48+
echo "Error: Option -$OPTARG requires an argument."
49+
display_help
50+
exit 1
51+
;;
52+
esac
53+
done
54+
size_bytes=$(($size / 8))
55+
56+
# Step 1: Generate key pairs
57+
. ./certgen/certgen/lib.sh
58+
name="rsa${size}"
59+
tmp_file="$(mktemp)"
60+
if ! x509KeyGen -s $size $name &> "$tmp_file"; then
61+
echo "ERROR $size bit key generation failed" >&2
62+
cat "$tmp_file" >&2
63+
exit 1
64+
fi
65+
if ! x509SelfSign $name &> "$tmp_file"; then
66+
echo "ERROR: $size bit key self-signing failed" >&2
67+
cat "$tmp_file" >&2
68+
exit 1
69+
fi
70+
71+
echo "RSA $size bit private key in old OpenSSL PEM format is in" $(x509Key $name)
72+
echo "RSA $size bit private key in old OpenSSL DER format is in" $(x509Key --der $name)
73+
echo "RSA $size bit private key in PKCS#8 PEM format is in" $(x509Key --pkcs8 $name)
74+
echo "RSA $size bit private key in PKCS#8 DER format is in" $(x509Key --der --pkcs8 $name)
75+
echo "RSA $size bit private key in PKCS#12 format is in" $(x509Key --with-cert --pkcs12 $name)
76+
echo "RSA $size bit self-signed certificate is in" $(x509Cert $name)
77+
echo
78+
79+
# Generate ciphertexts
80+
case $size in
81+
1024)
82+
PYTHONPATH=tlsfuzzer ./marvin-venv/bin/python ./step2.py \
83+
-c rsa1024/cert.pem -o rsa1024_repeat \
84+
--repeat ${repeat} --verbose \
85+
no_structure no_padding=48 signature_padding=8 \
86+
valid_repeated_byte_payload="118 0xff" \
87+
valid_repeated_byte_payload="118 0x01" \
88+
valid=48 header_only \
89+
no_header_with_payload=48 zero_byte_in_padding="48 4" \
90+
valid=0 valid=118
91+
;;
92+
2048)
93+
PYTHONPATH=tlsfuzzer ./marvin-venv/bin/python ./step2.py \
94+
-c rsa2048/cert.pem -o rsa2048_repeat \
95+
--repeat ${repeat} --verbose \
96+
no_structure no_padding=48 signature_padding=8 \
97+
valid_repeated_byte_payload="246 0xff" \
98+
valid_repeated_byte_payload="246 0x01" \
99+
valid=48 header_only \
100+
no_header_with_payload=48 zero_byte_in_padding="48 4" \
101+
valid=0 valid=192 valid=246
102+
;;
103+
4096)
104+
PYTHONPATH=tlsfuzzer ./marvin-venv/bin/python ./step2.py \
105+
-c rsa4096/cert.pem -o rsa4096_repeat \
106+
--repeat ${repeat} --verbose \
107+
no_structure no_padding=48 signature_padding=8 \
108+
valid_repeated_byte_payload="502 0xff" \
109+
valid_repeated_byte_payload="502 0x01" \
110+
valid=48 header_only \
111+
no_header_with_payload=48 zero_byte_in_padding="48 4" \
112+
valid=0 valid=192 valid=502
113+
;;
114+
esac
115+
116+
# Run decryptions and analyze data
117+
echo "Starting decryption"
118+
./example/rust-crypto/target/release/rust-crypto \
119+
-i rsa${size}_repeat/ciphers.bin \
120+
-o rsa${size}_repeat/raw_times.csv -k rsa${size}/pkcs8.pem -n $size_bytes
121+
echo "Decryptions finished"
122+
PYTHONPATH=tlsfuzzer marvin-venv/bin/python3 tlsfuzzer/tlsfuzzer/extract.py \
123+
-l rsa${size}_repeat/log.csv --raw-times rsa${size}_repeat/raw_times.csv \
124+
-o rsa${size}_repeat/ \
125+
--clock-frequency 1000
126+
PYTHONPATH=tlsfuzzer marvin-venv/bin/python3 tlsfuzzer/tlsfuzzer/analysis.py \
127+
-o rsa${size}_repeat/ --verbose
128+
129+
# Copy over the keys and the results, if the results directory exists
130+
if [[ -d ~/marvin-toolkit/outputs ]]; then
131+
cp -r rsa${size} ~/marvin-toolkit/outputs/keys
132+
cp -r rsa${size}_repeat ~/marvin-toolkit/outputs/results
133+
fi

0 commit comments

Comments
 (0)