mirror of
https://github.com/rosenpass/rosenpass.git
synced 2025-12-18 13:24:38 +03:00
Compare commits
1 Commits
dev/karo/k
...
dev/blipp/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf67344e86 |
@@ -32,9 +32,9 @@ let systems_map = {
|
||||
# aarch64-darwin
|
||||
# aarch64-linux
|
||||
|
||||
i686-linux: ubicloud-standard-2-ubuntu-2204,
|
||||
i686-linux: ubuntu-latest,
|
||||
x86_64-darwin: macos-13,
|
||||
x86_64-linux: ubicloud-standard-2-ubuntu-2204
|
||||
x86_64-linux: ubuntu-latest
|
||||
}
|
||||
|
||||
let targets = (get-attr-names ".#packages"
|
||||
@@ -61,13 +61,14 @@ mut release_workflow = {
|
||||
|
||||
let runner_setup = [
|
||||
{
|
||||
uses: "actions/checkout@v4"
|
||||
uses: "actions/checkout@v3"
|
||||
}
|
||||
{
|
||||
uses: "cachix/install-nix-action@v30",
|
||||
uses: "cachix/install-nix-action@v22",
|
||||
with: { nix_path: "nixpkgs=channel:nixos-unstable" }
|
||||
}
|
||||
{
|
||||
uses: "cachix/cachix-action@v15",
|
||||
uses: "cachix/cachix-action@v12",
|
||||
with: {
|
||||
name: rosenpass,
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
@@ -153,7 +154,7 @@ for system in ($targets | columns) {
|
||||
}
|
||||
{
|
||||
name: Release,
|
||||
uses: "softprops/action-gh-release@v2",
|
||||
uses: "softprops/action-gh-release@v1",
|
||||
with: {
|
||||
draft: "${{ contains(github.ref_name, 'rc') }}",
|
||||
prerelease: "${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}",
|
||||
@@ -181,7 +182,7 @@ $cachix_workflow.jobs = ($cachix_workflow.jobs | insert $"($system)---whitepaper
|
||||
}
|
||||
{
|
||||
name: "Deploy PDF artifacts",
|
||||
uses: "peaceiris/actions-gh-pages@v4",
|
||||
uses: "peaceiris/actions-gh-pages@v3",
|
||||
with: {
|
||||
github_token: "${{ secrets.GITHUB_TOKEN }}",
|
||||
publish_dir: result/,
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
.gitignore
|
||||
103
.github/workflows/bench-primitives.yml
vendored
103
.github/workflows/bench-primitives.yml
vendored
@@ -1,103 +0,0 @@
|
||||
name: rosenpass-ciphers - primitives - benchmark
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
prim-benchmark:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
system: ["x86_64-linux", "i686-linux"]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Install nix
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v27 # A popular action for installing Nix
|
||||
with:
|
||||
extra_nix_config: |
|
||||
experimental-features = nix-command flakes
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Set up environment
|
||||
|
||||
- name: 🛠️ Prepare Benchmark Path
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
BRANCH_NAME: ${{ github.ref_name }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
run: |
|
||||
case "$EVENT_NAME" in
|
||||
"push")
|
||||
echo "BENCH_PATH=branch/$BRANCH_NAME" >> $GITHUB_ENV
|
||||
;;
|
||||
"pull_request")
|
||||
echo "BENCH_PATH=pull/$PR_NUMBER" >> $GITHUB_ENV
|
||||
;;
|
||||
*)
|
||||
echo "don't know benchmark path for event of type $EVENT_NAME, aborting"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
# Benchmarks ...
|
||||
|
||||
- name: 🏃🏻♀️ Benchmarks (using Nix as shell)
|
||||
working-directory: ciphers
|
||||
run: nix develop ".#devShells.${{ matrix.system }}.benchmarks" --command cargo bench -F bench --bench primitives --verbose -- --output-format bencher | tee ../bench-primitives.txt
|
||||
|
||||
- name: Extract benchmarks
|
||||
uses: cryspen/benchmark-data-extract-transform@v2
|
||||
with:
|
||||
name: rosenpass-ciphers primitives benchmarks
|
||||
tool: "cargo"
|
||||
os: ${{ matrix.system }}
|
||||
output-file-path: bench-primitives.txt
|
||||
data-out-path: bench-primitives-os.json
|
||||
|
||||
- name: Fix up 'os' label in benchmark data
|
||||
run: jq 'map(with_entries(.key |= if . == "os" then "operating system" else . end))' <bench-primitives-os.json >bench-primitives.json
|
||||
|
||||
- name: Upload benchmarks
|
||||
uses: cryspen/benchmark-upload-and-plot-action@v3
|
||||
with:
|
||||
name: Crypto Primitives Benchmarks
|
||||
group-by: "operating system,primitive,algorithm"
|
||||
schema: "operating system,primitive,algorithm,implementation,operation,length"
|
||||
input-data-path: bench-primitives.json
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# NOTE: pushes to current repository
|
||||
gh-repository: github.com/${{ github.repository }}
|
||||
auto-push: true
|
||||
fail-on-alert: true
|
||||
base-path: benchmarks/
|
||||
|
||||
ciphers-primitives-bench-status:
|
||||
if: ${{ always() }}
|
||||
needs: [prim-benchmark]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Successful
|
||||
if: ${{ !(contains(needs.*.result, 'failure')) }}
|
||||
run: exit 0
|
||||
- name: Failing
|
||||
if: ${{ (contains(needs.*.result, 'failure')) }}
|
||||
run: exit 1
|
||||
90
.github/workflows/bench-protocol.yml
vendored
90
.github/workflows/bench-protocol.yml
vendored
@@ -1,90 +0,0 @@
|
||||
name: rosenpass - protocol - benchmark
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
proto-benchmark:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
system: ["x86_64-linux", "i686-linux"]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Install nix
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v27 # A popular action for installing Nix
|
||||
with:
|
||||
extra_nix_config: |
|
||||
experimental-features = nix-command flakes
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Set up environment
|
||||
|
||||
- name: 🛠️ Prepare Benchmark Path
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
BRANCH_NAME: ${{ github.ref_name }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
run: |
|
||||
case "$EVENT_NAME" in
|
||||
"push")
|
||||
echo "BENCH_PATH=branch/$BRANCH_NAME" >> $GITHUB_ENV
|
||||
;;
|
||||
"pull_request")
|
||||
echo "BENCH_PATH=pull/$PR_NUMBER" >> $GITHUB_ENV
|
||||
;;
|
||||
*)
|
||||
echo "don't know benchmark path for event of type $EVENT_NAME, aborting"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
# Benchmarks ...
|
||||
|
||||
- name: 🏃🏻♀️ Benchmarks
|
||||
run: nix develop ".#devShells.${{ matrix.system }}.benchmarks" --command cargo bench -p rosenpass --bench trace_handshake -F trace_bench --verbose >bench-protocol.json
|
||||
|
||||
- name: Upload benchmarks
|
||||
uses: cryspen/benchmark-upload-and-plot-action@v3
|
||||
with:
|
||||
name: Protocol Benchmarks
|
||||
group-by: "operating system,architecture,protocol version,run time"
|
||||
schema: "operating system,architecture,protocol version,run time,name"
|
||||
input-data-path: bench-protocol.json
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# NOTE: pushes to current repository
|
||||
gh-repository: github.com/${{ github.repository }}
|
||||
auto-push: true
|
||||
fail-on-alert: true
|
||||
base-path: benchmarks/
|
||||
|
||||
ciphers-protocol-bench-status:
|
||||
if: ${{ always() }}
|
||||
needs: [proto-benchmark]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Successful
|
||||
if: ${{ !(contains(needs.*.result, 'failure')) }}
|
||||
run: exit 0
|
||||
- name: Failing
|
||||
if: ${{ (contains(needs.*.result, 'failure')) }}
|
||||
run: exit 1
|
||||
288
.github/workflows/docker.yaml
vendored
288
.github/workflows/docker.yaml
vendored
@@ -1,288 +0,0 @@
|
||||
name: Build Docker Images
|
||||
|
||||
# Run this job on all non-pull-request events,
|
||||
# or if Docker-related files are changed in a pull request.
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
tags:
|
||||
- "v*"
|
||||
pull_request:
|
||||
paths:
|
||||
- "docker/Dockerfile"
|
||||
- ".github/workflows/docker.yaml"
|
||||
branches:
|
||||
- "main"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
# --------------------------------
|
||||
# 1. BUILD & TEST
|
||||
# --------------------------------
|
||||
build-and-test-rp:
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Build (no push) and Load
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
# no pushing here, so we can test locally
|
||||
push: false
|
||||
# load the built image into the local Docker daemon on the runner
|
||||
load: true
|
||||
target: rosenpass
|
||||
tags: rosenpass:test
|
||||
platforms: linux/${{ matrix.arch }}
|
||||
- name: Integration Test - Standalone Key Exchange
|
||||
run: |
|
||||
# Create separate workdirs
|
||||
mkdir -p workdir-server workdir-client
|
||||
|
||||
# Create a Docker network
|
||||
docker network create -d bridge rp
|
||||
|
||||
echo "=== GENERATE SERVER KEYS ==="
|
||||
docker run --rm \
|
||||
-v $PWD/workdir-server:/workdir \
|
||||
rosenpass:test gen-keys \
|
||||
--public-key=workdir/server-public \
|
||||
--secret-key=workdir/server-secret
|
||||
|
||||
echo "=== GENERATE CLIENT KEYS ==="
|
||||
docker run --rm \
|
||||
-v $PWD/workdir-client:/workdir \
|
||||
rosenpass:test gen-keys \
|
||||
--public-key=workdir/client-public \
|
||||
--secret-key=workdir/client-secret
|
||||
|
||||
echo "=== SHARE PUBLIC KEYS ==="
|
||||
cp workdir-client/client-public workdir-server/client-public
|
||||
cp workdir-server/server-public workdir-client/server-public
|
||||
|
||||
echo "=== START SERVER CONTAINER ==="
|
||||
docker run -d --rm \
|
||||
--name rpserver \
|
||||
--network rp \
|
||||
-v $PWD/workdir-server:/workdir \
|
||||
rosenpass:test exchange \
|
||||
private-key workdir/server-secret \
|
||||
public-key workdir/server-public \
|
||||
listen 0.0.0.0:9999 \
|
||||
peer public-key workdir/client-public \
|
||||
outfile workdir/server-sharedkey
|
||||
|
||||
# Get the container IP of the server
|
||||
SERVER_IP=$(docker inspect --format='{{.NetworkSettings.Networks.rp.IPAddress}}' rpserver)
|
||||
echo "SERVER_IP=$SERVER_IP"
|
||||
|
||||
echo "=== START CLIENT CONTAINER ==="
|
||||
docker run -d --rm \
|
||||
--name rpclient \
|
||||
--network rp \
|
||||
-v $PWD/workdir-client:/workdir \
|
||||
rosenpass:test exchange \
|
||||
private-key workdir/client-secret \
|
||||
public-key workdir/client-public \
|
||||
peer public-key workdir/server-public \
|
||||
endpoint ${SERVER_IP}:9999 \
|
||||
outfile workdir/client-sharedkey
|
||||
|
||||
echo "=== COMPARE SHARED KEYS ==="
|
||||
echo "Waiting up to 30 seconds for the server to generate 'server-sharedkey'..."
|
||||
for i in $(seq 1 30); do
|
||||
if [ -f "workdir-server/server-sharedkey" ]; then
|
||||
echo "server-sharedkey found!"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
sudo cmp workdir-server/server-sharedkey workdir-client/client-sharedkey
|
||||
|
||||
echo "Standalone Key Exchange test OK."
|
||||
# --------------------------------
|
||||
# 2. PUSH (only if tests pass)
|
||||
# --------------------------------
|
||||
docker-image-rp:
|
||||
needs:
|
||||
- build-and-test-rp
|
||||
# Skip if this is not a PR. Then we want to push this image.
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
# Use a matrix to build for both AMD64 and ARM64
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
# Switch the runner based on the architecture
|
||||
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/rp
|
||||
labels: |
|
||||
maintainer=Karolin Varner <karo@cupdev.net>, wucke13 <wucke13@gmail.com>
|
||||
org.opencontainers.image.authors=Karolin Varner <karo@cupdev.net>, wucke13 <wucke13@gmail.com>
|
||||
org.opencontainers.image.title=Rosenpass
|
||||
org.opencontainers.image.description=The rp command-line integrates Rosenpass and WireGuard to help you create a VPN
|
||||
org.opencontainers.image.vendor=Rosenpass e.V.
|
||||
org.opencontainers.image.licenses=MIT OR Apache-2.0
|
||||
org.opencontainers.image.url=https://rosenpass.eu
|
||||
org.opencontainers.image.documentation=https://rosenpass.eu/docs/
|
||||
org.opencontainers.image.source=https://github.com/rosenpass/rosenpass
|
||||
|
||||
- name: Log in to registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
tags: ghcr.io/${{ github.repository_owner }}/rp
|
||||
target: rp
|
||||
platforms: linux/${{ matrix.arch }}
|
||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
- name: Export digest
|
||||
run: |
|
||||
mkdir -p ${{ runner.temp }}/digests
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digests-rp-${{ matrix.arch }}
|
||||
path: ${{ runner.temp }}/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
docker-image-rosenpass:
|
||||
needs:
|
||||
- build-and-test-rp
|
||||
# Skip if this is not a PR. Then we want to push this image.
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
# Use a matrix to build for both AMD64 and ARM64
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
# Switch the runner based on the architecture
|
||||
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/rosenpass
|
||||
labels: |
|
||||
maintainer=Karolin Varner <karo@cupdev.net>, wucke13 <wucke13@gmail.com>
|
||||
org.opencontainers.image.authors=Karolin Varner <karo@cupdev.net>, wucke13 <wucke13@gmail.com>
|
||||
org.opencontainers.image.title=Rosenpass
|
||||
org.opencontainers.image.description=Reference implementation of the protocol rosenpass protocol
|
||||
org.opencontainers.image.vendor=Rosenpass e.V.
|
||||
org.opencontainers.image.licenses=MIT OR Apache-2.0
|
||||
org.opencontainers.image.url=https://rosenpass.eu
|
||||
org.opencontainers.image.documentation=https://rosenpass.eu/docs/
|
||||
org.opencontainers.image.source=https://github.com/rosenpass/rosenpass
|
||||
|
||||
- name: Log in to registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
tags: ghcr.io/${{ github.repository_owner }}/rosenpass
|
||||
target: rosenpass
|
||||
platforms: linux/${{ matrix.arch }}
|
||||
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
- name: Export digest
|
||||
run: |
|
||||
mkdir -p ${{ runner.temp }}/digests
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digests-rosenpass-${{ matrix.arch }}
|
||||
path: ${{ runner.temp }}/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
merge-digests:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- docker-image-rosenpass
|
||||
- docker-image-rp
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
strategy:
|
||||
matrix:
|
||||
target: [rp, rosenpass]
|
||||
steps:
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ${{ runner.temp }}/digests
|
||||
pattern: digests-${{ matrix.target }}-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Log in to registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository_owner }}/${{ matrix.target }}
|
||||
tags: |
|
||||
type=edge,branch=main
|
||||
type=sha,branch=main
|
||||
type=semver,pattern={{version}}
|
||||
|
||||
- name: Create manifest list and push
|
||||
working-directory: ${{ runner.temp }}/digests
|
||||
run: |
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
$(printf 'ghcr.io/${{ github.repository_owner }}/${{ matrix.target }}@sha256:%s ' *)
|
||||
|
||||
- name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect ghcr.io/${{ github.repository_owner }}/${{ matrix.target }}:${{ steps.meta.outputs.version }}
|
||||
19
.github/workflows/manual-mac-pr.yaml
vendored
19
.github/workflows/manual-mac-pr.yaml
vendored
@@ -1,19 +0,0 @@
|
||||
name: PR Validation on Mac
|
||||
on:
|
||||
workflow_dispatch:
|
||||
permissions:
|
||||
checks: write
|
||||
contents: write
|
||||
concurrency:
|
||||
group: manual-mac-${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
qc:
|
||||
uses: ./.github/workflows/qc-mac.yaml
|
||||
permissions:
|
||||
checks: write
|
||||
contents: read
|
||||
nix:
|
||||
uses: ./.github/workflows/nix-mac.yaml
|
||||
permissions:
|
||||
contents: write
|
||||
114
.github/workflows/nix-mac.yaml
vendored
114
.github/workflows/nix-mac.yaml
vendored
@@ -1,114 +0,0 @@
|
||||
name: Nix on Mac
|
||||
permissions:
|
||||
contents: write
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_call:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
aarch64-darwin---default:
|
||||
name: Build aarch64-darwin.default
|
||||
runs-on:
|
||||
- warp-macos-13-arm64-6x
|
||||
needs:
|
||||
- aarch64-darwin---rosenpass
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.aarch64-darwin.default --print-build-logs
|
||||
aarch64-darwin---release-package:
|
||||
name: Build aarch64-darwin.release-package
|
||||
runs-on:
|
||||
- warp-macos-13-arm64-6x
|
||||
needs:
|
||||
- aarch64-darwin---rosenpass
|
||||
- aarch64-darwin---rp
|
||||
- aarch64-darwin---rosenpass-oci-image
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.aarch64-darwin.release-package --print-build-logs
|
||||
aarch64-darwin---rosenpass:
|
||||
name: Build aarch64-darwin.rosenpass
|
||||
runs-on:
|
||||
- warp-macos-13-arm64-6x
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.aarch64-darwin.rosenpass --print-build-logs
|
||||
aarch64-darwin---rp:
|
||||
name: Build aarch64-darwin.rp
|
||||
runs-on:
|
||||
- warp-macos-13-arm64-6x
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.aarch64-darwin.rp --print-build-logs
|
||||
aarch64-darwin---rosenpass-oci-image:
|
||||
name: Build aarch64-darwin.rosenpass-oci-image
|
||||
runs-on:
|
||||
- warp-macos-13-arm64-6x
|
||||
needs:
|
||||
- aarch64-darwin---rosenpass
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.aarch64-darwin.rosenpass-oci-image --print-build-logs
|
||||
aarch64-darwin---check:
|
||||
name: Run Nix checks on aarch64-darwin
|
||||
runs-on:
|
||||
- warp-macos-13-arm64-6x
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Check
|
||||
run: nix flake check . --print-build-logs
|
||||
146
.github/workflows/nix.yaml
vendored
146
.github/workflows/nix.yaml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
i686-linux---default:
|
||||
name: Build i686-linux.default
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs:
|
||||
- i686-linux---rosenpass
|
||||
steps:
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
i686-linux---rosenpass:
|
||||
name: Build i686-linux.rosenpass
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
i686-linux---rosenpass-oci-image:
|
||||
name: Build i686-linux.rosenpass-oci-image
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs:
|
||||
- i686-linux---rosenpass
|
||||
steps:
|
||||
@@ -65,7 +65,107 @@ jobs:
|
||||
i686-linux---check:
|
||||
name: Run Nix checks on i686-linux
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Check
|
||||
run: nix flake check . --print-build-logs
|
||||
x86_64-darwin---default:
|
||||
name: Build x86_64-darwin.default
|
||||
runs-on:
|
||||
- macos-13
|
||||
needs:
|
||||
- x86_64-darwin---rosenpass
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-darwin.default --print-build-logs
|
||||
x86_64-darwin---release-package:
|
||||
name: Build x86_64-darwin.release-package
|
||||
runs-on:
|
||||
- macos-13
|
||||
needs:
|
||||
- x86_64-darwin---rosenpass
|
||||
- x86_64-darwin---rp
|
||||
- x86_64-darwin---rosenpass-oci-image
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-darwin.release-package --print-build-logs
|
||||
x86_64-darwin---rosenpass:
|
||||
name: Build x86_64-darwin.rosenpass
|
||||
runs-on:
|
||||
- macos-13
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-darwin.rosenpass --print-build-logs
|
||||
x86_64-darwin---rp:
|
||||
name: Build x86_64-darwin.rp
|
||||
runs-on:
|
||||
- macos-13
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-darwin.rp --print-build-logs
|
||||
x86_64-darwin---rosenpass-oci-image:
|
||||
name: Build x86_64-darwin.rosenpass-oci-image
|
||||
runs-on:
|
||||
- macos-13
|
||||
needs:
|
||||
- x86_64-darwin---rosenpass
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build
|
||||
run: nix build .#packages.x86_64-darwin.rosenpass-oci-image --print-build-logs
|
||||
x86_64-darwin---check:
|
||||
name: Run Nix checks on x86_64-darwin
|
||||
runs-on:
|
||||
- macos-13
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
@@ -80,7 +180,7 @@ jobs:
|
||||
x86_64-linux---default:
|
||||
name: Build x86_64-linux.default
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs:
|
||||
- x86_64-linux---rosenpass
|
||||
steps:
|
||||
@@ -97,7 +197,7 @@ jobs:
|
||||
x86_64-linux---proof-proverif:
|
||||
name: Build x86_64-linux.proof-proverif
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs:
|
||||
- x86_64-linux---proverif-patched
|
||||
steps:
|
||||
@@ -114,7 +214,7 @@ jobs:
|
||||
x86_64-linux---proverif-patched:
|
||||
name: Build x86_64-linux.proverif-patched
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -130,7 +230,7 @@ jobs:
|
||||
x86_64-linux---release-package:
|
||||
name: Build x86_64-linux.release-package
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs:
|
||||
- x86_64-linux---rosenpass-static
|
||||
- x86_64-linux---rosenpass-static-oci-image
|
||||
@@ -149,7 +249,7 @@ jobs:
|
||||
# aarch64-linux---release-package:
|
||||
# name: Build aarch64-linux.release-package
|
||||
# runs-on:
|
||||
# - ubicloud-standard-2-arm-ubuntu-2204
|
||||
# - ubuntu-latest
|
||||
# needs:
|
||||
# - aarch64-linux---rosenpass-oci-image
|
||||
# - aarch64-linux---rosenpass
|
||||
@@ -173,7 +273,7 @@ jobs:
|
||||
x86_64-linux---rosenpass:
|
||||
name: Build x86_64-linux.rosenpass
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -189,12 +289,12 @@ jobs:
|
||||
aarch64-linux---rosenpass:
|
||||
name: Build aarch64-linux.rosenpass
|
||||
runs-on:
|
||||
- ubicloud-standard-2-arm-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs: []
|
||||
steps:
|
||||
- run: |
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi-aarch64 binfmt-support qemu-user-static
|
||||
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi binfmt-support qemu-user-static
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
@@ -210,12 +310,12 @@ jobs:
|
||||
aarch64-linux---rp:
|
||||
name: Build aarch64-linux.rp
|
||||
runs-on:
|
||||
- ubicloud-standard-2-arm-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs: []
|
||||
steps:
|
||||
- run: |
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi-aarch64 binfmt-support qemu-user-static
|
||||
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi binfmt-support qemu-user-static
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
@@ -231,7 +331,7 @@ jobs:
|
||||
x86_64-linux---rosenpass-oci-image:
|
||||
name: Build x86_64-linux.rosenpass-oci-image
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs:
|
||||
- x86_64-linux---rosenpass
|
||||
steps:
|
||||
@@ -248,13 +348,13 @@ jobs:
|
||||
aarch64-linux---rosenpass-oci-image:
|
||||
name: Build aarch64-linux.rosenpass-oci-image
|
||||
runs-on:
|
||||
- ubicloud-standard-2-arm-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs:
|
||||
- aarch64-linux---rosenpass
|
||||
steps:
|
||||
- run: |
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi-aarch64 binfmt-support qemu-user-static
|
||||
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi binfmt-support qemu-user-static
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
@@ -270,7 +370,7 @@ jobs:
|
||||
x86_64-linux---rosenpass-static:
|
||||
name: Build x86_64-linux.rosenpass-static
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -286,7 +386,7 @@ jobs:
|
||||
x86_64-linux---rp-static:
|
||||
name: Build x86_64-linux.rp-static
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -302,7 +402,7 @@ jobs:
|
||||
x86_64-linux---rosenpass-static-oci-image:
|
||||
name: Build x86_64-linux.rosenpass-static-oci-image
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs:
|
||||
- x86_64-linux---rosenpass-static
|
||||
steps:
|
||||
@@ -319,7 +419,7 @@ jobs:
|
||||
x86_64-linux---whitepaper:
|
||||
name: Build x86_64-linux.whitepaper
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
needs: []
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -335,7 +435,7 @@ jobs:
|
||||
x86_64-linux---check:
|
||||
name: Run Nix checks on x86_64-linux
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
@@ -349,7 +449,7 @@ jobs:
|
||||
run: nix flake check . --print-build-logs
|
||||
x86_64-linux---whitepaper-upload:
|
||||
name: Upload whitepaper x86_64-linux
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.ref == 'refs/heads/main' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
32
.github/workflows/qc-mac.yaml
vendored
32
.github/workflows/qc-mac.yaml
vendored
@@ -1,32 +0,0 @@
|
||||
name: QC Mac
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_call:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
checks: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
cargo-test-mac:
|
||||
runs-on: warp-macos-13-arm64-6x
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
# liboqs requires quite a lot of stack memory, thus we adjust
|
||||
# the default stack size picked for new threads (which is used
|
||||
# by `cargo test`) to be _big enough_. Setting it to 8 MiB
|
||||
- run: RUST_MIN_STACK=8388608 cargo test --workspace --all-features
|
||||
68
.github/workflows/qc.yaml
vendored
68
.github/workflows/qc.yaml
vendored
@@ -14,7 +14,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
prettier:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actionsx/prettier@v3
|
||||
@@ -23,38 +23,22 @@ jobs:
|
||||
|
||||
shellcheck:
|
||||
name: Shellcheck
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Run ShellCheck
|
||||
uses: ludeeus/action-shellcheck@master
|
||||
|
||||
rustfmt:
|
||||
name: Rust code formatting
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
name: Rust Format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Install nightly toolchain
|
||||
run: |
|
||||
rustup toolchain install nightly
|
||||
rustup override set nightly
|
||||
- run: rustup component add rustfmt
|
||||
- name: Run Cargo Fmt
|
||||
run: cargo fmt --all --check
|
||||
- name: Run Rust Markdown code block Formatting Script
|
||||
- name: Run Rust Formatting Script
|
||||
run: bash format_rust_code.sh --mode check
|
||||
|
||||
cargo-bench:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
@@ -73,7 +57,7 @@ jobs:
|
||||
|
||||
mandoc:
|
||||
name: mandoc
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install mandoc
|
||||
run: sudo apt-get install -y mandoc
|
||||
@@ -82,7 +66,7 @@ jobs:
|
||||
run: doc/check.sh doc/rp.1
|
||||
|
||||
cargo-audit:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions-rs/audit-check@v1
|
||||
@@ -90,7 +74,7 @@ jobs:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
cargo-clippy:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
@@ -109,7 +93,7 @@ jobs:
|
||||
args: --all-features
|
||||
|
||||
cargo-doc:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
@@ -128,7 +112,12 @@ jobs:
|
||||
- run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items
|
||||
|
||||
cargo-test:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-13]
|
||||
# - ubuntu is x86-64
|
||||
# - macos-13 is also x86-64 architecture
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
@@ -147,7 +136,7 @@ jobs:
|
||||
|
||||
cargo-test-nix-devshell-x86_64-linux:
|
||||
runs-on:
|
||||
- ubicloud-standard-2-ubuntu-2204
|
||||
- ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
@@ -169,7 +158,7 @@ jobs:
|
||||
- run: nix develop --command cargo test --workspace --all-features
|
||||
|
||||
cargo-fuzz:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
@@ -184,7 +173,7 @@ jobs:
|
||||
- name: Install nightly toolchain
|
||||
run: |
|
||||
rustup toolchain install nightly
|
||||
rustup override set nightly
|
||||
rustup default nightly
|
||||
- name: Install cargo-fuzz
|
||||
run: cargo install cargo-fuzz
|
||||
- name: Run fuzzing
|
||||
@@ -202,24 +191,10 @@ jobs:
|
||||
cargo fuzz run fuzz_vec_secret_alloc_memfdsec_mallocfb -- -max_total_time=5
|
||||
|
||||
codecov:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
env:
|
||||
RUSTUP_TOOLCHAIN: nightly
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Install nightly toolchain
|
||||
run: |
|
||||
rustup toolchain install nightly
|
||||
rustup override set nightly
|
||||
- run: rustup default nightly
|
||||
- run: rustup component add llvm-tools-preview
|
||||
- run: |
|
||||
cargo install cargo-llvm-cov || true
|
||||
@@ -233,4 +208,5 @@ jobs:
|
||||
with:
|
||||
files: ./target/grcov/lcov
|
||||
verbose: true
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
4
.github/workflows/regressions.yml
vendored
4
.github/workflows/regressions.yml
vendored
@@ -14,7 +14,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
multi-peer:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: cargo build --bin rosenpass --release
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
[ $(ls -1 output/ate/out | wc -l) -eq 100 ]
|
||||
|
||||
boot-race:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: cargo build --bin rosenpass --release
|
||||
|
||||
25
.github/workflows/release.yaml
vendored
25
.github/workflows/release.yaml
vendored
@@ -13,6 +13,8 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
@@ -32,6 +34,8 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
@@ -65,24 +69,3 @@ jobs:
|
||||
draft: ${{ contains(github.ref_name, 'rc') }}
|
||||
prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}
|
||||
files: result/*
|
||||
linux-packages:
|
||||
name: Build and upload DEB and RPM packages
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v30
|
||||
- uses: cachix/cachix-action@v15
|
||||
with:
|
||||
name: rosenpass
|
||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||
- name: Build DEB & RPM package
|
||||
run: |
|
||||
mkdir packages
|
||||
for f in $(nix build .#package-deb .#package-rpm --print-out-paths); do cp "$f" "packages/${f#*-}"; done
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
draft: ${{ contains(github.ref_name, 'rc') }}
|
||||
prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}
|
||||
files: |
|
||||
packages/*
|
||||
|
||||
95
.github/workflows/supply-chain.yml
vendored
95
.github/workflows/supply-chain.yml
vendored
@@ -1,95 +0,0 @@
|
||||
name: Supply-Chain
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
cargo-deny:
|
||||
name: Deny dependencies with vulnerabilities or incompatible licenses
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: EmbarkStudios/cargo-deny-action@v2
|
||||
cargo-supply-chain:
|
||||
name: Supply Chain Report
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cache/cargo-supply-chain/
|
||||
key: cargo-supply-chain-cache
|
||||
- name: Install stable toolchain # Cargo-supply-chain is incompatible with older versions
|
||||
run: |
|
||||
rustup toolchain install stable
|
||||
rustup default stable
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ runner.tool_cache }}/cargo-supply-chain
|
||||
key: cargo-supply-chain-bin
|
||||
- name: Add the tool cache directory to the search path
|
||||
run: echo "${{ runner.tool_cache }}/cargo-supply-chain/bin" >> $GITHUB_PATH
|
||||
- name: Ensure that the tool cache is populated with the cargo-supply-chain binary
|
||||
run: cargo +stable install --root ${{ runner.tool_cache }}/cargo-supply-chain cargo-supply-chain
|
||||
- name: Update data for cargo-supply-chain
|
||||
run: cargo supply-chain update
|
||||
- name: Generate cargo-supply-chain report about publishers
|
||||
run: cargo supply-chain publishers
|
||||
- name: Generate cargo-supply-chain report about crates
|
||||
run: cargo supply-chain crates
|
||||
# The setup for cargo-vet follows the recommendations in the cargo-vet documentation: https://mozilla.github.io/cargo-vet/configuring-ci.html
|
||||
cargo-vet:
|
||||
name: Vet Dependencies
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
key: cargo-vet-cache
|
||||
- name: Install stable toolchain # Since we are running/compiling cargo-vet, we should rely on the stable toolchain.
|
||||
run: |
|
||||
rustup toolchain install stable
|
||||
rustup default stable
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ runner.tool_cache }}/cargo-vet
|
||||
key: cargo-vet-bin
|
||||
- name: Add the tool cache directory to the search path
|
||||
run: echo "${{ runner.tool_cache }}/cargo-vet/bin" >> $GITHUB_PATH
|
||||
- name: Ensure that the tool cache is populated with the cargo-vet binary
|
||||
run: cargo +stable install --root ${{ runner.tool_cache }}/cargo-vet cargo-vet
|
||||
- name: Regenerate vet exemptions for dependabot PRs
|
||||
if: github.actor == 'dependabot[bot]' # Run only for Dependabot PRs
|
||||
run: cargo vet regenerate exemptions
|
||||
- name: Check for changes in case of dependabot PR
|
||||
if: github.actor == 'dependabot[bot]' # Run only for Dependabot PRs
|
||||
run: git diff --exit-code || echo "Changes detected, committing..."
|
||||
- name: Commit and push changes for dependabot PRs
|
||||
if: success() && github.actor == 'dependabot[bot]'
|
||||
run: |
|
||||
git fetch origin ${{ github.head_ref }}
|
||||
git switch ${{ github.head_ref }}
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions@github.com"
|
||||
git add supply-chain/*
|
||||
git commit -m "Regenerate cargo vet exemptions"
|
||||
git push origin ${{ github.head_ref }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Invoke cargo-vet
|
||||
run: cargo vet --locked
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -25,4 +25,3 @@ _markdown_*
|
||||
.vscode
|
||||
|
||||
/output
|
||||
.nixos-test-history
|
||||
|
||||
867
Cargo.lock
generated
867
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
46
Cargo.toml
46
Cargo.toml
@@ -2,17 +2,17 @@
|
||||
resolver = "2"
|
||||
|
||||
members = [
|
||||
"rosenpass",
|
||||
"cipher-traits",
|
||||
"ciphers",
|
||||
"util",
|
||||
"constant-time",
|
||||
"oqs",
|
||||
"to",
|
||||
"fuzz",
|
||||
"secret-memory",
|
||||
"rp",
|
||||
"wireguard-broker",
|
||||
"rosenpass",
|
||||
"cipher-traits",
|
||||
"ciphers",
|
||||
"util",
|
||||
"constant-time",
|
||||
"oqs",
|
||||
"to",
|
||||
"fuzz",
|
||||
"secret-memory",
|
||||
"rp",
|
||||
"wireguard-broker",
|
||||
]
|
||||
|
||||
default-members = ["rosenpass", "rp", "wireguard-broker"]
|
||||
@@ -42,7 +42,7 @@ toml = "0.7.8"
|
||||
static_assertions = "1.1.0"
|
||||
allocator-api2 = "0.2.14"
|
||||
memsec = { git = "https://github.com/rosenpass/memsec.git", rev = "aceb9baee8aec6844125bd6612f92e9a281373df", features = [
|
||||
"alloc_ext",
|
||||
"alloc_ext",
|
||||
] }
|
||||
rand = "0.8.5"
|
||||
typenum = "1.17.0"
|
||||
@@ -55,32 +55,26 @@ arbitrary = { version = "1.4.1", features = ["derive"] }
|
||||
anyhow = { version = "1.0.95", features = ["backtrace", "std"] }
|
||||
mio = { version = "1.0.3", features = ["net", "os-poll"] }
|
||||
oqs-sys = { version = "0.9.1", default-features = false, features = [
|
||||
'classic_mceliece',
|
||||
'kyber',
|
||||
'classic_mceliece',
|
||||
'kyber',
|
||||
] }
|
||||
blake2 = "0.10.6"
|
||||
sha3 = "0.10.8"
|
||||
chacha20poly1305 = { version = "0.10.1", default-features = false, features = [
|
||||
"std",
|
||||
"heapless",
|
||||
"std",
|
||||
"heapless",
|
||||
] }
|
||||
zerocopy = { version = "0.7.35", features = ["derive"] }
|
||||
home = "=0.5.9" # 5.11 requires rustc 1.81
|
||||
home = "0.5.9"
|
||||
derive_builder = "0.20.1"
|
||||
tokio = { version = "1.42", features = ["macros", "rt-multi-thread"] }
|
||||
postcard = { version = "1.1.1", features = ["alloc"] }
|
||||
libcrux = { version = "0.0.2-pre.2" }
|
||||
libcrux-chacha20poly1305 = { version = "0.0.2-beta.3" }
|
||||
libcrux-ml-kem = { version = "0.0.2-beta.3" }
|
||||
libcrux-blake2 = { git = "https://github.com/cryspen/libcrux.git", rev = "10ce653e9476" }
|
||||
libcrux-test-utils = { git = "https://github.com/cryspen/libcrux.git", rev = "0ab6d2dd9c1f" }
|
||||
hex-literal = { version = "0.4.1" }
|
||||
hex = { version = "0.4.3" }
|
||||
heck = { version = "0.5.0" }
|
||||
libc = { version = "0.2" }
|
||||
uds = { git = "https://github.com/rosenpass/uds" }
|
||||
signal-hook = "0.3.17"
|
||||
lazy_static = "1.5"
|
||||
|
||||
#Dev dependencies
|
||||
serial_test = "3.2.0"
|
||||
@@ -88,14 +82,12 @@ tempfile = "3"
|
||||
stacker = "0.1.17"
|
||||
libfuzzer-sys = "0.4"
|
||||
test_bin = "0.4.0"
|
||||
criterion = "0.5.1"
|
||||
criterion = "0.4.0"
|
||||
allocator-api2-tests = "0.2.15"
|
||||
procspawn = { version = "1.0.1", features = ["test-support"] }
|
||||
|
||||
|
||||
#Broker dependencies (might need cleanup or changes)
|
||||
wireguard-uapi = { version = "3.0.0", features = ["xplatform"] }
|
||||
command-fds = "0.2.3"
|
||||
rustix = { version = "0.38.42", features = ["net", "fs", "process"] }
|
||||
futures = "0.3"
|
||||
futures-util = "0.3"
|
||||
x25519-dalek = "2"
|
||||
|
||||
@@ -8,13 +8,10 @@ description = "Rosenpass internal traits for cryptographic primitives"
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[dependencies]
|
||||
thiserror = { workspace = true }
|
||||
rosenpass-to = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rosenpass-oqs = { workspace = true }
|
||||
rosenpass-secret-memory = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
anyhow = {workspace = true}
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
//! This module contains the traits for all the cryptographic algorithms used throughout Rosenpass.
|
||||
//! These traits are marker traits that signal intent. They can also be used for trait objects.
|
||||
|
||||
/// Constants and trait for the Incorrect HMAC over Blake2b, with 256 key and hash length.
|
||||
pub mod keyed_hash_incorrect_hmac_blake2b {
|
||||
use crate::primitives::keyed_hash::*;
|
||||
|
||||
// These constants describe how they are used here, not what the algorithm defines.
|
||||
|
||||
/// The key length used in [`KeyedHashIncorrectHmacBlake2b`].
|
||||
pub const KEY_LEN: usize = 32;
|
||||
/// The hash length used in [`KeyedHashIncorrectHmacBlake2b`].
|
||||
pub const HASH_LEN: usize = 32;
|
||||
|
||||
/// A [`KeyedHash`] that is an incorrect HMAC over Blake2 (a custom Rosenpass construction)
|
||||
pub trait KeyedHashIncorrectHmacBlake2b: KeyedHash<KEY_LEN, HASH_LEN> {}
|
||||
}
|
||||
|
||||
/// Constants and trait for Blake2b, with 256 key and hash length.
|
||||
pub mod keyed_hash_blake2b {
|
||||
use crate::primitives::keyed_hash::*;
|
||||
|
||||
// These constants describe how they are used here, not what the algorithm defines.
|
||||
|
||||
/// The key length used in [`KeyedHashBlake2b`].
|
||||
pub const KEY_LEN: usize = 32;
|
||||
/// The hash length used in [`KeyedHashBlake2b`].
|
||||
pub const HASH_LEN: usize = 32;
|
||||
|
||||
/// A [`KeyedHash`] that is Blake2b
|
||||
pub trait KeyedHashBlake2b: KeyedHash<KEY_LEN, HASH_LEN> {}
|
||||
}
|
||||
|
||||
/// Constants and trait for SHAKE256, with 256 key and hash length.
|
||||
pub mod keyed_hash_shake256 {
|
||||
use crate::primitives::keyed_hash::*;
|
||||
|
||||
// These constants describe how they are used here, not what the algorithm defines.
|
||||
|
||||
/// The key length used in [`KeyedHashShake256`].
|
||||
pub const KEY_LEN: usize = 32;
|
||||
/// The hash length used in [`KeyedHashShake256`].
|
||||
pub const HASH_LEN: usize = 32;
|
||||
|
||||
/// A [`KeyedHash`] that is SHAKE256.
|
||||
pub trait KeyedHashShake256: KeyedHash<KEY_LEN, HASH_LEN> {}
|
||||
}
|
||||
|
||||
/// Constants and trait for the ChaCha20Poly1305 AEAD
|
||||
pub mod aead_chacha20poly1305 {
|
||||
use crate::primitives::aead::*;
|
||||
|
||||
// See https://datatracker.ietf.org/doc/html/rfc7539#section-2.8
|
||||
|
||||
/// The key length used in [`AeadChaCha20Poly1305`].
|
||||
pub const KEY_LEN: usize = 32;
|
||||
/// The nonce length used in [`AeadChaCha20Poly1305`].
|
||||
pub const NONCE_LEN: usize = 12;
|
||||
/// The tag length used in [`AeadChaCha20Poly1305`].
|
||||
pub const TAG_LEN: usize = 16;
|
||||
|
||||
/// An [`Aead`] that is ChaCha20Poly1305.
|
||||
pub trait AeadChaCha20Poly1305: Aead<KEY_LEN, NONCE_LEN, TAG_LEN> {}
|
||||
}
|
||||
|
||||
/// Constants and trait for the XChaCha20Poly1305 AEAD (i.e. ChaCha20Poly1305 with extended nonce
|
||||
/// lengths)
|
||||
pub mod aead_xchacha20poly1305 {
|
||||
use crate::primitives::aead::*;
|
||||
|
||||
// See https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha-03
|
||||
|
||||
/// The key length used in [`AeadXChaCha20Poly1305`].
|
||||
pub const KEY_LEN: usize = 32;
|
||||
/// The nonce length used in [`AeadXChaCha20Poly1305`].
|
||||
pub const NONCE_LEN: usize = 24;
|
||||
/// The tag length used in [`AeadXChaCha20Poly1305`].
|
||||
pub const TAG_LEN: usize = 16;
|
||||
|
||||
/// An [`Aead`] that is XChaCha20Poly1305.
|
||||
pub trait AeadXChaCha20Poly1305: Aead<KEY_LEN, NONCE_LEN, TAG_LEN> {}
|
||||
}
|
||||
|
||||
/// Constants and trait for the Kyber512 KEM
|
||||
pub mod kem_kyber512 {
|
||||
use crate::primitives::kem::*;
|
||||
|
||||
// page 39 of https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf
|
||||
// (which is ml-kem instead of kyber, but it's the same)
|
||||
|
||||
/// The secret key length used in [`KemKyber512`].
|
||||
pub const SK_LEN: usize = 1632;
|
||||
|
||||
/// The public key length used in [`KemKyber512`].
|
||||
pub const PK_LEN: usize = 800;
|
||||
|
||||
/// The ciphertext length used in [`KemKyber512`].
|
||||
pub const CT_LEN: usize = 768;
|
||||
|
||||
/// The shared key length used in [`KemKyber512`].
|
||||
pub const SHK_LEN: usize = 32;
|
||||
|
||||
/// A [`Kem`] that is Kyber512.
|
||||
pub trait KemKyber512: Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> {}
|
||||
}
|
||||
|
||||
/// Constants and trait for the Classic McEliece 460896 KEM
|
||||
pub mod kem_classic_mceliece460896 {
|
||||
use crate::primitives::kem::*;
|
||||
|
||||
// page 6 of https://classic.mceliece.org/mceliece-impl-20221023.pdf
|
||||
|
||||
/// The secret key length used in [`KemClassicMceliece460896`].
|
||||
pub const SK_LEN: usize = 13608;
|
||||
|
||||
/// The public key length used in [`KemClassicMceliece460896`].
|
||||
pub const PK_LEN: usize = 524160;
|
||||
|
||||
/// The ciphertext length used in [`KemClassicMceliece460896`].
|
||||
pub const CT_LEN: usize = 156;
|
||||
|
||||
/// The shared key length used in [`KemClassicMceliece460896`].
|
||||
pub const SHK_LEN: usize = 32;
|
||||
|
||||
/// A [`Kem`] that is ClassicMceliece460896.
|
||||
pub trait KemClassicMceliece460896: Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> {}
|
||||
}
|
||||
|
||||
pub use aead_chacha20poly1305::AeadChaCha20Poly1305;
|
||||
pub use aead_xchacha20poly1305::AeadXChaCha20Poly1305;
|
||||
|
||||
pub use kem_classic_mceliece460896::KemClassicMceliece460896;
|
||||
pub use kem_kyber512::KemKyber512;
|
||||
|
||||
pub use keyed_hash_blake2b::KeyedHashBlake2b;
|
||||
pub use keyed_hash_incorrect_hmac_blake2b::KeyedHashIncorrectHmacBlake2b;
|
||||
pub use keyed_hash_shake256::KeyedHashShake256;
|
||||
@@ -1,5 +1,2 @@
|
||||
//! This trait contains traits, constants and wrappers that provid= the interface between Rosenpass
|
||||
//! as a consumer of cryptographic libraries and the implementations of cryptographic algorithms.
|
||||
|
||||
pub mod algorithms;
|
||||
pub mod primitives;
|
||||
mod kem;
|
||||
pub use kem::Kem;
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
//! Traits for cryptographic primitives used in Rosenpass, specifically KEM, AEAD and keyed
|
||||
//! hashing.
|
||||
|
||||
pub(crate) mod aead;
|
||||
pub(crate) mod kem;
|
||||
pub(crate) mod keyed_hash;
|
||||
|
||||
pub use aead::{Aead, AeadWithNonceInCiphertext, Error as AeadError};
|
||||
pub use kem::{Error as KemError, Kem};
|
||||
pub use keyed_hash::*;
|
||||
@@ -1,175 +0,0 @@
|
||||
use rosenpass_to::{ops::copy_slice, To as _};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Models authenticated encryption with assiciated data (AEAD) functionality.
|
||||
///
|
||||
/// The methods of this trait take a `&self` argument as a receiver. This has two reasons:
|
||||
/// 1. It makes type inference a lot smoother
|
||||
/// 2. It allows to use the functionality through a trait object or having an enum that has
|
||||
/// variants for multiple options (like e.g. the `KeyedHash` enum in `rosenpass-ciphers`).
|
||||
///
|
||||
/// Since the caller needs an instance of the type to use the functionality, implementors are
|
||||
/// adviced to implement the [`Default`] trait where possible.
|
||||
///
|
||||
/// Example for encrypting a message with a specific [`Aead`] instance:
|
||||
/// ```
|
||||
/// use rosenpass_cipher_traits::primitives::Aead;
|
||||
///
|
||||
/// const KEY_LEN: usize = 32;
|
||||
/// const NONCE_LEN: usize = 12;
|
||||
/// const TAG_LEN: usize = 16;
|
||||
///
|
||||
/// fn encrypt_message_given_an_aead<AeadImpl>(
|
||||
/// aead: &AeadImpl,
|
||||
/// msg: &str,
|
||||
/// nonce: &[u8; NONCE_LEN],
|
||||
/// encrypted: &mut [u8]
|
||||
/// ) where AeadImpl: Aead<KEY_LEN, NONCE_LEN, TAG_LEN> {
|
||||
/// let key = [0u8; KEY_LEN]; // This is not a secure key!
|
||||
/// let ad = b""; // we don't need associated data here
|
||||
/// aead.encrypt(encrypted, &key, nonce, ad, msg.as_bytes()).unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If only the type (but no instance) is available, then we can still encrypt, as long as the type
|
||||
/// also is [`Default`]:
|
||||
/// ```
|
||||
/// use rosenpass_cipher_traits::primitives::Aead;
|
||||
///
|
||||
/// const KEY_LEN: usize = 32;
|
||||
/// const NONCE_LEN: usize = 12;
|
||||
/// const TAG_LEN: usize = 16;
|
||||
///
|
||||
/// fn encrypt_message_without_aead<AeadImpl>(
|
||||
/// msg: &str,
|
||||
/// nonce: &[u8; NONCE_LEN],
|
||||
/// encrypted: &mut [u8]
|
||||
/// ) where AeadImpl: Default + Aead<KEY_LEN, NONCE_LEN, TAG_LEN> {
|
||||
/// let key = [0u8; KEY_LEN]; // This is not a secure key!
|
||||
/// let ad = b""; // we don't need associated data here
|
||||
/// AeadImpl::default().encrypt(encrypted, &key, nonce, ad, msg.as_bytes()).unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
pub trait Aead<const KEY_LEN: usize, const NONCE_LEN: usize, const TAG_LEN: usize> {
|
||||
const KEY_LEN: usize = KEY_LEN;
|
||||
const NONCE_LEN: usize = NONCE_LEN;
|
||||
const TAG_LEN: usize = TAG_LEN;
|
||||
|
||||
/// Encrypts `plaintext` using the given `key` and `nonce`, taking into account the additional
|
||||
/// data `ad` and writes the result into `ciphertext`.
|
||||
///
|
||||
/// `ciphertext` must be exactly `TAG_LEN` longer than `plaintext`.
|
||||
fn encrypt(
|
||||
&self,
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> Result<(), Error>;
|
||||
|
||||
/// Decrypts `ciphertexttext` using the given `key` and `nonce`, taking into account the additional
|
||||
/// data `ad` and writes the result into `plaintext`.
|
||||
///
|
||||
/// `ciphertext` must be exactly `TAG_LEN` longer than `plaintext`.
|
||||
fn decrypt(
|
||||
&self,
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
/// Provides an AEAD API where the nonce is part of the ciphertext.
|
||||
///
|
||||
/// The old xaead API had the ciphertext begin with the `nonce`. In order to not having to change
|
||||
/// the calling code too much, we add a wrapper trait that provides this API and implement it for
|
||||
/// all AEAD.
|
||||
pub trait AeadWithNonceInCiphertext<
|
||||
const KEY_LEN: usize,
|
||||
const NONCE_LEN: usize,
|
||||
const TAG_LEN: usize,
|
||||
>: Aead<KEY_LEN, NONCE_LEN, TAG_LEN>
|
||||
{
|
||||
/// Encrypts `plaintext` using the given `key` and `nonce`, taking into account the additional
|
||||
/// data `ad` and writes the result into `ciphertext`.
|
||||
///
|
||||
/// `ciphertext` must be exactly `TAG_LEN` + `NONCE_LEN` longer than `plaintext`.
|
||||
fn encrypt_with_nonce_in_ctxt(
|
||||
&self,
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> Result<(), Error> {
|
||||
// The comparison looks complicated, but we need to do it this way to prevent
|
||||
// over/underflows.
|
||||
if ciphertext.len() < NONCE_LEN + TAG_LEN
|
||||
|| ciphertext.len() - TAG_LEN - NONCE_LEN < plaintext.len()
|
||||
{
|
||||
return Err(Error::InvalidLengths);
|
||||
}
|
||||
|
||||
let (n, rest) = ciphertext.split_at_mut(NONCE_LEN);
|
||||
copy_slice(nonce).to(n);
|
||||
|
||||
self.encrypt(rest, key, nonce, ad, plaintext)
|
||||
}
|
||||
|
||||
/// Decrypts `ciphertexttext` using the given `key` and `nonce`, taking into account the additional
|
||||
/// data `ad` and writes the result into `plaintext`.
|
||||
///
|
||||
/// `ciphertext` must be exactly `TAG_LEN` + `NONCE_LEN` longer than `plaintext`.
|
||||
fn decrypt_with_nonce_in_ctxt(
|
||||
&self,
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> Result<(), Error> {
|
||||
// The comparison looks complicated, but we need to do it this way to prevent
|
||||
// over/underflows.
|
||||
if ciphertext.len() < NONCE_LEN + TAG_LEN
|
||||
|| ciphertext.len() - TAG_LEN - NONCE_LEN < plaintext.len()
|
||||
{
|
||||
return Err(Error::InvalidLengths);
|
||||
}
|
||||
|
||||
let (nonce, rest) = ciphertext.split_at(NONCE_LEN);
|
||||
// We know this should be the right length (we just split it), and everything else would be
|
||||
// very unexpected.
|
||||
let nonce = nonce.try_into().map_err(|_| Error::InternalError)?;
|
||||
|
||||
self.decrypt(plaintext, key, nonce, ad, rest)
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
const KEY_LEN: usize,
|
||||
const NONCE_LEN: usize,
|
||||
const TAG_LEN: usize,
|
||||
T: Aead<KEY_LEN, NONCE_LEN, TAG_LEN>,
|
||||
> AeadWithNonceInCiphertext<KEY_LEN, NONCE_LEN, TAG_LEN> for T
|
||||
{
|
||||
}
|
||||
|
||||
/// The error returned by AEAD operations
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// An internal error occurred. This should never be happen and indicates an error in the
|
||||
/// AEAD implementation.
|
||||
#[error("internal error")]
|
||||
InternalError,
|
||||
|
||||
/// Could not decrypt a message because the message is not a valid ciphertext for the given
|
||||
/// key.
|
||||
#[error("decryption error")]
|
||||
DecryptError,
|
||||
|
||||
/// The provided buffers have the wrong lengths.
|
||||
#[error("buffers have invalid length")]
|
||||
InvalidLengths,
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
//! Traits and implementations for Key Encapsulation Mechanisms (KEMs)
|
||||
//!
|
||||
//! KEMs are the interface provided by almost all post-quantum
|
||||
//! secure key exchange mechanisms.
|
||||
//!
|
||||
//! Conceptually KEMs are akin to public-key encryption, but instead of encrypting
|
||||
//! arbitrary data, KEMs are limited to the transmission of keys, randomly chosen during
|
||||
//! encapsulation.
|
||||
//!
|
||||
//! The [Kem] Trait describes the basic API offered by a Key Encapsulation
|
||||
//! Mechanism. Two implementations for it are provided:
|
||||
//! [Kyber512](../../rosenpass_oqs/kyber_512/enum.Kyber512.html) and
|
||||
//! [ClassicMceliece460896](../../rosenpass_oqs/classic_mceliece_460896/enum.ClassicMceliece460896.html).
|
||||
//!
|
||||
//! An example where Alice generates a keypair and gives her public key to Bob, for Bob to
|
||||
//! encapsulate a symmetric key and Alice to decapsulate it would look as follows.
|
||||
//! In the example, we are using Kyber512, but any KEM that correctly implements the [Kem]
|
||||
//! trait could be used as well.
|
||||
//!```rust
|
||||
//! use rosenpass_cipher_traits::primitives::Kem;
|
||||
//! use rosenpass_oqs::Kyber512;
|
||||
//! # use rosenpass_secret_memory::{secret_policy_use_only_malloc_secrets, Secret};
|
||||
//!
|
||||
//! type MyKem = Kyber512;
|
||||
//! secret_policy_use_only_malloc_secrets();
|
||||
//! let mut alice_sk: Secret<{ MyKem::SK_LEN }> = Secret::zero();
|
||||
//! let mut alice_pk: [u8; MyKem::PK_LEN] = [0; MyKem::PK_LEN];
|
||||
//! MyKem::default().keygen(alice_sk.secret_mut(), &mut alice_pk)?;
|
||||
//!
|
||||
//! let mut bob_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
|
||||
//! let mut bob_ct: [u8; MyKem::CT_LEN] = [0; MyKem::CT_LEN];
|
||||
//! MyKem::default().encaps(bob_shk.secret_mut(), &mut bob_ct, &mut alice_pk)?;
|
||||
//!
|
||||
//! let mut alice_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
|
||||
//! MyKem::default().decaps(alice_shk.secret_mut(), alice_sk.secret_mut(), &mut bob_ct)?;
|
||||
//!
|
||||
//! # assert_eq!(alice_shk.secret(), bob_shk.secret());
|
||||
//! # Ok::<(), anyhow::Error>(())
|
||||
//!```
|
||||
//!
|
||||
//! Implementing the [Kem]-trait for a KEM is easy. Mostly, you must format the KEM's
|
||||
//! keys, and ciphertext as `u8` slices. Below, we provide an example for how the trait can
|
||||
//! be implemented using a **HORRIBLY INSECURE** DummyKem that only uses static values for keys
|
||||
//! and ciphertexts as an example.
|
||||
//!```rust
|
||||
//!# use rosenpass_cipher_traits::primitives::{Kem, KemError as Error};
|
||||
//!
|
||||
//! struct DummyKem {}
|
||||
//! impl Kem<1,1,1,1> for DummyKem {
|
||||
//!
|
||||
//! // For this DummyKem, we will use a single `u8` for everything
|
||||
//! const SK_LEN: usize = 1;
|
||||
//! const PK_LEN: usize = 1;
|
||||
//! const CT_LEN: usize = 1;
|
||||
//! const SHK_LEN: usize = 1;
|
||||
//!
|
||||
//! fn keygen(&self, sk: &mut [u8;1], pk: &mut [u8;1]) -> Result<(), Error> {
|
||||
//! sk[0] = 42;
|
||||
//! pk[0] = 21;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//!
|
||||
//! fn encaps(&self, shk: &mut [u8;1], ct: &mut [u8;1], pk: &[u8;1]) -> Result<(), Error> {
|
||||
//! if pk[0] != 21 {
|
||||
//! return Err(Error::InvalidArgument);
|
||||
//! }
|
||||
//! ct[0] = 7;
|
||||
//! shk[0] = 17;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//!
|
||||
//! fn decaps(&self, shk: &mut [u8;1 ], sk: &[u8;1], ct: &[u8;1]) -> Result<(), Error> {
|
||||
//! if sk[0] != 42 {
|
||||
//! return Err(Error::InvalidArgument);
|
||||
//! }
|
||||
//! if ct[0] != 7 {
|
||||
//! return Err(Error::InvalidArgument);
|
||||
//! }
|
||||
//! shk[0] = 17;
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! impl Default for DummyKem {
|
||||
//! fn default() -> Self {
|
||||
//! Self{}
|
||||
//! }
|
||||
//! }
|
||||
//! # use rosenpass_secret_memory::{secret_policy_use_only_malloc_secrets, Secret};
|
||||
//! #
|
||||
//! # type MyKem = DummyKem;
|
||||
//! # secret_policy_use_only_malloc_secrets();
|
||||
//! # let mut alice_sk: Secret<{ MyKem::SK_LEN }> = Secret::zero();
|
||||
//! # let mut alice_pk: [u8; MyKem::PK_LEN] = [0; MyKem::PK_LEN];
|
||||
//! # MyKem::default().keygen(alice_sk.secret_mut(), &mut alice_pk)?;
|
||||
//!
|
||||
//! # let mut bob_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
|
||||
//! # let mut bob_ct: [u8; MyKem::CT_LEN] = [0; MyKem::CT_LEN];
|
||||
//! # MyKem::default().encaps(bob_shk.secret_mut(), &mut bob_ct, &mut alice_pk)?;
|
||||
//! #
|
||||
//! # let mut alice_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
|
||||
//! # MyKem::default().decaps(alice_shk.secret_mut(), alice_sk.secret_mut(), &mut bob_ct)?;
|
||||
//! #
|
||||
//! # assert_eq!(alice_shk.secret(), bob_shk.secret());
|
||||
//! #
|
||||
//! # Ok::<(), Error>(())
|
||||
//!```
|
||||
//!
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
/// Key Encapsulation Mechanism
|
||||
///
|
||||
/// The KEM interface defines three operations: Key generation, key encapsulation and key
|
||||
/// decapsulation. The parameters are made available as associated constants for convenience.
|
||||
///
|
||||
/// The methods of this trait take a `&self` argument as a receiver. This has two reasons:
|
||||
/// 1. It makes type inference a lot smoother
|
||||
/// 2. It allows to use the functionality through a trait object or having an enum that has
|
||||
/// variants for multiple options (like e.g. the `KeyedHash` enum in `rosenpass-ciphers`).
|
||||
///
|
||||
/// Since the caller needs an instance of the type to use the functionality, implementors are
|
||||
/// adviced to implement the [`Default`] trait where possible.
|
||||
///
|
||||
/// Example for encrypting a message with a specific [`Kem`] instance:
|
||||
/// ```
|
||||
/// use rosenpass_cipher_traits::primitives::Kem;
|
||||
///
|
||||
/// const SK_LEN: usize = 1632;
|
||||
/// const PK_LEN: usize = 800;
|
||||
/// const CT_LEN: usize = 768;
|
||||
/// const SHK_LEN: usize = 32;
|
||||
///
|
||||
/// fn encaps_given_a_kem<KemImpl>(
|
||||
/// kem: &KemImpl,
|
||||
/// pk: &[u8; PK_LEN],
|
||||
/// ct: &mut [u8; CT_LEN]
|
||||
/// ) -> [u8; SHK_LEN] where KemImpl: Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN>{
|
||||
/// let mut shk = [0u8; SHK_LEN];
|
||||
/// kem.encaps(&mut shk, ct, pk).unwrap();
|
||||
/// shk
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If only the type (but no instance) is available, then we can still use the trait, as long as
|
||||
/// the type also is [`Default`]:
|
||||
/// ```
|
||||
/// use rosenpass_cipher_traits::primitives::Kem;
|
||||
///
|
||||
/// const SK_LEN: usize = 1632;
|
||||
/// const PK_LEN: usize = 800;
|
||||
/// const CT_LEN: usize = 768;
|
||||
/// const SHK_LEN: usize = 32;
|
||||
///
|
||||
/// fn encaps_without_kem<KemImpl>(
|
||||
/// pk: &[u8; PK_LEN],
|
||||
/// ct: &mut [u8; CT_LEN]
|
||||
/// ) -> [u8; SHK_LEN]
|
||||
/// where KemImpl: Default + Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> {
|
||||
/// let mut shk = [0u8; SHK_LEN];
|
||||
/// KemImpl::default().encaps(&mut shk, ct, pk).unwrap();
|
||||
/// shk
|
||||
/// }
|
||||
/// ```
|
||||
pub trait Kem<const SK_LEN: usize, const PK_LEN: usize, const CT_LEN: usize, const SHK_LEN: usize> {
|
||||
/// The length of the secret (decapsulation) key.
|
||||
const SK_LEN: usize = SK_LEN;
|
||||
|
||||
/// The length of the public (encapsulation) key.
|
||||
const PK_LEN: usize = PK_LEN;
|
||||
|
||||
/// The length of the ciphertext.
|
||||
const CT_LEN: usize = CT_LEN;
|
||||
|
||||
/// The legnth of the resulting shared key.
|
||||
const SHK_LEN: usize = SHK_LEN;
|
||||
|
||||
/// Generate a keypair consisting of secret key (`sk`) and public key (`pk`)
|
||||
///
|
||||
/// `keygen() -> sk, pk`
|
||||
fn keygen(&self, sk: &mut [u8; SK_LEN], pk: &mut [u8; PK_LEN]) -> Result<(), Error>;
|
||||
|
||||
/// From a public key (`pk`), generate a shared key (`shk`, for local use)
|
||||
/// and a cipher text (`ct`, to be sent to the owner of the `pk`).
|
||||
///
|
||||
/// `encaps(pk) -> shk, ct`
|
||||
fn encaps(
|
||||
&self,
|
||||
shk: &mut [u8; SHK_LEN],
|
||||
ct: &mut [u8; CT_LEN],
|
||||
pk: &[u8; PK_LEN],
|
||||
) -> Result<(), Error>;
|
||||
|
||||
/// From a secret key (`sk`) and a cipher text (`ct`) derive a shared key
|
||||
/// (`shk`)
|
||||
///
|
||||
/// `decaps(sk, ct) -> shk`
|
||||
fn decaps(
|
||||
&self,
|
||||
shk: &mut [u8; SHK_LEN],
|
||||
sk: &[u8; SK_LEN],
|
||||
ct: &[u8; CT_LEN],
|
||||
) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
#[error("invalid argument")]
|
||||
InvalidArgument,
|
||||
#[error("internal error")]
|
||||
InternalError,
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// Models a keyed hash function using an associated function (i.e. without `&self` receiver).
|
||||
pub trait KeyedHash<const KEY_LEN: usize, const HASH_LEN: usize> {
|
||||
/// The error type used to signal what went wrong.
|
||||
type Error;
|
||||
|
||||
/// Performs a keyed hash using `key` and `data` and writes the output to `out`
|
||||
fn keyed_hash(
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
/// Models a keyed hash function using a method (i.e. with a `&self` receiver).
|
||||
///
|
||||
/// This makes type inference easier, but also requires having a [`KeyedHashInstance`] value,
|
||||
/// instead of just the [`KeyedHash`] type.
|
||||
pub trait KeyedHashInstance<const KEY_LEN: usize, const HASH_LEN: usize> {
|
||||
/// The error type used to signal what went wrong.
|
||||
type Error;
|
||||
|
||||
/// Performs a keyed hash using `key` and `data` and writes the output to `out`
|
||||
fn keyed_hash(
|
||||
&self,
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
/// This is a helper to allow for type parameter inference when calling functions
|
||||
/// that need a [KeyedHash].
|
||||
///
|
||||
/// Really just binds the [KeyedHash] trait to a dummy variable, so the type of this dummy variable
|
||||
/// can be used for type inference. Less typing work.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct InferKeyedHash<Static, const KEY_LEN: usize, const HASH_LEN: usize>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, HASH_LEN>,
|
||||
{
|
||||
pub _phantom_keyed_hasher: PhantomData<*const Static>,
|
||||
}
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const HASH_LEN: usize> InferKeyedHash<Static, KEY_LEN, HASH_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, HASH_LEN>,
|
||||
{
|
||||
pub const KEY_LEN: usize = KEY_LEN;
|
||||
pub const HASH_LEN: usize = HASH_LEN;
|
||||
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
_phantom_keyed_hasher: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// This just forwards to [KeyedHash::keyed_hash] of the type parameter `Static`
|
||||
fn keyed_hash_internal<'a>(
|
||||
&self,
|
||||
key: &'a [u8; KEY_LEN],
|
||||
data: &'a [u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Static::Error> {
|
||||
Static::keyed_hash(key, data, out)
|
||||
}
|
||||
|
||||
/// Returns the key length of the keyed hash function.
|
||||
pub const fn key_len(self) -> usize {
|
||||
Self::KEY_LEN
|
||||
}
|
||||
|
||||
/// Returns the hash length of the keyed hash function.
|
||||
pub const fn hash_len(self) -> usize {
|
||||
Self::HASH_LEN
|
||||
}
|
||||
}
|
||||
|
||||
impl<const KEY_LEN: usize, const HASH_LEN: usize, Static: KeyedHash<KEY_LEN, HASH_LEN>>
|
||||
KeyedHashInstance<KEY_LEN, HASH_LEN> for InferKeyedHash<Static, KEY_LEN, HASH_LEN>
|
||||
{
|
||||
type Error = Static::Error;
|
||||
|
||||
fn keyed_hash(
|
||||
&self,
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Static::Error> {
|
||||
self.keyed_hash_internal(key, data, out)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper traits /////////////////////////////////////////////
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Default
|
||||
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, OUT_LEN>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Clone
|
||||
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, OUT_LEN>,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Copy
|
||||
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
|
||||
where
|
||||
Static: KeyedHash<KEY_LEN, OUT_LEN>,
|
||||
{
|
||||
}
|
||||
|
||||
use rosenpass_to::{with_destination, To};
|
||||
|
||||
/// Extends the [`KeyedHash`] trait with a [`To`]-flavoured function.
|
||||
pub trait KeyedHashTo<const KEY_LEN: usize, const HASH_LEN: usize>:
|
||||
KeyedHash<KEY_LEN, HASH_LEN>
|
||||
{
|
||||
fn keyed_hash_to(
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
) -> impl To<[u8; HASH_LEN], Result<(), Self::Error>> {
|
||||
with_destination(|out| Self::keyed_hash(key, data, out))
|
||||
}
|
||||
}
|
||||
|
||||
impl<const KEY_LEN: usize, const HASH_LEN: usize, T: KeyedHash<KEY_LEN, HASH_LEN>>
|
||||
KeyedHashTo<KEY_LEN, HASH_LEN> for T
|
||||
{
|
||||
}
|
||||
|
||||
/// Extends the [`KeyedHashInstance`] trait with a [`To`]-flavoured function.
|
||||
pub trait KeyedHashInstanceTo<const KEY_LEN: usize, const HASH_LEN: usize>:
|
||||
KeyedHashInstance<KEY_LEN, HASH_LEN>
|
||||
{
|
||||
fn keyed_hash_to(
|
||||
&self,
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
) -> impl To<[u8; HASH_LEN], Result<(), Self::Error>> {
|
||||
with_destination(|out| self.keyed_hash(key, data, out))
|
||||
}
|
||||
}
|
||||
|
||||
impl<const KEY_LEN: usize, const HASH_LEN: usize, T: KeyedHashInstance<KEY_LEN, HASH_LEN>>
|
||||
KeyedHashInstanceTo<KEY_LEN, HASH_LEN> for T
|
||||
{
|
||||
}
|
||||
@@ -8,42 +8,9 @@ description = "Rosenpass internal ciphers and other cryptographic primitives use
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[features]
|
||||
# whether the types should be defined
|
||||
experiment_libcrux_define_blake2 = ["dep:libcrux-blake2", "dep:thiserror"]
|
||||
experiment_libcrux_define_kyber = ["dep:libcrux-ml-kem", "dep:rand"]
|
||||
experiment_libcrux_define_chachapoly = ["dep:libcrux-chacha20poly1305"]
|
||||
|
||||
# whether the types should be used by default
|
||||
experiment_libcrux_blake2 = ["experiment_libcrux_define_blake2"]
|
||||
experiment_libcrux_kyber = ["experiment_libcrux_define_kyber"]
|
||||
experiment_libcrux_chachapoly = ["experiment_libcrux_define_chachapoly"]
|
||||
experiment_libcrux_chachapoly_test = [
|
||||
"experiment_libcrux_define_chachapoly",
|
||||
"dep:libcrux",
|
||||
]
|
||||
|
||||
# shorthands
|
||||
experiment_libcrux_define_all = [
|
||||
"experiment_libcrux_define_blake2",
|
||||
"experiment_libcrux_define_chachapoly",
|
||||
"experiment_libcrux_define_kyber",
|
||||
]
|
||||
experiment_libcrux_all = [
|
||||
"experiment_libcrux_blake2",
|
||||
"experiment_libcrux_chachapoly",
|
||||
"experiment_libcrux_chachapoly_test",
|
||||
"experiment_libcrux_kyber",
|
||||
]
|
||||
|
||||
bench = ["experiment_libcrux_define_all"]
|
||||
|
||||
[[bench]]
|
||||
name = "primitives"
|
||||
harness = false
|
||||
required-features = ["bench"]
|
||||
experiment_libcrux = ["dep:libcrux"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
@@ -52,22 +19,8 @@ rosenpass-constant-time = { workspace = true }
|
||||
rosenpass-secret-memory = { workspace = true }
|
||||
rosenpass-oqs = { workspace = true }
|
||||
rosenpass-util = { workspace = true }
|
||||
rosenpass-cipher-traits = { workspace = true }
|
||||
static_assertions = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
chacha20poly1305 = { workspace = true }
|
||||
blake2 = { workspace = true }
|
||||
sha3 = { workspace = true }
|
||||
rand = { workspace = true, optional = true }
|
||||
thiserror = { workspace = true, optional = true }
|
||||
|
||||
libcrux-chacha20poly1305 = { workspace = true, optional = true }
|
||||
libcrux-blake2 = { workspace = true, optional = true }
|
||||
libcrux-ml-kem = { workspace = true, optional = true, features = ["kyber"] }
|
||||
|
||||
# this one is only used in testing, so it requires the `experiment_libcrux_chachapoly_test` feature.
|
||||
libcrux = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { workspace = true }
|
||||
criterion = { workspace = true }
|
||||
|
||||
@@ -1,378 +0,0 @@
|
||||
criterion::criterion_main!(keyed_hash::benches, aead::benches, kem::benches);
|
||||
|
||||
fn benchid(base: KvPairs, last: KvPairs) -> String {
|
||||
format!("{base},{last}")
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct KvPair<'a>(&'a str, &'a str);
|
||||
|
||||
impl std::fmt::Display for KvPair<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{k}={v}", k = self.0, v = self.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct KvPairs<'a>(&'a [KvPair<'a>]);
|
||||
|
||||
impl std::fmt::Display for KvPairs<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.0.len() {
|
||||
0 => Ok(()),
|
||||
1 => write!(f, "{}", &self.0[0]),
|
||||
_ => {
|
||||
let mut delim = "";
|
||||
for pair in self.0 {
|
||||
write!(f, "{delim}{pair}")?;
|
||||
delim = ",";
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod kem {
|
||||
criterion::criterion_group!(
|
||||
benches,
|
||||
bench_kyber512_libcrux,
|
||||
bench_kyber512_oqs,
|
||||
bench_classicmceliece460896_oqs
|
||||
);
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
fn bench_classicmceliece460896_oqs(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"classicmceliece460896",
|
||||
"oqs",
|
||||
rosenpass_oqs::ClassicMceliece460896,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_kyber512_libcrux(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"kyber512",
|
||||
"libcrux",
|
||||
rosenpass_ciphers::subtle::libcrux::kyber512::Kyber512,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_kyber512_oqs(c: &mut Criterion) {
|
||||
template(c, "kyber512", "oqs", rosenpass_oqs::Kyber512);
|
||||
}
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
|
||||
fn template<
|
||||
const SK_LEN: usize,
|
||||
const PK_LEN: usize,
|
||||
const CT_LEN: usize,
|
||||
const SHK_LEN: usize,
|
||||
T: Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN>,
|
||||
>(
|
||||
c: &mut Criterion,
|
||||
alg_name: &str,
|
||||
impl_name: &str,
|
||||
scheme: T,
|
||||
) {
|
||||
use super::{benchid, KvPair, KvPairs};
|
||||
|
||||
let base = [
|
||||
KvPair("primitive", "kem"),
|
||||
KvPair("algorithm", alg_name),
|
||||
KvPair("implementation", impl_name),
|
||||
KvPair("length", "-1"),
|
||||
];
|
||||
|
||||
let kem_benchid = |op| benchid(KvPairs(&base), KvPairs(&[KvPair("operation", op)]));
|
||||
|
||||
c.bench_function(&kem_benchid("keygen"), |bench| {
|
||||
let mut sk = [0; SK_LEN];
|
||||
let mut pk = [0; PK_LEN];
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.keygen(&mut sk, &mut pk).unwrap();
|
||||
});
|
||||
});
|
||||
|
||||
c.bench_function(&kem_benchid("encaps"), |bench| {
|
||||
let mut sk = [0; SK_LEN];
|
||||
let mut pk = [0; PK_LEN];
|
||||
let mut ct = [0; CT_LEN];
|
||||
let mut shk = [0; SHK_LEN];
|
||||
|
||||
scheme.keygen(&mut sk, &mut pk).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.encaps(&mut shk, &mut ct, &pk).unwrap();
|
||||
});
|
||||
});
|
||||
|
||||
c.bench_function(&kem_benchid("decaps"), |bench| {
|
||||
let mut sk = [0; SK_LEN];
|
||||
let mut pk = [0; PK_LEN];
|
||||
let mut ct = [0; CT_LEN];
|
||||
let mut shk = [0; SHK_LEN];
|
||||
let mut shk2 = [0; SHK_LEN];
|
||||
|
||||
scheme.keygen(&mut sk, &mut pk).unwrap();
|
||||
scheme.encaps(&mut shk, &mut ct, &pk).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.decaps(&mut shk2, &sk, &ct).unwrap();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
mod aead {
|
||||
criterion::criterion_group!(
|
||||
benches,
|
||||
bench_chachapoly_libcrux,
|
||||
bench_chachapoly_rustcrypto,
|
||||
bench_xchachapoly_rustcrypto,
|
||||
);
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
const KEY_LEN: usize = rosenpass_ciphers::Aead::KEY_LEN;
|
||||
const TAG_LEN: usize = rosenpass_ciphers::Aead::TAG_LEN;
|
||||
|
||||
fn bench_xchachapoly_rustcrypto(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"xchacha20poly1305",
|
||||
"rustcrypto",
|
||||
rosenpass_ciphers::subtle::rust_crypto::xchacha20poly1305_ietf::XChaCha20Poly1305,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_chachapoly_rustcrypto(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"chacha20poly1305",
|
||||
"rustcrypto",
|
||||
rosenpass_ciphers::subtle::rust_crypto::chacha20poly1305_ietf::ChaCha20Poly1305,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_chachapoly_libcrux(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"chacha20poly1305",
|
||||
"libcrux",
|
||||
rosenpass_ciphers::subtle::libcrux::chacha20poly1305_ietf::ChaCha20Poly1305,
|
||||
);
|
||||
}
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Aead;
|
||||
|
||||
fn template<const NONCE_LEN: usize, T: Aead<KEY_LEN, NONCE_LEN, TAG_LEN>>(
|
||||
c: &mut Criterion,
|
||||
alg_name: &str,
|
||||
impl_name: &str,
|
||||
scheme: T,
|
||||
) {
|
||||
use crate::{benchid, KvPair, KvPairs};
|
||||
|
||||
let base = [
|
||||
KvPair("primitive", "aead"),
|
||||
KvPair("algorithm", alg_name),
|
||||
KvPair("implementation", impl_name),
|
||||
];
|
||||
let aead_benchid = |op, len| {
|
||||
benchid(
|
||||
KvPairs(&base),
|
||||
KvPairs(&[KvPair("operation", op), KvPair("length", len)]),
|
||||
)
|
||||
};
|
||||
|
||||
let key = [12; KEY_LEN];
|
||||
let nonce = [23; NONCE_LEN];
|
||||
let ad = [];
|
||||
|
||||
c.bench_function(&aead_benchid("encrypt", "0byte"), |bench| {
|
||||
const DATA_LEN: usize = 0;
|
||||
|
||||
let ptxt = [];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
});
|
||||
});
|
||||
|
||||
c.bench_function(&aead_benchid("decrypt", "0byte"), |bench| {
|
||||
const DATA_LEN: usize = 0;
|
||||
|
||||
let ptxt = [];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
let mut ptxt_out = [0u8; DATA_LEN];
|
||||
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme
|
||||
.decrypt(&mut ptxt_out, &key, &nonce, &ad, &mut ctxt)
|
||||
.unwrap()
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function(&aead_benchid("encrypt", "32byte"), |bench| {
|
||||
const DATA_LEN: usize = 32;
|
||||
|
||||
let ptxt = [34u8; DATA_LEN];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
});
|
||||
});
|
||||
|
||||
c.bench_function(&aead_benchid("decrypt", "32byte"), |bench| {
|
||||
const DATA_LEN: usize = 32;
|
||||
|
||||
let ptxt = [34u8; DATA_LEN];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
let mut ptxt_out = [0u8; DATA_LEN];
|
||||
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme
|
||||
.decrypt(&mut ptxt_out, &key, &nonce, &ad, &mut ctxt)
|
||||
.unwrap()
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function(&aead_benchid("encrypt", "1024byte"), |bench| {
|
||||
const DATA_LEN: usize = 1024;
|
||||
|
||||
let ptxt = [34u8; DATA_LEN];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
});
|
||||
});
|
||||
c.bench_function(&aead_benchid("decrypt", "1024byte"), |bench| {
|
||||
const DATA_LEN: usize = 1024;
|
||||
|
||||
let ptxt = [34u8; DATA_LEN];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
let mut ptxt_out = [0u8; DATA_LEN];
|
||||
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme
|
||||
.decrypt(&mut ptxt_out, &key, &nonce, &ad, &mut ctxt)
|
||||
.unwrap()
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
mod keyed_hash {
|
||||
criterion::criterion_group!(
|
||||
benches,
|
||||
bench_blake2b_rustcrypto,
|
||||
bench_blake2b_libcrux,
|
||||
bench_shake256_rustcrypto,
|
||||
);
|
||||
|
||||
const KEY_LEN: usize = 32;
|
||||
const HASH_LEN: usize = 32;
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
fn bench_shake256_rustcrypto(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"shake256",
|
||||
"rustcrypto",
|
||||
&rosenpass_ciphers::subtle::rust_crypto::keyed_shake256::SHAKE256Core,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_blake2b_rustcrypto(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"blake2b",
|
||||
"rustcrypto",
|
||||
&rosenpass_ciphers::subtle::rust_crypto::blake2b::Blake2b,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_blake2b_libcrux(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"blake2b",
|
||||
"libcrux",
|
||||
&rosenpass_ciphers::subtle::libcrux::blake2b::Blake2b,
|
||||
);
|
||||
}
|
||||
|
||||
use rosenpass_cipher_traits::primitives::KeyedHash;
|
||||
|
||||
fn template<H: KeyedHash<KEY_LEN, HASH_LEN>>(
|
||||
c: &mut Criterion,
|
||||
alg_name: &str,
|
||||
impl_name: &str,
|
||||
_: &H,
|
||||
) where
|
||||
H::Error: std::fmt::Debug,
|
||||
{
|
||||
use crate::{benchid, KvPair, KvPairs};
|
||||
|
||||
let key = [12u8; KEY_LEN];
|
||||
let mut out = [0u8; HASH_LEN];
|
||||
|
||||
let base = [
|
||||
KvPair("primitive", "keyedhash"),
|
||||
KvPair("algorithm", alg_name),
|
||||
KvPair("implementation", impl_name),
|
||||
KvPair("operation", "hash"),
|
||||
];
|
||||
let keyedhash_benchid = |len| benchid(KvPairs(&base), KvPairs(&[KvPair("length", len)]));
|
||||
|
||||
c.bench_function(&keyedhash_benchid("0byte"), |bench| {
|
||||
let bytes = [];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
})
|
||||
.bench_function(&keyedhash_benchid("32byte"), |bench| {
|
||||
let bytes = [34u8; 32];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
})
|
||||
.bench_function(&keyedhash_benchid("64byte"), |bench| {
|
||||
let bytes = [34u8; 64];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
})
|
||||
.bench_function(&keyedhash_benchid("128byte"), |bench| {
|
||||
let bytes = [34u8; 128];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
})
|
||||
.bench_function(&keyedhash_benchid("1024byte"), |bench| {
|
||||
let bytes = [34u8; 1024];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,75 +1,74 @@
|
||||
//!
|
||||
//!```rust
|
||||
//! # use rosenpass_ciphers::hash_domain::{HashDomain, HashDomainNamespace, SecretHashDomain, SecretHashDomainNamespace};
|
||||
//! use rosenpass_ciphers::KeyedHash;
|
||||
//! use rosenpass_secret_memory::Secret;
|
||||
//! # rosenpass_secret_memory::secret_policy_use_only_malloc_secrets();
|
||||
//!
|
||||
//! const PROTOCOL_IDENTIFIER: &str = "MY_PROTOCOL:IDENTIFIER";
|
||||
//! // create use once hash domain for the protocol identifier
|
||||
//! let mut hash_domain = HashDomain::zero(KeyedHash::keyed_shake256());
|
||||
//! hash_domain = hash_domain.mix(PROTOCOL_IDENTIFIER.as_bytes())?;
|
||||
//! // upgrade to reusable hash domain
|
||||
//! let hash_domain_namespace: HashDomainNamespace = hash_domain.dup();
|
||||
//! // derive new key
|
||||
//! let key_identifier = "my_key_identifier";
|
||||
//! let key = hash_domain_namespace.mix(key_identifier.as_bytes())?.into_value();
|
||||
//! // derive a new key based on a secret
|
||||
//! const MY_SECRET_LEN: usize = 21;
|
||||
//! let my_secret_bytes = "my super duper secret".as_bytes();
|
||||
//! let my_secret: Secret<21> = Secret::from_slice("my super duper secret".as_bytes());
|
||||
//! let secret_hash_domain: SecretHashDomain = hash_domain_namespace.mix_secret(my_secret)?;
|
||||
//! // derive a new key based on the secret key
|
||||
//! let new_key_identifier = "my_new_key_identifier".as_bytes();
|
||||
//! let new_key = secret_hash_domain.mix(new_key_identifier)?.into_secret();
|
||||
//!
|
||||
//! # Ok::<(), anyhow::Error>(())
|
||||
//!```
|
||||
//!
|
||||
|
||||
use anyhow::Result;
|
||||
use rosenpass_secret_memory::Secret;
|
||||
use rosenpass_to::To as _;
|
||||
use rosenpass_to::To;
|
||||
|
||||
pub use crate::{KeyedHash, KEY_LEN};
|
||||
use crate::keyed_hash as hash;
|
||||
|
||||
use rosenpass_cipher_traits::primitives::KeyedHashInstanceTo;
|
||||
pub use hash::KEY_LEN;
|
||||
|
||||
///
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::hash_domain::{HashDomain, HashDomainNamespace, SecretHashDomain, SecretHashDomainNamespace};
|
||||
/// use rosenpass_secret_memory::Secret;
|
||||
/// # rosenpass_secret_memory::secret_policy_use_only_malloc_secrets();
|
||||
///
|
||||
/// const PROTOCOL_IDENTIFIER: &str = "MY_PROTOCOL:IDENTIFIER";
|
||||
/// // create use once hash domain for the protocol identifier
|
||||
/// let mut hash_domain = HashDomain::zero();
|
||||
/// hash_domain = hash_domain.mix(PROTOCOL_IDENTIFIER.as_bytes())?;
|
||||
/// // upgrade to reusable hash domain
|
||||
/// let hash_domain_namespace: HashDomainNamespace = hash_domain.dup();
|
||||
/// // derive new key
|
||||
/// let key_identifier = "my_key_identifier";
|
||||
/// let key = hash_domain_namespace.mix(key_identifier.as_bytes())?.into_value();
|
||||
/// // derive a new key based on a secret
|
||||
/// const MY_SECRET_LEN: usize = 21;
|
||||
/// let my_secret_bytes = "my super duper secret".as_bytes();
|
||||
/// let my_secret: Secret<21> = Secret::from_slice("my super duper secret".as_bytes());
|
||||
/// let secret_hash_domain: SecretHashDomain = hash_domain_namespace.mix_secret(my_secret)?;
|
||||
/// // derive a new key based on the secret key
|
||||
/// let new_key_identifier = "my_new_key_identifier".as_bytes();
|
||||
/// let new_key = secret_hash_domain.mix(new_key_identifier)?.into_secret();
|
||||
///
|
||||
/// # Ok::<(), anyhow::Error>(())
|
||||
///```
|
||||
///
|
||||
|
||||
// TODO Use a proper Dec interface
|
||||
/// A use-once hash domain for a specified key that can be used directly.
|
||||
/// The key must consist of [KEY_LEN] many bytes. If the key must remain secret,
|
||||
/// use [SecretHashDomain] instead.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct HashDomain([u8; KEY_LEN], KeyedHash);
|
||||
pub struct HashDomain([u8; KEY_LEN]);
|
||||
/// A reusable hash domain for a namespace identified by the key.
|
||||
/// The key must consist of [KEY_LEN] many bytes. If the key must remain secret,
|
||||
/// use [SecretHashDomainNamespace] instead.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct HashDomainNamespace([u8; KEY_LEN], KeyedHash);
|
||||
pub struct HashDomainNamespace([u8; KEY_LEN]);
|
||||
/// A use-once hash domain for a specified key that can be used directly
|
||||
/// by wrapping it in [Secret]. The key must consist of [KEY_LEN] many bytes.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SecretHashDomain(Secret<KEY_LEN>, KeyedHash);
|
||||
pub struct SecretHashDomain(Secret<KEY_LEN>);
|
||||
/// A reusable secure hash domain for a namespace identified by the key and that keeps the key secure
|
||||
/// by wrapping it in [Secret]. The key must consist of [KEY_LEN] many bytes.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SecretHashDomainNamespace(Secret<KEY_LEN>, KeyedHash);
|
||||
pub struct SecretHashDomainNamespace(Secret<KEY_LEN>);
|
||||
|
||||
impl HashDomain {
|
||||
/// Creates a nw [HashDomain] initialized with a all-zeros key.
|
||||
pub fn zero(choice: KeyedHash) -> Self {
|
||||
Self([0u8; KEY_LEN], choice)
|
||||
pub fn zero() -> Self {
|
||||
Self([0u8; KEY_LEN])
|
||||
}
|
||||
|
||||
/// Turns this [HashDomain] into a [HashDomainNamespace], keeping the key.
|
||||
pub fn dup(self) -> HashDomainNamespace {
|
||||
HashDomainNamespace(self.0, self.1)
|
||||
HashDomainNamespace(self.0)
|
||||
}
|
||||
|
||||
/// Turns this [HashDomain] into a [SecretHashDomain] by wrapping the key into a [Secret]
|
||||
/// and creating a new [SecretHashDomain] from it.
|
||||
pub fn turn_secret(self) -> SecretHashDomain {
|
||||
SecretHashDomain(Secret::from_slice(&self.0), self.1)
|
||||
SecretHashDomain(Secret::from_slice(&self.0))
|
||||
}
|
||||
|
||||
// TODO: Protocol! Use domain separation to ensure that
|
||||
@@ -78,16 +77,14 @@ impl HashDomain {
|
||||
/// as the `data` and uses the result as the key for the new [HashDomain].
|
||||
///
|
||||
pub fn mix(self, v: &[u8]) -> Result<Self> {
|
||||
let mut new_key: [u8; KEY_LEN] = [0u8; KEY_LEN];
|
||||
self.1.keyed_hash_to(&self.0, v).to(&mut new_key)?;
|
||||
Ok(Self(new_key, self.1))
|
||||
Ok(Self(hash::hash(&self.0, v).collect::<[u8; KEY_LEN]>()?))
|
||||
}
|
||||
|
||||
/// Creates a new [SecretHashDomain] by mixing in a new key `v`
|
||||
/// by calling [SecretHashDomain::invoke_primitive] with this
|
||||
/// [HashDomain]'s key as `k` and `v` as `d`.
|
||||
pub fn mix_secret<const N: usize>(self, v: Secret<N>) -> Result<SecretHashDomain> {
|
||||
SecretHashDomain::invoke_primitive(&self.0, v.secret(), self.1)
|
||||
SecretHashDomain::invoke_primitive(&self.0, v.secret())
|
||||
}
|
||||
|
||||
/// Gets the key of this [HashDomain].
|
||||
@@ -101,9 +98,9 @@ impl HashDomainNamespace {
|
||||
/// it evaluates [hash::hash] with the key of this HashDomainNamespace key as the key and `v`
|
||||
/// as the `data` and uses the result as the key for the new [HashDomain].
|
||||
pub fn mix(&self, v: &[u8]) -> Result<HashDomain> {
|
||||
let mut new_key: [u8; KEY_LEN] = [0u8; KEY_LEN];
|
||||
self.1.keyed_hash_to(&self.0, v).to(&mut new_key)?;
|
||||
Ok(HashDomain(new_key, self.1.clone()))
|
||||
Ok(HashDomain(
|
||||
hash::hash(&self.0, v).collect::<[u8; KEY_LEN]>()?,
|
||||
))
|
||||
}
|
||||
|
||||
/// Creates a new [SecretHashDomain] by mixing in a new key `v`
|
||||
@@ -112,7 +109,7 @@ impl HashDomainNamespace {
|
||||
///
|
||||
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
|
||||
pub fn mix_secret<const N: usize>(&self, v: Secret<N>) -> Result<SecretHashDomain> {
|
||||
SecretHashDomain::invoke_primitive(&self.0, v.secret(), self.1.clone())
|
||||
SecretHashDomain::invoke_primitive(&self.0, v.secret())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,35 +118,27 @@ impl SecretHashDomain {
|
||||
/// [hash::hash] with `k` as the `key` and `d` s the `data`, and using the result
|
||||
/// as the content for the new [SecretHashDomain].
|
||||
/// Both `k` and `d` have to be exactly [KEY_LEN] bytes in length.
|
||||
/// TODO: docu
|
||||
pub fn invoke_primitive(
|
||||
k: &[u8],
|
||||
d: &[u8],
|
||||
hash_choice: KeyedHash,
|
||||
) -> Result<SecretHashDomain> {
|
||||
let mut new_secret_key = Secret::zero();
|
||||
hash_choice
|
||||
.keyed_hash_to(k.try_into()?, d)
|
||||
.to(new_secret_key.secret_mut())?;
|
||||
let r = SecretHashDomain(new_secret_key, hash_choice);
|
||||
pub fn invoke_primitive(k: &[u8], d: &[u8]) -> Result<SecretHashDomain> {
|
||||
let mut r = SecretHashDomain(Secret::zero());
|
||||
hash::hash(k, d).to(r.0.secret_mut())?;
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
/// Creates a new [SecretHashDomain] that is initialized with an all zeros key.
|
||||
pub fn zero(hash_choice: KeyedHash) -> Self {
|
||||
Self(Secret::zero(), hash_choice)
|
||||
pub fn zero() -> Self {
|
||||
Self(Secret::zero())
|
||||
}
|
||||
|
||||
/// Turns this [SecretHashDomain] into a [SecretHashDomainNamespace].
|
||||
pub fn dup(self) -> SecretHashDomainNamespace {
|
||||
SecretHashDomainNamespace(self.0, self.1)
|
||||
SecretHashDomainNamespace(self.0)
|
||||
}
|
||||
|
||||
/// Creates a new [SecretHashDomain] from a [Secret] `k`.
|
||||
///
|
||||
/// It requires that `k` consist of exactly [KEY_LEN] bytes.
|
||||
pub fn danger_from_secret(k: Secret<KEY_LEN>, hash_choice: KeyedHash) -> Self {
|
||||
Self(k, hash_choice)
|
||||
pub fn danger_from_secret(k: Secret<KEY_LEN>) -> Self {
|
||||
Self(k)
|
||||
}
|
||||
|
||||
/// Creates a new [SecretHashDomain] by mixing in a new key `v`. Specifically,
|
||||
@@ -158,7 +147,7 @@ impl SecretHashDomain {
|
||||
///
|
||||
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
|
||||
pub fn mix(self, v: &[u8]) -> Result<SecretHashDomain> {
|
||||
Self::invoke_primitive(self.0.secret(), v, self.1)
|
||||
Self::invoke_primitive(self.0.secret(), v)
|
||||
}
|
||||
|
||||
/// Creates a new [SecretHashDomain] by mixing in a new key `v`
|
||||
@@ -167,13 +156,21 @@ impl SecretHashDomain {
|
||||
///
|
||||
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
|
||||
pub fn mix_secret<const N: usize>(self, v: Secret<N>) -> Result<SecretHashDomain> {
|
||||
Self::invoke_primitive(self.0.secret(), v.secret(), self.1)
|
||||
Self::invoke_primitive(self.0.secret(), v.secret())
|
||||
}
|
||||
|
||||
/// Get the secret key data from this [SecretHashDomain].
|
||||
pub fn into_secret(self) -> Secret<KEY_LEN> {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Evaluate [hash::hash] with this [SecretHashDomain]'s data as the `key` and
|
||||
/// `dst` as the `data` and stores the result as the new data for this [SecretHashDomain].
|
||||
///
|
||||
/// It requires that both `v` and `d` consist of exactly [KEY_LEN] many bytes.
|
||||
pub fn into_secret_slice(mut self, v: &[u8], dst: &[u8]) -> Result<()> {
|
||||
hash::hash(v, dst).to(self.0.secret_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl SecretHashDomainNamespace {
|
||||
@@ -183,7 +180,7 @@ impl SecretHashDomainNamespace {
|
||||
///
|
||||
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
|
||||
pub fn mix(&self, v: &[u8]) -> Result<SecretHashDomain> {
|
||||
SecretHashDomain::invoke_primitive(self.0.secret(), v, self.1.clone())
|
||||
SecretHashDomain::invoke_primitive(self.0.secret(), v)
|
||||
}
|
||||
|
||||
/// Creates a new [SecretHashDomain] by mixing in a new key `v`
|
||||
@@ -192,7 +189,7 @@ impl SecretHashDomainNamespace {
|
||||
///
|
||||
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
|
||||
pub fn mix_secret<const N: usize>(&self, v: Secret<N>) -> Result<SecretHashDomain> {
|
||||
SecretHashDomain::invoke_primitive(self.0.secret(), v.secret(), self.1.clone())
|
||||
SecretHashDomain::invoke_primitive(self.0.secret(), v.secret())
|
||||
}
|
||||
|
||||
// TODO: This entire API is not very nice; we need this for biscuits, but
|
||||
@@ -202,8 +199,4 @@ impl SecretHashDomainNamespace {
|
||||
pub fn danger_into_secret(self) -> Secret<KEY_LEN> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn keyed_hash(&self) -> &KeyedHash {
|
||||
&self.1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
use rosenpass_cipher_traits::primitives::Aead as AeadTrait;
|
||||
use static_assertions::const_assert;
|
||||
|
||||
pub mod subtle;
|
||||
|
||||
/// All keyed primitives in this crate use 32 byte keys
|
||||
pub const KEY_LEN: usize = 32;
|
||||
const_assert!(KEY_LEN == Aead::KEY_LEN);
|
||||
const_assert!(KEY_LEN == XAead::KEY_LEN);
|
||||
const_assert!(KEY_LEN == aead::KEY_LEN);
|
||||
const_assert!(KEY_LEN == xaead::KEY_LEN);
|
||||
const_assert!(KEY_LEN == hash_domain::KEY_LEN);
|
||||
|
||||
/// Keyed hashing
|
||||
@@ -14,33 +13,41 @@ const_assert!(KEY_LEN == hash_domain::KEY_LEN);
|
||||
/// This should only be used for implementation details; anything with relevance
|
||||
/// to the cryptographic protocol should use the facilities in [hash_domain], (though
|
||||
/// hash domain uses this module internally)
|
||||
pub use crate::subtle::keyed_hash::KeyedHash;
|
||||
pub mod keyed_hash {
|
||||
pub use crate::subtle::incorrect_hmac_blake2b::{
|
||||
hash, KEY_LEN, KEY_MAX, KEY_MIN, OUT_MAX, OUT_MIN,
|
||||
};
|
||||
}
|
||||
|
||||
/// Authenticated encryption with associated data (AEAD)
|
||||
/// Authenticated encryption with associated data
|
||||
/// Chacha20poly1305 is used.
|
||||
#[cfg(feature = "experiment_libcrux_chachapoly")]
|
||||
pub use subtle::libcrux::chacha20poly1305_ietf::ChaCha20Poly1305 as Aead;
|
||||
pub mod aead {
|
||||
#[cfg(not(feature = "experiment_libcrux"))]
|
||||
pub use crate::subtle::chacha20poly1305_ietf::{decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN};
|
||||
#[cfg(feature = "experiment_libcrux")]
|
||||
pub use crate::subtle::chacha20poly1305_ietf_libcrux::{
|
||||
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN,
|
||||
};
|
||||
}
|
||||
|
||||
/// Authenticated encryption with associated data (AEAD)
|
||||
/// Chacha20poly1305 is used.
|
||||
#[cfg(not(feature = "experiment_libcrux_chachapoly"))]
|
||||
pub use crate::subtle::rust_crypto::chacha20poly1305_ietf::ChaCha20Poly1305 as Aead;
|
||||
|
||||
/// Authenticated encryption with associated data with a extended-length nonce (XAEAD)
|
||||
/// Authenticated encryption with associated data with a constant nonce
|
||||
/// XChacha20poly1305 is used.
|
||||
pub use crate::subtle::rust_crypto::xchacha20poly1305_ietf::XChaCha20Poly1305 as XAead;
|
||||
|
||||
/// Use Classic-McEcliece-460986 as the Static KEM.
|
||||
///
|
||||
/// See [rosenpass_oqs::ClassicMceliece460896] for more details.
|
||||
pub use rosenpass_oqs::ClassicMceliece460896 as StaticKem;
|
||||
|
||||
/// Use Kyber-512 as the Static KEM
|
||||
///
|
||||
/// See [rosenpass_oqs::Kyber512] for more details.
|
||||
#[cfg(not(feature = "experiment_libcrux_kyber"))]
|
||||
pub use rosenpass_oqs::Kyber512 as EphemeralKem;
|
||||
#[cfg(feature = "experiment_libcrux_kyber")]
|
||||
pub use subtle::libcrux::kyber512::Kyber512 as EphemeralKem;
|
||||
pub mod xaead {
|
||||
pub use crate::subtle::xchacha20poly1305_ietf::{
|
||||
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN,
|
||||
};
|
||||
}
|
||||
|
||||
pub mod hash_domain;
|
||||
|
||||
/// This crate includes two key encapsulation mechanisms.
|
||||
/// Namely ClassicMceliece460896 (also referred to as `StaticKem` sometimes) and
|
||||
/// Kyber512 (also referred to as `EphemeralKem` sometimes).
|
||||
///
|
||||
/// See [rosenpass_oqs::ClassicMceliece460896]
|
||||
/// and [rosenpass_oqs::Kyber512] for more details on the specific KEMS.
|
||||
///
|
||||
pub mod kem {
|
||||
pub use rosenpass_oqs::ClassicMceliece460896 as StaticKem;
|
||||
pub use rosenpass_oqs::Kyber512 as EphemeralKem;
|
||||
}
|
||||
|
||||
65
ciphers/src/subtle/blake2b.rs
Normal file
65
ciphers/src/subtle/blake2b.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use blake2::digest::crypto_common::generic_array::GenericArray;
|
||||
use blake2::digest::crypto_common::typenum::U32;
|
||||
use blake2::digest::crypto_common::KeySizeUser;
|
||||
use blake2::digest::{FixedOutput, Mac, OutputSizeUser};
|
||||
use blake2::Blake2bMac;
|
||||
|
||||
use rosenpass_to::{ops::copy_slice, with_destination, To};
|
||||
use rosenpass_util::typenum2const;
|
||||
|
||||
/// Specify that the used implementation of BLAKE2b is the MAC version of BLAKE2b
|
||||
/// with output and key length of 32 bytes (see [Blake2bMac]).
|
||||
type Impl = Blake2bMac<U32>;
|
||||
|
||||
type KeyLen = <Impl as KeySizeUser>::KeySize;
|
||||
type OutLen = <Impl as OutputSizeUser>::OutputSize;
|
||||
|
||||
/// The key length for BLAKE2b supported by this API. Currently 32 Bytes.
|
||||
const KEY_LEN: usize = typenum2const! { KeyLen };
|
||||
/// The output length for BLAKE2b supported by this API. Currently 32 Bytes.
|
||||
const OUT_LEN: usize = typenum2const! { OutLen };
|
||||
|
||||
/// Minimal key length supported by this API.
|
||||
pub const KEY_MIN: usize = KEY_LEN;
|
||||
/// maximal key length supported by this API.
|
||||
pub const KEY_MAX: usize = KEY_LEN;
|
||||
/// minimal output length supported by this API.
|
||||
pub const OUT_MIN: usize = OUT_LEN;
|
||||
/// maximal output length supported by this API.
|
||||
pub const OUT_MAX: usize = OUT_LEN;
|
||||
|
||||
/// Hashes the given `data` with the [Blake2bMac] hash function under the given `key`.
|
||||
/// The both the length of the output the length of the key 32 bytes (or 256 bits).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::blake2b::hash;
|
||||
/// use rosenpass_to::To;
|
||||
/// let zero_key: [u8; 32] = [0; 32];
|
||||
/// let data: [u8; 32] = [255; 32];
|
||||
/// // buffer for the hash output
|
||||
/// let mut hash_data: [u8; 32] = [0u8; 32];
|
||||
///
|
||||
/// assert!(hash(&zero_key, &data).to(&mut hash_data).is_ok(), "Hashing has to return OK result");
|
||||
///```
|
||||
///
|
||||
#[inline]
|
||||
pub fn hash<'a>(key: &'a [u8], data: &'a [u8]) -> impl To<[u8], anyhow::Result<()>> + 'a {
|
||||
with_destination(|out: &mut [u8]| {
|
||||
let mut h = Impl::new_from_slice(key)?;
|
||||
h.update(data);
|
||||
|
||||
// Jesus christ, blake2 crate, your usage of GenericArray might be nice and fancy
|
||||
// but it introduces a ton of complexity. This cost me half an hour just to figure
|
||||
// out the right way to use the imports while allowing for zeroization.
|
||||
// An API based on slices might actually be simpler.
|
||||
let mut tmp = Zeroizing::new([0u8; OUT_LEN]);
|
||||
let tmp = GenericArray::from_mut_slice(tmp.as_mut());
|
||||
h.finalize_into(tmp);
|
||||
copy_slice(tmp.as_ref()).to(out);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
99
ciphers/src/subtle/chacha20poly1305_ietf.rs
Normal file
99
ciphers/src/subtle/chacha20poly1305_ietf.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
use rosenpass_to::ops::copy_slice;
|
||||
use rosenpass_to::To;
|
||||
use rosenpass_util::typenum2const;
|
||||
|
||||
use chacha20poly1305::aead::generic_array::GenericArray;
|
||||
use chacha20poly1305::ChaCha20Poly1305 as AeadImpl;
|
||||
use chacha20poly1305::{AeadCore, AeadInPlace, KeyInit, KeySizeUser};
|
||||
|
||||
/// The key length is 32 bytes or 256 bits.
|
||||
pub const KEY_LEN: usize = typenum2const! { <AeadImpl as KeySizeUser>::KeySize };
|
||||
/// The MAC tag length is 16 bytes or 128 bits.
|
||||
pub const TAG_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::TagSize };
|
||||
/// The nonce length is 12 bytes or 96 bits.
|
||||
pub const NONCE_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::NonceSize };
|
||||
|
||||
/// Encrypts using ChaCha20Poly1305 as implemented in [RustCrypto](https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305).
|
||||
/// `key` MUST be chosen (pseudo-)randomly and `nonce` MOST NOT be reused. The `key` slice MUST have
|
||||
/// a length of [KEY_LEN]. The `nonce` slice MUST have a length of [NONCE_LEN]. The last [TAG_LEN] bytes
|
||||
/// written in `ciphertext` are the tag guaranteeing integrity. `ciphertext` MUST have a capacity of
|
||||
/// `plaintext.len()` + [TAG_LEN].
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::chacha20poly1305_ietf::{encrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
|
||||
///
|
||||
/// const PLAINTEXT_LEN: usize = 43;
|
||||
/// let plaintext = "post-quantum cryptography is very important".as_bytes();
|
||||
/// assert_eq!(PLAINTEXT_LEN, plaintext.len());
|
||||
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
|
||||
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
|
||||
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
|
||||
/// let mut ciphertext_buffer = [0u8;PLAINTEXT_LEN + TAG_LEN];
|
||||
///
|
||||
/// let res: anyhow::Result<()> = encrypt(&mut ciphertext_buffer, key, nonce, additional_data, plaintext);
|
||||
/// assert!(res.is_ok());
|
||||
/// # let expected_ciphertext: &[u8] = &[239, 104, 148, 202, 120, 32, 77, 27, 246, 206, 226, 17,
|
||||
/// # 83, 78, 122, 116, 187, 123, 70, 199, 58, 130, 21, 1, 107, 230, 58, 77, 18, 152, 31, 159, 80,
|
||||
/// # 151, 72, 27, 236, 137, 60, 55, 180, 31, 71, 97, 199, 12, 60, 155, 70, 221, 225, 110, 132, 191,
|
||||
/// # 8, 114, 85, 4, 25];
|
||||
/// # assert_eq!(expected_ciphertext, &ciphertext_buffer);
|
||||
///```
|
||||
#[inline]
|
||||
pub fn encrypt(
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8],
|
||||
nonce: &[u8],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
let nonce = GenericArray::from_slice(nonce);
|
||||
let (ct, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
|
||||
copy_slice(plaintext).to(ct);
|
||||
let mac_value = AeadImpl::new_from_slice(key)?.encrypt_in_place_detached(nonce, ad, ct)?;
|
||||
copy_slice(&mac_value[..]).to(mac);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Decrypts a `ciphertext` and verifies the integrity of the `ciphertext` and the additional data
|
||||
/// `ad`. using ChaCha20Poly1305 as implemented in [RustCrypto](https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305).
|
||||
///
|
||||
/// The `key` slice MUST have a length of [KEY_LEN]. The `nonce` slice MUST have a length of
|
||||
/// [NONCE_LEN]. The plaintext buffer must have a capacity of `ciphertext.len()` - [TAG_LEN].
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::chacha20poly1305_ietf::{decrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
|
||||
/// let ciphertext: &[u8] = &[239, 104, 148, 202, 120, 32, 77, 27, 246, 206, 226, 17,
|
||||
/// 83, 78, 122, 116, 187, 123, 70, 199, 58, 130, 21, 1, 107, 230, 58, 77, 18, 152, 31, 159, 80,
|
||||
/// 151, 72, 27, 236, 137, 60, 55, 180, 31, 71, 97, 199, 12, 60, 155, 70, 221, 225, 110, 132, 191,
|
||||
/// 8, 114, 85, 4, 25]; // this is the ciphertext generated by the example for the encryption
|
||||
/// const PLAINTEXT_LEN: usize = 43;
|
||||
/// assert_eq!(PLAINTEXT_LEN + TAG_LEN, ciphertext.len());
|
||||
///
|
||||
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
|
||||
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
|
||||
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
|
||||
/// let mut plaintext_buffer = [0u8; PLAINTEXT_LEN];
|
||||
///
|
||||
/// let res: anyhow::Result<()> = decrypt(&mut plaintext_buffer, key, nonce, additional_data, ciphertext);
|
||||
/// assert!(res.is_ok());
|
||||
/// let expected_plaintext = "post-quantum cryptography is very important".as_bytes();
|
||||
/// assert_eq!(expected_plaintext, plaintext_buffer);
|
||||
///
|
||||
///```
|
||||
#[inline]
|
||||
pub fn decrypt(
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8],
|
||||
nonce: &[u8],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
let nonce = GenericArray::from_slice(nonce);
|
||||
let (ct, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
|
||||
let tag = GenericArray::from_slice(mac);
|
||||
copy_slice(ct).to(plaintext);
|
||||
AeadImpl::new_from_slice(key)?.decrypt_in_place_detached(nonce, ad, plaintext, tag)?;
|
||||
Ok(())
|
||||
}
|
||||
117
ciphers/src/subtle/chacha20poly1305_ietf_libcrux.rs
Normal file
117
ciphers/src/subtle/chacha20poly1305_ietf_libcrux.rs
Normal file
@@ -0,0 +1,117 @@
|
||||
use rosenpass_to::ops::copy_slice;
|
||||
use rosenpass_to::To;
|
||||
|
||||
use zeroize::Zeroize;
|
||||
|
||||
/// The key length is 32 bytes or 256 bits.
|
||||
pub const KEY_LEN: usize = 32; // Grrrr! Libcrux, please provide me these constants.
|
||||
/// The MAC tag length is 16 bytes or 128 bits.
|
||||
pub const TAG_LEN: usize = 16;
|
||||
/// The nonce length is 12 bytes or 96 bits.
|
||||
pub const NONCE_LEN: usize = 12;
|
||||
|
||||
/// Encrypts using ChaCha20Poly1305 as implemented in [libcrux](https://github.com/cryspen/libcrux).
|
||||
/// Key and nonce MUST be chosen (pseudo-)randomly. The `key` slice MUST have a length of
|
||||
/// [KEY_LEN]. The `nonce` slice MUST have a length of [NONCE_LEN]. The last [TAG_LEN] bytes
|
||||
/// written in `ciphertext` are the tag guaranteeing integrity. `ciphertext` MUST have a capacity of
|
||||
/// `plaintext.len()` + [TAG_LEN].
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::chacha20poly1305_ietf_libcrux::{encrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
|
||||
///
|
||||
/// const PLAINTEXT_LEN: usize = 43;
|
||||
/// let plaintext = "post-quantum cryptography is very important".as_bytes();
|
||||
/// assert_eq!(PLAINTEXT_LEN, plaintext.len());
|
||||
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
|
||||
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
|
||||
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
|
||||
/// let mut ciphertext_buffer = [0u8; PLAINTEXT_LEN + TAG_LEN];
|
||||
///
|
||||
/// let res: anyhow::Result<()> = encrypt(&mut ciphertext_buffer, key, nonce, additional_data, plaintext);
|
||||
/// assert!(res.is_ok());
|
||||
/// # let expected_ciphertext: &[u8] = &[239, 104, 148, 202, 120, 32, 77, 27, 246, 206, 226, 17,
|
||||
/// # 83, 78, 122, 116, 187, 123, 70, 199, 58, 130, 21, 1, 107, 230, 58, 77, 18, 152, 31, 159, 80,
|
||||
/// # 151, 72, 27, 236, 137, 60, 55, 180, 31, 71, 97, 199, 12, 60, 155, 70, 221, 225, 110, 132, 191,
|
||||
/// # 8, 114, 85, 4, 25];
|
||||
/// # assert_eq!(expected_ciphertext, &ciphertext_buffer);
|
||||
///```
|
||||
///
|
||||
#[inline]
|
||||
pub fn encrypt(
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8],
|
||||
nonce: &[u8],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
let (ciphertext, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
|
||||
|
||||
use libcrux::aead as C;
|
||||
let crux_key = C::Key::Chacha20Poly1305(C::Chacha20Key(key.try_into().unwrap()));
|
||||
let crux_iv = C::Iv(nonce.try_into().unwrap());
|
||||
|
||||
copy_slice(plaintext).to(ciphertext);
|
||||
let crux_tag = libcrux::aead::encrypt(&crux_key, ciphertext, crux_iv, ad).unwrap();
|
||||
copy_slice(crux_tag.as_ref()).to(mac);
|
||||
|
||||
match crux_key {
|
||||
C::Key::Chacha20Poly1305(mut k) => k.0.zeroize(),
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Decrypts a `ciphertext` and verifies the integrity of the `ciphertext` and the additional data
|
||||
/// `ad`. using ChaCha20Poly1305 as implemented in [libcrux](https://github.com/cryspen/libcrux).
|
||||
///
|
||||
/// The `key` slice MUST have a length of [KEY_LEN]. The `nonce` slice MUST have a length of
|
||||
/// [NONCE_LEN]. The plaintext buffer must have a capacity of `ciphertext.len()` - [TAG_LEN].
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::chacha20poly1305_ietf_libcrux::{decrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
|
||||
/// let ciphertext: &[u8] = &[239, 104, 148, 202, 120, 32, 77, 27, 246, 206, 226, 17,
|
||||
/// 83, 78, 122, 116, 187, 123, 70, 199, 58, 130, 21, 1, 107, 230, 58, 77, 18, 152, 31, 159, 80,
|
||||
/// 151, 72, 27, 236, 137, 60, 55, 180, 31, 71, 97, 199, 12, 60, 155, 70, 221, 225, 110, 132, 191,
|
||||
/// 8, 114, 85, 4, 25]; // this is the ciphertext generated by the example for the encryption
|
||||
/// const PLAINTEXT_LEN: usize = 43;
|
||||
/// assert_eq!(PLAINTEXT_LEN + TAG_LEN, ciphertext.len());
|
||||
///
|
||||
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
|
||||
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
|
||||
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
|
||||
/// let mut plaintext_buffer = [0u8; PLAINTEXT_LEN];
|
||||
///
|
||||
/// let res: anyhow::Result<()> = decrypt(&mut plaintext_buffer, key, nonce, additional_data, ciphertext);
|
||||
/// assert!(res.is_ok());
|
||||
/// let expected_plaintext = "post-quantum cryptography is very important".as_bytes();
|
||||
/// assert_eq!(expected_plaintext, plaintext_buffer);
|
||||
///
|
||||
///```
|
||||
#[inline]
|
||||
pub fn decrypt(
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8],
|
||||
nonce: &[u8],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
let (ciphertext, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
|
||||
|
||||
use libcrux::aead as C;
|
||||
let crux_key = C::Key::Chacha20Poly1305(C::Chacha20Key(key.try_into().unwrap()));
|
||||
let crux_iv = C::Iv(nonce.try_into().unwrap());
|
||||
let crux_tag = C::Tag::from_slice(mac).unwrap();
|
||||
|
||||
copy_slice(ciphertext).to(plaintext);
|
||||
libcrux::aead::decrypt(&crux_key, plaintext, crux_iv, ad, &crux_tag).unwrap();
|
||||
|
||||
match crux_key {
|
||||
C::Key::Chacha20Poly1305(mut k) => k.0.zeroize(),
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
use rosenpass_cipher_traits::{
|
||||
algorithms::KeyedHashIncorrectHmacBlake2b,
|
||||
primitives::{InferKeyedHash, KeyedHash, KeyedHashTo},
|
||||
};
|
||||
use rosenpass_constant_time::xor;
|
||||
use rosenpass_to::{ops::copy_slice, To};
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
#[cfg(not(feature = "experiment_libcrux_blake2"))]
|
||||
use crate::subtle::rust_crypto::blake2b::Blake2b;
|
||||
#[cfg(not(feature = "experiment_libcrux_blake2"))]
|
||||
use anyhow::Error;
|
||||
|
||||
#[cfg(feature = "experiment_libcrux_blake2")]
|
||||
use crate::subtle::libcrux::blake2b::{Blake2b, Error};
|
||||
|
||||
/// The key length, 32 bytes or 256 bits.
|
||||
pub const KEY_LEN: usize = 32;
|
||||
|
||||
/// The hash length, 32 bytes or 256 bits.
|
||||
pub const HASH_LEN: usize = 32;
|
||||
|
||||
/// This is a woefully incorrect implementation of hmac_blake2b.
|
||||
/// See <https://github.com/rosenpass/rosenpass/issues/68#issuecomment-1563612222>
|
||||
///
|
||||
/// It accepts 32 byte keys, exclusively.
|
||||
///
|
||||
/// This will be replaced, likely by Kekkac at some point soon.
|
||||
/// <https://github.com/rosenpass/rosenpass/pull/145>
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::custom::incorrect_hmac_blake2b::IncorrectHmacBlake2bCore;
|
||||
/// use rosenpass_cipher_traits::primitives::KeyedHashTo;
|
||||
/// use rosenpass_to::To;
|
||||
/// let key: [u8; 32] = [0; 32];
|
||||
/// let data: [u8; 32] = [255; 32];
|
||||
/// // buffer for the hash output
|
||||
/// let mut hash_data: [u8; 32] = [0u8; 32];
|
||||
///
|
||||
/// assert!(IncorrectHmacBlake2bCore::keyed_hash_to(&key, &data).to(&mut hash_data).is_ok(), "Hashing has to return OK result");
|
||||
/// # let expected_hash: &[u8] = &[5, 152, 135, 141, 151, 106, 147, 8, 220, 95, 38, 66, 29, 33, 3,
|
||||
/// 104, 250, 114, 131, 119, 27, 56, 59, 44, 11, 67, 230, 113, 112, 20, 80, 103];
|
||||
/// # assert_eq!(hash_data, expected_hash);
|
||||
///```
|
||||
///
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct IncorrectHmacBlake2bCore;
|
||||
|
||||
impl KeyedHash<KEY_LEN, HASH_LEN> for IncorrectHmacBlake2bCore {
|
||||
type Error = Error;
|
||||
|
||||
fn keyed_hash(
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error> {
|
||||
const IPAD: [u8; KEY_LEN] = [0x36u8; KEY_LEN];
|
||||
const OPAD: [u8; KEY_LEN] = [0x5Cu8; KEY_LEN];
|
||||
|
||||
type Key = Zeroizing<[u8; KEY_LEN]>;
|
||||
let mut tmp_key = Key::default();
|
||||
|
||||
copy_slice(key).to(tmp_key.as_mut());
|
||||
xor(&IPAD).to(tmp_key.as_mut());
|
||||
let mut outer_data = Key::default();
|
||||
Blake2b::keyed_hash_to(&tmp_key, data).to(&mut outer_data)?;
|
||||
|
||||
copy_slice(key).to(tmp_key.as_mut());
|
||||
xor(&OPAD).to(tmp_key.as_mut());
|
||||
Blake2b::keyed_hash_to(&tmp_key, outer_data.as_ref()).to(out)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub type IncorrectHmacBlake2b = InferKeyedHash<IncorrectHmacBlake2bCore, KEY_LEN, HASH_LEN>;
|
||||
|
||||
impl KeyedHashIncorrectHmacBlake2b for IncorrectHmacBlake2bCore {}
|
||||
@@ -1,3 +0,0 @@
|
||||
//! Own implementations of custom algorithms
|
||||
|
||||
pub mod incorrect_hmac_blake2b;
|
||||
67
ciphers/src/subtle/incorrect_hmac_blake2b.rs
Normal file
67
ciphers/src/subtle/incorrect_hmac_blake2b.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
use anyhow::ensure;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use rosenpass_constant_time::xor;
|
||||
use rosenpass_to::{ops::copy_slice, with_destination, To};
|
||||
|
||||
use crate::subtle::blake2b;
|
||||
|
||||
/// The key length, 32 bytes or 256 bits.
|
||||
pub const KEY_LEN: usize = 32;
|
||||
/// The minimal key length, identical to [KEY_LEN]
|
||||
pub const KEY_MIN: usize = KEY_LEN;
|
||||
/// The maximal key length, identical to [KEY_LEN]
|
||||
pub const KEY_MAX: usize = KEY_LEN;
|
||||
/// The minimal output length, see [blake2b::OUT_MIN]
|
||||
pub const OUT_MIN: usize = blake2b::OUT_MIN;
|
||||
/// The maximal output length, see [blake2b::OUT_MAX]
|
||||
pub const OUT_MAX: usize = blake2b::OUT_MAX;
|
||||
|
||||
/// This is a woefully incorrect implementation of hmac_blake2b.
|
||||
/// See <https://github.com/rosenpass/rosenpass/issues/68#issuecomment-1563612222>
|
||||
///
|
||||
/// It accepts 32 byte keys, exclusively.
|
||||
///
|
||||
/// This will be replaced, likely by Kekkac at some point soon.
|
||||
/// <https://github.com/rosenpass/rosenpass/pull/145>
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::incorrect_hmac_blake2b::hash;
|
||||
/// use rosenpass_to::To;
|
||||
/// let key: [u8; 32] = [0; 32];
|
||||
/// let data: [u8; 32] = [255; 32];
|
||||
/// // buffer for the hash output
|
||||
/// let mut hash_data: [u8; 32] = [0u8; 32];
|
||||
///
|
||||
/// assert!(hash(&key, &data).to(&mut hash_data).is_ok(), "Hashing has to return OK result");
|
||||
/// # let expected_hash: &[u8] = &[5, 152, 135, 141, 151, 106, 147, 8, 220, 95, 38, 66, 29, 33, 3,
|
||||
/// 104, 250, 114, 131, 119, 27, 56, 59, 44, 11, 67, 230, 113, 112, 20, 80, 103];
|
||||
/// # assert_eq!(hash_data, expected_hash);
|
||||
///```
|
||||
///
|
||||
#[inline]
|
||||
pub fn hash<'a>(key: &'a [u8], data: &'a [u8]) -> impl To<[u8], anyhow::Result<()>> + 'a {
|
||||
const IPAD: [u8; KEY_LEN] = [0x36u8; KEY_LEN];
|
||||
const OPAD: [u8; KEY_LEN] = [0x5Cu8; KEY_LEN];
|
||||
|
||||
with_destination(|out: &mut [u8]| {
|
||||
// Not bothering with padding; the implementation
|
||||
// uses appropriately sized keys.
|
||||
ensure!(key.len() == KEY_LEN);
|
||||
|
||||
type Key = Zeroizing<[u8; KEY_LEN]>;
|
||||
let mut tmp_key = Key::default();
|
||||
|
||||
copy_slice(key).to(tmp_key.as_mut());
|
||||
xor(&IPAD).to(tmp_key.as_mut());
|
||||
let mut outer_data = Key::default();
|
||||
blake2b::hash(tmp_key.as_ref(), data).to(outer_data.as_mut())?;
|
||||
|
||||
copy_slice(key).to(tmp_key.as_mut());
|
||||
xor(&OPAD).to(tmp_key.as_mut());
|
||||
blake2b::hash(tmp_key.as_ref(), outer_data.as_ref()).to(out)?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
//! This module provides types that enabling choosing the keyed hash building block to be used at
|
||||
//! runtime (using enums) instead of at compile time (using generics).
|
||||
|
||||
use anyhow::Result;
|
||||
use rosenpass_cipher_traits::primitives::KeyedHashInstance;
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::subtle::{
|
||||
custom::incorrect_hmac_blake2b::IncorrectHmacBlake2b, rust_crypto::keyed_shake256::SHAKE256_32,
|
||||
};
|
||||
|
||||
/// Length of symmetric key throughout Rosenpass.
|
||||
pub const KEY_LEN: usize = 32;
|
||||
|
||||
/// The hash is used as a symmetric key and should have the same length.
|
||||
pub const HASH_LEN: usize = KEY_LEN;
|
||||
|
||||
/// Provides a way to pick which keyed hash to use at runtime.
|
||||
/// Implements [`KeyedHashInstance`] to allow hashing using the respective algorithm.
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
pub enum KeyedHash {
|
||||
/// A hasher backed by [`SHAKE256_32`].
|
||||
KeyedShake256(SHAKE256_32),
|
||||
/// A hasher backed by [`IncorrectHmacBlake2b`].
|
||||
IncorrectHmacBlake2b(IncorrectHmacBlake2b),
|
||||
}
|
||||
|
||||
impl KeyedHash {
|
||||
/// Creates an [`KeyedHash`] backed by SHAKE256.
|
||||
pub fn keyed_shake256() -> Self {
|
||||
Self::KeyedShake256(Default::default())
|
||||
}
|
||||
|
||||
/// Creates an [`KeyedHash`] backed by Blake2B.
|
||||
pub fn incorrect_hmac_blake2b() -> Self {
|
||||
Self::IncorrectHmacBlake2b(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyedHashInstance<KEY_LEN, HASH_LEN> for KeyedHash {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn keyed_hash(
|
||||
&self,
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error> {
|
||||
match self {
|
||||
Self::KeyedShake256(h) => h.keyed_hash(key, data, out)?,
|
||||
Self::IncorrectHmacBlake2b(h) => h.keyed_hash(key, data, out)?,
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for KeyedHash {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::KeyedShake256(_) => write!(f, "KeyedShake256_32"),
|
||||
Self::IncorrectHmacBlake2b(_) => write!(f, "IncorrectHmacBlake2b"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
//! Implementation of the [`KeyedHashBlake2b`] trait based on the [`libcrux_blake2`] crate.
|
||||
|
||||
use libcrux_blake2::Blake2bBuilder;
|
||||
|
||||
use rosenpass_cipher_traits::algorithms::KeyedHashBlake2b;
|
||||
use rosenpass_cipher_traits::primitives::KeyedHash;
|
||||
|
||||
pub use rosenpass_cipher_traits::algorithms::keyed_hash_blake2b::HASH_LEN;
|
||||
pub use rosenpass_cipher_traits::algorithms::keyed_hash_blake2b::KEY_LEN;
|
||||
|
||||
/// Describles which error occurred
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
/// An unexpected internal error occurred. Should never be returned and points to a bug in the
|
||||
/// implementation.
|
||||
#[error("internal error")]
|
||||
InternalError,
|
||||
|
||||
/// Indicates that the provided data was too long.
|
||||
#[error("data is too long")]
|
||||
DataTooLong,
|
||||
}
|
||||
|
||||
/// Hasher for the given `data` with the Blake2b hash function.
|
||||
pub struct Blake2b;
|
||||
|
||||
impl KeyedHash<KEY_LEN, HASH_LEN> for Blake2b {
|
||||
type Error = Error;
|
||||
|
||||
fn keyed_hash(
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error> {
|
||||
let mut h = Blake2bBuilder::new_keyed_const(key)
|
||||
// this may fail if the key length is invalid, but 32 is fine
|
||||
.map_err(|_| Error::InternalError)?
|
||||
.build_const_digest_len()
|
||||
.map_err(|_|
|
||||
// this can only fail if the output length is invalid, but 32 is fine.
|
||||
Error::InternalError)?;
|
||||
|
||||
h.update(data).map_err(|_| Error::DataTooLong)?;
|
||||
h.finalize(out);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyedHashBlake2b for Blake2b {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod equivalence_tests {
|
||||
use super::*;
|
||||
use rand::RngCore;
|
||||
|
||||
#[test]
|
||||
fn fuzz_equivalence_libcrux_old_new() {
|
||||
let datas: [&[u8]; 3] = [
|
||||
b"".as_slice(),
|
||||
b"test".as_slice(),
|
||||
b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
|
||||
];
|
||||
|
||||
let mut key = [0; KEY_LEN];
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let mut hash_left = [0; 32];
|
||||
let mut hash_right = [0; 32];
|
||||
|
||||
for data in datas {
|
||||
for _ in 0..1000 {
|
||||
rng.fill_bytes(&mut key);
|
||||
|
||||
crate::subtle::rust_crypto::blake2b::Blake2b::keyed_hash(
|
||||
&key,
|
||||
data,
|
||||
&mut hash_left,
|
||||
)
|
||||
.unwrap();
|
||||
crate::subtle::libcrux::blake2b::Blake2b::keyed_hash(&key, data, &mut hash_right)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(hash_left, hash_right);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,274 +0,0 @@
|
||||
//! Implementation of the [`AeadChaCha20Poly1305`] trait based on the [`libcrux_chacha20poly1305`] crate.
|
||||
|
||||
use rosenpass_cipher_traits::algorithms::AeadChaCha20Poly1305;
|
||||
use rosenpass_cipher_traits::primitives::{Aead, AeadError};
|
||||
|
||||
pub use rosenpass_cipher_traits::algorithms::aead_chacha20poly1305::{KEY_LEN, NONCE_LEN, TAG_LEN};
|
||||
|
||||
/// An implementation of the ChaCha20Poly1305 AEAD based on libcrux
|
||||
pub struct ChaCha20Poly1305;
|
||||
|
||||
impl Aead<KEY_LEN, NONCE_LEN, TAG_LEN> for ChaCha20Poly1305 {
|
||||
fn encrypt(
|
||||
&self,
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> Result<(), AeadError> {
|
||||
let (ctxt, tag) = libcrux_chacha20poly1305::encrypt(key, plaintext, ciphertext, ad, nonce)
|
||||
.map_err(|_| AeadError::InternalError)?;
|
||||
|
||||
// return an error of the destination buffer is longer than expected
|
||||
// because the caller wouldn't know where the end is
|
||||
if ctxt.len() + tag.len() != ciphertext.len() {
|
||||
return Err(AeadError::InternalError);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decrypt(
|
||||
&self,
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> Result<(), AeadError> {
|
||||
let ptxt = libcrux_chacha20poly1305::decrypt(key, plaintext, ciphertext, ad, nonce)
|
||||
.map_err(|_| AeadError::DecryptError)?;
|
||||
|
||||
// return an error of the destination buffer is longer than expected
|
||||
// because the caller wouldn't know where the end is
|
||||
if ptxt.len() != plaintext.len() {
|
||||
return Err(AeadError::DecryptError);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl AeadChaCha20Poly1305 for ChaCha20Poly1305 {}
|
||||
|
||||
/// The idea of these tests is to check that the above implemenatation behaves, by and large, the
|
||||
/// same as the one from the old libcrux and the one from RustCrypto. You can consider them janky,
|
||||
/// self-rolled property-based tests.
|
||||
#[cfg(test)]
|
||||
mod equivalence_tests {
|
||||
use super::*;
|
||||
use rand::RngCore;
|
||||
|
||||
#[test]
|
||||
fn proptest_equivalence_libcrux_rustcrypto() {
|
||||
use crate::subtle::rust_crypto::chacha20poly1305_ietf::ChaCha20Poly1305 as RustCryptoChaCha20Poly1305;
|
||||
let ptxts: [&[u8]; 3] = [
|
||||
b"".as_slice(),
|
||||
b"test".as_slice(),
|
||||
b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
|
||||
];
|
||||
let mut key = [0; KEY_LEN];
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let mut ctxt_left = [0; 64 + TAG_LEN];
|
||||
let mut ctxt_right = [0; 64 + TAG_LEN];
|
||||
|
||||
let mut ptxt_left = [0; 64];
|
||||
let mut ptxt_right = [0; 64];
|
||||
|
||||
let nonce = [0; NONCE_LEN];
|
||||
let ad = b"";
|
||||
|
||||
for ptxt in ptxts {
|
||||
for _ in 0..1000 {
|
||||
rng.fill_bytes(&mut key);
|
||||
let ctxt_left = &mut ctxt_left[..ptxt.len() + TAG_LEN];
|
||||
let ctxt_right = &mut ctxt_right[..ptxt.len() + TAG_LEN];
|
||||
|
||||
let ptxt_left = &mut ptxt_left[..ptxt.len()];
|
||||
let ptxt_right = &mut ptxt_right[..ptxt.len()];
|
||||
|
||||
RustCryptoChaCha20Poly1305
|
||||
.encrypt(ctxt_left, &key, &nonce, ad, ptxt)
|
||||
.unwrap();
|
||||
ChaCha20Poly1305
|
||||
.encrypt(ctxt_right, &key, &nonce, ad, ptxt)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(ctxt_left, ctxt_right);
|
||||
|
||||
RustCryptoChaCha20Poly1305
|
||||
.decrypt(ptxt_left, &key, &nonce, ad, ctxt_left)
|
||||
.unwrap();
|
||||
ChaCha20Poly1305
|
||||
.decrypt(ptxt_right, &key, &nonce, ad, ctxt_right)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(ptxt_left, ptxt);
|
||||
assert_eq!(ptxt_right, ptxt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "experiment_libcrux_chachapoly_test")]
|
||||
fn proptest_equivalence_libcrux_old_new() {
|
||||
let ptxts: [&[u8]; 3] = [
|
||||
b"".as_slice(),
|
||||
b"test".as_slice(),
|
||||
b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
|
||||
];
|
||||
let mut key = [0; KEY_LEN];
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let mut ctxt_left = [0; 64 + TAG_LEN];
|
||||
let mut ctxt_right = [0; 64 + TAG_LEN];
|
||||
|
||||
let mut ptxt_left = [0; 64];
|
||||
let mut ptxt_right = [0; 64];
|
||||
|
||||
let nonce = [0; NONCE_LEN];
|
||||
let ad = b"";
|
||||
|
||||
for ptxt in ptxts {
|
||||
for _ in 0..1000 {
|
||||
rng.fill_bytes(&mut key);
|
||||
let ctxt_left = &mut ctxt_left[..ptxt.len() + TAG_LEN];
|
||||
let ctxt_right = &mut ctxt_right[..ptxt.len() + TAG_LEN];
|
||||
|
||||
let ptxt_left = &mut ptxt_left[..ptxt.len()];
|
||||
let ptxt_right = &mut ptxt_right[..ptxt.len()];
|
||||
|
||||
encrypt(ctxt_left, &key, &nonce, ad, ptxt).unwrap();
|
||||
ChaCha20Poly1305
|
||||
.encrypt(ctxt_right, &key, &nonce, ad, ptxt)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(ctxt_left, ctxt_right);
|
||||
|
||||
decrypt(ptxt_left, &key, &nonce, ad, ctxt_left).unwrap();
|
||||
ChaCha20Poly1305
|
||||
.decrypt(ptxt_right, &key, &nonce, ad, ctxt_right)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(ptxt_left, ptxt);
|
||||
assert_eq!(ptxt_right, ptxt);
|
||||
}
|
||||
}
|
||||
|
||||
// The old libcrux functions:
|
||||
|
||||
// The functions below are from the old libcrux backend. I am keeping them around so we can
|
||||
// check if they behave the same.
|
||||
use rosenpass_to::ops::copy_slice;
|
||||
use rosenpass_to::To;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
/// Encrypts using ChaCha20Poly1305 as implemented in [libcrux](https://github.com/cryspen/libcrux).
|
||||
/// Key and nonce MUST be chosen (pseudo-)randomly. The `key` slice MUST have a length of
|
||||
/// [KEY_LEN]. The `nonce` slice MUST have a length of [NONCE_LEN]. The last [TAG_LEN] bytes
|
||||
/// written in `ciphertext` are the tag guaranteeing integrity. `ciphertext` MUST have a capacity of
|
||||
/// `plaintext.len()` + [TAG_LEN].
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::chacha20poly1305_ietf_libcrux::{encrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
|
||||
///
|
||||
/// const PLAINTEXT_LEN: usize = 43;
|
||||
/// let plaintext = "post-quantum cryptography is very important".as_bytes();
|
||||
/// assert_eq!(PLAINTEXT_LEN, plaintext.len());
|
||||
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
|
||||
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
|
||||
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
|
||||
/// let mut ciphertext_buffer = [0u8; PLAINTEXT_LEN + TAG_LEN];
|
||||
///
|
||||
/// let res: anyhow::Result<()> = encrypt(&mut ciphertext_buffer, key, nonce, additional_data, plaintext);
|
||||
/// assert!(res.is_ok());
|
||||
/// # let expected_ciphertext: &[u8] = &[239, 104, 148, 202, 120, 32, 77, 27, 246, 206, 226, 17,
|
||||
/// # 83, 78, 122, 116, 187, 123, 70, 199, 58, 130, 21, 1, 107, 230, 58, 77, 18, 152, 31, 159, 80,
|
||||
/// # 151, 72, 27, 236, 137, 60, 55, 180, 31, 71, 97, 199, 12, 60, 155, 70, 221, 225, 110, 132, 191,
|
||||
/// # 8, 114, 85, 4, 25];
|
||||
/// # assert_eq!(expected_ciphertext, &ciphertext_buffer);
|
||||
///```
|
||||
///
|
||||
#[inline]
|
||||
pub fn encrypt(
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8],
|
||||
nonce: &[u8],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
let (ciphertext, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
|
||||
|
||||
use libcrux::aead as C;
|
||||
let crux_key = C::Key::Chacha20Poly1305(C::Chacha20Key(key.try_into().unwrap()));
|
||||
let crux_iv = C::Iv(nonce.try_into().unwrap());
|
||||
|
||||
copy_slice(plaintext).to(ciphertext);
|
||||
let crux_tag = libcrux::aead::encrypt(&crux_key, ciphertext, crux_iv, ad).unwrap();
|
||||
copy_slice(crux_tag.as_ref()).to(mac);
|
||||
|
||||
match crux_key {
|
||||
C::Key::Chacha20Poly1305(mut k) => k.0.zeroize(),
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Decrypts a `ciphertext` and verifies the integrity of the `ciphertext` and the additional data
|
||||
/// `ad`. using ChaCha20Poly1305 as implemented in [libcrux](https://github.com/cryspen/libcrux).
|
||||
///
|
||||
/// The `key` slice MUST have a length of [KEY_LEN]. The `nonce` slice MUST have a length of
|
||||
/// [NONCE_LEN]. The plaintext buffer must have a capacity of `ciphertext.len()` - [TAG_LEN].
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::chacha20poly1305_ietf_libcrux::{decrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
|
||||
/// let ciphertext: &[u8] = &[239, 104, 148, 202, 120, 32, 77, 27, 246, 206, 226, 17,
|
||||
/// 83, 78, 122, 116, 187, 123, 70, 199, 58, 130, 21, 1, 107, 230, 58, 77, 18, 152, 31, 159, 80,
|
||||
/// 151, 72, 27, 236, 137, 60, 55, 180, 31, 71, 97, 199, 12, 60, 155, 70, 221, 225, 110, 132, 191,
|
||||
/// 8, 114, 85, 4, 25]; // this is the ciphertext generated by the example for the encryption
|
||||
/// const PLAINTEXT_LEN: usize = 43;
|
||||
/// assert_eq!(PLAINTEXT_LEN + TAG_LEN, ciphertext.len());
|
||||
///
|
||||
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
|
||||
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
|
||||
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
|
||||
/// let mut plaintext_buffer = [0u8; PLAINTEXT_LEN];
|
||||
///
|
||||
/// let res: anyhow::Result<()> = decrypt(&mut plaintext_buffer, key, nonce, additional_data, ciphertext);
|
||||
/// assert!(res.is_ok());
|
||||
/// let expected_plaintext = "post-quantum cryptography is very important".as_bytes();
|
||||
/// assert_eq!(expected_plaintext, plaintext_buffer);
|
||||
///
|
||||
///```
|
||||
#[inline]
|
||||
pub fn decrypt(
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8],
|
||||
nonce: &[u8],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
let (ciphertext, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
|
||||
|
||||
use libcrux::aead as C;
|
||||
let crux_key = C::Key::Chacha20Poly1305(C::Chacha20Key(key.try_into().unwrap()));
|
||||
let crux_iv = C::Iv(nonce.try_into().unwrap());
|
||||
let crux_tag = C::Tag::from_slice(mac).unwrap();
|
||||
|
||||
copy_slice(ciphertext).to(plaintext);
|
||||
libcrux::aead::decrypt(&crux_key, plaintext, crux_iv, ad, &crux_tag).unwrap();
|
||||
|
||||
match crux_key {
|
||||
C::Key::Chacha20Poly1305(mut k) => k.0.zeroize(),
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
//! Implementation of the [`KemKyber512`] trait based on the [`libcrux_ml_kem`] crate.
|
||||
|
||||
use libcrux_ml_kem::kyber512;
|
||||
use rand::RngCore;
|
||||
|
||||
use rosenpass_cipher_traits::algorithms::KemKyber512;
|
||||
use rosenpass_cipher_traits::primitives::{Kem, KemError};
|
||||
|
||||
pub use rosenpass_cipher_traits::algorithms::kem_kyber512::{CT_LEN, PK_LEN, SHK_LEN, SK_LEN};
|
||||
|
||||
/// An implementation of the Kyber512 KEM based on libcrux
|
||||
pub struct Kyber512;
|
||||
|
||||
impl Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> for Kyber512 {
|
||||
fn keygen(&self, sk: &mut [u8; SK_LEN], pk: &mut [u8; PK_LEN]) -> Result<(), KemError> {
|
||||
let mut randomness = [0u8; libcrux_ml_kem::KEY_GENERATION_SEED_SIZE];
|
||||
rand::thread_rng().fill_bytes(&mut randomness);
|
||||
|
||||
let key_pair = kyber512::generate_key_pair(randomness);
|
||||
|
||||
let new_sk: &[u8; SK_LEN] = key_pair.sk();
|
||||
let new_pk: &[u8; PK_LEN] = key_pair.pk();
|
||||
|
||||
sk.clone_from_slice(new_sk);
|
||||
pk.clone_from_slice(new_pk);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn encaps(
|
||||
&self,
|
||||
shk: &mut [u8; SHK_LEN],
|
||||
ct: &mut [u8; CT_LEN],
|
||||
pk: &[u8; PK_LEN],
|
||||
) -> Result<(), KemError> {
|
||||
let mut randomness = [0u8; libcrux_ml_kem::SHARED_SECRET_SIZE];
|
||||
rand::thread_rng().fill_bytes(&mut randomness);
|
||||
|
||||
let (new_ct, new_shk) = kyber512::encapsulate(&pk.into(), randomness);
|
||||
let new_ct: &[u8; CT_LEN] = new_ct.as_slice();
|
||||
|
||||
shk.clone_from_slice(&new_shk);
|
||||
ct.clone_from_slice(new_ct);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decaps(
|
||||
&self,
|
||||
shk: &mut [u8; SHK_LEN],
|
||||
sk: &[u8; SK_LEN],
|
||||
ct: &[u8; CT_LEN],
|
||||
) -> Result<(), KemError> {
|
||||
let new_shk: [u8; SHK_LEN] = kyber512::decapsulate(&sk.into(), &ct.into());
|
||||
shk.clone_from(&new_shk);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Kyber512 {
|
||||
fn default() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl KemKyber512 for Kyber512 {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod equivalence_tests {
|
||||
use super::*;
|
||||
|
||||
// Test that libcrux and OQS produce the same results
|
||||
#[test]
|
||||
fn proptest_equivalence_libcrux_oqs() {
|
||||
use rosenpass_oqs::Kyber512 as OqsKyber512;
|
||||
|
||||
let (mut sk1, mut pk1) = ([0; SK_LEN], [0; PK_LEN]);
|
||||
let (mut sk2, mut pk2) = ([0; SK_LEN], [0; PK_LEN]);
|
||||
|
||||
let mut ct_left = [0; CT_LEN];
|
||||
let mut ct_right = [0; CT_LEN];
|
||||
|
||||
let mut shk_enc_left = [0; SHK_LEN];
|
||||
let mut shk_enc_right = [0; SHK_LEN];
|
||||
|
||||
// naming schema: shk_dec_{encapsing lib}_{decapsing lib}
|
||||
// should be the same if the encapsing lib was the same.
|
||||
let mut shk_dec_left_left = [0; SHK_LEN];
|
||||
let mut shk_dec_left_right = [0; SHK_LEN];
|
||||
let mut shk_dec_right_left = [0; SHK_LEN];
|
||||
let mut shk_dec_right_right = [0; SHK_LEN];
|
||||
|
||||
for _ in 0..1000 {
|
||||
let sk1 = &mut sk1;
|
||||
let pk1 = &mut pk1;
|
||||
let sk2 = &mut sk2;
|
||||
let pk2 = &mut pk2;
|
||||
|
||||
let ct_left = &mut ct_left;
|
||||
let ct_right = &mut ct_right;
|
||||
|
||||
let shk_enc_left = &mut shk_enc_left;
|
||||
let shk_enc_right = &mut shk_enc_right;
|
||||
|
||||
let shk_dec_left_left = &mut shk_dec_left_left;
|
||||
let shk_dec_left_right = &mut shk_dec_left_right;
|
||||
let shk_dec_right_left = &mut shk_dec_right_left;
|
||||
let shk_dec_right_right = &mut shk_dec_right_right;
|
||||
|
||||
Kyber512.keygen(sk1, pk1).unwrap();
|
||||
Kyber512.keygen(sk2, pk2).unwrap();
|
||||
|
||||
Kyber512.encaps(shk_enc_left, ct_left, pk2).unwrap();
|
||||
OqsKyber512.encaps(shk_enc_right, ct_right, pk2).unwrap();
|
||||
|
||||
Kyber512.decaps(shk_dec_left_left, sk2, ct_left).unwrap();
|
||||
Kyber512.decaps(shk_dec_right_left, sk2, ct_right).unwrap();
|
||||
|
||||
OqsKyber512
|
||||
.decaps(shk_dec_left_right, sk2, ct_left)
|
||||
.unwrap();
|
||||
OqsKyber512
|
||||
.decaps(shk_dec_right_right, sk2, ct_right)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(shk_enc_left, shk_dec_left_left);
|
||||
assert_eq!(shk_enc_left, shk_dec_left_right);
|
||||
|
||||
assert_eq!(shk_enc_right, shk_dec_right_left);
|
||||
assert_eq!(shk_enc_right, shk_dec_right_right);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
//! Implementations backed by libcrux, a verified crypto library.
|
||||
//!
|
||||
//! [Website](https://cryspen.com/libcrux/)
|
||||
//!
|
||||
//! [Github](https://github.com/cryspen/libcrux)
|
||||
|
||||
#[cfg(feature = "experiment_libcrux_define_blake2")]
|
||||
pub mod blake2b;
|
||||
|
||||
#[cfg(feature = "experiment_libcrux_define_chachapoly")]
|
||||
pub mod chacha20poly1305_ietf;
|
||||
|
||||
#[cfg(feature = "experiment_libcrux_define_kyber")]
|
||||
pub mod kyber512;
|
||||
@@ -1,16 +1,13 @@
|
||||
//! Contains the implementations of the crypto algorithms used throughout Rosenpass.
|
||||
|
||||
pub mod keyed_hash;
|
||||
|
||||
pub use custom::incorrect_hmac_blake2b;
|
||||
pub use rust_crypto::{blake2b, keyed_shake256};
|
||||
|
||||
pub mod custom;
|
||||
pub mod rust_crypto;
|
||||
|
||||
#[cfg(any(
|
||||
feature = "experiment_libcrux_define_blake2",
|
||||
feature = "experiment_libcrux_define_chachapoly",
|
||||
feature = "experiment_libcrux_define_kyber",
|
||||
))]
|
||||
pub mod libcrux;
|
||||
/// This module provides the following cryptographic schemes:
|
||||
/// - [blake2b]: The blake2b hash function
|
||||
/// - [chacha20poly1305_ietf]: The Chacha20Poly1305 AEAD as implemented in [RustCrypto](https://crates.io/crates/chacha20poly1305) (only used when the feature `experiment_libcrux` is disabled).
|
||||
/// - [chacha20poly1305_ietf_libcrux]: The Chacha20Poly1305 AEAD as implemented in [libcrux](https://github.com/cryspen/libcrux) (only used when the feature `experiment_libcrux` is enabled).
|
||||
/// - [incorrect_hmac_blake2b]: An (incorrect) hmac based on [blake2b].
|
||||
/// - [xchacha20poly1305_ietf] The Chacha20Poly1305 AEAD as implemented in [RustCrypto](https://crates.io/crates/chacha20poly1305)
|
||||
pub mod blake2b;
|
||||
#[cfg(not(feature = "experiment_libcrux"))]
|
||||
pub mod chacha20poly1305_ietf;
|
||||
#[cfg(feature = "experiment_libcrux")]
|
||||
pub mod chacha20poly1305_ietf_libcrux;
|
||||
pub mod incorrect_hmac_blake2b;
|
||||
pub mod xchacha20poly1305_ietf;
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use blake2::digest::crypto_common::generic_array::GenericArray;
|
||||
use blake2::digest::crypto_common::typenum::U32;
|
||||
use blake2::digest::{FixedOutput, Mac};
|
||||
use blake2::Blake2bMac;
|
||||
|
||||
use rosenpass_cipher_traits::primitives::KeyedHash;
|
||||
use rosenpass_to::{ops::copy_slice, To};
|
||||
|
||||
pub use rosenpass_cipher_traits::algorithms::keyed_hash_blake2b::{HASH_LEN, KEY_LEN};
|
||||
|
||||
/// Specify that the used implementation of BLAKE2b is the MAC version of BLAKE2b
|
||||
/// with output and key length of 32 bytes (see [Blake2bMac]).
|
||||
type Impl = Blake2bMac<U32>;
|
||||
|
||||
/// Hashes the given `data` with the [Blake2bMac] hash function under the given `key`.
|
||||
/// The both the length of the output the length of the key 32 bytes (or 256 bits).
|
||||
pub struct Blake2b;
|
||||
|
||||
impl KeyedHash<KEY_LEN, HASH_LEN> for Blake2b {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn keyed_hash(
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error> {
|
||||
let mut h = Impl::new_from_slice(key)?;
|
||||
h.update(data);
|
||||
|
||||
// Jesus christ, blake2 crate, your usage of GenericArray might be nice and fancy,
|
||||
// but it introduces a ton of complexity. This cost me half an hour just to figure
|
||||
// out the right way to use the imports while allowing for zeroization.
|
||||
// An API based on slices might actually be simpler.
|
||||
let mut tmp = Zeroizing::new([0u8; HASH_LEN]);
|
||||
let tmp = GenericArray::from_mut_slice(tmp.as_mut());
|
||||
h.finalize_into(tmp);
|
||||
copy_slice(tmp.as_ref()).to(out);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl rosenpass_cipher_traits::algorithms::KeyedHashBlake2b for Blake2b {}
|
||||
@@ -1,79 +0,0 @@
|
||||
use rosenpass_to::ops::copy_slice;
|
||||
use rosenpass_to::To;
|
||||
|
||||
use rosenpass_cipher_traits::algorithms::AeadChaCha20Poly1305;
|
||||
use rosenpass_cipher_traits::primitives::{Aead, AeadError};
|
||||
|
||||
use chacha20poly1305::aead::generic_array::GenericArray;
|
||||
use chacha20poly1305::ChaCha20Poly1305 as AeadImpl;
|
||||
use chacha20poly1305::{AeadInPlace, KeyInit};
|
||||
|
||||
pub use rosenpass_cipher_traits::algorithms::aead_chacha20poly1305::{KEY_LEN, NONCE_LEN, TAG_LEN};
|
||||
|
||||
/// Implements the [`Aead`] and [`AeadChaCha20Poly1305`] traits backed by the RustCrypto
|
||||
/// implementation.
|
||||
pub struct ChaCha20Poly1305;
|
||||
|
||||
impl Aead<KEY_LEN, NONCE_LEN, TAG_LEN> for ChaCha20Poly1305 {
|
||||
fn encrypt(
|
||||
&self,
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> Result<(), AeadError> {
|
||||
// The comparison looks complicated, but we need to do it this way to prevent
|
||||
// over/underflows.
|
||||
if ciphertext.len() < TAG_LEN || ciphertext.len() - TAG_LEN < plaintext.len() {
|
||||
return Err(AeadError::InvalidLengths);
|
||||
}
|
||||
|
||||
let nonce = GenericArray::from_slice(nonce);
|
||||
let (ct, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
|
||||
copy_slice(plaintext).to(ct);
|
||||
|
||||
// This only fails if the length is wrong, which really shouldn't happen and would
|
||||
// constitute an internal error.
|
||||
let encrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
|
||||
|
||||
let mac_value = encrypter
|
||||
.encrypt_in_place_detached(nonce, ad, ct)
|
||||
.map_err(|_| AeadError::InternalError)?;
|
||||
copy_slice(&mac_value[..]).to(mac);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decrypt(
|
||||
&self,
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> Result<(), AeadError> {
|
||||
// The comparison looks complicated, but we need to do it this way to prevent
|
||||
// over/underflows.
|
||||
if ciphertext.len() < TAG_LEN || ciphertext.len() - TAG_LEN < plaintext.len() {
|
||||
return Err(AeadError::InvalidLengths);
|
||||
}
|
||||
|
||||
let nonce = GenericArray::from_slice(nonce);
|
||||
let (ct, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
|
||||
let tag = GenericArray::from_slice(mac);
|
||||
copy_slice(ct).to(plaintext);
|
||||
|
||||
// This only fails if the length is wrong, which really shouldn't happen and would
|
||||
// constitute an internal error.
|
||||
let decrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
|
||||
|
||||
decrypter
|
||||
.decrypt_in_place_detached(nonce, ad, plaintext, tag)
|
||||
.map_err(|_| AeadError::DecryptError)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl AeadChaCha20Poly1305 for ChaCha20Poly1305 {}
|
||||
@@ -1,117 +0,0 @@
|
||||
use anyhow::ensure;
|
||||
use rosenpass_cipher_traits::primitives::{InferKeyedHash, KeyedHash};
|
||||
use sha3::digest::{ExtendableOutput, Update, XofReader};
|
||||
use sha3::Shake256;
|
||||
|
||||
pub use rosenpass_cipher_traits::algorithms::keyed_hash_shake256::{HASH_LEN, KEY_LEN};
|
||||
|
||||
/// An implementation of the [`KeyedHash`] trait backed by the RustCrypto implementation of SHAKE256.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SHAKE256Core<const KEY_LEN: usize, const HASH_LEN: usize>;
|
||||
|
||||
impl<const KEY_LEN: usize, const HASH_LEN: usize> KeyedHash<KEY_LEN, HASH_LEN>
|
||||
for SHAKE256Core<KEY_LEN, HASH_LEN>
|
||||
{
|
||||
type Error = anyhow::Error;
|
||||
|
||||
/// Provides a keyed hash function based on SHAKE256. To work for the protocol, the output length
|
||||
/// and key length are fixed to 32 bytes (also see [KEY_LEN] and [HASH_LEN]).
|
||||
///
|
||||
/// Note that the SHAKE256 is designed for 64 bytes output length, which we truncate to 32 bytes
|
||||
/// to work well with the overall protocol. Referring to Table 4 of FIPS 202, this offers the
|
||||
/// same collision resistance as SHAKE128, but 256 bits of preimage resistance. We therefore
|
||||
/// prefer a truncated SHAKE256 over SHAKE128.
|
||||
///
|
||||
/// #Examples
|
||||
/// ```rust
|
||||
/// # use rosenpass_ciphers::subtle::rust_crypto::keyed_shake256::SHAKE256Core;
|
||||
/// use rosenpass_cipher_traits::primitives::KeyedHash;
|
||||
/// const KEY_LEN: usize = 32;
|
||||
/// const HASH_LEN: usize = 32;
|
||||
/// let key: [u8; 32] = [0; KEY_LEN];
|
||||
/// let data: [u8; 32] = [255; 32]; // arbitrary data, could also be longer
|
||||
/// // buffer for the hash output
|
||||
/// let mut hash_data: [u8; 32] = [0u8; HASH_LEN];
|
||||
///
|
||||
/// assert!(SHAKE256Core::<32, 32>::keyed_hash(&key, &data, &mut hash_data).is_ok(), "Hashing has to return OK result");
|
||||
/// # let expected_hash: &[u8] = &[174, 4, 47, 188, 1, 228, 179, 246, 67, 43, 255, 94, 155, 11,
|
||||
/// 187, 161, 38, 110, 217, 23, 4, 62, 172, 30, 218, 187, 249, 80, 171, 21, 145, 238];
|
||||
/// # assert_eq!(hash_data, expected_hash);
|
||||
/// ```
|
||||
fn keyed_hash(
|
||||
key: &[u8; KEY_LEN],
|
||||
data: &[u8],
|
||||
out: &mut [u8; HASH_LEN],
|
||||
) -> Result<(), Self::Error> {
|
||||
// Since SHAKE256 is a XOF, we fix the output length manually to what is required for the
|
||||
// protocol.
|
||||
ensure!(out.len() == HASH_LEN);
|
||||
// Not bothering with padding; the implementation
|
||||
// uses appropriately sized keys.
|
||||
ensure!(key.len() == KEY_LEN);
|
||||
let mut shake256 = Shake256::default();
|
||||
shake256.update(key);
|
||||
shake256.update(data);
|
||||
|
||||
// Since we use domain separation extensively, related outputs of the truncated XOF
|
||||
// are not a concern. This follows the NIST recommendations in Section A.2 of the FIPS 202
|
||||
// standard, (pages 24/25, i.e., 32/33 in the PDF).
|
||||
shake256.finalize_xof().read(out);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const KEY_LEN: usize, const HASH_LEN: usize> SHAKE256Core<KEY_LEN, HASH_LEN> {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl<const KEY_LEN: usize, const HASH_LEN: usize> Default for SHAKE256Core<KEY_LEN, HASH_LEN> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// This type provides the same functionality as [SHAKE256Core], but bound to an instance.
|
||||
/// In contrast to [SHAKE256Core], this allows for type interference and thus allows the user of the
|
||||
/// type to omit explicit type parameters when instantiating the type or using it.
|
||||
///
|
||||
/// The instantiation is based on the [InferKeyedHash] trait.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use rosenpass_ciphers::subtle::rust_crypto::keyed_shake256::{SHAKE256};
|
||||
/// use rosenpass_cipher_traits::primitives::KeyedHashInstance;
|
||||
/// const KEY_LEN: usize = 32;
|
||||
/// const HASH_LEN: usize = 32;
|
||||
/// let key: [u8; KEY_LEN] = [0; KEY_LEN];
|
||||
/// let data: [u8; 32] = [255; 32]; // arbitrary data, could also be longer
|
||||
/// // buffer for the hash output
|
||||
/// let mut hash_data: [u8; 32] = [0u8; HASH_LEN];
|
||||
/// assert!(SHAKE256::new().keyed_hash(&key, &data, &mut hash_data).is_ok(), "Hashing has to return OK result");
|
||||
/// # let expected_hash: &[u8] = &[174, 4, 47, 188, 1, 228, 179, 246, 67, 43, 255, 94, 155, 11, 187,
|
||||
/// 161, 38, 110, 217, 23, 4, 62, 172, 30, 218, 187, 249, 80, 171, 21, 145, 238];
|
||||
/// # assert_eq!(hash_data, expected_hash);
|
||||
/// ```
|
||||
pub type SHAKE256<const KEY_LEN: usize, const HASH_LEN: usize> =
|
||||
InferKeyedHash<SHAKE256Core<KEY_LEN, HASH_LEN>, KEY_LEN, HASH_LEN>;
|
||||
|
||||
/// The SHAKE256_32 type is a specific instance of the [SHAKE256] type with the key length and hash
|
||||
/// length fixed to 32 bytes.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use rosenpass_ciphers::subtle::keyed_shake256::{SHAKE256_32};
|
||||
/// use rosenpass_cipher_traits::primitives::KeyedHashInstance;
|
||||
/// const KEY_LEN: usize = 32;
|
||||
/// const HASH_LEN: usize = 32;
|
||||
/// let key: [u8; 32] = [0; KEY_LEN];
|
||||
/// let data: [u8; 32] = [255; 32]; // arbitrary data, could also be longer
|
||||
/// // buffer for the hash output
|
||||
/// let mut hash_data: [u8; 32] = [0u8; HASH_LEN];
|
||||
///
|
||||
/// assert!(SHAKE256_32::new().keyed_hash(&key, &data, &mut hash_data).is_ok(), "Hashing has to return OK result");
|
||||
/// # let expected_hash: &[u8] = &[174, 4, 47, 188, 1, 228, 179, 246, 67, 43, 255, 94, 155, 11, 187,
|
||||
/// 161, 38, 110, 217, 23, 4, 62, 172, 30, 218, 187, 249, 80, 171, 21, 145, 238];
|
||||
/// # assert_eq!(hash_data, expected_hash);
|
||||
/// ```
|
||||
pub type SHAKE256_32 = SHAKE256<32, 32>;
|
||||
@@ -1,7 +0,0 @@
|
||||
//! Implementations backed by RustCrypto
|
||||
|
||||
pub mod blake2b;
|
||||
pub mod keyed_shake256;
|
||||
|
||||
pub mod chacha20poly1305_ietf;
|
||||
pub mod xchacha20poly1305_ietf;
|
||||
@@ -1,82 +1,17 @@
|
||||
use rosenpass_to::ops::copy_slice;
|
||||
use rosenpass_to::To;
|
||||
|
||||
use rosenpass_cipher_traits::algorithms::aead_xchacha20poly1305::AeadXChaCha20Poly1305;
|
||||
use rosenpass_cipher_traits::primitives::{Aead, AeadError, AeadWithNonceInCiphertext};
|
||||
use rosenpass_util::typenum2const;
|
||||
|
||||
use chacha20poly1305::aead::generic_array::GenericArray;
|
||||
use chacha20poly1305::XChaCha20Poly1305 as AeadImpl;
|
||||
use chacha20poly1305::{AeadInPlace, KeyInit};
|
||||
use chacha20poly1305::{AeadCore, AeadInPlace, KeyInit, KeySizeUser};
|
||||
|
||||
pub use rosenpass_cipher_traits::algorithms::aead_xchacha20poly1305::{
|
||||
KEY_LEN, NONCE_LEN, TAG_LEN,
|
||||
};
|
||||
/// Implements the [`Aead`] and [`AeadXChaCha20Poly1305`] traits backed by the RustCrypto
|
||||
/// implementation.
|
||||
pub struct XChaCha20Poly1305;
|
||||
|
||||
impl Aead<KEY_LEN, NONCE_LEN, TAG_LEN> for XChaCha20Poly1305 {
|
||||
fn encrypt(
|
||||
&self,
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> Result<(), AeadError> {
|
||||
// The comparison looks complicated, but we need to do it this way to prevent
|
||||
// over/underflows.
|
||||
if ciphertext.len() < TAG_LEN || ciphertext.len() - TAG_LEN < plaintext.len() {
|
||||
return Err(AeadError::InvalidLengths);
|
||||
}
|
||||
|
||||
let (ct, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
|
||||
copy_slice(plaintext).to(ct);
|
||||
|
||||
let nonce = GenericArray::from_slice(nonce);
|
||||
|
||||
// This only fails if the length is wrong, which really shouldn't happen and would
|
||||
// constitute an internal error.
|
||||
let encrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
|
||||
|
||||
let mac_value = encrypter
|
||||
.encrypt_in_place_detached(nonce, ad, ct)
|
||||
.map_err(|_| AeadError::InternalError)?;
|
||||
copy_slice(&mac_value[..]).to(mac);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decrypt(
|
||||
&self,
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> Result<(), AeadError> {
|
||||
// The comparison looks complicated, but we need to do it this way to prevent
|
||||
// over/underflows.
|
||||
if ciphertext.len() < TAG_LEN || ciphertext.len() - TAG_LEN < plaintext.len() {
|
||||
return Err(AeadError::InvalidLengths);
|
||||
}
|
||||
|
||||
let (ct, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
|
||||
let nonce = GenericArray::from_slice(nonce);
|
||||
let tag = GenericArray::from_slice(mac);
|
||||
copy_slice(ct).to(plaintext);
|
||||
|
||||
// This only fails if the length is wrong, which really shouldn't happen and would
|
||||
// constitute an internal error.
|
||||
let decrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
|
||||
|
||||
decrypter
|
||||
.decrypt_in_place_detached(nonce, ad, plaintext, tag)
|
||||
.map_err(|_| AeadError::DecryptError)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl AeadXChaCha20Poly1305 for XChaCha20Poly1305 {}
|
||||
/// The key length is 32 bytes or 256 bits.
|
||||
pub const KEY_LEN: usize = typenum2const! { <AeadImpl as KeySizeUser>::KeySize };
|
||||
/// The MAC tag length is 16 bytes or 128 bits.
|
||||
pub const TAG_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::TagSize };
|
||||
/// The nonce length is 24 bytes or 192 bits.
|
||||
pub const NONCE_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::NonceSize };
|
||||
|
||||
/// Encrypts using XChaCha20Poly1305 as implemented in [RustCrypto](https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305).
|
||||
/// `key` and `nonce` MUST be chosen (pseudo-)randomly. The `key` slice MUST have a length of
|
||||
@@ -88,12 +23,12 @@ impl AeadXChaCha20Poly1305 for XChaCha20Poly1305 {}
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::rust_crypto::xchacha20poly1305_ietf::{encrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
|
||||
/// # use rosenpass_ciphers::subtle::xchacha20poly1305_ietf::{encrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
|
||||
/// const PLAINTEXT_LEN: usize = 43;
|
||||
/// let plaintext = "post-quantum cryptography is very important".as_bytes();
|
||||
/// assert_eq!(PLAINTEXT_LEN, plaintext.len());
|
||||
/// let key: &[u8; KEY_LEN] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
|
||||
/// let nonce: &[u8; NONCE_LEN] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
|
||||
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
|
||||
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
|
||||
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
|
||||
/// let mut ciphertext_buffer = [0u8; NONCE_LEN + PLAINTEXT_LEN + TAG_LEN];
|
||||
///
|
||||
@@ -109,14 +44,19 @@ impl AeadXChaCha20Poly1305 for XChaCha20Poly1305 {}
|
||||
#[inline]
|
||||
pub fn encrypt(
|
||||
ciphertext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
nonce: &[u8; NONCE_LEN],
|
||||
key: &[u8],
|
||||
nonce: &[u8],
|
||||
ad: &[u8],
|
||||
plaintext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
XChaCha20Poly1305
|
||||
.encrypt_with_nonce_in_ctxt(ciphertext, key, nonce, ad, plaintext)
|
||||
.map_err(anyhow::Error::from)
|
||||
let nonce = GenericArray::from_slice(nonce);
|
||||
let (n, ct_mac) = ciphertext.split_at_mut(NONCE_LEN);
|
||||
let (ct, mac) = ct_mac.split_at_mut(ct_mac.len() - TAG_LEN);
|
||||
copy_slice(nonce).to(n);
|
||||
copy_slice(plaintext).to(ct);
|
||||
let mac_value = AeadImpl::new_from_slice(key)?.encrypt_in_place_detached(nonce, ad, ct)?;
|
||||
copy_slice(&mac_value[..]).to(mac);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Decrypts a `ciphertext` and verifies the integrity of the `ciphertext` and the additional data
|
||||
@@ -131,7 +71,7 @@ pub fn encrypt(
|
||||
///
|
||||
/// # Examples
|
||||
///```rust
|
||||
/// # use rosenpass_ciphers::subtle::rust_crypto::xchacha20poly1305_ietf::{decrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
|
||||
/// # use rosenpass_ciphers::subtle::xchacha20poly1305_ietf::{decrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
|
||||
/// let ciphertext: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/// # 0, 0, 0, 0, 8, 241, 229, 253, 200, 81, 248, 30, 183, 149, 134, 168, 149, 87, 109, 49, 159, 108,
|
||||
/// # 206, 89, 51, 232, 232, 197, 163, 253, 254, 208, 73, 76, 253, 13, 247, 162, 133, 184, 177, 44,
|
||||
@@ -140,8 +80,8 @@ pub fn encrypt(
|
||||
/// const PLAINTEXT_LEN: usize = 43;
|
||||
/// assert_eq!(PLAINTEXT_LEN + TAG_LEN + NONCE_LEN, ciphertext.len());
|
||||
///
|
||||
/// let key: &[u8; KEY_LEN] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
|
||||
/// let nonce: &[u8; NONCE_LEN] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
|
||||
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
|
||||
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
|
||||
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
|
||||
/// let mut plaintext_buffer = [0u8; PLAINTEXT_LEN];
|
||||
///
|
||||
@@ -154,11 +94,15 @@ pub fn encrypt(
|
||||
#[inline]
|
||||
pub fn decrypt(
|
||||
plaintext: &mut [u8],
|
||||
key: &[u8; KEY_LEN],
|
||||
key: &[u8],
|
||||
ad: &[u8],
|
||||
ciphertext: &[u8],
|
||||
) -> anyhow::Result<()> {
|
||||
XChaCha20Poly1305
|
||||
.decrypt_with_nonce_in_ctxt(plaintext, key, ad, ciphertext)
|
||||
.map_err(anyhow::Error::from)
|
||||
let (n, ct_mac) = ciphertext.split_at(NONCE_LEN);
|
||||
let (ct, mac) = ct_mac.split_at(ct_mac.len() - TAG_LEN);
|
||||
let nonce = GenericArray::from_slice(n);
|
||||
let tag = GenericArray::from_slice(mac);
|
||||
copy_slice(ct).to(plaintext);
|
||||
AeadImpl::new_from_slice(key)?.decrypt_in_place_detached(nonce, ad, plaintext, tag)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -8,7 +8,6 @@ description = "Rosenpass internal utilities for constant time crypto implementat
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -20,7 +19,7 @@ rosenpass-to = { workspace = true }
|
||||
memsec = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { workspace = true }
|
||||
rand = "0.8.5"
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(coverage)'] }
|
||||
|
||||
@@ -32,11 +32,8 @@ pub fn memcmp(a: &[u8], b: &[u8]) -> bool {
|
||||
/// For discussion on how to (further) ensure the constant-time execution of this function,
|
||||
/// see <https://github.com/rosenpass/rosenpass/issues/232>
|
||||
#[cfg(all(test, feature = "constant_time_tests"))]
|
||||
// Stopgap measure against https://github.com/rosenpass/rosenpass/issues/634
|
||||
#[cfg(not(all(target_os = "macos", target_arch = "aarch64")))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use core::hint::black_box;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use std::time::Instant;
|
||||
@@ -53,12 +50,14 @@ mod tests {
|
||||
fn memcmp_runs_in_constant_time() {
|
||||
// prepare data to compare
|
||||
let n: usize = 1E6 as usize; // number of comparisons to run
|
||||
const LEN: usize = 1024; // length of each slice passed as parameters to the tested comparison function
|
||||
let len = 1024; // length of each slice passed as parameters to the tested comparison function
|
||||
let a1 = "a".repeat(len);
|
||||
let a2 = a1.clone();
|
||||
let b = "b".repeat(len);
|
||||
|
||||
let a = [b'a'; LEN];
|
||||
let b = [b'b'; LEN];
|
||||
|
||||
let mut tmp = [0u8; LEN];
|
||||
let a1 = a1.as_bytes();
|
||||
let a2 = a2.as_bytes();
|
||||
let b = b.as_bytes();
|
||||
|
||||
// vector representing all timing tests
|
||||
//
|
||||
@@ -72,14 +71,12 @@ mod tests {
|
||||
|
||||
// run comparisons / call function to test
|
||||
for test in tests.iter_mut() {
|
||||
let src = match test.0 {
|
||||
true => a,
|
||||
false => b,
|
||||
};
|
||||
tmp.copy_from_slice(&src);
|
||||
|
||||
let now = Instant::now();
|
||||
memcmp(black_box(&a), black_box(&tmp));
|
||||
if test.0 {
|
||||
memcmp(a1, a2);
|
||||
} else {
|
||||
memcmp(a1, b);
|
||||
}
|
||||
test.1 = now.elapsed();
|
||||
// println!("eq: {}, elapsed: {:.2?}", test.0, test.1);
|
||||
}
|
||||
@@ -120,6 +117,6 @@ mod tests {
|
||||
assert!(
|
||||
correlation.abs() < 0.01,
|
||||
"execution time correlates with result"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
121
deny.toml
121
deny.toml
@@ -1,121 +0,0 @@
|
||||
# The graph table configures how the dependency graph is constructed and thus
|
||||
# which crates the checks are performed against
|
||||
[graph]
|
||||
# If true, metadata will be collected with `--all-features`. Note that this can't
|
||||
# be toggled off if true, if you want to conditionally enable `--all-features` it
|
||||
# is recommended to pass `--all-features` on the cmd line instead
|
||||
all-features = true
|
||||
# If true, metadata will be collected with `--no-default-features`. The same
|
||||
# caveat with `all-features` applies
|
||||
no-default-features = false
|
||||
|
||||
# The output table provides options for how/if diagnostics are outputted
|
||||
[output]
|
||||
# When outputting inclusion graphs in diagnostics that include features, this
|
||||
# option can be used to specify the depth at which feature edges will be added.
|
||||
# This option is included since the graphs can be quite large and the addition
|
||||
# of features from the crate(s) to all of the graph roots can be far too verbose.
|
||||
# This option can be overridden via `--feature-depth` on the cmd line
|
||||
feature-depth = 1
|
||||
|
||||
# This section is considered when running `cargo deny check advisories`
|
||||
# More documentation for the advisories section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
|
||||
[advisories]
|
||||
# A list of advisory IDs to ignore. Note that ignored advisories will still
|
||||
# output a note when they are encountered.
|
||||
ignore = ["RUSTSEC-2024-0370", "RUSTSEC-2024-0436", "RUSTSEC-2023-0089"]
|
||||
# If this is true, then cargo deny will use the git executable to fetch advisory database.
|
||||
# If this is false, then it uses a built-in git library.
|
||||
# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support.
|
||||
# See Git Authentication for more information about setting up git authentication.
|
||||
#git-fetch-with-cli = true
|
||||
|
||||
# This section is considered when running `cargo deny check #licenses`
|
||||
# More documentation for the licenses section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
|
||||
[licenses]
|
||||
# List of explicitly allowed licenses
|
||||
# See https://spdx.org/licenses/ for list of possible licenses
|
||||
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
|
||||
allow = [
|
||||
"MIT",
|
||||
"Apache-2.0",
|
||||
"Apache-2.0 WITH LLVM-exception",
|
||||
"BSD-3-Clause",
|
||||
"ISC",
|
||||
]
|
||||
# The confidence threshold for detecting a license from license text.
|
||||
# The higher the value, the more closely the license text must be to the
|
||||
# canonical license text of a valid SPDX license file.
|
||||
# [possible values: any between 0.0 and 1.0].
|
||||
confidence-threshold = 0.8
|
||||
# Allow 1 or more licenses on a per-crate basis, so that particular licenses
|
||||
# aren't accepted for every possible crate as with the normal allow list
|
||||
exceptions = [
|
||||
# Each entry is the crate and version constraint, and its specific allow
|
||||
# list
|
||||
{ allow = ["Unicode-DFS-2016", "Unicode-3.0"], crate = "unicode-ident" },
|
||||
{ allow = ["NCSA"], crate = "libfuzzer-sys" },
|
||||
|
||||
]
|
||||
|
||||
[licenses.private]
|
||||
# If true, ignores workspace crates that aren't published, or are only
|
||||
# published to private registries.
|
||||
# To see how to mark a crate as unpublished (to the official registry),
|
||||
# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field.
|
||||
ignore = true
|
||||
|
||||
# This section is considered when running `cargo deny check bans`.
|
||||
# More documentation about the 'bans' section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
|
||||
[bans]
|
||||
# Lint level for when multiple versions of the same crate are detected
|
||||
multiple-versions = "warn"
|
||||
# Lint level for when a crate version requirement is `*`
|
||||
wildcards = "allow"
|
||||
# The graph highlighting used when creating dotgraphs for crates
|
||||
# with multiple versions
|
||||
# * lowest-version - The path to the lowest versioned duplicate is highlighted
|
||||
# * simplest-path - The path to the version with the fewest edges is highlighted
|
||||
# * all - Both lowest-version and simplest-path are used
|
||||
highlight = "all"
|
||||
# The default lint level for `default` features for crates that are members of
|
||||
# the workspace that is being checked. This can be overridden by allowing/denying
|
||||
# `default` on a crate-by-crate basis if desired.
|
||||
workspace-default-features = "allow"
|
||||
# The default lint level for `default` features for external crates that are not
|
||||
# members of the workspace. This can be overridden by allowing/denying `default`
|
||||
# on a crate-by-crate basis if desired.
|
||||
external-default-features = "allow"
|
||||
# List of crates that are allowed. Use with care!
|
||||
allow = []
|
||||
# List of crates to deny
|
||||
deny = []
|
||||
|
||||
skip-tree = []
|
||||
|
||||
# This section is considered when running `cargo deny check sources`.
|
||||
# More documentation about the 'sources' section can be found here:
|
||||
# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
|
||||
[sources]
|
||||
# Lint level for what to happen when a crate from a crate registry that is not
|
||||
# in the allow list is encountered
|
||||
unknown-registry = "warn"
|
||||
# Lint level for what to happen when a crate from a git repository that is not
|
||||
# in the allow list is encountered
|
||||
unknown-git = "warn"
|
||||
# List of URLs for allowed crate registries. Defaults to the crates.io index
|
||||
# if not specified. If it is specified but empty, no registries are allowed.
|
||||
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
|
||||
# List of URLs for allowed Git repositories
|
||||
allow-git = ["git+https://github.com/rosenpass/memsec.git?branch=master"]
|
||||
|
||||
[sources.allow-org]
|
||||
# github.com organizations to allow git sources for
|
||||
github = []
|
||||
# gitlab.com organizations to allow git sources for
|
||||
gitlab = []
|
||||
# bitbucket.org organizations to allow git sources for
|
||||
bitbucket = []
|
||||
@@ -1,45 +0,0 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
ARG BASE_IMAGE=debian:bookworm-slim
|
||||
|
||||
# Stage 1: Base image with cargo-chef installed
|
||||
FROM rust:latest AS chef
|
||||
RUN cargo install cargo-chef
|
||||
# install software required for liboqs-rust
|
||||
RUN apt-get update && apt-get install -y clang cmake && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Stage 2: Prepare the cargo-chef recipe
|
||||
FROM chef AS planner
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN cargo chef prepare --recipe-path recipe.json
|
||||
|
||||
# Stage 3: Cache dependencies using the recipe
|
||||
FROM chef AS cacher
|
||||
WORKDIR /app
|
||||
COPY --from=planner /app/recipe.json recipe.json
|
||||
RUN cargo chef cook --release --recipe-path recipe.json
|
||||
|
||||
# Stage 4: Build the application
|
||||
FROM cacher AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN cargo build --release
|
||||
|
||||
# Stage 5: Install runtime-dependencies in the base image
|
||||
FROM ${BASE_IMAGE} AS base_image_with_dependencies
|
||||
|
||||
RUN apt-get update && apt-get install -y iproute2 && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Final Stage (rosenpass): Copy the rosenpass binary
|
||||
FROM base_image_with_dependencies AS rosenpass
|
||||
COPY --from=builder /app/target/release/rosenpass /usr/local/bin/rosenpass
|
||||
ENTRYPOINT [ "/usr/local/bin/rosenpass" ]
|
||||
|
||||
# Final Stage (rp): Copy the rp binary
|
||||
FROM base_image_with_dependencies AS rp
|
||||
|
||||
RUN apt-get update && apt-get install -y wireguard && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=builder /app/target/release/rp /usr/local/bin/rp
|
||||
ENTRYPOINT [ "/usr/local/bin/rp" ]
|
||||
203
docker/USAGE.md
203
docker/USAGE.md
@@ -1,203 +0,0 @@
|
||||
# Rosenpass in Docker
|
||||
|
||||
Rosenpass provides post-quantum-secure key exchange for VPNs. It generates symmetric keys used by [WireGuard](https://www.wireguard.com/papers/wireguard.pdf) or other applications. The protocol enhances "Post-Quantum WireGuard" ([PQWG](https://eprint.iacr.org/2020/379)) with a cookie mechanism for better security against state disruption attacks.
|
||||
|
||||
Prebuilt Docker images are available for easy deployment:
|
||||
|
||||
- [`ghcr.io/rosenpass/rosenpass`](https://github.com/rosenpass/rosenpass/pkgs/container/rosenpass) – the core key exchange tool
|
||||
- [`ghcr.io/rosenpass/rp`](https://github.com/rosenpass/rosenpass/pkgs/container/rp) – a frontend for setting up WireGuard VPNs
|
||||
|
||||
The entrypoint of the `rosenpass` image is the `rosenpass` executable, whose documentation can be found [here](https://rosenpass.eu/docs/rosenpass-tool/manuals/rp_manual/).
|
||||
Similarly, the entrypoint of the `rp` image is the `rp` executable, with its documentation available [here](https://rosenpass.eu/docs/rosenpass-tool/manuals/rp1/).
|
||||
|
||||
## Usage - Standalone Key Exchange
|
||||
|
||||
The `ghcr.io/rosenpass/rosenpass` image can be used in a server-client setup to exchange quantum-secure shared keys.
|
||||
This setup uses rosenpass as a standalone application, without using any other component such as wireguard.
|
||||
What follows, is a simple setup for illustrative purposes.
|
||||
|
||||
Create a docker network that is used to connect the containers:
|
||||
|
||||
```bash
|
||||
docker network create -d bridge rp
|
||||
export NET=rp
|
||||
```
|
||||
|
||||
Generate the server and client key pairs:
|
||||
|
||||
```bash
|
||||
mkdir ./workdir-client ./workdir-server
|
||||
docker run -it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rosenpass \
|
||||
gen-keys --public-key=workdir/server-public --secret-key=workdir/server-secret
|
||||
docker run -it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rosenpass \
|
||||
gen-keys --public-key=workdir/client-public --secret-key=workdir/client-secret
|
||||
# share the public keys between client and server
|
||||
cp workdir-client/client-public workdir-server/client-public
|
||||
cp workdir-server/server-public workdir-client/server-public
|
||||
```
|
||||
|
||||
Start the server container:
|
||||
|
||||
```bash
|
||||
docker run --name "rpserver" --network ${NET} \
|
||||
-it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rosenpass \
|
||||
exchange \
|
||||
private-key workdir/server-secret \
|
||||
public-key workdir/server-public \
|
||||
listen 0.0.0.0:9999 \
|
||||
peer public-key workdir/client-public \
|
||||
outfile workdir/server-sharedkey
|
||||
```
|
||||
|
||||
Find out the ip address of the server container:
|
||||
|
||||
```bash
|
||||
EP="rpserver"
|
||||
EP=$(docker inspect --format '{{ .NetworkSettings.Networks.rp.IPAddress }}' $EP)
|
||||
```
|
||||
|
||||
Run the client container and perform the key exchange:
|
||||
|
||||
```bash
|
||||
docker run --name "rpclient" --network ${NET} \
|
||||
-it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rosenpass \
|
||||
exchange \
|
||||
private-key workdir/client-secret \
|
||||
public-key workdir/client-public \
|
||||
peer public-key workdir/server-public endpoint ${EP}:9999 \
|
||||
outfile workdir/client-sharedkey
|
||||
```
|
||||
|
||||
Now the containers will exchange shared keys and each put them into their respective outfile.
|
||||
|
||||
Comparing the outfiles shows that these shared keys equal:
|
||||
|
||||
```bash
|
||||
cmp workdir-server/server-sharedkey workdir-client/client-sharedkey
|
||||
```
|
||||
|
||||
It is now possible to set add these keys as pre-shared keys within a wireguard interface.
|
||||
For example as the server,
|
||||
|
||||
```bash
|
||||
PREKEY=$(cat workdir-server/server-sharedkey)
|
||||
wg set <server-interface> peer <client-peer-public-key> preshared-key <(echo "$PREKEY")
|
||||
```
|
||||
|
||||
## Usage - Combined with wireguard
|
||||
|
||||
The `ghcr.io/rosenpass/rp` image can be used to build a VPN with WireGuard and Rosenpass.
|
||||
In this example, we run two containers on the same system and connect them with a bridge network within the docker overlay network.
|
||||
|
||||
Create the named docker network, to be able to connect the containers.
|
||||
|
||||
Create a docker network that is used to connect the containers:
|
||||
|
||||
```bash
|
||||
docker network create -d bridge rp
|
||||
export NET=rp
|
||||
```
|
||||
|
||||
Generate the server and client secret keys and extract public keys.
|
||||
|
||||
```bash
|
||||
mkdir -p ./workdir-server ./workdir-client
|
||||
|
||||
# server
|
||||
docker run -it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rp \
|
||||
genkey workdir/server.rosenpass-secret
|
||||
docker run -it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rp \
|
||||
pubkey workdir/server.rosenpass-secret workdir/server.rosenpass-public
|
||||
|
||||
# client
|
||||
docker run -it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rp \
|
||||
genkey workdir/client.rosenpass-secret
|
||||
docker run -it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rp \
|
||||
pubkey workdir/client.rosenpass-secret workdir/client.rosenpass-public
|
||||
|
||||
# share the public keys between client and server
|
||||
cp -r workdir-client/client.rosenpass-public workdir-server/client.rosenpass-public
|
||||
cp -r workdir-server/server.rosenpass-public workdir-client/server.rosenpass-public
|
||||
```
|
||||
|
||||
Start the server container.
|
||||
Note that the `NET_ADMIN` capability is neccessary, the rp command will create and manage wireguard interfaces.
|
||||
Also make sure the `wireguard` kernel module is loaded by the host. (`lsmod | grep wireguard`)
|
||||
|
||||
```bash
|
||||
docker run --name "rpserver" --network ${NET} -it -d --rm -v ./workdir-server:/workdir \
|
||||
--cap-add=NET_ADMIN \
|
||||
ghcr.io/rosenpass/rp \
|
||||
exchange workdir/server.rosenpass-secret dev rosenpass0 \
|
||||
listen 0.0.0.0:9999 peer workdir/client.rosenpass-public allowed-ips 10.0.0.0/8
|
||||
```
|
||||
|
||||
Now find out the ip-address of the server container and then start the client container:
|
||||
|
||||
```bash
|
||||
EP="rpserver"
|
||||
EP=$(docker inspect --format '{{ .NetworkSettings.Networks.rp.IPAddress }}' $EP)
|
||||
docker run --name "rpclient" --network ${NET} -it -d --rm -v ./workdir-client:/workdir \
|
||||
--cap-add=NET_ADMIN \
|
||||
ghcr.io/rosenpass/rp \
|
||||
exchange workdir/client.rosenpass-secret dev rosenpass1 \
|
||||
peer workdir/server.rosenpass-public endpoint ${EP}:9999 allowed-ips 10.0.0.1
|
||||
```
|
||||
|
||||
Inside the docker containers assign the IP addresses:
|
||||
|
||||
```bash
|
||||
# server
|
||||
docker exec -it rpserver ip a add 10.0.0.1/24 dev rosenpass0
|
||||
|
||||
# client
|
||||
docker exec -it rpclient ip a add 10.0.0.2/24 dev rosenpass1
|
||||
```
|
||||
|
||||
Done! The two containers should now be connected through a wireguard VPN (Port 1000) with pre-shared keys exchanged by rosenpass (Port 9999).
|
||||
|
||||
Now, test the connection by starting a shell inside the client container, and ping the server through the VPN:
|
||||
|
||||
```bash
|
||||
# client
|
||||
docker exec -it rpclient bash
|
||||
apt update; apt install iputils-ping
|
||||
ping 10.0.0.1
|
||||
```
|
||||
|
||||
The ping command should continuously show ping-logs:
|
||||
|
||||
```
|
||||
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
|
||||
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.119 ms
|
||||
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.132 ms
|
||||
64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=0.394 ms
|
||||
...
|
||||
```
|
||||
|
||||
While the ping is running, you may stop the server container, and verify that the ping-log halts. In another terminal do:
|
||||
|
||||
```
|
||||
docker stop -t 1 rpserver
|
||||
```
|
||||
|
||||
## Building the Docker Images Locally
|
||||
|
||||
Clone the Rosenpass repository:
|
||||
|
||||
```
|
||||
git clone https://github.com/rosenpass/rosenpass
|
||||
cd rosenpass
|
||||
```
|
||||
|
||||
Build the rp image from the root of the repository as follows:
|
||||
|
||||
```
|
||||
docker build -f docker/Dockerfile -t ghcr.io/rosenpass/rp --target rp .
|
||||
```
|
||||
|
||||
Build the rosenpass image from the root of the repostiry with the following command:
|
||||
|
||||
```
|
||||
docker build -f docker/Dockerfile -t ghcr.io/rosenpass/rosenpass --target rosenpass .
|
||||
```
|
||||
90
flake.lock
generated
90
flake.lock
generated
@@ -1,5 +1,26 @@
|
||||
{
|
||||
"nodes": {
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1728282832,
|
||||
"narHash": "sha256-I7AbcwGggf+CHqpyd/9PiAjpIBGTGx5woYHqtwxaV7I=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "1ec71be1f4b8f3105c5d38da339cb061fefc43f4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
@@ -18,26 +39,6 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-vm-test": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1734355073,
|
||||
"narHash": "sha256-FfdPOGy1zElTwKzjgIMp5K2D3gfPn6VWjVa4MJ9L1Tc=",
|
||||
"owner": "numtide",
|
||||
"repo": "nix-vm-test",
|
||||
"rev": "5948de39a616f2261dbbf4b6f25cbe1cbefd788c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "nix-vm-test",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1728193676,
|
||||
@@ -56,30 +57,25 @@
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"fenix": "fenix",
|
||||
"flake-utils": "flake-utils",
|
||||
"nix-vm-test": "nix-vm-test",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1744513456,
|
||||
"narHash": "sha256-NLVluTmK8d01Iz+WyarQhwFcXpHEwU7m5hH3YQQFJS0=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "730fd8e82799219754418483fabe1844262fd1e2",
|
||||
"lastModified": 1728249780,
|
||||
"narHash": "sha256-J269DvCI5dzBmPrXhAAtj566qt0b22TJtF3TIK+tMsI=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "2b750da1a1a2c1d2c70896108d7096089842d877",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
@@ -97,26 +93,6 @@
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1743748085,
|
||||
"narHash": "sha256-uhjnlaVTWo5iD3LXics1rp9gaKgDRQj6660+gbUU3cE=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "815e4121d6a5d504c0f96e5be2dd7f871e4fd99d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
||||
282
flake.nix
282
flake.nix
@@ -3,51 +3,37 @@
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
|
||||
nix-vm-test.url = "github:numtide/nix-vm-test";
|
||||
nix-vm-test.inputs.nixpkgs.follows = "nixpkgs";
|
||||
nix-vm-test.inputs.flake-utils.follows = "flake-utils";
|
||||
|
||||
# for rust nightly with llvm-tools-preview
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
rust-overlay.inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
|
||||
fenix.url = "github:nix-community/fenix";
|
||||
fenix.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
nix-vm-test,
|
||||
rust-overlay,
|
||||
treefmt-nix,
|
||||
...
|
||||
}@inputs:
|
||||
outputs = { self, nixpkgs, flake-utils, ... }@inputs:
|
||||
nixpkgs.lib.foldl (a: b: nixpkgs.lib.recursiveUpdate a b) { } [
|
||||
|
||||
|
||||
#
|
||||
### Export the overlay.nix from this flake ###
|
||||
#
|
||||
{ overlays.default = import ./overlay.nix; }
|
||||
{
|
||||
overlays.default = import ./overlay.nix;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
### Actual Rosenpass Package and Docker Container Images ###
|
||||
#
|
||||
(flake-utils.lib.eachSystem
|
||||
[
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
(flake-utils.lib.eachSystem [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
|
||||
# unsuported best-effort
|
||||
"i686-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-darwin"
|
||||
# "x86_64-windows"
|
||||
]
|
||||
(
|
||||
system:
|
||||
# unsuported best-effort
|
||||
"i686-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-darwin"
|
||||
# "x86_64-windows"
|
||||
]
|
||||
(system:
|
||||
let
|
||||
# normal nixpkgs
|
||||
pkgs = import nixpkgs {
|
||||
@@ -58,159 +44,115 @@
|
||||
};
|
||||
in
|
||||
{
|
||||
packages =
|
||||
{
|
||||
default = pkgs.rosenpass;
|
||||
rosenpass = pkgs.rosenpass;
|
||||
rosenpass-oci-image = pkgs.rosenpass-oci-image;
|
||||
rp = pkgs.rp;
|
||||
packages = {
|
||||
default = pkgs.rosenpass;
|
||||
rosenpass = pkgs.rosenpass;
|
||||
rosenpass-oci-image = pkgs.rosenpass-oci-image;
|
||||
rp = pkgs.rp;
|
||||
|
||||
release-package = pkgs.release-package;
|
||||
release-package = pkgs.release-package;
|
||||
|
||||
# for good measure, we also offer to cross compile to Linux on Arm
|
||||
aarch64-linux-rosenpass-static = pkgs.pkgsCross.aarch64-multiplatform.pkgsStatic.rosenpass;
|
||||
aarch64-linux-rp-static = pkgs.pkgsCross.aarch64-multiplatform.pkgsStatic.rp;
|
||||
}
|
||||
//
|
||||
# We only offer static builds for linux, as this is not supported on OS X
|
||||
(nixpkgs.lib.attrsets.optionalAttrs pkgs.stdenv.isLinux {
|
||||
rosenpass-static = pkgs.pkgsStatic.rosenpass;
|
||||
rosenpass-static-oci-image = pkgs.pkgsStatic.rosenpass-oci-image;
|
||||
rp-static = pkgs.pkgsStatic.rp;
|
||||
});
|
||||
# for good measure, we also offer to cross compile to Linux on Arm
|
||||
aarch64-linux-rosenpass-static =
|
||||
pkgs.pkgsCross.aarch64-multiplatform.pkgsStatic.rosenpass;
|
||||
aarch64-linux-rp-static = pkgs.pkgsCross.aarch64-multiplatform.pkgsStatic.rp;
|
||||
}
|
||||
//
|
||||
# We only offer static builds for linux, as this is not supported on OS X
|
||||
(nixpkgs.lib.attrsets.optionalAttrs pkgs.stdenv.isLinux {
|
||||
rosenpass-static = pkgs.pkgsStatic.rosenpass;
|
||||
rosenpass-static-oci-image = pkgs.pkgsStatic.rosenpass-oci-image;
|
||||
rp-static = pkgs.pkgsStatic.rp;
|
||||
});
|
||||
}
|
||||
)
|
||||
)
|
||||
))
|
||||
|
||||
|
||||
#
|
||||
### Linux specifics ###
|
||||
#
|
||||
(flake-utils.lib.eachSystem
|
||||
[
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
"i686-linux"
|
||||
]
|
||||
(
|
||||
system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
(flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
|
||||
overlays = [
|
||||
# apply our own overlay, overriding/inserting our packages as defined in ./pkgs
|
||||
self.overlays.default
|
||||
# apply our own overlay, overriding/inserting our packages as defined in ./pkgs
|
||||
overlays = [ self.overlays.default ];
|
||||
};
|
||||
in
|
||||
{
|
||||
|
||||
nix-vm-test.overlays.default
|
||||
#
|
||||
### Reading materials ###
|
||||
#
|
||||
packages.whitepaper = pkgs.whitepaper;
|
||||
|
||||
# apply rust-overlay to get specific versions of the rust toolchain for a MSRV check
|
||||
(import rust-overlay)
|
||||
];
|
||||
};
|
||||
#
|
||||
### Proof and Proof Tools ###
|
||||
#
|
||||
packages.proverif-patched = pkgs.proverif-patched;
|
||||
packages.proof-proverif = pkgs.proof-proverif;
|
||||
|
||||
treefmtEval = treefmt-nix.lib.evalModule pkgs ./treefmt.nix;
|
||||
in
|
||||
{
|
||||
packages.package-deb = pkgs.callPackage ./pkgs/package-deb.nix {
|
||||
rosenpass = pkgs.pkgsStatic.rosenpass;
|
||||
};
|
||||
packages.package-rpm = pkgs.callPackage ./pkgs/package-rpm.nix {
|
||||
rosenpass = pkgs.pkgsStatic.rosenpass;
|
||||
};
|
||||
|
||||
#
|
||||
### Reading materials ###
|
||||
#
|
||||
packages.whitepaper = pkgs.whitepaper;
|
||||
#
|
||||
### Devshells ###
|
||||
#
|
||||
devShells.default = pkgs.mkShell {
|
||||
inherit (pkgs.proof-proverif) CRYPTOVERIF_LIB;
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cargo-release
|
||||
clippy
|
||||
rustfmt
|
||||
nodePackages.prettier
|
||||
nushell # for the .ci/gen-workflow-files.nu script
|
||||
proverif-patched
|
||||
];
|
||||
};
|
||||
# TODO: Write this as a patched version of the default environment
|
||||
devShells.fullEnv = pkgs.mkShell {
|
||||
inherit (pkgs.proof-proverif) CRYPTOVERIF_LIB;
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cargo-release
|
||||
rustfmt
|
||||
nodePackages.prettier
|
||||
nushell # for the .ci/gen-workflow-files.nu script
|
||||
proverif-patched
|
||||
inputs.fenix.packages.${system}.complete.toolchain
|
||||
pkgs.cargo-llvm-cov
|
||||
pkgs.grcov
|
||||
];
|
||||
};
|
||||
devShells.coverage = pkgs.mkShell {
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = [
|
||||
inputs.fenix.packages.${system}.complete.toolchain
|
||||
pkgs.cargo-llvm-cov
|
||||
pkgs.grcov
|
||||
];
|
||||
};
|
||||
|
||||
#
|
||||
### Proof and Proof Tools ###
|
||||
#
|
||||
packages.proverif-patched = pkgs.proverif-patched;
|
||||
packages.proof-proverif = pkgs.proof-proverif;
|
||||
|
||||
#
|
||||
### Devshells ###
|
||||
#
|
||||
devShells.default = pkgs.mkShell {
|
||||
inherit (pkgs.proof-proverif) CRYPTOVERIF_LIB;
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cargo-release
|
||||
clippy
|
||||
rustfmt
|
||||
nodePackages.prettier
|
||||
nushell # for the .ci/gen-workflow-files.nu script
|
||||
proverif-patched
|
||||
];
|
||||
};
|
||||
# TODO: Write this as a patched version of the default environment
|
||||
devShells.fullEnv = pkgs.mkShell {
|
||||
inherit (pkgs.proof-proverif) CRYPTOVERIF_LIB;
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cargo-audit
|
||||
cargo-msrv
|
||||
cargo-release
|
||||
cargo-vet
|
||||
rustfmt
|
||||
nodePackages.prettier
|
||||
nushell # for the .ci/gen-workflow-files.nu script
|
||||
proverif-patched
|
||||
pkgs.cargo-llvm-cov
|
||||
pkgs.grcov
|
||||
pkgs.rust-bin.stable.latest.complete
|
||||
];
|
||||
};
|
||||
devShells.coverage = pkgs.mkShell {
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = [
|
||||
pkgs.cargo-llvm-cov
|
||||
pkgs.grcov
|
||||
pkgs.rustc.llvmPackages.llvm
|
||||
];
|
||||
env = {
|
||||
inherit (pkgs.cargo-llvm-cov) LLVM_COV LLVM_PROFDATA;
|
||||
};
|
||||
};
|
||||
devShells.benchmarks = pkgs.mkShell {
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cargo-release
|
||||
clippy
|
||||
rustfmt
|
||||
];
|
||||
};
|
||||
checks = {
|
||||
systemd-rosenpass = pkgs.testers.runNixOSTest ./tests/systemd/rosenpass.nix;
|
||||
systemd-rp = pkgs.testers.runNixOSTest ./tests/systemd/rp.nix;
|
||||
|
||||
checks =
|
||||
{
|
||||
systemd-rosenpass = pkgs.testers.runNixOSTest ./tests/systemd/rosenpass.nix;
|
||||
systemd-rp = pkgs.testers.runNixOSTest ./tests/systemd/rp.nix;
|
||||
formatting = treefmtEval.config.build.check self;
|
||||
rosenpass-msrv-check =
|
||||
let
|
||||
rosenpassCargoToml = pkgs.lib.trivial.importTOML ./rosenpass/Cargo.toml;
|
||||
cargo-fmt = pkgs.runCommand "check-cargo-fmt"
|
||||
{ inherit (self.devShells.${system}.default) nativeBuildInputs buildInputs; } ''
|
||||
cargo fmt --manifest-path=${./.}/Cargo.toml --check --all && touch $out
|
||||
'';
|
||||
nixpkgs-fmt = pkgs.runCommand "check-nixpkgs-fmt"
|
||||
{ nativeBuildInputs = [ pkgs.nixpkgs-fmt ]; } ''
|
||||
nixpkgs-fmt --check ${./.} && touch $out
|
||||
'';
|
||||
prettier-check = pkgs.runCommand "check-with-prettier"
|
||||
{ nativeBuildInputs = [ pkgs.nodePackages.prettier ]; } ''
|
||||
cd ${./.} && prettier --check . && touch $out
|
||||
'';
|
||||
};
|
||||
|
||||
rustToolchain = pkgs.rust-bin.stable.${rosenpassCargoToml.package.rust-version}.default;
|
||||
rustPlatform = pkgs.makeRustPlatform {
|
||||
cargo = rustToolchain;
|
||||
rustc = rustToolchain;
|
||||
};
|
||||
in
|
||||
pkgs.rosenpass.override { inherit rustPlatform; };
|
||||
}
|
||||
// pkgs.lib.optionalAttrs (system == "x86_64-linux") (
|
||||
import ./tests/legacy-distro-packaging.nix {
|
||||
inherit pkgs;
|
||||
rosenpass-deb = self.packages.${system}.package-deb;
|
||||
rosenpass-rpm = self.packages.${system}.package-rpm;
|
||||
}
|
||||
);
|
||||
|
||||
# for `nix fmt`
|
||||
formatter = treefmtEval.config.build.wrapper;
|
||||
}
|
||||
)
|
||||
)
|
||||
formatter = pkgs.nixpkgs-fmt;
|
||||
}))
|
||||
];
|
||||
}
|
||||
|
||||
@@ -3,10 +3,9 @@ name = "rosenpass-fuzzing"
|
||||
version = "0.0.1"
|
||||
publish = false
|
||||
edition = "2021"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[features]
|
||||
experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux_all"]
|
||||
experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux"]
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
@@ -4,8 +4,7 @@ extern crate rosenpass;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Aead as _;
|
||||
use rosenpass_ciphers::Aead;
|
||||
use rosenpass_ciphers::aead;
|
||||
|
||||
#[derive(arbitrary::Arbitrary, Debug)]
|
||||
pub struct Input {
|
||||
@@ -18,7 +17,7 @@ pub struct Input {
|
||||
fuzz_target!(|input: Input| {
|
||||
let mut ciphertext = vec![0u8; input.plaintext.len() + 16];
|
||||
|
||||
Aead.encrypt(
|
||||
aead::encrypt(
|
||||
ciphertext.as_mut_slice(),
|
||||
&input.key,
|
||||
&input.nonce,
|
||||
|
||||
@@ -4,7 +4,6 @@ extern crate rosenpass;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use rosenpass_cipher_traits::primitives::KeyedHashTo;
|
||||
use rosenpass_ciphers::subtle::blake2b;
|
||||
use rosenpass_to::To;
|
||||
|
||||
@@ -17,7 +16,5 @@ pub struct Blake2b {
|
||||
fuzz_target!(|input: Blake2b| {
|
||||
let mut out = [0u8; 32];
|
||||
|
||||
blake2b::Blake2b::keyed_hash_to(&input.key, &input.data)
|
||||
.to(&mut out)
|
||||
.unwrap();
|
||||
blake2b::hash(&input.key, &input.data).to(&mut out).unwrap();
|
||||
});
|
||||
|
||||
@@ -4,8 +4,8 @@ extern crate rosenpass;
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use rosenpass::protocol::CryptoServer;
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_ciphers::kem::StaticKem;
|
||||
use rosenpass_secret_memory::policy::*;
|
||||
use rosenpass_secret_memory::{PublicBox, Secret};
|
||||
use std::sync::Once;
|
||||
|
||||
@@ -4,8 +4,8 @@ extern crate rosenpass;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::EphemeralKem;
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_ciphers::kem::EphemeralKem;
|
||||
|
||||
#[derive(arbitrary::Arbitrary, Debug)]
|
||||
pub struct Input {
|
||||
@@ -16,7 +16,5 @@ fuzz_target!(|input: Input| {
|
||||
let mut ciphertext = [0u8; EphemeralKem::CT_LEN];
|
||||
let mut shared_secret = [0u8; EphemeralKem::SHK_LEN];
|
||||
|
||||
EphemeralKem
|
||||
.encaps(&mut shared_secret, &mut ciphertext, &input.pk)
|
||||
.unwrap();
|
||||
EphemeralKem::encaps(&mut shared_secret, &mut ciphertext, &input.pk).unwrap();
|
||||
});
|
||||
|
||||
@@ -3,13 +3,13 @@ extern crate rosenpass;
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_ciphers::kem::StaticKem;
|
||||
|
||||
fuzz_target!(|input: [u8; StaticKem::PK_LEN]| {
|
||||
let mut ciphertext = [0u8; StaticKem::CT_LEN];
|
||||
let mut shared_secret = [0u8; StaticKem::SHK_LEN];
|
||||
|
||||
// We expect errors while fuzzing therefore we do not check the result.
|
||||
let _ = StaticKem.encaps(&mut shared_secret, &mut ciphertext, &input);
|
||||
let _ = StaticKem::encaps(&mut shared_secret, &mut ciphertext, &input);
|
||||
});
|
||||
|
||||
@@ -8,7 +8,6 @@ description = "Rosenpass internal bindings to liboqs"
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[dependencies]
|
||||
rosenpass-cipher-traits = { workspace = true }
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
/// Generate bindings to a liboqs-provided KEM
|
||||
macro_rules! oqs_kem {
|
||||
($name:ident, $algo_trait:path) => { ::paste::paste!{
|
||||
($name:ident) => { ::paste::paste!{
|
||||
#[doc = "Bindings for ::oqs_sys::kem::" [<"OQS_KEM" _ $name:snake>] "_*"]
|
||||
mod [< $name:snake >] {
|
||||
use rosenpass_cipher_traits::primitives::{Kem, KemError};
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_util::result::Guaranteed;
|
||||
|
||||
#[doc = "Bindings for ::oqs_sys::kem::" [<"OQS_KEM" _ $name:snake>] "_*"]
|
||||
#[doc = ""]
|
||||
@@ -13,7 +14,7 @@ macro_rules! oqs_kem {
|
||||
#[doc = ""]
|
||||
#[doc = "```rust"]
|
||||
#[doc = "use std::borrow::{Borrow, BorrowMut};"]
|
||||
#[doc = "use rosenpass_cipher_traits::primitives::Kem;"]
|
||||
#[doc = "use rosenpass_cipher_traits::Kem;"]
|
||||
#[doc = "use rosenpass_oqs::" $name:camel " as MyKem;"]
|
||||
#[doc = "use rosenpass_secret_memory::{Secret, Public};"]
|
||||
#[doc = ""]
|
||||
@@ -22,26 +23,21 @@ macro_rules! oqs_kem {
|
||||
#[doc = "// Recipient generates secret key, transfers pk to sender"]
|
||||
#[doc = "let mut sk = Secret::<{ MyKem::SK_LEN }>::zero();"]
|
||||
#[doc = "let mut pk = Public::<{ MyKem::PK_LEN }>::zero();"]
|
||||
#[doc = "MyKem.keygen(sk.secret_mut(), &mut pk);"]
|
||||
#[doc = "MyKem::keygen(sk.secret_mut(), pk.borrow_mut());"]
|
||||
#[doc = ""]
|
||||
#[doc = "// Sender generates ciphertext and local shared key, sends ciphertext to recipient"]
|
||||
#[doc = "let mut shk_enc = Secret::<{ MyKem::SHK_LEN }>::zero();"]
|
||||
#[doc = "let mut ct = Public::<{ MyKem::CT_LEN }>::zero();"]
|
||||
#[doc = "MyKem.encaps(shk_enc.secret_mut(), &mut ct, &pk);"]
|
||||
#[doc = "MyKem::encaps(shk_enc.secret_mut(), ct.borrow_mut(), pk.borrow());"]
|
||||
#[doc = ""]
|
||||
#[doc = "// Recipient decapsulates ciphertext"]
|
||||
#[doc = "let mut shk_dec = Secret::<{ MyKem::SHK_LEN }>::zero();"]
|
||||
#[doc = "MyKem.decaps(shk_dec.secret_mut(), sk.secret_mut(), &ct);"]
|
||||
#[doc = "MyKem::decaps(shk_dec.secret_mut(), sk.secret(), ct.borrow());"]
|
||||
#[doc = ""]
|
||||
#[doc = "// Both parties end up with the same shared key"]
|
||||
#[doc = "assert!(rosenpass_constant_time::compare(shk_enc.secret(), shk_dec.secret()) == 0);"]
|
||||
#[doc = "assert!(rosenpass_constant_time::compare(shk_enc.secret_mut(), shk_dec.secret_mut()) == 0);"]
|
||||
#[doc = "```"]
|
||||
pub struct [< $name:camel >];
|
||||
|
||||
pub const SK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_secret_key >] as usize;
|
||||
pub const PK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_public_key >] as usize;
|
||||
pub const CT_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_ciphertext >] as usize;
|
||||
pub const SHK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_shared_secret >] as usize;
|
||||
pub enum [< $name:camel >] {}
|
||||
|
||||
/// # Panic & Safety
|
||||
///
|
||||
@@ -55,8 +51,17 @@ macro_rules! oqs_kem {
|
||||
/// to only check that the buffers are big enough, allowing them to be even
|
||||
/// bigger. However, from a correctness point of view it does not make sense to
|
||||
/// allow bigger buffers.
|
||||
impl Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> for [< $name:camel >] {
|
||||
fn keygen(&self, sk: &mut [u8; SK_LEN], pk: &mut [u8; PK_LEN]) -> Result<(), KemError> {
|
||||
impl Kem for [< $name:camel >] {
|
||||
type Error = ::std::convert::Infallible;
|
||||
|
||||
const SK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_secret_key >] as usize;
|
||||
const PK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_public_key >] as usize;
|
||||
const CT_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_ciphertext >] as usize;
|
||||
const SHK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_shared_secret >] as usize;
|
||||
|
||||
fn keygen(sk: &mut [u8], pk: &mut [u8]) -> Guaranteed<()> {
|
||||
assert_eq!(sk.len(), Self::SK_LEN);
|
||||
assert_eq!(pk.len(), Self::PK_LEN);
|
||||
unsafe {
|
||||
oqs_call!(
|
||||
::oqs_sys::kem::[< OQS_KEM _ $name:snake _ keypair >],
|
||||
@@ -68,7 +73,10 @@ macro_rules! oqs_kem {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn encaps(&self, shk: &mut [u8; SHK_LEN], ct: &mut [u8; CT_LEN], pk: &[u8; PK_LEN]) -> Result<(), KemError> {
|
||||
fn encaps(shk: &mut [u8], ct: &mut [u8], pk: &[u8]) -> Guaranteed<()> {
|
||||
assert_eq!(shk.len(), Self::SHK_LEN);
|
||||
assert_eq!(ct.len(), Self::CT_LEN);
|
||||
assert_eq!(pk.len(), Self::PK_LEN);
|
||||
unsafe {
|
||||
oqs_call!(
|
||||
::oqs_sys::kem::[< OQS_KEM _ $name:snake _ encaps >],
|
||||
@@ -81,7 +89,10 @@ macro_rules! oqs_kem {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decaps(&self, shk: &mut [u8; SHK_LEN], sk: &[u8; SK_LEN], ct: &[u8; CT_LEN]) -> Result<(), KemError> {
|
||||
fn decaps(shk: &mut [u8], sk: &[u8], ct: &[u8]) -> Guaranteed<()> {
|
||||
assert_eq!(shk.len(), Self::SHK_LEN);
|
||||
assert_eq!(sk.len(), Self::SK_LEN);
|
||||
assert_eq!(ct.len(), Self::CT_LEN);
|
||||
unsafe {
|
||||
oqs_call!(
|
||||
::oqs_sys::kem::[< OQS_KEM _ $name:snake _ decaps >],
|
||||
@@ -94,16 +105,9 @@ macro_rules! oqs_kem {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for [< $name:camel >] {
|
||||
fn default() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl $algo_trait for [< $name:camel >] {}
|
||||
|
||||
pub use [< $name:snake >] :: [< $name:camel >];
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,5 @@ macro_rules! oqs_call {
|
||||
|
||||
#[macro_use]
|
||||
mod kem_macro;
|
||||
oqs_kem!(kyber_512, rosenpass_cipher_traits::algorithms::KemKyber512);
|
||||
oqs_kem!(
|
||||
classic_mceliece_460896,
|
||||
rosenpass_cipher_traits::algorithms::KemClassicMceliece460896
|
||||
);
|
||||
oqs_kem!(kyber_512);
|
||||
oqs_kem!(classic_mceliece_460896);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
final: prev: {
|
||||
|
||||
|
||||
#
|
||||
### Actual rosenpass software ###
|
||||
#
|
||||
@@ -26,10 +27,7 @@ final: prev: {
|
||||
"marzipan(/marzipan.awk)?"
|
||||
"analysis(/.*)?"
|
||||
];
|
||||
nativeBuildInputs = [
|
||||
final.proverif
|
||||
final.graphviz
|
||||
];
|
||||
nativeBuildInputs = [ final.proverif final.graphviz ];
|
||||
CRYPTOVERIF_LIB = final.proverif-patched + "/lib/cryptoverif.pvl";
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
|
||||
@@ -196,13 +196,3 @@ Vadim Lyubashevsky and John M. Schanck and Peter Schwabe and Gregor Seiler and D
|
||||
type = {NIST Post-Quantum Cryptography Selected Algorithm},
|
||||
url = {https://pq-crystals.org/kyber/}
|
||||
}
|
||||
|
||||
|
||||
@misc{SHAKE256,
|
||||
author = "National Institute of Standards and Technology",
|
||||
title = "FIPS PUB 202: SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions",
|
||||
year = {2015},
|
||||
month = {August},
|
||||
doi = {10.6028/NIST.FIPS.202}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ abstract: |
|
||||
Rosenpass inherits most security properties from Post-Quantum WireGuard (PQWG). The security properties mentioned here are covered by the symbolic analysis in the Rosenpass repository.
|
||||
|
||||
## Secrecy
|
||||
Three key encapsulations using the keypairs `sski`/`spki`, `sskr`/`spkr`, and `eski`/`epki` provide secrecy (see Section \ref{variables} for an introduction of the variables). Their respective ciphertexts are called `scti`, `sctr`, and `ectr` and the resulting keys are called `spti`, `sptr`, `epti`. A single secure encapsulation is sufficient to provide secrecy. We use two different KEMs (Key Encapsulation Mechanisms; see Section \ref{skem}): Kyber and Classic McEliece.
|
||||
Three key encapsulations using the keypairs `sski`/`spki`, `sskr`/`spkr`, and `eski`/`epki` provide secrecy (see Section \ref{variables} for an introduction of the variables). Their respective ciphertexts are called `scti`, `sctr`, and `ectr` and the resulting keys are called `spti`, `sptr`, `epti`. A single secure encapsulation is sufficient to provide secrecy. We use two different KEMs (Key Encapsulation Mechanisms; see section \ref{skem}): Kyber and Classic McEliece.
|
||||
|
||||
## Authenticity
|
||||
|
||||
@@ -64,12 +64,9 @@ Note that while Rosenpass is secure against state disruption, using it does not
|
||||
All symmetric keys and hash values used in Rosenpass are 32 bytes long.
|
||||
|
||||
|
||||
### Hash {#hash}
|
||||
### Hash
|
||||
|
||||
A keyed hash function with one 32-byte input, one variable-size input, and one 32-byte output. As keyed hash function we offer two options that can be configured on a peer-basis, with Blake2s being the default:
|
||||
|
||||
1. the HMAC construction [@rfc_hmac] with BLAKE2s [@rfc_blake2] as the inner hash function.
|
||||
2. the SHAKE256 extendable output function (XOF) [@SHAKE256] truncated to a 32-byte output. The result is produced be concatenating the 32-byte input with the variable-size input in this order.
|
||||
A keyed hash function with one 32-byte input, one variable-size input, and one 32-byte output. As keyed hash function we use the HMAC construction [@rfc_hmac] with BLAKE2s [@rfc_blake2] as the inner hash function.
|
||||
|
||||
```pseudorust
|
||||
hash(key, data) -> key
|
||||
@@ -175,8 +172,6 @@ Rosenpass uses a cryptographic hash function for multiple purposes:
|
||||
* Key derivation during and after the handshake
|
||||
* Computing the additional data for the biscuit encryption, to provide some privacy for its contents
|
||||
|
||||
Recall from Section \ref{hash} that rosenpass supports using either BLAKE2s or SHAKE256 as hash function, which can be configured for each peer ID. However, as noted above, rosenpass uses a hash function to compute the peer ID and thus also to access the configuration for a peer ID. This is an issue when receiving an `InitHello`-message, because the correct hash function is not known when a responder receives this message and at the same the responders needs it in order to compute the peer ID and by that also identfy the hash function for that peer. The reference implementation resolves this issue by first trying to derive the peer ID using SHAKE256. If that does not work (i.e. leads to an AEAD decryption error), the reference implementation tries again with BLAKE2s. The reference implementation verifies that the hash function matches the one confgured for the peer. Similarly, if the correct peer ID is not cached when receiving an InitConf message, the reference implementation proceeds in the same manner.
|
||||
|
||||
Using one hash function for multiple purposes can cause real-world security issues and even key recovery attacks [@oraclecloning]. We choose a tree-based domain separation scheme based on a keyed hash function – the previously introduced primitive `hash` – to make sure all our hash function calls can be seen as distinct.
|
||||
|
||||
\setupimage{landscape,fullpage,label=img:HashingTree}
|
||||
@@ -184,13 +179,13 @@ Using one hash function for multiple purposes can cause real-world security issu
|
||||
|
||||
Each tree node $\circ{}$ in Figure 3 represents the application of the keyed hash function, using the previous chaining key value as first parameter. The root of the tree is the zero key. In level one, the `PROTOCOL` identifier is applied to the zero key to generate a label unique across cryptographic protocols (unless the same label is deliberately used elsewhere). In level two, purpose identifiers are applied to the protocol label to generate labels to use with each separate hash function application within the Rosenpass protocol. The following layers contain the inputs used in each separate usage of the hash function: Beneath the identifiers `"mac"`, `"cookie"`, `"peer id"`, and `"biscuit additional data"` are hash functions or message authentication codes with a small number of inputs. The second, third, and fourth column in Figure 3 cover the long sequential branch beneath the identifier `"chaining key init"` representing the entire protocol execution, one column for each message processed during the handshake. The leaves beneath `"chaining key extract"` in the left column represent pseudo-random labels for use when extracting values from the chaining key during the protocol execution. These values such as `mix >` appear as outputs in the left column, and then as inputs `< mix` in the other three columns.
|
||||
|
||||
The protocol identifier depends on the hash function used with the respective peer is defined as follows if BLAKE2s [@rfc_blake2] is used:
|
||||
The protocol identifier is defined as follows:
|
||||
|
||||
```pseudorust
|
||||
PROTOCOL = "rosenpass 1 rosenpass.eu aead=chachapoly1305 hash=blake2s ekem=kyber512 skem=mceliece460896 xaead=xchachapoly1305"
|
||||
```
|
||||
|
||||
If SHAKE256 [@SHAKE256] is used, `blake2s` is replaced by `shake256` in `PROTOCOL`. Since every tree node represents a sequence of `hash` calls, the node beneath `"handshake encryption"` called `hs_enc` can be written as follows:
|
||||
Since every tree node represents a sequence of `hash` calls, the node beneath `"handshake encryption"` called `hs_enc` can be written as follows:
|
||||
|
||||
```pseudorust
|
||||
hs_enc = hash(hash(hash(0, PROTOCOL), "chaining key extract"), "handshake encryption")
|
||||
@@ -238,7 +233,6 @@ For each peer, the server stores:
|
||||
* `psk` – The pre-shared key used with the peer
|
||||
* `spkt` – The peer's public key
|
||||
* `biscuit_used` – The `biscuit_no` from the last biscuit accepted for the peer as part of InitConf processing
|
||||
* `hash_function` – The hash function, SHAKE256 or BLAKE2s, used with the peer.
|
||||
|
||||
### Handshake State and Biscuits
|
||||
|
||||
@@ -458,14 +452,14 @@ For an initiator, Rosenpass ignores all messages when under load.
|
||||
|
||||
#### Cookie Reply Message
|
||||
|
||||
The cookie reply message is sent by the responder on receiving an InitHello message when under load. It consists of the `sidi` of the initiator, a random 24-byte bitstring `nonce` and encrypting `cookie_value` into a `cookie_encrypted` reply field, which consists of the following:
|
||||
The cookie reply message is sent by the responder on receiving an InitHello message when under load. It consists of the `sidi` of the initiator, a random 24-byte bitstring `nonce` and encrypting `cookie_value` into a `cookie_encrypted` reply field which consists of the following:
|
||||
|
||||
```pseudorust
|
||||
cookie_value = lhash("cookie-value", cookie_secret, initiator_host_info)[0..16]
|
||||
cookie_encrypted = XAEAD(lhash("cookie-key", spkm), nonce, cookie_value, mac_peer)
|
||||
```
|
||||
|
||||
where `cookie_secret` is a secret variable that changes every two minutes to a random value. Moreover, `lhash` is always instantiated with SHAKE256 when computing `cookie_value` for compatability reasons. `initiator_host_info` is used to identify the initiator host, and is implementation-specific for the client. This paramaters used to identify the host must be carefully chosen to ensure there is a unique mapping, especially when using IPv4 and IPv6 addresses to identify the host (such as taking care of IPv6 link-local addresses). `cookie_value` is a truncated 16 byte value from the above hash operation. `mac_peer` is the `mac` field of the peer's handshake message to which message is the reply.
|
||||
where `cookie_secret` is a secret variable that changes every two minutes to a random value. `initiator_host_info` is used to identify the initiator host, and is implementation-specific for the client. This paramaters used to identify the host must be carefully chosen to ensure there is a unique mapping, especially when using IPv4 and IPv6 addresses to identify the host (such as taking care of IPv6 link-local addresses). `cookie_value` is a truncated 16 byte value from the above hash operation. `mac_peer` is the `mac` field of the peer's handshake message to which message is the reply.
|
||||
|
||||
#### Envelope `mac` Field
|
||||
|
||||
@@ -501,7 +495,7 @@ However, when the responder is under load, it may reject InitHello messages with
|
||||
|
||||
This whitepaper does not mandate any specific mechanism to detect responder contention (also mentioned as the under load condition) that would trigger use of the cookie mechanism.
|
||||
|
||||
For the reference implemenation, Rosenpass has derived inspiration from the Linux implementation of Wireguard. This implementation suggests that the reciever keep track of the number of messages it is processing at a given time.
|
||||
For the reference implemenation, Rosenpass has derived inspiration from the linux implementation of Wireguard. This implementation suggests that the reciever keep track of the number of messages it is processing at a given time.
|
||||
|
||||
On receiving an incoming message, if the length of the message queue to be processed exceeds a threshold `MAX_QUEUED_INCOMING_HANDSHAKES_THRESHOLD`, the client is considered under load and its state is stored as under load. In addition, the timestamp of this instant when the client was last under load is stored. When recieving subsequent messages, if the client is still in an under load state, the client will check if the time ellpased since the client was last under load has exceeded `LAST_UNDER_LOAD_WINDOW` seconds. If this is the case, the client will update its state to normal operation, and process the message in a normal fashion.
|
||||
|
||||
@@ -532,24 +526,6 @@ When the responder is under load and it recieves an InitConf message, the messag
|
||||
|
||||
### 0.3.x
|
||||
|
||||
#### 2025-05-22 - SHAKE256 keyed hash
|
||||
\vspace{0.5em}
|
||||
|
||||
Author: David Niehues
|
||||
PR: [#653](https://github.com/rosenpass/rosenpass/pull/653)
|
||||
|
||||
\vspace{0.5em}
|
||||
|
||||
We document the support for SHAKE256 with prepended key as an alternative to BLAKE2s with HMAC.
|
||||
|
||||
Previously, BLAKE2s with HMAC was the only supported keyed hash function. Recently, SHAKE256 was added as an option. SHAKE256 is used as a keyed hash function by prepending the key to the variable-length data and then evaluating SHAKE256.
|
||||
In order to maintain compatablity without introducing an explcit version number in the protocol messages, SHAKE256 is truncated to 32 bytes. In the update to the whitepaper, we explain where and how SHAKE256 is used. That is:
|
||||
|
||||
1. We explain that SHAKE256 or BLAKE2s can be configured to be used on a peer basis.
|
||||
2. We explain under which circumstances, the reference implementation tries both hash functions for messages in order to determine the correct hash function.
|
||||
3. We document that the cookie mechanism always uses SHAKE256.
|
||||
|
||||
|
||||
#### 2024-10-30 – InitConf retransmission updates
|
||||
|
||||
\vspace{0.5em}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
dev = "rp-example"
|
||||
ip = "fc00::1/64"
|
||||
listen = "[::]:51821"
|
||||
private_keys_dir = "/run/credentials/rp@example.service"
|
||||
verbose = true
|
||||
|
||||
[[peers]]
|
||||
public_keys_dir = "/etc/rosenpass/example/peers/client"
|
||||
allowed_ips = "fc00::2"
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
runCommand,
|
||||
dpkg,
|
||||
rosenpass,
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (rosenpass) version;
|
||||
in
|
||||
|
||||
runCommand "rosenpass-${version}.deb" { } ''
|
||||
mkdir -p packageroot/DEBIAN
|
||||
|
||||
cat << EOF > packageroot/DEBIAN/control
|
||||
Package: rosenpass
|
||||
Version: ${version}
|
||||
Architecture: all
|
||||
Maintainer: Jacek Galowicz <jacek@galowicz.de>
|
||||
Depends:
|
||||
Description: Post-quantum-secure VPN tool Rosenpass
|
||||
Rosenpass is a post-quantum-secure VPN
|
||||
that uses WireGuard to transport the actual data.
|
||||
EOF
|
||||
|
||||
|
||||
mkdir -p packageroot/usr/bin
|
||||
install -m755 -t packageroot/usr/bin ${rosenpass}/bin/*
|
||||
|
||||
mkdir -p packageroot/etc/rosenpass
|
||||
cp -r ${rosenpass}/lib/systemd packageroot/etc/
|
||||
cp ${./example.toml} packageroot/etc/rosenpass/example.toml
|
||||
|
||||
${dpkg}/bin/dpkg --build packageroot $out
|
||||
''
|
||||
@@ -1,60 +0,0 @@
|
||||
{
|
||||
lib,
|
||||
system,
|
||||
runCommand,
|
||||
rosenpass,
|
||||
rpm,
|
||||
}:
|
||||
|
||||
let
|
||||
splitVersion = lib.strings.splitString "-" rosenpass.version;
|
||||
version = builtins.head splitVersion;
|
||||
release = if builtins.length splitVersion != 2 then "release" else builtins.elemAt splitVersion 1;
|
||||
arch = builtins.head (builtins.split "-" system);
|
||||
in
|
||||
|
||||
runCommand "rosenpass-${version}.rpm" { } ''
|
||||
mkdir -p rpmbuild/SPECS
|
||||
|
||||
cat << EOF > rpmbuild/SPECS/rosenpass.spec
|
||||
Name: rosenpass
|
||||
Release: ${release}
|
||||
Version: ${version}
|
||||
Summary: Post-quantum-secure VPN key exchange
|
||||
License: Apache-2.0
|
||||
|
||||
%description
|
||||
Post-quantum-secure VPN tool Rosenpass
|
||||
Rosenpass is a post-quantum-secure VPN
|
||||
that uses WireGuard to transport the actual data.
|
||||
|
||||
%files
|
||||
/usr/bin/rosenpass
|
||||
/usr/bin/rp
|
||||
/etc/systemd/system/rosenpass.target
|
||||
/etc/systemd/system/rosenpass@.service
|
||||
/etc/systemd/system/rp@.service
|
||||
/etc/rosenpass/example.toml
|
||||
EOF
|
||||
|
||||
buildroot=rpmbuild/BUILDROOT/rosenpass-${version}-${release}.${arch}
|
||||
mkdir -p $buildroot/usr/bin
|
||||
install -m755 -t $buildroot/usr/bin ${rosenpass}/bin/*
|
||||
|
||||
mkdir -p $buildroot/etc/rosenpass
|
||||
cp -r ${rosenpass}/lib/systemd $buildroot/etc/
|
||||
chmod -R 744 $buildroot/etc/systemd
|
||||
cp ${./example.toml} $buildroot/etc/rosenpass/example.toml
|
||||
|
||||
export HOME=/build
|
||||
mkdir -p /build/tmp
|
||||
ls -R rpmbuild
|
||||
|
||||
${rpm}/bin/rpmbuild \
|
||||
-bb \
|
||||
--dbpath=$HOME \
|
||||
--define "_tmppath /build/tmp" \
|
||||
rpmbuild/SPECS/rosenpass.spec
|
||||
|
||||
cp rpmbuild/RPMS/${arch}/rosenpass*.rpm $out
|
||||
''
|
||||
@@ -1,24 +1,21 @@
|
||||
{
|
||||
lib,
|
||||
stdenvNoCC,
|
||||
runCommandNoCC,
|
||||
pkgsStatic,
|
||||
rosenpass,
|
||||
rosenpass-oci-image,
|
||||
rp,
|
||||
}@args:
|
||||
{ lib, stdenvNoCC, runCommandNoCC, pkgsStatic, rosenpass, rosenpass-oci-image, rp } @ args:
|
||||
|
||||
let
|
||||
version = rosenpass.version;
|
||||
|
||||
# select static packages on Linux, default packages otherwise
|
||||
package = if stdenvNoCC.hostPlatform.isLinux then pkgsStatic.rosenpass else args.rosenpass;
|
||||
rp = if stdenvNoCC.hostPlatform.isLinux then pkgsStatic.rp else args.rp;
|
||||
package =
|
||||
if stdenvNoCC.hostPlatform.isLinux then
|
||||
pkgsStatic.rosenpass
|
||||
else args.rosenpass;
|
||||
rp =
|
||||
if stdenvNoCC.hostPlatform.isLinux then
|
||||
pkgsStatic.rp
|
||||
else args.rp;
|
||||
oci-image =
|
||||
if stdenvNoCC.hostPlatform.isLinux then
|
||||
pkgsStatic.rosenpass-oci-image
|
||||
else
|
||||
args.rosenpass-oci-image;
|
||||
else args.rosenpass-oci-image;
|
||||
in
|
||||
runCommandNoCC "lace-result" { } ''
|
||||
mkdir {bin,$out}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
{
|
||||
dockerTools,
|
||||
buildEnv,
|
||||
rosenpass,
|
||||
}:
|
||||
{ dockerTools, buildEnv, rosenpass }:
|
||||
|
||||
dockerTools.buildImage {
|
||||
name = rosenpass.name + "-oci";
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
rustPlatform,
|
||||
cmake,
|
||||
mandoc,
|
||||
removeReferencesTo,
|
||||
bash,
|
||||
package ? "rosenpass",
|
||||
}:
|
||||
{ lib, stdenv, rustPlatform, cmake, mandoc, removeReferencesTo, bash, package ? "rosenpass" }:
|
||||
|
||||
let
|
||||
# whether we want to build a statically linked binary
|
||||
@@ -26,30 +17,24 @@ let
|
||||
"toml"
|
||||
];
|
||||
# Files to explicitly include
|
||||
files = [ "to/README.md" ];
|
||||
files = [
|
||||
"to/README.md"
|
||||
];
|
||||
|
||||
src = ../.;
|
||||
filter = (
|
||||
path: type:
|
||||
scoped rec {
|
||||
inherit (lib)
|
||||
any
|
||||
id
|
||||
removePrefix
|
||||
hasSuffix
|
||||
;
|
||||
anyof = (any id);
|
||||
filter = (path: type: scoped rec {
|
||||
inherit (lib) any id removePrefix hasSuffix;
|
||||
anyof = (any id);
|
||||
|
||||
basename = baseNameOf (toString path);
|
||||
relative = removePrefix (toString src + "/") (toString path);
|
||||
basename = baseNameOf (toString path);
|
||||
relative = removePrefix (toString src + "/") (toString path);
|
||||
|
||||
result = anyof [
|
||||
(type == "directory")
|
||||
(any (ext: hasSuffix ".${ext}" basename) extensions)
|
||||
(any (file: file == relative) files)
|
||||
];
|
||||
}
|
||||
);
|
||||
result = anyof [
|
||||
(type == "directory")
|
||||
(any (ext: hasSuffix ".${ext}" basename) extensions)
|
||||
(any (file: file == relative) files)
|
||||
];
|
||||
});
|
||||
|
||||
result = lib.sources.cleanSourceWith { inherit src filter; };
|
||||
};
|
||||
@@ -62,14 +47,10 @@ rustPlatform.buildRustPackage {
|
||||
version = cargoToml.package.version;
|
||||
inherit src;
|
||||
|
||||
cargoBuildOptions = [
|
||||
"--package"
|
||||
package
|
||||
];
|
||||
cargoTestOptions = [
|
||||
"--package"
|
||||
package
|
||||
];
|
||||
cargoBuildOptions = [ "--package" package ];
|
||||
cargoTestOptions = [ "--package" package ];
|
||||
|
||||
buildFeatures = [ "experiment_api" ];
|
||||
|
||||
doCheck = true;
|
||||
|
||||
@@ -78,8 +59,6 @@ rustPlatform.buildRustPackage {
|
||||
outputHashes = {
|
||||
"memsec-0.6.3" = "sha256-4ri+IEqLd77cLcul3lZrmpDKj4cwuYJ8oPRAiQNGeLw=";
|
||||
"uds-0.4.2" = "sha256-qlxr/iJt2AV4WryePIvqm/8/MK/iqtzegztNliR93W8=";
|
||||
"libcrux-blake2-0.0.3-pre" = "sha256-0CLjuzwJqGooiODOHf5D8Hc8ClcG/XcGvVGyOVnLmJY=";
|
||||
"libcrux-macros-0.0.3" = "sha256-Tb5uRirwhRhoFEK8uu1LvXl89h++40pxzZ+7kXe8RAI=";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -103,10 +82,7 @@ rustPlatform.buildRustPackage {
|
||||
|
||||
meta = {
|
||||
inherit (cargoToml.package) description homepage;
|
||||
license = with lib.licenses; [
|
||||
mit
|
||||
asl20
|
||||
];
|
||||
license = with lib.licenses; [ mit asl20 ];
|
||||
maintainers = [ lib.maintainers.wucke13 ];
|
||||
platforms = lib.platforms.all;
|
||||
};
|
||||
|
||||
@@ -1,52 +1,13 @@
|
||||
{
|
||||
stdenvNoCC,
|
||||
texlive,
|
||||
ncurses,
|
||||
python3Packages,
|
||||
which,
|
||||
}:
|
||||
{ stdenvNoCC, texlive, ncurses, python3Packages, which }:
|
||||
|
||||
let
|
||||
customTexLiveSetup = (
|
||||
texlive.combine {
|
||||
inherit (texlive)
|
||||
acmart
|
||||
amsfonts
|
||||
biber
|
||||
biblatex
|
||||
biblatex-software
|
||||
biblatex-trad
|
||||
ccicons
|
||||
csquotes
|
||||
csvsimple
|
||||
doclicense
|
||||
eso-pic
|
||||
fancyvrb
|
||||
fontspec
|
||||
gitinfo2
|
||||
gobble
|
||||
ifmtarg
|
||||
koma-script
|
||||
latexmk
|
||||
lm
|
||||
lualatex-math
|
||||
markdown
|
||||
mathtools
|
||||
minted
|
||||
noto
|
||||
nunito
|
||||
paralist
|
||||
pgf
|
||||
scheme-basic
|
||||
soul
|
||||
unicode-math
|
||||
upquote
|
||||
xifthen
|
||||
xkeyval
|
||||
xurl
|
||||
;
|
||||
}
|
||||
);
|
||||
customTexLiveSetup = (texlive.combine {
|
||||
inherit (texlive) acmart amsfonts biber biblatex biblatex-software
|
||||
biblatex-trad ccicons csquotes csvsimple doclicense eso-pic fancyvrb
|
||||
fontspec gitinfo2 gobble ifmtarg koma-script latexmk lm lualatex-math
|
||||
markdown mathtools minted noto nunito paralist pgf scheme-basic soul
|
||||
unicode-math upquote xifthen xkeyval xurl;
|
||||
});
|
||||
in
|
||||
stdenvNoCC.mkDerivation {
|
||||
name = "whitepaper";
|
||||
|
||||
58
readme.md
58
readme.md
@@ -14,7 +14,7 @@ This repository contains
|
||||
|
||||
## Getting started
|
||||
|
||||
First, [install rosenpass](#getting-rosenpass). Then, check out the help functions of `rp` & `rosenpass`:
|
||||
First, [install rosenpass](#Getting-Rosenpass). Then, check out the help functions of `rp` & `rosenpass`:
|
||||
|
||||
```sh
|
||||
rp help
|
||||
@@ -64,7 +64,11 @@ The analysis is implemented according to modern software engineering principles:
|
||||
The code uses a variety of optimizations to speed up analysis such as using secret functions to model trusted/malicious setup. We split the model into two separate entry points which can be analyzed in parallel. Each is much faster than both models combined.
|
||||
A wrapper script provides instant feedback about which queries execute as expected in color: A red cross if a query fails and a green check if it succeeds.
|
||||
|
||||
[^liboqs]: <https://openquantumsafe.org/liboqs/>
|
||||
[^liboqs]: https://openquantumsafe.org/liboqs/
|
||||
[^wg]: https://www.wireguard.com/
|
||||
[^pqwg]: https://eprint.iacr.org/2020/379
|
||||
[^pqwg-statedis]: Unless supplied with a pre-shared-key, but this defeats the purpose of a key exchange protocol
|
||||
[^wg-statedis]: https://lists.zx2c4.com/pipermail/wireguard/2021-August/006916.htmlA
|
||||
|
||||
# Getting Rosenpass
|
||||
|
||||
@@ -74,56 +78,6 @@ Rosenpass is packaged for more and more distributions, maybe also for the distri
|
||||
|
||||
[](https://repology.org/project/rosenpass/versions)
|
||||
|
||||
## Docker Images
|
||||
|
||||
Rosenpass is also available as prebuilt Docker images:
|
||||
|
||||
- [`ghcr.io/rosenpass/rosenpass`](https://github.com/rosenpass/rosenpass/pkgs/container/rosenpass)
|
||||
- [`ghcr.io/rosenpass/rp`](https://github.com/rosenpass/rosenpass/pkgs/container/rp)
|
||||
|
||||
For details on how to use these images, refer to the [Docker usage guide](docker/USAGE.md).
|
||||
|
||||
## Benchmarks
|
||||
|
||||
This repository contains facilities for benchmarking both the Rosenpass
|
||||
protocol code and the implementations of the cryptographic primitives used
|
||||
by it. The primitives are benchmarked using criterion. For the protocol code
|
||||
benchmarks we use a library for instrumenting the code such that events are
|
||||
written to a trace, which is then inspected after a run.
|
||||
|
||||
Benchmarks are automatically run on CI. The measurements are visualized in the
|
||||
[Benchmark Dashboard].
|
||||
|
||||
[Benchmark Dashboard]: https://rosenpass.github.io/rosenpass/benchmarks
|
||||
|
||||
### Primitive Benchmarks
|
||||
|
||||
There are benchmarks for the functions of the traits `Kem`, `Aead` and
|
||||
`KeyedHash`. They are run for all implementations in the `primitives`
|
||||
benchmark of `rosenpass-ciphers`. Run the benchmarks and view their results using
|
||||
|
||||
```
|
||||
cargo bench -p rosenpass-ciphers --bench primitives -F bench
|
||||
```
|
||||
|
||||
Note that the `bench` feature enables the inclusion of the libcrux-backed
|
||||
trait implementations in the module tree, but does not enable them
|
||||
as default.
|
||||
|
||||
### Protocol Benchmarks
|
||||
|
||||
The trace that is being written to lives in a new module
|
||||
`trace_bench` in the util crate. A basic benchmark that
|
||||
performs some minor statistical analysis of the trace can be run using
|
||||
|
||||
```
|
||||
cargo bench -p rosenpass --bench trace_handshake -F trace_bench
|
||||
```
|
||||
|
||||
This runs the benchmarks and prints the results in machine-readable JSON.
|
||||
|
||||
---
|
||||
|
||||
# Mirrors
|
||||
|
||||
Don't want to use GitHub or only have an IPv6 connection? Rosenpass has set up two mirrors for this:
|
||||
|
||||
@@ -8,7 +8,6 @@ description = "Build post-quantum-secure VPNs with WireGuard!"
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[[bin]]
|
||||
name = "rosenpass"
|
||||
@@ -29,16 +28,7 @@ required-features = ["experiment_api", "internal_testing"]
|
||||
|
||||
[[test]]
|
||||
name = "gen-ipc-msg-types"
|
||||
required-features = [
|
||||
"experiment_api",
|
||||
"internal_testing",
|
||||
"internal_bin_gen_ipc_msg_types",
|
||||
]
|
||||
|
||||
[[bench]]
|
||||
name = "trace_handshake"
|
||||
harness = false
|
||||
required-features = ["trace_bench"]
|
||||
required-features = ["experiment_api", "internal_testing", "internal_bin_gen_ipc_msg_types"]
|
||||
|
||||
[[bench]]
|
||||
name = "handshake"
|
||||
@@ -77,7 +67,6 @@ command-fds = { workspace = true, optional = true }
|
||||
rustix = { workspace = true, optional = true }
|
||||
uds = { workspace = true, optional = true, features = ["mio_1xx"] }
|
||||
signal-hook = { workspace = true, optional = true }
|
||||
libcrux-test-utils = { workspace = true, optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
anyhow = { workspace = true }
|
||||
@@ -92,27 +81,20 @@ tempfile = { workspace = true }
|
||||
rustix = { workspace = true }
|
||||
|
||||
[features]
|
||||
#default = ["experiment_libcrux_all"]
|
||||
experiment_cookie_dos_mitigation = []
|
||||
default = []
|
||||
experiment_memfd_secret = ["rosenpass-wireguard-broker/experiment_memfd_secret"]
|
||||
experiment_libcrux_all = ["rosenpass-ciphers/experiment_libcrux_all"]
|
||||
experiment_libcrux_blake2 = ["rosenpass-ciphers/experiment_libcrux_blake2"]
|
||||
experiment_libcrux_chachapoly = [
|
||||
"rosenpass-ciphers/experiment_libcrux_chachapoly",
|
||||
]
|
||||
experiment_libcrux_kyber = ["rosenpass-ciphers/experiment_libcrux_kyber"]
|
||||
experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux"]
|
||||
experiment_api = [
|
||||
"hex-literal",
|
||||
"uds",
|
||||
"command-fds",
|
||||
"rustix",
|
||||
"rosenpass-util/experiment_file_descriptor_passing",
|
||||
"rosenpass-wireguard-broker/experiment_api",
|
||||
"hex-literal",
|
||||
"uds",
|
||||
"command-fds",
|
||||
"rustix",
|
||||
"rosenpass-util/experiment_file_descriptor_passing",
|
||||
"rosenpass-wireguard-broker/experiment_api",
|
||||
]
|
||||
internal_signal_handling_for_coverage_reports = ["signal-hook"]
|
||||
internal_testing = []
|
||||
internal_bin_gen_ipc_msg_types = ["hex", "heck"]
|
||||
trace_bench = ["rosenpass-util/trace_bench", "dep:libcrux-test-utils"]
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(coverage)'] }
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
use anyhow::Result;
|
||||
use rosenpass::protocol::{
|
||||
CryptoServer, HandleMsgResult, MsgBuf, PeerPtr, ProtocolVersion, SPk, SSk, SymKey,
|
||||
};
|
||||
use rosenpass::protocol::{CryptoServer, HandleMsgResult, MsgBuf, PeerPtr, SPk, SSk, SymKey};
|
||||
use std::ops::DerefMut;
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_ciphers::kem::StaticKem;
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use rosenpass_secret_memory::secret_policy_try_use_memfd_secrets;
|
||||
@@ -43,33 +41,25 @@ fn hs(ini: &mut CryptoServer, res: &mut CryptoServer) -> Result<()> {
|
||||
|
||||
fn keygen() -> Result<(SSk, SPk)> {
|
||||
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
|
||||
StaticKem.keygen(sk.secret_mut(), pk.deref_mut())?;
|
||||
StaticKem::keygen(sk.secret_mut(), pk.deref_mut())?;
|
||||
Ok((sk, pk))
|
||||
}
|
||||
|
||||
fn make_server_pair(protocol_version: ProtocolVersion) -> Result<(CryptoServer, CryptoServer)> {
|
||||
fn make_server_pair() -> Result<(CryptoServer, CryptoServer)> {
|
||||
let psk = SymKey::random();
|
||||
let ((ska, pka), (skb, pkb)) = (keygen()?, keygen()?);
|
||||
let (mut a, mut b) = (
|
||||
CryptoServer::new(ska, pka.clone()),
|
||||
CryptoServer::new(skb, pkb.clone()),
|
||||
);
|
||||
a.add_peer(Some(psk.clone()), pkb, protocol_version.clone())?;
|
||||
b.add_peer(Some(psk), pka, protocol_version)?;
|
||||
a.add_peer(Some(psk.clone()), pkb)?;
|
||||
b.add_peer(Some(psk), pka)?;
|
||||
Ok((a, b))
|
||||
}
|
||||
|
||||
fn criterion_benchmark_v02(c: &mut Criterion) {
|
||||
criterion_benchmark(c, ProtocolVersion::V02)
|
||||
}
|
||||
|
||||
fn criterion_benchmark_v03(c: &mut Criterion) {
|
||||
criterion_benchmark(c, ProtocolVersion::V03)
|
||||
}
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion, protocol_version: ProtocolVersion) {
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
secret_policy_try_use_memfd_secrets();
|
||||
let (mut a, mut b) = make_server_pair(protocol_version).unwrap();
|
||||
let (mut a, mut b) = make_server_pair().unwrap();
|
||||
c.bench_function("cca_secret_alloc", |bench| {
|
||||
bench.iter(|| {
|
||||
SSk::zero();
|
||||
@@ -92,6 +82,5 @@ fn criterion_benchmark(c: &mut Criterion, protocol_version: ProtocolVersion) {
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches_v02, criterion_benchmark_v02);
|
||||
criterion_group!(benches_v03, criterion_benchmark_v03);
|
||||
criterion_main!(benches_v02, benches_v03);
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_main!(benches);
|
||||
|
||||
@@ -1,386 +0,0 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
hint::black_box,
|
||||
io::{self, Write},
|
||||
ops::DerefMut,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use libcrux_test_utils::tracing::{EventType, Trace as _};
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
use rosenpass_secret_memory::secret_policy_try_use_memfd_secrets;
|
||||
use rosenpass_util::trace_bench::RpEventType;
|
||||
|
||||
use rosenpass::protocol::{
|
||||
CryptoServer, HandleMsgResult, MsgBuf, PeerPtr, ProtocolVersion, SPk, SSk, SymKey,
|
||||
};
|
||||
|
||||
const ITERATIONS: usize = 100;
|
||||
|
||||
/// Performs a full protocol run by processing a message and recursing into handling that message,
|
||||
/// until no further response is produced. Returns the keys produce by the two parties.
|
||||
///
|
||||
/// Ensures that each party produces one of the two keys.
|
||||
fn handle(
|
||||
tx: &mut CryptoServer,
|
||||
msgb: &mut MsgBuf,
|
||||
msgl: usize,
|
||||
rx: &mut CryptoServer,
|
||||
resb: &mut MsgBuf,
|
||||
) -> Result<(Option<SymKey>, Option<SymKey>)> {
|
||||
let HandleMsgResult {
|
||||
exchanged_with: xch,
|
||||
resp,
|
||||
} = rx.handle_msg(&msgb[..msgl], &mut **resb)?;
|
||||
|
||||
assert!(matches!(xch, None | Some(PeerPtr(0))));
|
||||
|
||||
let xch = xch.map(|p| rx.osk(p).unwrap());
|
||||
|
||||
let (rxk, txk) = resp
|
||||
.map(|resl| handle(rx, resb, resl, tx, msgb))
|
||||
.transpose()?
|
||||
.unwrap_or((None, None));
|
||||
|
||||
assert!(rxk.is_none() || xch.is_none());
|
||||
|
||||
Ok((txk, rxk.or(xch)))
|
||||
}
|
||||
|
||||
/// Performs the full handshake by calling `handle` with the correct values, based on just two
|
||||
/// `CryptoServer`s.
|
||||
///
|
||||
/// Ensures that both parties compute the same keys.
|
||||
fn hs(ini: &mut CryptoServer, res: &mut CryptoServer) -> Result<()> {
|
||||
let (mut inib, mut resb) = (MsgBuf::zero(), MsgBuf::zero());
|
||||
let sz = ini.initiate_handshake(PeerPtr(0), &mut *inib)?;
|
||||
let (kini, kres) = handle(ini, &mut inib, sz, res, &mut resb)?;
|
||||
assert!(kini.unwrap().secret() == kres.unwrap().secret());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generates a new key pair.
|
||||
fn keygen() -> Result<(SSk, SPk)> {
|
||||
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
|
||||
StaticKem.keygen(sk.secret_mut(), pk.deref_mut())?;
|
||||
Ok((sk, pk))
|
||||
}
|
||||
|
||||
/// Creates two instanves of `CryptoServer`, generating key pairs for each.
|
||||
fn make_server_pair(protocol_version: ProtocolVersion) -> Result<(CryptoServer, CryptoServer)> {
|
||||
let psk = SymKey::random();
|
||||
let ((ska, pka), (skb, pkb)) = (keygen()?, keygen()?);
|
||||
let (mut a, mut b) = (
|
||||
CryptoServer::new(ska, pka.clone()),
|
||||
CryptoServer::new(skb, pkb.clone()),
|
||||
);
|
||||
a.add_peer(Some(psk.clone()), pkb, protocol_version.clone())?;
|
||||
b.add_peer(Some(psk), pka, protocol_version)?;
|
||||
Ok((a, b))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let trace = rosenpass_util::trace_bench::trace();
|
||||
|
||||
// Attempt to use memfd_secrets for storing sensitive key material
|
||||
secret_policy_try_use_memfd_secrets();
|
||||
|
||||
// Run protocol for V02
|
||||
let (mut a_v02, mut b_v02) = make_server_pair(ProtocolVersion::V02).unwrap();
|
||||
for _ in 0..ITERATIONS {
|
||||
hs(black_box(&mut a_v02), black_box(&mut b_v02)).unwrap();
|
||||
}
|
||||
|
||||
// Emit a marker event to separate V02 and V03 trace sections
|
||||
trace.emit_on_the_fly("start-hs-v03");
|
||||
|
||||
// Run protocol for V03
|
||||
let (mut a_v03, mut b_v03) = make_server_pair(ProtocolVersion::V03).unwrap();
|
||||
for _ in 0..ITERATIONS {
|
||||
hs(black_box(&mut a_v03), black_box(&mut b_v03)).unwrap();
|
||||
}
|
||||
|
||||
// Collect the trace events generated during the handshakes
|
||||
let trace: Vec<_> = trace.clone().report();
|
||||
|
||||
// Split the trace into V02 and V03 sections based on the marker
|
||||
let (trace_v02, trace_v03) = {
|
||||
let cutoff = trace
|
||||
.iter()
|
||||
.position(|entry| entry.label == "start-hs-v03")
|
||||
.unwrap();
|
||||
// Exclude the marker itself from the V03 trace
|
||||
let (v02, v03_with_marker) = trace.split_at(cutoff);
|
||||
(v02, &v03_with_marker[1..])
|
||||
};
|
||||
|
||||
// Perform statistical analysis on both trace sections and write results as JSON
|
||||
write_json_arrays(
|
||||
&mut std::io::stdout(), // Write to standard output
|
||||
vec![
|
||||
("V02", statistical_analysis(trace_v02.to_vec())),
|
||||
("V03", statistical_analysis(trace_v03.to_vec())),
|
||||
],
|
||||
)
|
||||
.expect("error writing json data");
|
||||
}
|
||||
|
||||
/// Performs a simple statistical analysis:
|
||||
/// - bins trace events by label
|
||||
/// - extracts durations of spamns
|
||||
/// - filters out empty bins
|
||||
/// - calculates aggregate statistics (mean, std dev)
|
||||
fn statistical_analysis(trace: Vec<RpEventType>) -> Vec<(&'static str, AggregateStat<Duration>)> {
|
||||
bin_events(trace)
|
||||
.into_iter()
|
||||
.map(|(label, spans)| (label, extract_span_durations(label, spans.as_slice())))
|
||||
.filter(|(_, durations)| !durations.is_empty())
|
||||
.map(|(label, durations)| (label, AggregateStat::analyze_durations(&durations)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Takes an iterator of ("protocol_version", iterator_of_stats) pairs and writes them
|
||||
/// as a single flat JSON array to the provided writer.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `w` - The writer to output JSON to (e.g., stdout, file).
|
||||
/// * `item_groups` - An iterator producing tuples `(version, stats): (&'static str, II)`.
|
||||
/// Here `II` is itself an iterator producing `(label, agg_stat): (&'static str, AggregateStat<Duration>)`,
|
||||
/// where the label is the label of the span, e.g. "IHI2".
|
||||
///
|
||||
/// # Type Parameters
|
||||
/// * `W` - A type that implements `std::io::Write`.
|
||||
/// * `II` - An iterator type yielding (`&'static str`, `AggregateStat<Duration>`).
|
||||
fn write_json_arrays<W: Write, II: IntoIterator<Item = (&'static str, AggregateStat<Duration>)>>(
|
||||
w: &mut W,
|
||||
item_groups: impl IntoIterator<Item = (&'static str, II)>,
|
||||
) -> io::Result<()> {
|
||||
// Flatten the groups into a single iterator of (protocol_version, label, stats)
|
||||
let iter = item_groups.into_iter().flat_map(|(version, items)| {
|
||||
items
|
||||
.into_iter()
|
||||
.map(move |(label, agg_stat)| (version, label, agg_stat))
|
||||
});
|
||||
let mut delim = ""; // Start with no delimiter
|
||||
|
||||
// Start the JSON array
|
||||
write!(w, "[")?;
|
||||
|
||||
// Write the flattened statistics as JSON objects, separated by commas.
|
||||
for (version, label, agg_stat) in iter {
|
||||
write!(w, "{delim}")?; // Write delimiter (empty for first item, "," for subsequent)
|
||||
agg_stat.write_json_ns(label, version, w)?; // Write the JSON object for the stat entry
|
||||
delim = ","; // Set delimiter for the next iteration
|
||||
}
|
||||
|
||||
// End the JSON array
|
||||
write!(w, "]")
|
||||
}
|
||||
|
||||
/// Used to group benchmark results in visualizations
|
||||
enum RunTimeGroup {
|
||||
/// For particularly long operations.
|
||||
Long,
|
||||
/// Operations of moderate duration.
|
||||
Medium,
|
||||
/// Operations expected to complete under a millisecond.
|
||||
BelowMillisec,
|
||||
/// Very fast operations, likely under a microsecond.
|
||||
BelowMicrosec,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for RunTimeGroup {
|
||||
/// Used when writing the group information to JSON output.
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let txt = match self {
|
||||
RunTimeGroup::Long => "long",
|
||||
RunTimeGroup::Medium => "medium",
|
||||
RunTimeGroup::BelowMillisec => "below 1ms",
|
||||
RunTimeGroup::BelowMicrosec => "below 1us",
|
||||
};
|
||||
write!(f, "{txt}")
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps specific internal timing labels (likely from rosenpass internals)
|
||||
/// to the broader SpanGroup categories.
|
||||
fn run_time_group(label: &str) -> RunTimeGroup {
|
||||
match label {
|
||||
// Explicitly categorized labels based on expected performance characteristics
|
||||
"handle_init_hello" | "handle_resp_hello" | "RHI5" | "IHR5" => RunTimeGroup::Long,
|
||||
"RHR1" | "IHI2" | "ICR6" => RunTimeGroup::BelowMicrosec,
|
||||
"RHI6" | "ICI7" | "ICR7" | "RHR3" | "ICR3" | "IHR8" | "ICI4" | "RHI3" | "RHI4" | "RHR4"
|
||||
| "RHR7" | "ICI3" | "IHI3" | "IHI8" | "ICR2" | "ICR4" | "IHR4" | "IHR6" | "IHI4"
|
||||
| "RHI7" => RunTimeGroup::BelowMillisec,
|
||||
// Default protocol_version for any other labels
|
||||
_ => RunTimeGroup::Medium,
|
||||
}
|
||||
}
|
||||
|
||||
/// Used temporarily within `extract_span_durations` to track open spans
|
||||
/// and calculated durations.
|
||||
#[derive(Debug, Clone)]
|
||||
enum StatEntry {
|
||||
/// Represents an unmatched SpanOpen event with its timestamp.
|
||||
Start(Instant),
|
||||
/// Represents a completed span with its calculated duration.
|
||||
Duration(Duration),
|
||||
}
|
||||
|
||||
/// Takes a flat list of events and organizes them into a HashMap where keys
|
||||
/// are event labels and values are vectors of events with that label.
|
||||
fn bin_events(events: Vec<RpEventType>) -> HashMap<&'static str, Vec<RpEventType>> {
|
||||
let mut spans = HashMap::<_, Vec<_>>::new();
|
||||
for event in events {
|
||||
// Get the vector for the event's label, or create a new one
|
||||
let spans_for_label = spans.entry(event.label).or_default();
|
||||
// Add the event to the vector
|
||||
spans_for_label.push(event);
|
||||
}
|
||||
spans
|
||||
}
|
||||
|
||||
/// Processes a list of events (assumed to be for the same label), matching
|
||||
/// `SpanOpen` and `SpanClose` events to calculate the duration of each span.
|
||||
/// It handles potentially interleaved spans correctly.
|
||||
fn extract_span_durations(label: &str, events: &[RpEventType]) -> Vec<Duration> {
|
||||
let mut processing_list: Vec<StatEntry> = vec![]; // List to track open spans and final durations
|
||||
|
||||
for entry in events {
|
||||
match &entry.ty {
|
||||
EventType::SpanOpen => {
|
||||
// Record the start time of a new span
|
||||
processing_list.push(StatEntry::Start(entry.at));
|
||||
}
|
||||
EventType::SpanClose => {
|
||||
// Find the most recent unmatched 'Start' entry
|
||||
let start_index = processing_list
|
||||
.iter()
|
||||
.rposition(|span| matches!(span, StatEntry::Start(_))); // Find last Start
|
||||
|
||||
match start_index {
|
||||
Some(index) => {
|
||||
// Retrieve the start time
|
||||
let start_time = match processing_list[index] {
|
||||
StatEntry::Start(t) => t,
|
||||
_ => unreachable!(), // Should always be Start based on rposition logic
|
||||
};
|
||||
// Calculate duration and replace the 'Start' entry with 'Duration'
|
||||
processing_list[index] = StatEntry::Duration(entry.at - start_time);
|
||||
}
|
||||
None => {
|
||||
// This should not happen with well-formed traces
|
||||
eprintln!(
|
||||
"Warning: Found SpanClose without a matching SpanOpen for label '{}': {:?}",
|
||||
label, entry
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
EventType::OnTheFly => {
|
||||
// Ignore OnTheFly events for duration calculation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all calculated durations, reporting any unmatched starts
|
||||
processing_list
|
||||
.into_iter()
|
||||
.filter_map(|span| match span {
|
||||
StatEntry::Start(at) => {
|
||||
// Report error if a span was opened but never closed
|
||||
eprintln!(
|
||||
"Warning: Unmatched SpanOpen at {:?} for label '{}'",
|
||||
at, label
|
||||
);
|
||||
None // Discard unmatched starts
|
||||
}
|
||||
StatEntry::Duration(dur) => Some(dur), // Keep calculated durations
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Stores the mean, standard deviation, relative standard deviation (sd/mean),
|
||||
/// and the number of samples used for calculation.
|
||||
#[derive(Debug)]
|
||||
struct AggregateStat<T> {
|
||||
/// Average duration.
|
||||
mean_duration: T,
|
||||
/// Standard deviation of durations.
|
||||
sd_duration: T,
|
||||
/// Standard deviation as a percentage of the mean.
|
||||
sd_by_mean: String,
|
||||
/// Number of duration measurements.
|
||||
sample_size: usize,
|
||||
}
|
||||
|
||||
impl AggregateStat<Duration> {
|
||||
/// Calculates mean, variance, and standard deviation for a slice of Durations.
|
||||
fn analyze_durations(durations: &[Duration]) -> Self {
|
||||
let sample_size = durations.len();
|
||||
assert!(sample_size > 0, "Cannot analyze empty duration slice");
|
||||
|
||||
// Calculate the sum of durations
|
||||
let sum: Duration = durations.iter().sum();
|
||||
// Calculate the mean duration
|
||||
let mean = sum / (sample_size as u32);
|
||||
|
||||
// Calculate mean in nanoseconds, adding 1 to avoid potential division by zero later
|
||||
// (though highly unlikely with realistic durations)
|
||||
let mean_ns = mean.as_nanos().saturating_add(1);
|
||||
|
||||
// Calculate variance (sum of squared differences from the mean) / N
|
||||
let variance = durations
|
||||
.iter()
|
||||
.map(Duration::as_nanos)
|
||||
.map(|d_ns| d_ns.abs_diff(mean_ns).pow(2)) // (duration_ns - mean_ns)^2
|
||||
.sum::<u128>() // Sum of squares
|
||||
/ (sample_size as u128); // Divide by sample size
|
||||
|
||||
// Calculate standard deviation (sqrt of variance)
|
||||
let sd_ns = (variance as f64).sqrt() as u128;
|
||||
let sd = Duration::from_nanos(sd_ns as u64); // Convert back to Duration
|
||||
|
||||
// Calculate relative standard deviation (sd / mean) as a percentage string
|
||||
let sd_rel_permille = (10000 * sd_ns).checked_div(mean_ns).unwrap_or(0); // Calculate sd/mean * 10000
|
||||
let sd_rel_formatted = format!("{}.{:02}%", sd_rel_permille / 100, sd_rel_permille % 100);
|
||||
|
||||
AggregateStat {
|
||||
mean_duration: mean,
|
||||
sd_duration: sd,
|
||||
sd_by_mean: sd_rel_formatted,
|
||||
sample_size,
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes the statistics as a JSON object to the provided writer.
|
||||
/// Includes metadata like label, protocol_version, OS, architecture, and run time group.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `label` - The specific benchmark/span label.
|
||||
/// * `protocol_version` - Version of the protocol that is benchmarked.
|
||||
/// * `w` - The output writer (must implement `std::io::Write`).
|
||||
fn write_json_ns(
|
||||
&self,
|
||||
label: &str,
|
||||
protocol_version: &str,
|
||||
w: &mut impl io::Write,
|
||||
) -> io::Result<()> {
|
||||
// Format the JSON string using measured values and environment constants
|
||||
writeln!(
|
||||
w,
|
||||
r#"{{"name":"{name}", "unit":"ns/iter", "value":"{value}", "range":"± {range}", "protocol version":"{protocol_version}", "sample size":"{sample_size}", "operating system":"{os}", "architecture":"{arch}", "run time":"{run_time}"}}"#,
|
||||
name = label, // Benchmark name
|
||||
value = self.mean_duration.as_nanos(), // Mean duration in nanoseconds
|
||||
range = self.sd_duration.as_nanos(), // Standard deviation in nanoseconds
|
||||
sample_size = self.sample_size, // Number of samples
|
||||
os = std::env::consts::OS, // Operating system
|
||||
arch = std::env::consts::ARCH, // CPU architecture
|
||||
run_time = run_time_group(label), // Run time group category (long, medium, etc.)
|
||||
protocol_version = protocol_version // Overall protocol_version (e.g., protocol version)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,6 @@ use std::slice;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::config::ProtocolVersion;
|
||||
use crate::protocol::BuildCryptoServer;
|
||||
use crate::protocol::HostIdentification;
|
||||
use crate::{
|
||||
@@ -333,7 +332,7 @@ pub struct AppServer {
|
||||
///
|
||||
/// Because the API supports initializing the server with a keypair
|
||||
/// and CryptoServer needs to be initialized with a keypair, the struct
|
||||
/// is wrapped in a ConstructionSite
|
||||
/// struct is wrapped in a ConstructionSite
|
||||
pub crypto_site: ConstructionSite<BuildCryptoServer, CryptoServer>,
|
||||
/// The UDP sockets used to send and receive protocol messages
|
||||
pub sockets: Vec<mio::net::UdpSocket>,
|
||||
@@ -1043,12 +1042,11 @@ impl AppServer {
|
||||
outfile: Option<PathBuf>,
|
||||
broker_peer: Option<BrokerPeer>,
|
||||
hostname: Option<String>,
|
||||
protocol_version: ProtocolVersion,
|
||||
) -> anyhow::Result<AppPeerPtr> {
|
||||
let PeerPtr(pn) = match &mut self.crypto_site {
|
||||
ConstructionSite::Void => bail!("Crypto server construction site is void"),
|
||||
ConstructionSite::Builder(builder) => builder.add_peer(psk, pk, protocol_version),
|
||||
ConstructionSite::Product(srv) => srv.add_peer(psk, pk, protocol_version.into())?,
|
||||
ConstructionSite::Builder(builder) => builder.add_peer(psk, pk),
|
||||
ConstructionSite::Product(srv) => srv.add_peer(psk, pk)?,
|
||||
};
|
||||
assert!(pn == self.peers.len());
|
||||
|
||||
@@ -1264,7 +1262,7 @@ impl AppServer {
|
||||
}
|
||||
|
||||
/// Used as a helper by [Self::event_loop_without_error_handling] when
|
||||
/// a new output key has been exchanged
|
||||
/// a new output key has been echanged
|
||||
pub fn output_key(
|
||||
&mut self,
|
||||
peer: AppPeerPtr,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use anyhow::{Context, Result};
|
||||
use heck::ToShoutySnakeCase;
|
||||
|
||||
use rosenpass_ciphers::subtle::keyed_hash::KeyedHash;
|
||||
use rosenpass_ciphers::{hash_domain::HashDomain, KEY_LEN};
|
||||
|
||||
/// Recursively calculate a concrete hash value for an API message type
|
||||
@@ -13,12 +12,12 @@ fn calculate_hash_value(hd: HashDomain, values: &[&str]) -> Result<[u8; KEY_LEN]
|
||||
}
|
||||
|
||||
/// Print a hash literal for pasting into the Rosenpass source code
|
||||
fn print_literal(path: &[&str], shake_or_blake: KeyedHash) -> Result<()> {
|
||||
let val = calculate_hash_value(HashDomain::zero(shake_or_blake.clone()), path)?;
|
||||
fn print_literal(path: &[&str]) -> Result<()> {
|
||||
let val = calculate_hash_value(HashDomain::zero(), path)?;
|
||||
let (last, prefix) = path.split_last().context("developer error!")?;
|
||||
let var_name = last.to_shouty_snake_case();
|
||||
|
||||
print!("// hash domain hash with hash {} of: ", shake_or_blake);
|
||||
print!("// hash domain hash of: ");
|
||||
for n in prefix.iter() {
|
||||
print!("{n} -> ");
|
||||
}
|
||||
@@ -52,24 +51,24 @@ impl Tree {
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_code_inner(&self, prefix: &[&str], shake_or_blake: KeyedHash) -> Result<()> {
|
||||
fn gen_code_inner(&self, prefix: &[&str]) -> Result<()> {
|
||||
let mut path = prefix.to_owned();
|
||||
path.push(self.name());
|
||||
|
||||
match self {
|
||||
Self::Branch(_, ref children) => {
|
||||
for c in children.iter() {
|
||||
c.gen_code_inner(&path, shake_or_blake.clone())?
|
||||
c.gen_code_inner(&path)?
|
||||
}
|
||||
}
|
||||
Self::Leaf(_) => print_literal(&path, shake_or_blake)?,
|
||||
Self::Leaf(_) => print_literal(&path)?,
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn gen_code(&self, shake_or_blake: KeyedHash) -> Result<()> {
|
||||
self.gen_code_inner(&[], shake_or_blake)
|
||||
fn gen_code(&self) -> Result<()> {
|
||||
self.gen_code_inner(&[])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +93,5 @@ fn main() -> Result<()> {
|
||||
|
||||
println!("type RawMsgType = u128;");
|
||||
println!();
|
||||
tree.gen_code(KeyedHash::keyed_shake256())?;
|
||||
println!();
|
||||
tree.gen_code(KeyedHash::incorrect_hmac_blake2b())
|
||||
tree.gen_code()
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
use anyhow::{bail, ensure, Context};
|
||||
use clap::{Parser, Subcommand};
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_ciphers::kem::StaticKem;
|
||||
use rosenpass_secret_memory::file::StoreSecret;
|
||||
use rosenpass_util::file::{LoadValue, LoadValueB64, StoreValue};
|
||||
use rosenpass_wireguard_broker::brokers::native_unix::{
|
||||
@@ -490,7 +490,6 @@ impl CliArgs {
|
||||
cfg_peer.key_out,
|
||||
broker_peer,
|
||||
cfg_peer.endpoint.clone(),
|
||||
cfg_peer.protocol_version.into(),
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -609,7 +608,7 @@ impl CliArgs {
|
||||
pub fn generate_and_save_keypair(secret_key: PathBuf, public_key: PathBuf) -> anyhow::Result<()> {
|
||||
let mut ssk = crate::protocol::SSk::random();
|
||||
let mut spk = crate::protocol::SPk::random();
|
||||
StaticKem.keygen(ssk.secret_mut(), spk.deref_mut())?;
|
||||
StaticKem::keygen(ssk.secret_mut(), spk.deref_mut())?;
|
||||
ssk.store_secret(secret_key)?;
|
||||
spk.store(public_key)
|
||||
}
|
||||
|
||||
@@ -109,14 +109,6 @@ pub enum Verbosity {
|
||||
Verbose,
|
||||
}
|
||||
|
||||
/// The protocol version to be used by a peer.
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Copy, Clone, Default)]
|
||||
pub enum ProtocolVersion {
|
||||
#[default]
|
||||
V02,
|
||||
V03,
|
||||
}
|
||||
|
||||
/// Configuration data for a single Rosenpass peer
|
||||
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct RosenpassPeer {
|
||||
@@ -146,10 +138,6 @@ pub struct RosenpassPeer {
|
||||
/// Information for supplying exchanged keys directly to WireGuard
|
||||
#[serde(flatten)]
|
||||
pub wg: Option<WireGuard>,
|
||||
|
||||
#[serde(default)]
|
||||
/// The protocol version to use for the exchange
|
||||
pub protocol_version: ProtocolVersion,
|
||||
}
|
||||
|
||||
/// Information for supplying exchanged keys directly to WireGuard
|
||||
@@ -782,53 +770,6 @@ mod test {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_protocol_version() {
|
||||
let mut rosenpass = Rosenpass::empty();
|
||||
let mut peer_v_02 = RosenpassPeer::default();
|
||||
peer_v_02.protocol_version = ProtocolVersion::V02;
|
||||
rosenpass.peers.push(peer_v_02);
|
||||
let mut peer_v_03 = RosenpassPeer::default();
|
||||
peer_v_03.protocol_version = ProtocolVersion::V03;
|
||||
rosenpass.peers.push(peer_v_03);
|
||||
#[cfg(feature = "experiment_api")]
|
||||
{
|
||||
rosenpass.api.listen_fd = vec![];
|
||||
rosenpass.api.listen_path = vec![];
|
||||
rosenpass.api.stream_fd = vec![];
|
||||
}
|
||||
#[cfg(feature = "experiment_api")]
|
||||
let expected_toml = r#"listen = []
|
||||
verbosity = "Quiet"
|
||||
|
||||
[api]
|
||||
listen_fd = []
|
||||
listen_path = []
|
||||
stream_fd = []
|
||||
|
||||
[[peers]]
|
||||
protocol_version = "V02"
|
||||
public_key = ""
|
||||
|
||||
[[peers]]
|
||||
protocol_version = "V03"
|
||||
public_key = ""
|
||||
"#;
|
||||
#[cfg(not(feature = "experiment_api"))]
|
||||
let expected_toml = r#"listen = []
|
||||
verbosity = "Quiet"
|
||||
|
||||
[[peers]]
|
||||
protocol_version = "V02"
|
||||
public_key = ""
|
||||
|
||||
[[peers]]
|
||||
protocol_version = "V03"
|
||||
public_key = ""
|
||||
"#;
|
||||
assert_toml_round(rosenpass, expected_toml).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cli_parse_multiple_peers() {
|
||||
let args = split_str(
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
//! use rosenpass::{hash_domain, hash_domain_ns};
|
||||
//! use rosenpass::hash_domains::protocol;
|
||||
//!
|
||||
//! use rosenpass_ciphers::subtle::keyed_hash::KeyedHash;
|
||||
//!
|
||||
//! // Declaring a custom hash domain
|
||||
//! hash_domain_ns!(protocol, custom_domain, "my custom hash domain label");
|
||||
//!
|
||||
@@ -28,18 +26,15 @@
|
||||
//! hash_domain!(domain_separators, sep1, "1");
|
||||
//! hash_domain!(domain_separators, sep2, "2");
|
||||
//!
|
||||
//! // We use the SHAKE256 hash function for this example
|
||||
//! let hash_choice = KeyedHash::keyed_shake256();
|
||||
//!
|
||||
//! // Generating values under hasher1 with both domain separators
|
||||
//! let h1 = hasher1(hash_choice.clone())?.mix(b"some data")?.dup();
|
||||
//! let h1v1 = h1.mix(&sep1(hash_choice.clone())?)?.mix(b"More data")?.into_value();
|
||||
//! let h1v2 = h1.mix(&sep2(hash_choice.clone())?)?.mix(b"More data")?.into_value();
|
||||
//! let h1 = hasher1()?.mix(b"some data")?.dup();
|
||||
//! let h1v1 = h1.mix(&sep1()?)?.mix(b"More data")?.into_value();
|
||||
//! let h1v2 = h1.mix(&sep2()?)?.mix(b"More data")?.into_value();
|
||||
//!
|
||||
//! // Generating values under hasher2 with both domain separators
|
||||
//! let h2 = hasher2(hash_choice.clone())?.mix(b"some data")?.dup();
|
||||
//! let h2v1 = h2.mix(&sep1(hash_choice.clone())?)?.mix(b"More data")?.into_value();
|
||||
//! let h2v2 = h2.mix(&sep2(hash_choice.clone())?)?.mix(b"More data")?.into_value();
|
||||
//! let h2 = hasher2()?.mix(b"some data")?.dup();
|
||||
//! let h2v1 = h2.mix(&sep1()?)?.mix(b"More data")?.into_value();
|
||||
//! let h2v2 = h2.mix(&sep2()?)?.mix(b"More data")?.into_value();
|
||||
//!
|
||||
//! // All of the domain separators are now different, random strings
|
||||
//! let values = [h1v1, h1v2, h2v1, h2v2];
|
||||
@@ -54,7 +49,6 @@
|
||||
|
||||
use anyhow::Result;
|
||||
use rosenpass_ciphers::hash_domain::HashDomain;
|
||||
use rosenpass_ciphers::subtle::keyed_hash::KeyedHash;
|
||||
|
||||
/// Declare a hash function
|
||||
///
|
||||
@@ -68,8 +62,8 @@ use rosenpass_ciphers::subtle::keyed_hash::KeyedHash;
|
||||
macro_rules! hash_domain_ns {
|
||||
($(#[$($attrss:tt)*])* $base:ident, $name:ident, $($lbl:expr),+ ) => {
|
||||
$(#[$($attrss)*])*
|
||||
pub fn $name(hash_choice: KeyedHash) -> ::anyhow::Result<::rosenpass_ciphers::hash_domain::HashDomain> {
|
||||
let t = $base(hash_choice)?;
|
||||
pub fn $name() -> ::anyhow::Result<::rosenpass_ciphers::hash_domain::HashDomain> {
|
||||
let t = $base()?;
|
||||
$( let t = t.mix($lbl.as_bytes())?; )*
|
||||
Ok(t)
|
||||
}
|
||||
@@ -87,8 +81,8 @@ macro_rules! hash_domain_ns {
|
||||
macro_rules! hash_domain {
|
||||
($(#[$($attrss:tt)*])* $base:ident, $name:ident, $($lbl:expr),+ ) => {
|
||||
$(#[$($attrss)*])*
|
||||
pub fn $name(hash_choice: KeyedHash) -> ::anyhow::Result<[u8; ::rosenpass_ciphers::KEY_LEN]> {
|
||||
let t = $base(hash_choice)?;
|
||||
pub fn $name() -> ::anyhow::Result<[u8; ::rosenpass_ciphers::KEY_LEN]> {
|
||||
let t = $base()?;
|
||||
$( let t = t.mix($lbl.as_bytes())?; )*
|
||||
Ok(t.into_value())
|
||||
}
|
||||
@@ -100,22 +94,15 @@ macro_rules! hash_domain {
|
||||
/// This serves as a global [domain separator](https://en.wikipedia.org/wiki/Domain_separation)
|
||||
/// used in various places in the rosenpass protocol.
|
||||
///
|
||||
/// This is generally used to create further hash-domains for specific purposes. Depending on
|
||||
/// the used hash function, the protocol string is different.
|
||||
/// This is generally used to create further hash-domains for specific purposes. See
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// See the source file for details about how this is used concretely.
|
||||
///
|
||||
/// See the [module](self) documentation on how to use the hash domains in general
|
||||
pub fn protocol(hash_choice: KeyedHash) -> Result<HashDomain> {
|
||||
// Depending on the hash function, we use different protocol strings
|
||||
match hash_choice {
|
||||
KeyedHash::KeyedShake256(_) => HashDomain::zero(hash_choice)
|
||||
.mix("Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 SHAKE256".as_bytes()),
|
||||
KeyedHash::IncorrectHmacBlake2b(_) => HashDomain::zero(hash_choice)
|
||||
.mix("Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 BLAKE2s".as_bytes()),
|
||||
}
|
||||
pub fn protocol() -> Result<HashDomain> {
|
||||
HashDomain::zero().mix("Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 BLAKE2s".as_bytes())
|
||||
}
|
||||
|
||||
hash_domain_ns!(
|
||||
|
||||
@@ -9,12 +9,13 @@
|
||||
//! To achieve this we utilize the zerocopy library.
|
||||
//!
|
||||
use std::mem::size_of;
|
||||
use std::u8;
|
||||
use zerocopy::{AsBytes, FromBytes, FromZeroes};
|
||||
|
||||
use super::RosenpassError;
|
||||
use rosenpass_cipher_traits::primitives::{Aead as _, Kem};
|
||||
use rosenpass_ciphers::{Aead, XAead, KEY_LEN};
|
||||
use rosenpass_ciphers::{EphemeralKem, StaticKem};
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_ciphers::kem::{EphemeralKem, StaticKem};
|
||||
use rosenpass_ciphers::{aead, xaead, KEY_LEN};
|
||||
|
||||
/// Length of a session ID such as [InitHello::sidi]
|
||||
pub const SESSION_ID_LEN: usize = 4;
|
||||
@@ -31,7 +32,7 @@ pub const MAX_MESSAGE_LEN: usize = 2500; // TODO fix this
|
||||
pub const BISCUIT_PT_LEN: usize = size_of::<Biscuit>();
|
||||
|
||||
/// Length in bytes of an encrypted Biscuit (cipher text)
|
||||
pub const BISCUIT_CT_LEN: usize = BISCUIT_PT_LEN + XAead::NONCE_LEN + XAead::TAG_LEN;
|
||||
pub const BISCUIT_CT_LEN: usize = BISCUIT_PT_LEN + xaead::NONCE_LEN + xaead::TAG_LEN;
|
||||
|
||||
/// Size of the field [Envelope::mac]
|
||||
pub const MAC_SIZE: usize = 16;
|
||||
@@ -135,9 +136,9 @@ pub struct InitHello {
|
||||
/// Classic McEliece Ciphertext
|
||||
pub sctr: [u8; StaticKem::CT_LEN],
|
||||
/// Encryped: 16 byte hash of McEliece initiator static key
|
||||
pub pidic: [u8; Aead::TAG_LEN + 32],
|
||||
pub pidic: [u8; aead::TAG_LEN + 32],
|
||||
/// Encrypted TAI64N Time Stamp (against replay attacks)
|
||||
pub auth: [u8; Aead::TAG_LEN],
|
||||
pub auth: [u8; aead::TAG_LEN],
|
||||
}
|
||||
|
||||
/// This is the second message sent by the responder to the initiator
|
||||
@@ -186,7 +187,7 @@ pub struct RespHello {
|
||||
/// Classic McEliece Ciphertext
|
||||
pub scti: [u8; StaticKem::CT_LEN],
|
||||
/// Empty encrypted message (just an auth tag)
|
||||
pub auth: [u8; Aead::TAG_LEN],
|
||||
pub auth: [u8; aead::TAG_LEN],
|
||||
/// Responders handshake state in encrypted form
|
||||
pub biscuit: [u8; BISCUIT_CT_LEN],
|
||||
}
|
||||
@@ -235,7 +236,7 @@ pub struct InitConf {
|
||||
/// Responders handshake state in encrypted form
|
||||
pub biscuit: [u8; BISCUIT_CT_LEN],
|
||||
/// Empty encrypted message (just an auth tag)
|
||||
pub auth: [u8; Aead::TAG_LEN],
|
||||
pub auth: [u8; aead::TAG_LEN],
|
||||
}
|
||||
|
||||
/// This is the fourth message sent by the initiator to the responder
|
||||
@@ -291,7 +292,7 @@ pub struct EmptyData {
|
||||
/// Nonce
|
||||
pub ctr: [u8; 8],
|
||||
/// Empty encrypted message (just an auth tag)
|
||||
pub auth: [u8; Aead::TAG_LEN],
|
||||
pub auth: [u8; aead::TAG_LEN],
|
||||
}
|
||||
|
||||
/// Cookie encrypted and sent to the initiator by the responder in [RespHello]
|
||||
@@ -345,7 +346,7 @@ pub struct CookieReplyInner {
|
||||
/// Session ID of the sender (initiator)
|
||||
pub sid: [u8; 4],
|
||||
/// Encrypted cookie with authenticated initiator `mac`
|
||||
pub cookie_encrypted: [u8; XAead::NONCE_LEN + COOKIE_SIZE + XAead::TAG_LEN],
|
||||
pub cookie_encrypted: [u8; xaead::NONCE_LEN + COOKIE_SIZE + xaead::TAG_LEN],
|
||||
}
|
||||
|
||||
/// Specialized message for use in the cookie mechanism.
|
||||
@@ -436,8 +437,7 @@ impl From<MsgType> for u8 {
|
||||
#[cfg(test)]
|
||||
mod test_constants {
|
||||
use crate::msgs::{BISCUIT_CT_LEN, BISCUIT_PT_LEN};
|
||||
use rosenpass_cipher_traits::primitives::Aead as _;
|
||||
use rosenpass_ciphers::{XAead, KEY_LEN};
|
||||
use rosenpass_ciphers::{xaead, KEY_LEN};
|
||||
|
||||
#[test]
|
||||
fn sodium_keysize() {
|
||||
@@ -453,7 +453,7 @@ mod test_constants {
|
||||
fn biscuit_ct_len() {
|
||||
assert_eq!(
|
||||
BISCUIT_CT_LEN,
|
||||
BISCUIT_PT_LEN + XAead::NONCE_LEN + XAead::TAG_LEN
|
||||
BISCUIT_PT_LEN + xaead::NONCE_LEN + xaead::TAG_LEN
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use super::{CryptoServer, PeerPtr, SPk, SSk, SymKey};
|
||||
use crate::config::ProtocolVersion;
|
||||
use rosenpass_util::{
|
||||
build::Build,
|
||||
mem::{DiscardResultExt, SwapWithDefaultExt},
|
||||
@@ -7,6 +5,8 @@ use rosenpass_util::{
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
use super::{CryptoServer, PeerPtr, SPk, SSk, SymKey};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// A pair of matching public/secret keys used to launch the crypto server.
|
||||
///
|
||||
@@ -146,18 +146,17 @@ pub struct MissingKeypair;
|
||||
/// ```rust
|
||||
/// use rosenpass_util::build::Build;
|
||||
/// use rosenpass::protocol::{BuildCryptoServer, Keypair, PeerParams, SPk, SymKey};
|
||||
/// use rosenpass::config::ProtocolVersion;
|
||||
///
|
||||
/// // We have to define the security policy before using Secrets.
|
||||
/// use rosenpass_secret_memory::secret_policy_use_only_malloc_secrets;
|
||||
/// secret_policy_use_only_malloc_secrets();
|
||||
///
|
||||
/// let keypair = Keypair::random();
|
||||
/// let peer1 = PeerParams { psk: Some(SymKey::random()), pk: SPk::random(), protocol_version: ProtocolVersion::V02 };
|
||||
/// let peer2 = PeerParams { psk: None, pk: SPk::random(), protocol_version: ProtocolVersion::V02 };
|
||||
/// let peer1 = PeerParams { psk: Some(SymKey::random()), pk: SPk::random() };
|
||||
/// let peer2 = PeerParams { psk: None, pk: SPk::random() };
|
||||
///
|
||||
/// let mut builder = BuildCryptoServer::new(Some(keypair.clone()), vec![peer1]);
|
||||
/// builder.add_peer(peer2.psk.clone(), peer2.pk, ProtocolVersion::V02);
|
||||
/// builder.add_peer(peer2.psk.clone(), peer2.pk);
|
||||
///
|
||||
/// let server = builder.build().expect("build failed");
|
||||
/// assert_eq!(server.peers.len(), 2);
|
||||
@@ -187,16 +186,8 @@ impl Build<CryptoServer> for BuildCryptoServer {
|
||||
|
||||
let mut srv = CryptoServer::new(sk, pk);
|
||||
|
||||
for (
|
||||
idx,
|
||||
PeerParams {
|
||||
psk,
|
||||
pk,
|
||||
protocol_version,
|
||||
},
|
||||
) in self.peers.into_iter().enumerate()
|
||||
{
|
||||
let PeerPtr(idx2) = srv.add_peer(psk, pk, protocol_version.into())?;
|
||||
for (idx, PeerParams { psk, pk }) in self.peers.into_iter().enumerate() {
|
||||
let PeerPtr(idx2) = srv.add_peer(psk, pk)?;
|
||||
assert!(idx == idx2, "Peer id changed during CryptoServer construction from {idx} to {idx2}. This is a developer error.")
|
||||
}
|
||||
|
||||
@@ -217,8 +208,6 @@ pub struct PeerParams {
|
||||
pub psk: Option<SymKey>,
|
||||
/// Public key identifying the peer.
|
||||
pub pk: SPk,
|
||||
/// The used protocol version.
|
||||
pub protocol_version: ProtocolVersion,
|
||||
}
|
||||
|
||||
impl BuildCryptoServer {
|
||||
@@ -316,7 +305,6 @@ impl BuildCryptoServer {
|
||||
/// Adding peers to an existing builder:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rosenpass::config::ProtocolVersion;
|
||||
/// // We have to define the security policy before using Secrets.
|
||||
/// use rosenpass_secret_memory::secret_policy_use_only_malloc_secrets;
|
||||
/// secret_policy_use_only_malloc_secrets();
|
||||
@@ -335,7 +323,7 @@ impl BuildCryptoServer {
|
||||
/// // Now we've found a peer that should be added to the configuration
|
||||
/// let pre_shared_key = SymKey::random();
|
||||
/// let public_key = SPk::random();
|
||||
/// builder.with_added_peer(Some(pre_shared_key.clone()), public_key.clone(), ProtocolVersion::V02);
|
||||
/// builder.with_added_peer(Some(pre_shared_key.clone()), public_key.clone());
|
||||
///
|
||||
/// // New server instances will then start with the peer being registered already
|
||||
/// let server = builder.build().expect("build failed");
|
||||
@@ -345,30 +333,16 @@ impl BuildCryptoServer {
|
||||
/// assert_eq!(peer.spkt, public_key);
|
||||
/// assert_eq!(peer_psk.secret(), pre_shared_key.secret());
|
||||
/// ```
|
||||
pub fn with_added_peer(
|
||||
&mut self,
|
||||
psk: Option<SymKey>,
|
||||
pk: SPk,
|
||||
protocol_version: ProtocolVersion,
|
||||
) -> &mut Self {
|
||||
pub fn with_added_peer(&mut self, psk: Option<SymKey>, pk: SPk) -> &mut Self {
|
||||
// TODO: Check here already whether peer was already added
|
||||
self.peers.push(PeerParams {
|
||||
psk,
|
||||
pk,
|
||||
protocol_version,
|
||||
});
|
||||
self.peers.push(PeerParams { psk, pk });
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a new entry to the list of registered peers, with or without a pre-shared key.
|
||||
pub fn add_peer(
|
||||
&mut self,
|
||||
psk: Option<SymKey>,
|
||||
pk: SPk,
|
||||
protocol_version: ProtocolVersion,
|
||||
) -> PeerPtr {
|
||||
pub fn add_peer(&mut self, psk: Option<SymKey>, pk: SPk) -> PeerPtr {
|
||||
let id = PeerPtr(self.peers.len());
|
||||
self.with_added_peer(psk, pk, protocol_version);
|
||||
self.with_added_peer(psk, pk);
|
||||
id
|
||||
}
|
||||
|
||||
@@ -382,8 +356,6 @@ impl BuildCryptoServer {
|
||||
///
|
||||
/// ```rust
|
||||
/// // We have to define the security policy before using Secrets.
|
||||
/// use rosenpass::config::ProtocolVersion;
|
||||
/// use rosenpass::hash_domains::protocol;
|
||||
/// use rosenpass_secret_memory::secret_policy_use_only_malloc_secrets;
|
||||
/// secret_policy_use_only_malloc_secrets();
|
||||
///
|
||||
@@ -393,7 +365,7 @@ impl BuildCryptoServer {
|
||||
/// let keypair = Keypair::random();
|
||||
/// let peer_pk = SPk::random();
|
||||
/// let mut builder = BuildCryptoServer::new(Some(keypair.clone()), vec![]);
|
||||
/// builder.add_peer(None, peer_pk, ProtocolVersion::V02);
|
||||
/// builder.add_peer(None, peer_pk);
|
||||
///
|
||||
/// // Extract configuration parameters from the decomissioned builder
|
||||
/// let (keypair_option, peers) = builder.take_parts();
|
||||
|
||||
@@ -25,24 +25,23 @@
|
||||
//! ```
|
||||
//! use std::ops::DerefMut;
|
||||
//! use rosenpass_secret_memory::policy::*;
|
||||
//! use rosenpass_cipher_traits::primitives::Kem;
|
||||
//! use rosenpass_ciphers::StaticKem;
|
||||
//! use rosenpass_cipher_traits::Kem;
|
||||
//! use rosenpass_ciphers::kem::StaticKem;
|
||||
//! use rosenpass::{
|
||||
//! protocol::{SSk, SPk, MsgBuf, PeerPtr, CryptoServer, SymKey},
|
||||
//! };
|
||||
//! # fn main() -> anyhow::Result<()> {
|
||||
//! // Set security policy for storing secrets
|
||||
//!
|
||||
//! use rosenpass::protocol::ProtocolVersion;
|
||||
//! secret_policy_try_use_memfd_secrets();
|
||||
//!
|
||||
//! // initialize secret and public key for peer a ...
|
||||
//! let (mut peer_a_sk, mut peer_a_pk) = (SSk::zero(), SPk::zero());
|
||||
//! StaticKem.keygen(peer_a_sk.secret_mut(), peer_a_pk.deref_mut())?;
|
||||
//! StaticKem::keygen(peer_a_sk.secret_mut(), peer_a_pk.deref_mut())?;
|
||||
//!
|
||||
//! // ... and for peer b
|
||||
//! let (mut peer_b_sk, mut peer_b_pk) = (SSk::zero(), SPk::zero());
|
||||
//! StaticKem.keygen(peer_b_sk.secret_mut(), peer_b_pk.deref_mut())?;
|
||||
//! StaticKem::keygen(peer_b_sk.secret_mut(), peer_b_pk.deref_mut())?;
|
||||
//!
|
||||
//! // initialize server and a pre-shared key
|
||||
//! let psk = SymKey::random();
|
||||
@@ -50,8 +49,8 @@
|
||||
//! let mut b = CryptoServer::new(peer_b_sk, peer_b_pk.clone());
|
||||
//!
|
||||
//! // introduce peers to each other
|
||||
//! a.add_peer(Some(psk.clone()), peer_b_pk, ProtocolVersion::V03)?;
|
||||
//! b.add_peer(Some(psk), peer_a_pk, ProtocolVersion::V03)?;
|
||||
//! a.add_peer(Some(psk.clone()), peer_b_pk)?;
|
||||
//! b.add_peer(Some(psk), peer_a_pk)?;
|
||||
//!
|
||||
//! // declare buffers for message exchange
|
||||
//! let (mut a_buf, mut b_buf) = (MsgBuf::zero(), MsgBuf::zero());
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,8 +14,6 @@ use rosenpass::api::{
|
||||
self, add_listen_socket_response_status, add_psk_broker_response_status,
|
||||
supply_keypair_response_status,
|
||||
};
|
||||
use rosenpass::config::ProtocolVersion;
|
||||
use rosenpass::protocol::SymKey;
|
||||
use rosenpass_util::{
|
||||
b64::B64Display,
|
||||
file::LoadValueB64,
|
||||
@@ -29,6 +27,8 @@ use std::os::fd::{AsFd, AsRawFd};
|
||||
use tempfile::TempDir;
|
||||
use zerocopy::AsBytes;
|
||||
|
||||
use rosenpass::protocol::SymKey;
|
||||
|
||||
struct KillChild(std::process::Child);
|
||||
|
||||
impl Drop for KillChild {
|
||||
@@ -48,16 +48,7 @@ impl Drop for KillChild {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn api_integration_api_setup_v02() -> anyhow::Result<()> {
|
||||
api_integration_api_setup(ProtocolVersion::V02)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn api_integration_api_setup_v03() -> anyhow::Result<()> {
|
||||
api_integration_api_setup(ProtocolVersion::V03)
|
||||
}
|
||||
|
||||
fn api_integration_api_setup(protocol_version: ProtocolVersion) -> anyhow::Result<()> {
|
||||
fn api_integration_api_setup() -> anyhow::Result<()> {
|
||||
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
||||
|
||||
let dir = TempDir::with_prefix("rosenpass-api-integration-test")?;
|
||||
@@ -105,7 +96,6 @@ fn api_integration_api_setup(protocol_version: ProtocolVersion) -> anyhow::Resul
|
||||
peer: format!("{}", peer_b_wg_peer_id.fmt_b64::<8129>()),
|
||||
extra_params: vec![],
|
||||
}),
|
||||
protocol_version: protocol_version.clone(),
|
||||
}],
|
||||
};
|
||||
|
||||
@@ -126,7 +116,6 @@ fn api_integration_api_setup(protocol_version: ProtocolVersion) -> anyhow::Resul
|
||||
endpoint: Some(peer_a_endpoint.to_owned()),
|
||||
pre_shared_key: None,
|
||||
wg: None,
|
||||
protocol_version: protocol_version.clone(),
|
||||
}],
|
||||
};
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ use rosenpass_util::{mem::DiscardResultExt, zerocopy::ZerocopySliceExt};
|
||||
use tempfile::TempDir;
|
||||
use zerocopy::AsBytes;
|
||||
|
||||
use rosenpass::config::ProtocolVersion;
|
||||
use rosenpass::protocol::SymKey;
|
||||
|
||||
struct KillChild(std::process::Child);
|
||||
@@ -38,15 +37,7 @@ impl Drop for KillChild {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn api_integration_test_v02() -> anyhow::Result<()> {
|
||||
api_integration_test(ProtocolVersion::V02)
|
||||
}
|
||||
|
||||
fn api_integration_test_v03() -> anyhow::Result<()> {
|
||||
api_integration_test(ProtocolVersion::V03)
|
||||
}
|
||||
|
||||
fn api_integration_test(protocol_version: ProtocolVersion) -> anyhow::Result<()> {
|
||||
fn api_integration_test() -> anyhow::Result<()> {
|
||||
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
||||
|
||||
let dir = TempDir::with_prefix("rosenpass-api-integration-test")?;
|
||||
@@ -82,7 +73,6 @@ fn api_integration_test(protocol_version: ProtocolVersion) -> anyhow::Result<()>
|
||||
endpoint: None,
|
||||
pre_shared_key: None,
|
||||
wg: None,
|
||||
protocol_version: protocol_version.clone(),
|
||||
}],
|
||||
};
|
||||
|
||||
@@ -103,7 +93,6 @@ fn api_integration_test(protocol_version: ProtocolVersion) -> anyhow::Result<()>
|
||||
endpoint: Some(peer_a_endpoint.to_owned()),
|
||||
pre_shared_key: None,
|
||||
wg: None,
|
||||
protocol_version: protocol_version.clone(),
|
||||
}],
|
||||
};
|
||||
|
||||
|
||||
@@ -1,32 +1,25 @@
|
||||
use std::{
|
||||
net::SocketAddr,
|
||||
ops::DerefMut,
|
||||
path::PathBuf,
|
||||
str::FromStr,
|
||||
sync::mpsc,
|
||||
thread::{self, sleep},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use rosenpass::config::ProtocolVersion;
|
||||
use anyhow::ensure;
|
||||
use rosenpass::{
|
||||
app_server::{AppServer, AppServerTest, MAX_B64_KEY_SIZE},
|
||||
app_server::{ipv4_any_binding, ipv6_any_binding, AppServer, AppServerTest, MAX_B64_KEY_SIZE},
|
||||
protocol::{SPk, SSk, SymKey},
|
||||
};
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_ciphers::kem::StaticKem;
|
||||
use rosenpass_secret_memory::Secret;
|
||||
use rosenpass_util::{file::LoadValueB64, functional::run, mem::DiscardResultExt, result::OkExt};
|
||||
|
||||
#[test]
|
||||
fn key_exchange_with_app_server_v02() -> anyhow::Result<()> {
|
||||
key_exchange_with_app_server(ProtocolVersion::V02)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn key_exchange_with_app_server_v03() -> anyhow::Result<()> {
|
||||
key_exchange_with_app_server(ProtocolVersion::V03)
|
||||
}
|
||||
|
||||
fn key_exchange_with_app_server(protocol_version: ProtocolVersion) -> anyhow::Result<()> {
|
||||
fn key_exchange_with_app_server() -> anyhow::Result<()> {
|
||||
let tmpdir = tempfile::tempdir()?;
|
||||
let outfile_a = tmpdir.path().join("osk_a");
|
||||
let outfile_b = tmpdir.path().join("osk_b");
|
||||
@@ -63,14 +56,8 @@ fn key_exchange_with_app_server(protocol_version: ProtocolVersion) -> anyhow::Re
|
||||
let outfile = Some(osk);
|
||||
let port = otr_port;
|
||||
let hostname = is_client.then(|| format!("[::1]:{port}"));
|
||||
srv.app_srv.add_peer(
|
||||
psk,
|
||||
pk,
|
||||
outfile,
|
||||
broker_peer,
|
||||
hostname,
|
||||
protocol_version.clone(),
|
||||
)?;
|
||||
srv.app_srv
|
||||
.add_peer(psk, pk, outfile, broker_peer, hostname)?;
|
||||
|
||||
srv.app_srv.event_loop()
|
||||
})
|
||||
@@ -114,7 +101,7 @@ struct TestServer {
|
||||
impl TestServer {
|
||||
fn new(termination_queue: mpsc::Receiver<()>) -> anyhow::Result<Self> {
|
||||
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
|
||||
StaticKem.keygen(sk.secret_mut(), pk.deref_mut())?;
|
||||
StaticKem::keygen(sk.secret_mut(), pk.deref_mut())?;
|
||||
|
||||
let keypair = Some((sk, pk));
|
||||
let addrs = vec![
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::process::Command;
|
||||
use std::{borrow::Borrow, process::Command};
|
||||
|
||||
#[test]
|
||||
fn test_gen_ipc_msg_types() -> anyhow::Result<()> {
|
||||
@@ -9,11 +9,7 @@ fn test_gen_ipc_msg_types() -> anyhow::Result<()> {
|
||||
|
||||
// Smoke tests only
|
||||
assert!(stdout.contains("type RawMsgType = u128;"));
|
||||
// For Blake2b:
|
||||
assert!(stdout.contains("const SUPPLY_KEYPAIR_RESPONSE : RawMsgType = RawMsgType::from_le_bytes(hex!(\"f2dc 49bd e261 5f10 40b7 3c16 ec61 edb9\"));"));
|
||||
// For SHAKE256:
|
||||
assert!(stdout.contains("const SUPPLY_KEYPAIR_RESPONSE : RawMsgType = RawMsgType::from_le_bytes(hex!(\"ff80 3886 68a4 47ce 2ae6 0915 0972 682f\"))"));
|
||||
|
||||
// TODO: Also test SHAKE256 here
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ fn run_server_client_exchange(
|
||||
});
|
||||
|
||||
// give them some time to do the key exchange under load
|
||||
std::thread::sleep(Duration::from_secs(30));
|
||||
std::thread::sleep(Duration::from_secs(10));
|
||||
|
||||
// time's up, kill the childs
|
||||
server_terminate.send(()).unwrap();
|
||||
@@ -251,7 +251,7 @@ fn check_exchange_under_normal() {
|
||||
fs::remove_dir_all(&tmpdir).unwrap();
|
||||
}
|
||||
|
||||
// check that we can trigger a DoS condition, and we can exchange keys under DoS
|
||||
// check that we can trigger a DoS condition and we can exchange keys under DoS
|
||||
// This test creates a responder (server) with the feature flag "integration_test_always_under_load" to always be under load condition for the test.
|
||||
#[test]
|
||||
#[serial]
|
||||
|
||||
@@ -46,6 +46,7 @@ fn main_fn_generates_manpages() -> anyhow::Result<()> {
|
||||
"rosenpass-exchange-config.1",
|
||||
"rosenpass-gen-config.1",
|
||||
"rosenpass-gen-keys.1",
|
||||
"rosenpass-keygen.1",
|
||||
"rosenpass-validate.1",
|
||||
];
|
||||
|
||||
@@ -55,10 +56,7 @@ fn main_fn_generates_manpages() -> anyhow::Result<()> {
|
||||
.map(|name| (name, dir.path().join(name)))
|
||||
.map(|(name, path)| {
|
||||
let res = std::process::Command::new("man").arg(path).output()?;
|
||||
assert!(
|
||||
res.status.success(),
|
||||
"Error rendering manpage {name} using man"
|
||||
);
|
||||
assert!(res.status.success());
|
||||
let body = res
|
||||
.stdout
|
||||
.apply(String::from_utf8)?
|
||||
@@ -66,6 +64,7 @@ fn main_fn_generates_manpages() -> anyhow::Result<()> {
|
||||
Ok((name, body))
|
||||
})
|
||||
.collect::<anyhow::Result<_>>()?;
|
||||
|
||||
for (name, body) in man_texts.iter() {
|
||||
expect_sections(body, &["NAME", "SYNOPSIS", "OPTIONS"])?;
|
||||
|
||||
|
||||
@@ -5,33 +5,24 @@ use std::{
|
||||
ops::DerefMut,
|
||||
};
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_ciphers::kem::StaticKem;
|
||||
use rosenpass_util::result::OkExt;
|
||||
|
||||
use rosenpass::protocol::{
|
||||
testutils::time_travel_forward, CryptoServer, HostIdentification, MsgBuf, PeerPtr, PollResult,
|
||||
ProtocolVersion, SPk, SSk, SymKey, Timing, UNENDING,
|
||||
SPk, SSk, SymKey, Timing, UNENDING,
|
||||
};
|
||||
|
||||
// TODO: Most of the utility functions in here should probably be moved to
|
||||
// rosenpass::protocol::testutils;
|
||||
|
||||
#[test]
|
||||
fn test_successful_exchange_with_poll_v02() -> anyhow::Result<()> {
|
||||
test_successful_exchange_with_poll(ProtocolVersion::V02)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_successful_exchange_with_poll_v03() -> anyhow::Result<()> {
|
||||
test_successful_exchange_with_poll(ProtocolVersion::V03)
|
||||
}
|
||||
|
||||
fn test_successful_exchange_with_poll(protocol_version: ProtocolVersion) -> anyhow::Result<()> {
|
||||
fn test_successful_exchange_with_poll() -> anyhow::Result<()> {
|
||||
// Set security policy for storing secrets; choose the one that is faster for testing
|
||||
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
||||
|
||||
let mut sim = RosenpassSimulator::new(protocol_version)?;
|
||||
let mut sim = RosenpassSimulator::new()?;
|
||||
sim.poll_loop(150)?; // Poll 75 times
|
||||
let transcript = sim.transcript;
|
||||
|
||||
@@ -51,9 +42,9 @@ fn test_successful_exchange_with_poll(protocol_version: ProtocolVersion) -> anyh
|
||||
);
|
||||
#[cfg(not(coverage))]
|
||||
assert!(
|
||||
_completions[0].0 < 60.0,
|
||||
_completions[0].0 < 20.0,
|
||||
"\
|
||||
First key exchange should happen in under 60 seconds!\n\
|
||||
First key exchange should happen in under twenty seconds!\n\
|
||||
Transcript: {transcript:?}\n\
|
||||
Completions: {_completions:?}\
|
||||
"
|
||||
@@ -88,23 +79,12 @@ fn test_successful_exchange_with_poll(protocol_version: ProtocolVersion) -> anyh
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_successful_exchange_under_packet_loss_v02() -> anyhow::Result<()> {
|
||||
test_successful_exchange_under_packet_loss(ProtocolVersion::V02)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_successful_exchange_under_packet_loss_v03() -> anyhow::Result<()> {
|
||||
test_successful_exchange_under_packet_loss(ProtocolVersion::V03)
|
||||
}
|
||||
|
||||
fn test_successful_exchange_under_packet_loss(
|
||||
protocol_version: ProtocolVersion,
|
||||
) -> anyhow::Result<()> {
|
||||
fn test_successful_exchange_under_packet_loss() -> anyhow::Result<()> {
|
||||
// Set security policy for storing secrets; choose the one that is faster for testing
|
||||
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
||||
|
||||
// Create the simulator
|
||||
let mut sim = RosenpassSimulator::new(protocol_version)?;
|
||||
let mut sim = RosenpassSimulator::new()?;
|
||||
|
||||
// Make sure the servers are set to under load condition
|
||||
sim.srv_a.under_load = true;
|
||||
@@ -119,7 +99,7 @@ fn test_successful_exchange_under_packet_loss(
|
||||
event: ServerEvent::Transmit(_, _),
|
||||
} = ev
|
||||
{
|
||||
// Drop every tenth package
|
||||
// Drop every fifth package
|
||||
if pkg_counter % 10 == 0 {
|
||||
source.drop_outgoing_packet(&mut sim);
|
||||
}
|
||||
@@ -145,9 +125,9 @@ fn test_successful_exchange_under_packet_loss(
|
||||
);
|
||||
#[cfg(not(coverage))]
|
||||
assert!(
|
||||
_completions[0].0 < 60.0,
|
||||
_completions[0].0 < 10.0,
|
||||
"\
|
||||
First key exchange should happen in under 60 seconds!\n\
|
||||
First key exchange should happen in under twenty seconds!\n\
|
||||
Transcript: {transcript:?}\n\
|
||||
Completions: {_completions:?}\
|
||||
"
|
||||
@@ -292,21 +272,21 @@ struct SimulatorServer {
|
||||
|
||||
impl RosenpassSimulator {
|
||||
/// Set up the simulator
|
||||
fn new(protocol_version: ProtocolVersion) -> anyhow::Result<Self> {
|
||||
fn new() -> anyhow::Result<Self> {
|
||||
// Set up the first server
|
||||
let (mut peer_a_sk, mut peer_a_pk) = (SSk::zero(), SPk::zero());
|
||||
StaticKem.keygen(peer_a_sk.secret_mut(), peer_a_pk.deref_mut())?;
|
||||
StaticKem::keygen(peer_a_sk.secret_mut(), peer_a_pk.deref_mut())?;
|
||||
let mut srv_a = CryptoServer::new(peer_a_sk, peer_a_pk.clone());
|
||||
|
||||
// …and the second server.
|
||||
let (mut peer_b_sk, mut peer_b_pk) = (SSk::zero(), SPk::zero());
|
||||
StaticKem.keygen(peer_b_sk.secret_mut(), peer_b_pk.deref_mut())?;
|
||||
StaticKem::keygen(peer_b_sk.secret_mut(), peer_b_pk.deref_mut())?;
|
||||
let mut srv_b = CryptoServer::new(peer_b_sk, peer_b_pk.clone());
|
||||
|
||||
// Generate a PSK and introduce the Peers to each other.
|
||||
let psk = SymKey::random();
|
||||
let peer_a = srv_a.add_peer(Some(psk.clone()), peer_b_pk, protocol_version.clone())?;
|
||||
let peer_b = srv_b.add_peer(Some(psk), peer_a_pk, protocol_version.clone())?;
|
||||
let peer_a = srv_a.add_peer(Some(psk.clone()), peer_b_pk)?;
|
||||
let peer_b = srv_b.add_peer(Some(psk), peer_a_pk)?;
|
||||
|
||||
// Set up the individual server data structures
|
||||
let srv_a = SimulatorServer::new(srv_a, peer_b);
|
||||
@@ -334,8 +314,8 @@ impl RosenpassSimulator {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Every call to poll produces one [TranscriptEvent]
|
||||
/// and implicitly adds it to [Self::transcript]
|
||||
/// Every call to poll produces one [TranscriptEvent] and
|
||||
/// and implicitly adds it to [Self:::transcript]
|
||||
fn poll(&mut self) -> anyhow::Result<&TranscriptEvent> {
|
||||
let ev = TranscriptEvent::begin_poll()
|
||||
.try_fold_with(|| self.poll_focus.poll(self))?
|
||||
@@ -510,11 +490,8 @@ impl ServerPtr {
|
||||
// Let the crypto server handle the message now
|
||||
let mut tx_buf = MsgBuf::zero();
|
||||
let handle_msg_result = if self.get(sim).under_load {
|
||||
self.srv_mut(sim).handle_msg_under_load(
|
||||
rx_msg.borrow(),
|
||||
tx_buf.borrow_mut(),
|
||||
&self.other(),
|
||||
)
|
||||
self.srv_mut(sim)
|
||||
.handle_msg_under_load(rx_msg.borrow(), tx_buf.borrow_mut(), &self)
|
||||
} else {
|
||||
self.srv_mut(sim)
|
||||
.handle_msg(rx_msg.borrow(), tx_buf.borrow_mut())
|
||||
|
||||
@@ -6,7 +6,6 @@ license = "MIT OR Apache-2.0"
|
||||
description = "Build post-quantum-secure VPNs with WireGuard!"
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -15,7 +14,7 @@ anyhow = { workspace = true }
|
||||
base64ct = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
x25519-dalek = { workspace = true, features = ["static_secrets"] }
|
||||
x25519-dalek = { version = "2", features = ["static_secrets"] }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
rosenpass = { workspace = true }
|
||||
@@ -27,8 +26,8 @@ rosenpass-wireguard-broker = { workspace = true }
|
||||
|
||||
tokio = { workspace = true }
|
||||
|
||||
futures = { workspace = true }
|
||||
futures-util = { workspace = true }
|
||||
futures = "0.3"
|
||||
futures-util = "0.3"
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "freebsd"))'.dependencies]
|
||||
ctrlc-async = "3.2"
|
||||
@@ -44,4 +43,4 @@ stacker = { workspace = true }
|
||||
|
||||
[features]
|
||||
experiment_memfd_secret = []
|
||||
experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux_all"]
|
||||
experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux"]
|
||||
|
||||
@@ -6,10 +6,10 @@ use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::{net::SocketAddr, path::PathBuf, process::Command};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
use crate::key::WG_B64_LEN;
|
||||
use anyhow::Result;
|
||||
use rosenpass::config::ProtocolVersion;
|
||||
|
||||
/// Used to define a peer for the rosenpass connection that consists of
|
||||
/// a directory for storing public keys and optionally an IP address and port of the endpoint,
|
||||
@@ -24,9 +24,6 @@ pub struct ExchangePeer {
|
||||
pub persistent_keepalive: Option<u32>,
|
||||
/// The IPs that are allowed for this peer.
|
||||
pub allowed_ips: Option<String>,
|
||||
/// The protocol version used by the peer.
|
||||
#[serde(default)]
|
||||
pub protocol_version: ProtocolVersion,
|
||||
}
|
||||
|
||||
/// Options for the exchange operation of the `rp` binary.
|
||||
@@ -359,7 +356,6 @@ pub async fn exchange(options: ExchangeOptions) -> Result<()> {
|
||||
None,
|
||||
broker_peer,
|
||||
peer.endpoint.map(|x| x.to_string()),
|
||||
peer.protocol_version,
|
||||
)?;
|
||||
|
||||
// Configure routes, equivalent to `ip route replace <allowed_ips> dev <dev>` and set up
|
||||
|
||||
@@ -10,8 +10,8 @@ use rosenpass_util::file::{LoadValueB64, StoreValue, StoreValueB64};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use rosenpass::protocol::{SPk, SSk};
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_ciphers::kem::StaticKem;
|
||||
use rosenpass_secret_memory::{file::StoreSecret as _, Public, Secret};
|
||||
|
||||
/// The length of wireguard keys as a length in base 64 encoding.
|
||||
@@ -66,7 +66,7 @@ pub fn genkey(private_keys_dir: &Path) -> Result<()> {
|
||||
if !pqsk_path.exists() && !pqpk_path.exists() {
|
||||
let mut pqsk = SSk::random();
|
||||
let mut pqpk = SPk::random();
|
||||
StaticKem.keygen(pqsk.secret_mut(), pqpk.deref_mut())?;
|
||||
StaticKem::keygen(pqsk.secret_mut(), pqpk.deref_mut())?;
|
||||
pqpk.store(pqpk_path)?;
|
||||
pqsk.store_secret(pqsk_path)?;
|
||||
} else {
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
[toolchain]
|
||||
channel = "1.77.0"
|
||||
@@ -8,7 +8,6 @@ description = "Rosenpass internal utilities for storing secrets in memory"
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
# Supply Chain Protection
|
||||
|
||||
The CI for this repository uses the following tools to protect the supply chain:
|
||||
|
||||
- [cargo-vet](https://github.com/mozilla/cargo-vet): vets dependencies based on existing audits with the aim of incrementally using fewer and fewer unaudited dependencies.
|
||||
- [cargo-deny](https://github.com/EmbarkStudios/cargo-deny): checks for unwanted licenses, crates, and other security issues.
|
||||
- [cargo-supply-chain](https://github.com/rust-secure-code/cargo-supply-chain): generates reports on dependencies and their authors.
|
||||
|
||||
Below, we briefly explain how to configure these tools and how to make appropriate adjustments when dependencies change.
|
||||
|
||||
## cargo-vet
|
||||
|
||||
`cargo-vet` vets dependencies based on performed audits. In order to avoid redundant work, it encourages the use of already
|
||||
performed audits by trusted organizations or people. As of now, we trust audits performed by the
|
||||
[actix team](https://raw.githubusercontent.com/actix/supply-chain/main/audits.toml), the [bytecode-alliance](https://raw.githubusercontent.com/bytecodealliance/wasmtime/main/supply-chain/audits.toml)
|
||||
[embark-studios](https://raw.githubusercontent.com/EmbarkStudios/rust-ecosystem/main/audits.toml),
|
||||
[fermyon](https://raw.githubusercontent.com/fermyon/spin/main/supply-chain/audits.toml),
|
||||
[google](https://raw.githubusercontent.com/google/supply-chain/main/audits.toml),
|
||||
the [ISRG](https://raw.githubusercontent.com/divviup/libprio-rs/main/supply-chain/audits.toml),
|
||||
the [mozilla team](https://raw.githubusercontent.com/mozilla/cargo-vet/main/audits.toml),
|
||||
and the [ZCash foundaton](https://raw.githubusercontent.com/zcash/rust-ecosystem/main/supply-chain/audits.toml).
|
||||
Since, as of now, only a minority of crates have been audited, the tool aims at incrementally using fewer and fewer unaudited dependencies by initially exempting all dependencies
|
||||
from the need to be audited for the CI to pass. When more and more crates are audited, the tool prompts to reevaluate
|
||||
the list of exemptions and remove as many as possible.
|
||||
|
||||
### Configuration
|
||||
|
||||
The configuration files for cargo-vet are located in the `supply-chain` directory. The central configuration file is
|
||||
`config.toml`, where the lst of trusted organizations and the list of exemptions are defined.
|
||||
|
||||
### Adding new dependencies
|
||||
|
||||
Make sure to [install cargo vet](https://mozilla.github.io/cargo-vet/install.html) first.
|
||||
Then, when adding new dependencies, run `cargo vet suggest` before committing. If the dependency is not safe-to-deploy,
|
||||
add it to the exemptions in the file `supply-chain/config.toml`.
|
||||
|
||||
For all further configration options, please refer to the [cargo-vet documentation](https://mozilla.github.io/cargo-vet/).
|
||||
|
||||
## cargo-deny
|
||||
|
||||
`cargo-deny` checks for unwanted licenses, crates, and other security issues. It is configured in the file `deny.toml`.
|
||||
|
||||
### Licenses
|
||||
|
||||
The only allowed licenses are the MIT license, the Apache-2.0 license, Apache-2.0 license WITH LLVM-exception,
|
||||
BSD-3-Clause license and the ISC license. All other licenses are banned. An exception is made for the
|
||||
`unicode-ident`-crate, for which we allow the Unicode-DFS-2016 license.
|
||||
|
||||
### Security vulnerabilities
|
||||
|
||||
The tool checks for security vulnerabilities in dependencies. If a vulnerability is found, the CI will fail. If you must,
|
||||
you can add exceptions in the `deny.toml` file, but this should only be a last resort.
|
||||
|
||||
### Adding new dependencies
|
||||
|
||||
Make sure to [install cargo deny](https://embarkstudios.github.io/cargo-deny/) first. Then, when adding new dependencies,
|
||||
run `cargo deny check` before committing. If there are issues wth the dependency reported by `cargo deny check`, you
|
||||
should try to resolve it appropriately. If this is not possible thoroughly consider if the dependency is necessary and
|
||||
an exception should be made in the `deny.toml` file.
|
||||
|
||||
For all further configration options, please refer to the [cargo-deny documentation](https://embarkstudios.github.io/cargo-deny/).
|
||||
|
||||
## cargo-supply-chain
|
||||
|
||||
`cargo-supply-chain` generates reports on dependencies and their authors. These reports should be reviewed regularly.
|
||||
However, they will not cause the CI to fail.
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
# cargo-vet audits file
|
||||
|
||||
[audits]
|
||||
@@ -1,970 +0,0 @@
|
||||
|
||||
# cargo-vet config file
|
||||
|
||||
[cargo-vet]
|
||||
version = "0.10"
|
||||
|
||||
[imports.actix]
|
||||
url = "https://raw.githubusercontent.com/actix/supply-chain/main/audits.toml"
|
||||
|
||||
[imports.bytecode-alliance]
|
||||
url = "https://raw.githubusercontent.com/bytecodealliance/wasmtime/main/supply-chain/audits.toml"
|
||||
|
||||
[imports.embark-studios]
|
||||
url = "https://raw.githubusercontent.com/EmbarkStudios/rust-ecosystem/main/audits.toml"
|
||||
|
||||
[imports.fermyon]
|
||||
url = "https://raw.githubusercontent.com/fermyon/spin/main/supply-chain/audits.toml"
|
||||
|
||||
[imports.google]
|
||||
url = "https://raw.githubusercontent.com/google/supply-chain/main/audits.toml"
|
||||
|
||||
[imports.isrg]
|
||||
url = "https://raw.githubusercontent.com/divviup/libprio-rs/main/supply-chain/audits.toml"
|
||||
|
||||
[imports.mozilla]
|
||||
url = "https://raw.githubusercontent.com/mozilla/supply-chain/main/audits.toml"
|
||||
|
||||
[imports.zcash]
|
||||
url = "https://raw.githubusercontent.com/zcash/rust-ecosystem/main/supply-chain/audits.toml"
|
||||
|
||||
[policy.memsec]
|
||||
audit-as-crates-io = true
|
||||
|
||||
[policy.rosenpass]
|
||||
audit-as-crates-io = false
|
||||
|
||||
[policy.uds]
|
||||
audit-as-crates-io = true
|
||||
|
||||
[[exemptions.addr2line]]
|
||||
version = "0.24.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.aead]]
|
||||
version = "0.5.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.aho-corasick]]
|
||||
version = "1.1.3"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.allocator-api2-tests]]
|
||||
version = "0.2.15"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.anstream]]
|
||||
version = "0.6.18"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.anstyle]]
|
||||
version = "1.0.10"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.anstyle-parse]]
|
||||
version = "0.2.6"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.anstyle-query]]
|
||||
version = "1.1.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.anstyle-wincon]]
|
||||
version = "3.0.7"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.anyhow]]
|
||||
version = "1.0.96"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.atomic-polyfill]]
|
||||
version = "1.0.3"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.backtrace]]
|
||||
version = "0.3.74"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.base64ct]]
|
||||
version = "1.6.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.bincode]]
|
||||
version = "1.3.3"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.blake2]]
|
||||
version = "0.10.6"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.build-deps]]
|
||||
version = "0.1.4"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.bytes]]
|
||||
version = "1.10.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.cc]]
|
||||
version = "1.2.15"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.chacha20]]
|
||||
version = "0.9.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.chacha20poly1305]]
|
||||
version = "0.10.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.clang-sys]]
|
||||
version = "1.8.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.clap]]
|
||||
version = "4.5.30"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.clap_builder]]
|
||||
version = "4.5.30"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.clap_complete]]
|
||||
version = "4.5.45"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.clap_derive]]
|
||||
version = "4.5.28"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.clap_lex]]
|
||||
version = "0.7.4"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.clap_mangen]]
|
||||
version = "0.2.24"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.cmake]]
|
||||
version = "0.1.54"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.colorchoice]]
|
||||
version = "1.0.3"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.command-fds]]
|
||||
version = "0.2.3"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.cpufeatures]]
|
||||
version = "0.2.17"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.criterion]]
|
||||
version = "0.5.1"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.criterion-plot]]
|
||||
version = "0.5.0"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.critical-section]]
|
||||
version = "1.2.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.crossbeam-deque]]
|
||||
version = "0.8.6"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.crossbeam-utils]]
|
||||
version = "0.8.20"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.ctrlc-async]]
|
||||
version = "3.2.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.curve25519-dalek]]
|
||||
version = "4.1.3"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.curve25519-dalek-derive]]
|
||||
version = "0.1.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.darling]]
|
||||
version = "0.12.4"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.darling]]
|
||||
version = "0.20.10"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.darling_core]]
|
||||
version = "0.12.4"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.darling_core]]
|
||||
version = "0.20.10"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.darling_macro]]
|
||||
version = "0.12.4"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.darling_macro]]
|
||||
version = "0.20.10"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.derive_arbitrary]]
|
||||
version = "1.4.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.derive_builder]]
|
||||
version = "0.10.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.derive_builder]]
|
||||
version = "0.20.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.derive_builder_core]]
|
||||
version = "0.10.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.derive_builder_core]]
|
||||
version = "0.20.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.derive_builder_macro]]
|
||||
version = "0.10.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.derive_builder_macro]]
|
||||
version = "0.20.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.digest]]
|
||||
version = "0.10.7"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.embedded-io]]
|
||||
version = "0.6.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.env_logger]]
|
||||
version = "0.10.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.fastrand]]
|
||||
version = "2.3.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.findshlibs]]
|
||||
version = "0.10.2"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.futures-task]]
|
||||
version = "0.3.31"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.futures-util]]
|
||||
version = "0.3.31"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.generic-array]]
|
||||
version = "0.14.7"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.genetlink]]
|
||||
version = "0.2.5"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.getrandom]]
|
||||
version = "0.2.15"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.gimli]]
|
||||
version = "0.31.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.hash32]]
|
||||
version = "0.2.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.hashbrown]]
|
||||
version = "0.15.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.hax-lib]]
|
||||
version = "0.1.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.hax-lib]]
|
||||
version = "0.2.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.hax-lib-macros]]
|
||||
version = "0.1.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.hax-lib-macros]]
|
||||
version = "0.2.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.hax-lib-macros-types]]
|
||||
version = "0.1.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.hax-lib-macros-types]]
|
||||
version = "0.2.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.heapless]]
|
||||
version = "0.7.17"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.hermit-abi]]
|
||||
version = "0.4.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.hex-literal]]
|
||||
version = "0.4.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.home]]
|
||||
version = "0.5.9"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.humantime]]
|
||||
version = "2.1.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.ipc-channel]]
|
||||
version = "0.18.3"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.is-terminal]]
|
||||
version = "0.4.15"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.is_terminal_polyfill]]
|
||||
version = "1.70.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.jobserver]]
|
||||
version = "0.1.32"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.js-sys]]
|
||||
version = "0.3.77"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.keccak]]
|
||||
version = "0.1.5"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.lazycell]]
|
||||
version = "1.3.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.libc]]
|
||||
version = "0.2.169"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.libcrux]]
|
||||
version = "0.0.2-pre.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.libcrux-chacha20poly1305]]
|
||||
version = "0.0.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.libcrux-hacl]]
|
||||
version = "0.0.2-pre.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.libcrux-hacl-rs]]
|
||||
version = "0.0.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.libcrux-intrinsics]]
|
||||
version = "0.0.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.libcrux-macros]]
|
||||
version = "0.0.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.libcrux-ml-kem]]
|
||||
version = "0.0.2-beta.3"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.libcrux-platform]]
|
||||
version = "0.0.2-pre.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.libcrux-poly1305]]
|
||||
version = "0.0.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.libcrux-sha3]]
|
||||
version = "0.0.2-beta.3"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.libfuzzer-sys]]
|
||||
version = "0.4.9"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.libjade-sys]]
|
||||
version = "0.0.2-pre.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.libloading]]
|
||||
version = "0.8.6"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.linux-raw-sys]]
|
||||
version = "0.4.15"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.lock_api]]
|
||||
version = "0.4.12"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.memchr]]
|
||||
version = "2.7.4"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.memoffset]]
|
||||
version = "0.6.5"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.memoffset]]
|
||||
version = "0.9.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.memsec]]
|
||||
version = "0.6.3@git:aceb9baee8aec6844125bd6612f92e9a281373df"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.minimal-lexical]]
|
||||
version = "0.2.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.mio]]
|
||||
version = "1.0.3"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.neli]]
|
||||
version = "0.6.3"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.neli-proc-macros]]
|
||||
version = "0.1.4"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.netlink-packet-core]]
|
||||
version = "0.7.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.netlink-packet-generic]]
|
||||
version = "0.3.3"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.netlink-packet-route]]
|
||||
version = "0.19.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.netlink-packet-utils]]
|
||||
version = "0.5.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.netlink-packet-wireguard]]
|
||||
version = "0.2.3"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.netlink-proto]]
|
||||
version = "0.11.5"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.netlink-sys]]
|
||||
version = "0.8.7"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.nix]]
|
||||
version = "0.23.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.nix]]
|
||||
version = "0.27.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.num-bigint]]
|
||||
version = "0.4.6"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.object]]
|
||||
version = "0.36.7"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.once_cell]]
|
||||
version = "1.20.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.oqs-sys]]
|
||||
version = "0.9.1+liboqs-0.9.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.parking_lot]]
|
||||
version = "0.12.3"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.parking_lot_core]]
|
||||
version = "0.9.10"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.paste]]
|
||||
version = "1.0.15"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.pin-project-lite]]
|
||||
version = "0.2.16"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.pkg-config]]
|
||||
version = "0.3.31"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.plotters]]
|
||||
version = "0.3.7"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.plotters-backend]]
|
||||
version = "0.3.7"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.plotters-svg]]
|
||||
version = "0.3.7"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.poly1305]]
|
||||
version = "0.8.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.postcard]]
|
||||
version = "1.1.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.ppv-lite86]]
|
||||
version = "0.2.20"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.prettyplease]]
|
||||
version = "0.2.29"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.proc-macro-error]]
|
||||
version = "1.0.4"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.procspawn]]
|
||||
version = "1.0.1"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.psm]]
|
||||
version = "0.1.25"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.rand]]
|
||||
version = "0.9.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.rand_chacha]]
|
||||
version = "0.9.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.rand_core]]
|
||||
version = "0.9.3"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.redox_syscall]]
|
||||
version = "0.5.9"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.regex]]
|
||||
version = "1.11.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.regex-automata]]
|
||||
version = "0.4.9"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.roff]]
|
||||
version = "0.2.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.rtnetlink]]
|
||||
version = "0.14.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.rustix]]
|
||||
version = "0.38.44"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.ryu]]
|
||||
version = "1.0.19"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.scc]]
|
||||
version = "2.3.3"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.scopeguard]]
|
||||
version = "1.2.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.sdd]]
|
||||
version = "3.0.7"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.serde_json]]
|
||||
version = "1.0.139"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.serde_spanned]]
|
||||
version = "0.6.8"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.serial_test]]
|
||||
version = "3.2.0"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.serial_test_derive]]
|
||||
version = "3.2.0"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.signal-hook]]
|
||||
version = "0.3.17"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.signal-hook-registry]]
|
||||
version = "1.4.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.slab]]
|
||||
version = "0.4.9"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.socket2]]
|
||||
version = "0.5.8"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.spin]]
|
||||
version = "0.9.8"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.stacker]]
|
||||
version = "0.1.19"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.syn]]
|
||||
version = "1.0.109"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.syn]]
|
||||
version = "2.0.98"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.take-until]]
|
||||
version = "0.1.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.tempfile]]
|
||||
version = "3.17.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.termcolor]]
|
||||
version = "1.4.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.test_bin]]
|
||||
version = "0.4.0"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.thiserror]]
|
||||
version = "2.0.11"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.thiserror-impl]]
|
||||
version = "2.0.11"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.tokio]]
|
||||
version = "1.44.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.tokio-macros]]
|
||||
version = "2.5.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.toml]]
|
||||
version = "0.7.8"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.toml_datetime]]
|
||||
version = "0.6.8"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.toml_edit]]
|
||||
version = "0.19.15"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.typenum]]
|
||||
version = "1.18.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.uds]]
|
||||
version = "0.4.2@git:b47934fe52422e559f7278938875f9105f91c5a2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.unicode-ident]]
|
||||
version = "1.0.17"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.utf8parse]]
|
||||
version = "0.2.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.uuid]]
|
||||
version = "1.14.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.version_check]]
|
||||
version = "0.9.5"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.walkdir]]
|
||||
version = "2.5.0"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.wasi]]
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.wasi]]
|
||||
version = "0.13.3+wasi-0.2.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.wasm-bindgen]]
|
||||
version = "0.2.100"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.wasm-bindgen-backend]]
|
||||
version = "0.2.100"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.wasm-bindgen-macro]]
|
||||
version = "0.2.100"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.wasm-bindgen-macro-support]]
|
||||
version = "0.2.100"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.wasm-bindgen-shared]]
|
||||
version = "0.2.100"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.web-sys]]
|
||||
version = "0.3.77"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.which]]
|
||||
version = "4.4.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.winapi]]
|
||||
version = "0.3.9"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.winapi-i686-pc-windows-gnu]]
|
||||
version = "0.4.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.winapi-util]]
|
||||
version = "0.1.9"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.winapi-x86_64-pc-windows-gnu]]
|
||||
version = "0.4.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows]]
|
||||
version = "0.58.0"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.windows-core]]
|
||||
version = "0.58.0"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.windows-implement]]
|
||||
version = "0.58.0"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.windows-interface]]
|
||||
version = "0.58.0"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.windows-result]]
|
||||
version = "0.2.0"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.windows-strings]]
|
||||
version = "0.1.0"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.windows-sys]]
|
||||
version = "0.45.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows-sys]]
|
||||
version = "0.48.0"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.windows-sys]]
|
||||
version = "0.52.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows-sys]]
|
||||
version = "0.59.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows-targets]]
|
||||
version = "0.42.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows-targets]]
|
||||
version = "0.48.5"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows-targets]]
|
||||
version = "0.52.6"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_aarch64_gnullvm]]
|
||||
version = "0.42.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_aarch64_gnullvm]]
|
||||
version = "0.48.5"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_aarch64_gnullvm]]
|
||||
version = "0.52.6"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_aarch64_msvc]]
|
||||
version = "0.42.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_aarch64_msvc]]
|
||||
version = "0.48.5"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_aarch64_msvc]]
|
||||
version = "0.52.6"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_i686_gnu]]
|
||||
version = "0.42.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_i686_gnu]]
|
||||
version = "0.48.5"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_i686_gnu]]
|
||||
version = "0.52.6"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_i686_gnullvm]]
|
||||
version = "0.52.6"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_i686_msvc]]
|
||||
version = "0.42.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_i686_msvc]]
|
||||
version = "0.48.5"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_i686_msvc]]
|
||||
version = "0.52.6"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_x86_64_gnu]]
|
||||
version = "0.42.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_x86_64_gnu]]
|
||||
version = "0.48.5"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_x86_64_gnu]]
|
||||
version = "0.52.6"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_x86_64_gnullvm]]
|
||||
version = "0.42.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_x86_64_gnullvm]]
|
||||
version = "0.48.5"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_x86_64_gnullvm]]
|
||||
version = "0.52.6"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_x86_64_msvc]]
|
||||
version = "0.42.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_x86_64_msvc]]
|
||||
version = "0.48.5"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.windows_x86_64_msvc]]
|
||||
version = "0.52.6"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.winnow]]
|
||||
version = "0.5.40"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.wireguard-uapi]]
|
||||
version = "3.0.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.x25519-dalek]]
|
||||
version = "2.0.1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.zerocopy]]
|
||||
version = "0.7.35"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.zerocopy]]
|
||||
version = "0.8.24"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.zerocopy-derive]]
|
||||
version = "0.7.35"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.zerocopy-derive]]
|
||||
version = "0.8.24"
|
||||
criteria = "safe-to-deploy"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
||||
{
|
||||
pkgs,
|
||||
rosenpass-deb,
|
||||
rosenpass-rpm,
|
||||
}:
|
||||
|
||||
let
|
||||
wg-deb = pkgs.fetchurl {
|
||||
url = "https://ftp.de.debian.org/debian/pool/main/w/wireguard/wireguard-tools_1.0.20210914-1.1_amd64.deb";
|
||||
hash = "sha256-s/hCUisQLR19kEbV6d8JXzzTAWUPM+NV0APgHizRGA4=";
|
||||
};
|
||||
wg-rpm = pkgs.fetchurl {
|
||||
url = "https://mirrors.n-ix.net/fedora/linux/releases/40/Everything/x86_64/os/Packages/w/wireguard-tools-1.0.20210914-6.fc40.x86_64.rpm";
|
||||
hash = "sha256-lh6kCW5gh9bfuOwzjPv96ol1d6u1JTIr/oKH5QbAlK0=";
|
||||
};
|
||||
|
||||
pkgsDirDeb = pkgs.runCommand "packages" { } ''
|
||||
mkdir $out
|
||||
cp ${rosenpass-deb} $out/rosenpass.deb
|
||||
cp ${wg-deb} $out/wireguard.deb
|
||||
cp ${./prepare-test.sh} $out/prepare-test.sh
|
||||
'';
|
||||
pkgsDirRpm = pkgs.runCommand "packages" { } ''
|
||||
mkdir $out
|
||||
cp ${rosenpass-rpm} $out/rosenpass.rpm
|
||||
cp ${wg-rpm} $out/wireguard.rpm
|
||||
cp ${./prepare-test.sh} $out/prepare-test.sh
|
||||
'';
|
||||
|
||||
test =
|
||||
{
|
||||
tester,
|
||||
installPrefix,
|
||||
suffix,
|
||||
source,
|
||||
}:
|
||||
(tester {
|
||||
sharedDirs.share = {
|
||||
inherit source;
|
||||
target = "/mnt/share";
|
||||
};
|
||||
testScript = ''
|
||||
vm.wait_for_unit("multi-user.target")
|
||||
vm.succeed("${installPrefix} /mnt/share/wireguard.${suffix}")
|
||||
vm.succeed("${installPrefix} /mnt/share/rosenpass.${suffix}")
|
||||
vm.succeed("bash /mnt/share/prepare-test.sh")
|
||||
|
||||
vm.succeed(f"systemctl start rp@server")
|
||||
vm.succeed(f"systemctl start rp@client")
|
||||
|
||||
vm.wait_for_unit("rp@server.service")
|
||||
vm.wait_for_unit("rp@client.service")
|
||||
|
||||
vm.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5);
|
||||
|
||||
psk_server = vm.succeed("wg show rp-server preshared-keys").strip().split()[-1]
|
||||
psk_client = vm.succeed("wg show rp-client preshared-keys").strip().split()[-1]
|
||||
|
||||
assert psk_server == psk_client, "preshared-key exchange must be successful"
|
||||
'';
|
||||
}).sandboxed;
|
||||
in
|
||||
{
|
||||
package-deb-debian-13 = test {
|
||||
tester = pkgs.testers.nonNixOSDistros.debian."13";
|
||||
installPrefix = "dpkg --install";
|
||||
suffix = "deb";
|
||||
source = pkgsDirDeb;
|
||||
};
|
||||
package-deb-ubuntu-23_10 = test {
|
||||
tester = pkgs.testers.nonNixOSDistros.ubuntu."23_10";
|
||||
installPrefix = "dpkg --install";
|
||||
suffix = "deb";
|
||||
source = pkgsDirDeb;
|
||||
};
|
||||
package-rpm-fedora_40 = test {
|
||||
tester = pkgs.testers.nonNixOSDistros.fedora."40";
|
||||
installPrefix = "rpm -i";
|
||||
suffix = "rpm";
|
||||
source = pkgsDirRpm;
|
||||
};
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user