Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Marvin toolkit container #400

Merged
merged 4 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions marvin-toolkit/Cargo.toml
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" }
23 changes: 23 additions & 0 deletions marvin-toolkit/Dockerfile
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"]
66 changes: 66 additions & 0 deletions marvin-toolkit/README.md
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`
133 changes: 133 additions & 0 deletions marvin-toolkit/entrypoint.sh
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