-
Notifications
You must be signed in to change notification settings - Fork 156
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This contains a Docker image which can be used for testing for the Marvin Attack: https://people.redhat.com/~hkario/marvin/
- Loading branch information
Showing
4 changed files
with
235 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
name = "rust-crypto" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
anyhow = "1" | ||
clap = { version = "4", features = ["derive"] } | ||
rsa = "0.9" | ||
|
||
[patch.crates-io] | ||
rsa = { git = "https://github.com/RustCrypto/RSA", branch = "const-crypto-biguint" } | ||
crypto-bigint = { git = "https://github.com/RustCrypto/crypto-bigint", branch = "master" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
FROM python:3.12-bookworm | ||
|
||
# Create non-root user | ||
RUN adduser rustcrypto --disabled-password --gecos "" | ||
|
||
USER rustcrypto | ||
|
||
# Install Rust | ||
RUN curl -sSf https://sh.rustup.rs | sh -s -- -y | ||
ENV PATH="/home/rustcrypto/.cargo/bin:${PATH}" | ||
|
||
# Clone the marvin-toolkit repository | ||
RUN cd $HOME \ | ||
&& git clone https://github.com/tomato42/marvin-toolkit.git \ | ||
&& cd marvin-toolkit \ | ||
&& chmod +x *.sh \ | ||
&& ./step0.sh | ||
WORKDIR "/home/rustcrypto/marvin-toolkit" | ||
|
||
# Generating private keys, ciphertexts, building RustCrypto/RSA, should all be done at runtime | ||
COPY --chmod=777 entrypoint.sh ./entrypoint.sh | ||
|
||
ENTRYPOINT ["./entrypoint.sh"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# Marvin tool-kit integration | ||
This document describes the procedure for replicating the analysis for the Marvin attack. This analysis is best done on a container for reproducibility. | ||
|
||
**TL;DR**: | ||
```bash | ||
# Build the image | ||
docker build -t marvin:latest . | ||
|
||
# Create the output directory and allow container to write to it | ||
mkdir -p outputs | ||
chmod a+rw outputs | ||
|
||
# Run the analysis | ||
docker run -d --rm \ | ||
--name marvin \ | ||
-v $(pwd)/outputs:/home/rustcrypto/marvin-toolkit/outputs \ | ||
-v $(pwd)/Cargo.toml:/home/rustcrypto/marvin-toolkit/example/rust-crypto/Cargo.toml \ | ||
marvin:latest | ||
|
||
# Use "docker logs -f marvin" to read live output | ||
|
||
# Read the output | ||
cat outputs/results/report.txt | ||
``` | ||
|
||
## Adjusting analysis parameters | ||
For more help on the options pass in the `-h` flag in the `docker run` command: | ||
|
||
``` | ||
docker run ... marvin:latest -h | ||
``` | ||
|
||
There are two main parameters of the analysis: RSA key size and the number of repetitions during ciphertext generation. | ||
|
||
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. | ||
|
||
```bash | ||
# Run analysis for RSA 4096 with 1 million repetition | ||
docker run -d --rm \ | ||
--name marvin \ | ||
marvin:latest -s 4096 -n 1000000 | ||
``` | ||
|
||
## Extracting keys, ciphertexts, and analysis results (WIP) | ||
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: | ||
|
||
```bash | ||
mkdir -p outputs | ||
chmod a+rw outputs | ||
|
||
# Mount | ||
docker run -d --rm --name "marvin" \ | ||
-v $(pwd)/outputs:/home/rustcrypto/marvin-toolkit/outputs \ | ||
marvin:latest | ||
``` | ||
|
||
## Compile test harness with custom `Cargo.toml` | ||
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`: | ||
|
||
```bash | ||
docker run -d --rm --name "marvin" \ | ||
-v $(pwd)/Cargo.toml:/home/rustcrypto/marvin-toolkit/example/rust-crypto/Cargo.toml \ | ||
marvin:latest | ||
``` | ||
|
||
If no `Cargo.toml` is specified, the default one will use `rsa = 0.9` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
#!/bin/bash | ||
|
||
# Build the test harness | ||
cd example/rust-crypto | ||
cargo update --quiet | ||
cargo build --profile release --quiet | ||
cd ~/marvin-toolkit | ||
|
||
# Parse CLI inputs to $size and $repeat | ||
size=2048 | ||
repeat=100000 | ||
|
||
# Function to display help message | ||
display_help() { | ||
echo "Usage: $0 [-s SIZE] [-n NUMBER] [-h]" | ||
echo " -s SIZE Set the RSA key size (1024, 2048, or 4096; default: 2048)" | ||
echo " -n NUMBER Set the repeat number (integer; default: 100000)" | ||
echo " -h Display this help message" | ||
} | ||
|
||
# Parse command-line arguments using getopts | ||
while getopts ":s:n:h" opt; do | ||
case $opt in | ||
s) | ||
size=$OPTARG | ||
if [[ ! "$size" =~ ^(1024|2048|4096)$ ]]; then | ||
echo "Error: Invalid size. Please choose 1024, 2048, or 4096." | ||
exit 1 | ||
fi | ||
;; | ||
n) | ||
repeat=$OPTARG | ||
if ! [[ "$repeat" =~ ^[0-9]+$ ]]; then | ||
echo "Error: Invalid number. Please specify a valid integer." | ||
exit 1 | ||
fi | ||
;; | ||
h) | ||
display_help | ||
exit 0 | ||
;; | ||
\?) | ||
echo "Error: Invalid option -$OPTARG" | ||
display_help | ||
exit 1 | ||
;; | ||
:) | ||
echo "Error: Option -$OPTARG requires an argument." | ||
display_help | ||
exit 1 | ||
;; | ||
esac | ||
done | ||
size_bytes=$(($size / 8)) | ||
|
||
# Step 1: Generate key pairs | ||
. ./certgen/certgen/lib.sh | ||
name="rsa${size}" | ||
tmp_file="$(mktemp)" | ||
if ! x509KeyGen -s $size $name &> "$tmp_file"; then | ||
echo "ERROR $size bit key generation failed" >&2 | ||
cat "$tmp_file" >&2 | ||
exit 1 | ||
fi | ||
if ! x509SelfSign $name &> "$tmp_file"; then | ||
echo "ERROR: $size bit key self-signing failed" >&2 | ||
cat "$tmp_file" >&2 | ||
exit 1 | ||
fi | ||
|
||
echo "RSA $size bit private key in old OpenSSL PEM format is in" $(x509Key $name) | ||
echo "RSA $size bit private key in old OpenSSL DER format is in" $(x509Key --der $name) | ||
echo "RSA $size bit private key in PKCS#8 PEM format is in" $(x509Key --pkcs8 $name) | ||
echo "RSA $size bit private key in PKCS#8 DER format is in" $(x509Key --der --pkcs8 $name) | ||
echo "RSA $size bit private key in PKCS#12 format is in" $(x509Key --with-cert --pkcs12 $name) | ||
echo "RSA $size bit self-signed certificate is in" $(x509Cert $name) | ||
echo | ||
|
||
# Generate ciphertexts | ||
case $size in | ||
1024) | ||
PYTHONPATH=tlsfuzzer ./marvin-venv/bin/python ./step2.py \ | ||
-c rsa1024/cert.pem -o rsa1024_repeat \ | ||
--repeat ${repeat} --verbose \ | ||
no_structure no_padding=48 signature_padding=8 \ | ||
valid_repeated_byte_payload="118 0xff" \ | ||
valid_repeated_byte_payload="118 0x01" \ | ||
valid=48 header_only \ | ||
no_header_with_payload=48 zero_byte_in_padding="48 4" \ | ||
valid=0 valid=118 | ||
;; | ||
2048) | ||
PYTHONPATH=tlsfuzzer ./marvin-venv/bin/python ./step2.py \ | ||
-c rsa2048/cert.pem -o rsa2048_repeat \ | ||
--repeat ${repeat} --verbose \ | ||
no_structure no_padding=48 signature_padding=8 \ | ||
valid_repeated_byte_payload="246 0xff" \ | ||
valid_repeated_byte_payload="246 0x01" \ | ||
valid=48 header_only \ | ||
no_header_with_payload=48 zero_byte_in_padding="48 4" \ | ||
valid=0 valid=192 valid=246 | ||
;; | ||
4096) | ||
PYTHONPATH=tlsfuzzer ./marvin-venv/bin/python ./step2.py \ | ||
-c rsa4096/cert.pem -o rsa4096_repeat \ | ||
--repeat ${repeat} --verbose \ | ||
no_structure no_padding=48 signature_padding=8 \ | ||
valid_repeated_byte_payload="502 0xff" \ | ||
valid_repeated_byte_payload="502 0x01" \ | ||
valid=48 header_only \ | ||
no_header_with_payload=48 zero_byte_in_padding="48 4" \ | ||
valid=0 valid=192 valid=502 | ||
;; | ||
esac | ||
|
||
# Run decryptions and analyze data | ||
echo "Starting decryption" | ||
./example/rust-crypto/target/release/rust-crypto \ | ||
-i rsa${size}_repeat/ciphers.bin \ | ||
-o rsa${size}_repeat/raw_times.csv -k rsa${size}/pkcs8.pem -n $size_bytes | ||
echo "Decryptions finished" | ||
PYTHONPATH=tlsfuzzer marvin-venv/bin/python3 tlsfuzzer/tlsfuzzer/extract.py \ | ||
-l rsa${size}_repeat/log.csv --raw-times rsa${size}_repeat/raw_times.csv \ | ||
-o rsa${size}_repeat/ \ | ||
--clock-frequency 1000 | ||
PYTHONPATH=tlsfuzzer marvin-venv/bin/python3 tlsfuzzer/tlsfuzzer/analysis.py \ | ||
-o rsa${size}_repeat/ --verbose | ||
|
||
# Copy over the keys and the results, if the results directory exists | ||
if [[ -d ~/marvin-toolkit/outputs ]]; then | ||
cp -r rsa${size} ~/marvin-toolkit/outputs/keys | ||
cp -r rsa${size}_repeat ~/marvin-toolkit/outputs/results | ||
fi |