Compare commits

..

28 Commits

Author SHA1 Message Date
wucke13
60155a5530 add first draft of rp rust binary 2023-03-08 22:34:12 +01:00
wucke13
664c591138 transform repo to cargo workspace 2023-03-08 22:34:09 +01:00
wucke13
566795afd2 Merge pull request #25 from rosenpass/dev/karo/remove_research_warning
fix(usage): Remove warning about this being a research project
2023-03-08 21:52:28 +01:00
Karolin Varner
8eea5284bf fix(usage): Remove warning about this being a research project 2023-03-04 22:24:09 +01:00
Emil Engler
df00c1987c fix typos 2023-03-04 22:15:32 +01:00
wucke13
becc8c057a Merge pull request #17 from rosenpass/dev/karo/kem_is_mechanism
chore: Consistently use the term `Key Encapsulation Mechanism`
2023-02-28 19:18:08 +01:00
wucke13
1625d94b71 Merge pull request #16 from rosenpass/dev/karo/asset_license
Dev/karo/asset license
2023-02-28 18:37:25 +01:00
Karolin Varner
a62405190e chore: Consistently use the term Key Encapsulation Mechanism 2023-02-27 21:37:56 +01:00
Karolin Varner
5afa6c19a6 feat: Add licensing infos 2023-02-27 21:28:14 +01:00
Karolin Varner
ecc1b75b00 chore: Delete outdated illustrations 2023-02-27 21:27:44 +01:00
wucke13
fe80792873 add proper flagging of prerelease and draft in CI 2023-02-27 21:15:13 +01:00
Marei (peiTeX)
3fc28a0b70 whitepaper-release 2023-02-27 13:21:28 +01:00
wucke13
97f5d75838 chore: Release rosenpass version 0.1.1 2023-02-25 23:34:40 +01:00
wucke13
aa15872f2b chore: Release rosenpass version 0.1.1-rc.7 2023-02-25 23:21:35 +01:00
wucke13
1d10e7f036 chore: Release rosenpass version 0.1.1-rc.6 2023-02-25 23:10:25 +01:00
wucke13
cc01472942 Merge pull request #13 from rosenpass/dev/fix-release-2
add missing permission for release workflow
2023-02-25 23:09:52 +01:00
wucke13
4b33938d66 add missing permission for release workflow 2023-02-25 23:09:09 +01:00
wucke13
f4c351c74b chore: Release rosenpass version 0.1.1-rc.5 2023-02-25 19:53:38 +01:00
wucke13
12522e90ea Merge pull request #12 from rosenpass/dev/fix-release-2
add dedicated release workflow
2023-02-25 19:53:17 +01:00
wucke13
0995317fa6 add dedicated release workflow 2023-02-25 19:51:44 +01:00
wucke13
4b4902cacd chore: Release rosenpass version 0.1.1-rc.4 2023-02-25 13:47:30 +01:00
wucke13
c389d39fbd Merge pull request #11 from rosenpass/dev/fix-release
chore: Release rosenpass version 0.1.1-rc.3
2023-02-25 13:44:15 +01:00
sevenautumns
12933de42b release action smaller if 2023-02-25 13:36:53 +01:00
wucke13
9b3f4670af chore: Release rosenpass version 0.1.1-rc.3 2023-02-24 22:59:39 +01:00
wucke13
8313a61cc7 chore: Release rosenpass version 0.1.1-rc.3 2023-02-24 20:37:03 +01:00
wucke13
175a9c20af Merge pull request #10 from rosenpass/dev/release-action
Automatic Release
2023-02-24 20:34:12 +01:00
wucke13
a9c13caeaa refine CI release setup 2023-02-24 20:28:48 +01:00
sevenautumns
92838250b5 Automatic Release 2023-02-24 18:22:56 +01:00
31 changed files with 267 additions and 1662 deletions

View File

@@ -31,38 +31,37 @@ jobs:
- name: Generate gitHeadInfo.gin for the whitepaper
if: ${{ matrix.derivation == 'whitepaper' }}
run: ( cd papers && ./tex/gitinfo2.sh && git add gitHeadInfo.gin )
- name: Build ${{ matrix.derivation }}
- name: Build ${{ matrix.derivation }}@${{ matrix.nix-system }}
run: |
# build the package
nix build .#packages.${{ matrix.nix-system }}.${{ matrix.derivation }} --print-build-logs
# copy over the results
if [[ -f $(readlink --canonicalize result ) ]]; then
mkdir -- ${{ matrix.derivation }}
mkdir -- ${{ matrix.derivation }}-${{ matrix.nix-system }}
fi
cp --recursive -- $(readlink --canonicalize -- result) ${{ matrix.derivation }}
chmod --recursive -- ug+rw ${{ matrix.derivation }}
cp --recursive -- $(readlink --canonicalize result) ${{ matrix.derivation }}-${{ matrix.nix-system }}
chmod --recursive ug+rw -- ${{ matrix.derivation }}-${{ matrix.nix-system }}
# add version information
git rev-parse --abbrev-ref HEAD > ${{ matrix.derivation }}/git-version
git rev-parse HEAD > ${{ matrix.derivation }}/git-sha
git rev-parse --abbrev-ref HEAD > ${{ matrix.derivation }}-${{ matrix.nix-system }}/git-version
git rev-parse HEAD > ${{ matrix.derivation }}-${{ matrix.nix-system }}/git-sha
# override the `rp` script to keep compatible with non-nix systems
if [[ -f ${{ matrix.derivation }}/bin/rp ]]
then
cp --force rp ${{ matrix.derivation }}/bin/
if [[ -f ${{ matrix.derivation }}-${{ matrix.nix-system }}/bin/rp ]]; then
cp --force -- rp ${{ matrix.derivation }}-${{ matrix.nix-system }}/bin/
fi
- name: Upload build results
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.derivation }}@${{ matrix.nix-system }}
path: ${{ matrix.derivation }}
name: ${{ matrix.derivation }}-${{ matrix.nix-system }}
path: ${{ matrix.derivation }}-${{ matrix.nix-system }}
- name: Deploy PDF artifacts
if: ${{ matrix.derivation == 'whitepaper' && github.ref == 'refs/heads/main' }}
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: whitepaper
publish_dir: ${{ matrix.derivation }}-${{ matrix.nix-system }}
publish_branch: papers-pdf
force_orphan: true
checks:

30
.github/workflows/release.yaml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Release
permissions:
contents: write
on:
push:
tags: ["v*"]
jobs:
release:
name: Release for ${{ matrix.nix-system }}
runs-on:
- nix
- ${{ matrix.nix-system }}
strategy:
fail-fast: false
matrix:
nix-system:
- x86_64-linux
# - aarch64-linux
steps:
- uses: actions/checkout@v3
- name: Build release-package for ${{ matrix.nix-system }}
run: nix build .#release-package --print-build-logs
- name: Release
uses: softprops/action-gh-release@v1
with:
draft: ${{ contains(github.ref_name, 'rc') }}
prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}
files: |
result/*

84
Cargo.lock generated
View File

@@ -186,7 +186,7 @@ checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5"
dependencies = [
"atty",
"bitflags",
"clap_lex",
"clap_lex 0.2.4",
"indexmap",
"strsim",
"termcolor",
@@ -194,6 +194,34 @@ dependencies = [
"yaml-rust",
]
[[package]]
name = "clap"
version = "4.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5"
dependencies = [
"bitflags",
"clap_derive",
"clap_lex 0.3.2",
"is-terminal",
"once_cell",
"strsim",
"termcolor",
]
[[package]]
name = "clap_derive"
version = "4.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.2.4"
@@ -203,6 +231,15 @@ dependencies = [
"os_str_bytes",
]
[[package]]
name = "clap_lex"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "cmake"
version = "0.1.49"
@@ -429,6 +466,12 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.1.19"
@@ -776,6 +819,30 @@ dependencies = [
"plotters-backend",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.51"
@@ -865,7 +932,7 @@ checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
[[package]]
name = "rosenpass"
version = "0.1.1-rc.2"
version = "0.1.1"
dependencies = [
"anyhow",
"base64",
@@ -883,6 +950,13 @@ dependencies = [
"thiserror",
]
[[package]]
name = "rp"
version = "0.1.0"
dependencies = [
"clap 4.1.8",
]
[[package]]
name = "rustc-demangle"
version = "0.1.21"
@@ -1176,6 +1250,12 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "walkdir"
version = "2.3.2"

View File

@@ -1,35 +1,6 @@
[package]
name = "rosenpass"
version = "0.1.1-rc.2"
authors = ["Karolin Varner <karo@cupdev.net>", "wucke13 <wucke13@gmail.com>"]
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Build post-quantum-secure VPNs with WireGuard!"
homepage = "https://rosenpass.eu/"
repository = "https://github.com/rosenpass/rosenpass"
readme = "readme.md"
[workspace]
[[bench]]
name = "handshake"
harness = false
[dependencies]
anyhow = { version = "1.0.52", features = ["backtrace"] }
base64 = "0.13.0"
clap = { version = "3.0.0", features = ["yaml"] }
static_assertions = "1.1.0"
memoffset = "0.6.5"
libsodium-sys-stable = { version = "1.19.26", features = ["use-pkg-config"] }
oqs-sys = { version = "0.7.1", default-features = false, features = ['classic_mceliece', 'kyber'] }
lazy_static = "1.4.0"
thiserror = "1.0.38"
paste = "1.0.11"
log = { version = "0.4.17", optional = true }
env_logger = { version = "0.10.0", optional = true }
[dev-dependencies]
criterion = "0.3.5"
test_bin = "0.4.0"
[features]
default = ["log", "env_logger"]
members = [
"rosenpass",
"rp",
]

View File

@@ -132,6 +132,29 @@
default = rosenpass;
rosenpass = rpDerivation pkgs;
rosenpass-oci-image = rosenpassOCI "rosenpass";
# derivation for the release
release-package =
let
version = cargoToml.package.version;
package =
if pkgs.hostPlatform.isLinux then
packages.rosenpass-static
else packages.rosenpass;
oci-image =
if pkgs.hostPlatform.isLinux then
packages.rosenpass-static-oci-image
else packages.rosenpass-oci-image;
in
pkgs.runCommandNoCC "lace-result" { }
''
mkdir {bin,$out}
cp ${./.}/rp bin/
tar -cvf $out/rosenpass-${system}-${version}.tar bin/rp \
-C ${package} bin/rosenpass
cp ${oci-image} \
$out/rosenpass-oci-image-${system}-${version}.tar.gz
'';
} // (if pkgs.stdenv.isLinux then rec {
rosenpass-static = rpDerivation pkgs.pkgsStatic;
rosenpass-static-oci-image = rosenpassOCI "rosenpass-static";

View File

@@ -0,0 +1,5 @@
# Illustrations
## License
The graphics graphics (SVG, PDF, and PNG files) in this folder are released under the CC BY-SA 4.0 license.

View File

@@ -1,218 +0,0 @@
root: 0 { shape: text }
PROTOCOL: "PROTOCOL" { shape: text }
protocol_comment: 'PROTOCOL = "rosenpass 1 rosenpass.eu aead=chachapoly1305 dprf=blake2s ekem=lightsaber skem=mceliece460896 xaead=xchachapoly1305"' { shape: text}
ck_init: '"chaining key init"' { shape: text }
ck_ext: '"chaining key extract"' { shape: text }
mac: '"mac"' { shape: text }
mac_param: MAC_WIRE_DATA { shape: text }
cookie: '"cookie"' { shape: text }
cookie_param: COOKIE_WIRE_DATA { shape: text }
peer_id: '"peer_id"' { shape: text }
peer_id_p1: spkm { shape: text}
peer_id_p2: spkt { shape: text}
root -> PROTOCOL
PROTOCOL -> mac -> mac_param
PROTOCOL -> cookie -> cookie_param
PROTOCOL -> peer_id -> peer_id_p1 -> peer_id_p2
PROTOCOL -> ck_init
PROTOCOL -> ck_ext
mix: '"mix"' { shape: text }
user: '"user"' { shape: text }
rp_eu: '"rosenpass.eu"' { shape: text }
wg_psk: '"wireguard psk"' { shape: text }
hs_enc: '"handshake encryption"' { shape: text }
ini_enc: '"initiator session encryption"' { shape: text }
res_enc: '"responder session encryption"' { shape: text }
ck_ext -> mix
ck_ext -> user -> rp_eu -> wg_psk
ck_ext -> hs_enc
ck_ext -> ini_enc
ck_ext -> res_enc
# ck_init -> InitHello.start
InitHello {
start -> d0 \
-> m1 -> d1 \
-> m2 -> d2
d2 -> encaps_spkr.m1
encaps_spkr.d3 -> encrypt_ltk.m1
encaps_spkr.d3 -> encrypt_ltk.key
encrypt_ltk.d1 -> encrypt_auth.m1
encrypt_ltk.d1 -> encrypt_auth.key
m1: "mix" { shape: text }
m2: "mix" { shape: text }
start: '"chaining key init"' { shape: text }
d0: "spkr" { shape: circle }
d1: "sidi" { shape: circle }
d2: "epki" { shape: circle }
encaps_spkr {
m1 -> d1 \
-> m2 -> d2 \
-> m3 -> d3 \
m1: "mix" { shape: text }
m2: "mix" { shape: text }
m3: "mix" { shape: text }
d1: "spkr" { shape: circle }
d2: "sctr" { shape: circle }
d3: "sptr" { shape: circle }
}
encrypt_ltk {
m1 -> d1
encrypt: 'Aead::enc(peer_id(spkr, spki))'
key -> encrypt: {
target-arrowhead.label: key
}
data -> encrypt: {
target-arrowhead.label: data
}
encrypt -> d1: {
source-arrowhead.label: output
}
m1: "mix" { shape: text }
key: '"handshake encryption"' { shape: text }
data: 'ref from "peer id" branch after spkt' { shape: text }
d1: "ct" { shape: diamond }
}
encrypt_auth {
m1 -> d1
encrypt: 'Aead::enc(empty())'
key -> encrypt: {
target-arrowhead.label: key
}
encrypt -> d1: {
source-arrowhead.label: output
}
m1: "mix" { shape: text }
key: '"handshake encryption"' { shape: text }
d1: "ct" { shape: diamond }
}
}
RespHello {
start -> d0 -> m1 -> d1
d1 -> encaps_epki.m1
encaps_epki.d3 -> encaps_spki.m1
encaps_spki.d3 -> m2 -> d2
d2 -> encrypt_auth.m1
store_biscuit -> d2
"pidi" -> store_biscuit {
target-arrowhead.label: "field=peerid"
}
encaps_spki.d3 -> store_biscuit {
target-arrowhead.label: "field=ck"
}
m1: "mix" { shape: text }
m2: "mix" { shape: text }
start: '(state from InitHello)' { shape: text }
d0: "sidr" { shape: circle }
d1: "sidi" { shape: circle }
d2: "biscuit" { shape: diamond }
store_biscuit: "store_biscuit()"
encaps_epki {
m1 -> d1 \
-> m2 -> d2 \
-> m3 -> d3 \
m1: "mix" { shape: text }
m2: "mix" { shape: text }
m3: "mix" { shape: text }
d1: "epki" { shape: circle }
d2: "ecti" { shape: circle }
d3: "epti" { shape: circle }
}
encaps_spki {
m1 -> d1 \
-> m2 -> d2 \
-> m3 -> d3 \
m1: "mix" { shape: text }
m2: "mix" { shape: text }
m3: "mix" { shape: text }
d1: "spki" { shape: circle }
d2: "scti" { shape: circle }
d3: "spti" { shape: circle }
}
encrypt_auth {
m1 -> d1
encrypt: 'Aead::enc(empty())'
key -> encrypt: {
target-arrowhead.label: key
}
encrypt -> d1: {
source-arrowhead.label: output
}
m1: "mix" { shape: text }
key: '"handshake encryption"' { shape: text }
d1: "ct" { shape: diamond }
}
}
InitConf {
start -> d0 -> m1 -> d1 -> encrypt_auth.m1
encrypt_auth.d1 -> ol1 -> o1
encrypt_auth.d1 -> ol2 -> o2
encrypt_auth.d1 -> ol3 -> o3
m1: "mix" { shape: text }
start: '(state from RespHello)' { shape: text }
d0: "sidi" { shape: circle }
d1: "sidr" { shape: circle }
ol1: '"wireguard psk"' { shape: text }
ol2: '"initiator session encryption"' { shape: text }
ol3: '"responder session encryption"' { shape: text}
o2: "" { shape: page }
o1: "" { shape: step }
o2: "" { shape: step }
o3: "" { shape: step }
encrypt_auth {
m1 -> d1
encrypt: 'Aead::enc(empty())'
key -> encrypt: {
target-arrowhead.label: key
}
encrypt -> d1: {
source-arrowhead.label: output
}
m1: "mix" { shape: text }
key: '"handshake encryption"' { shape: text }
d1: "ct" { shape: diamond }
}
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 847 KiB

View File

@@ -23,3 +23,7 @@ inside `papers/`. The PDF files will be located directly in `papers/`.
The version info is using gitinfo2. To use the setup one has to run the `papers/tex/gitinfo2.sh` script. In local copies it's also possible to add this as a post-checkout or post-commit hook to keep it automatically up to date.
The version information in the footer automatically includes a “draft”. This can be removed by tagging a release version using `\jobname-release`, e.h. `whitepaper-release` for the `whitepaper.md` file.
## Licensing of assets
The text files and graphics in this folder (i.e. whitepaper.md, the SVG, PDF, and PNG files in the graphics/ folder) are released under the CC BY-SA 4.0 license.

View File

@@ -1,81 +0,0 @@
Protocol: {
shape: sequence_diagram
ini: "Initiator"
res: "Responder"
ini -> res: "InitHello"
res -> ini: "RespHello"
ini -> res: "InitConf"
res -> ini: "EmptyData"
}
Envelope: "Envelope" {
shape: class
type: "1"
'': 3
payload: variable
mac: 16
cookie: 16
}
Envelope.payload -> InitHello
InitHello: "InitHello (type=0x81)" {
shape: class
sidi: 4
epki: 800
sctr: 188
peerid: 32 + 16 = 48
auth: 16
}
Envelope.payload -> RespHello
RespHello: "RespHello (type=0x82)" {
shape: class
sidr: 4
sidi: 4
ecti: 768
scti: 188
biscuit: 76 + 24 + 16 = 116
auth: 16
}
Envelope.payload -> InitConf
InitConf: "InitConf (type=0x83)" {
shape: class
sidi: 4
sidr: 4
biscuit: 76 + 24 +16 = 116
auth: 16
}
Envelope.payload -> EmptyData
EmptyData: "EmptyData (type=0x84)" {
shape: class
sidx: 4
ctr: 8
auth: 16
}
Envelope.payload -> Data
Data: "Data (type=0x85)" {
shape: class
sidx: 4
ctr: 8
data: variable + 16
}
Envelope.payload -> CookieReply
CookieReply: "CookieReply (type=0x86)" {
shape: class
sidx: 4
nonce: 24
cookie: 16 + 16 = 32
}
RespHello.biscuit -> Biscuit
InitConf.biscuit -> Biscuit
Biscuit: "Biscuit" {
shape: class
peerid: 32
no: 12
ck: 32
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 669 KiB

View File

@@ -130,7 +130,7 @@
\bool_set_false:N \l_tmpa_bool
\gitAbbrevHash{}~(\gitAuthorDate
\clist_map_inline:Nn \gitTags {
\exp_args:Nx \str_if_eq:nnT {\jobname-release} {test-whitepaper} {\bool_set_true:N \l_tmpa_bool\clist_map_break:}
\exp_args:Nx \str_if_eq:nnT {\jobname-release} {whitepaper-release} {\bool_set_true:N \l_tmpa_bool\clist_map_break:}
}
\bool_if:NF \l_tmpa_bool {~--~draft}
)

View File

@@ -33,7 +33,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 Methods; 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

35
rosenpass/Cargo.toml Normal file
View File

@@ -0,0 +1,35 @@
[package]
name = "rosenpass"
version = "0.1.1"
authors = ["Karolin Varner <karo@cupdev.net>", "wucke13 <wucke13@gmail.com>"]
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Build post-quantum-secure VPNs with WireGuard!"
homepage = "https://rosenpass.eu/"
repository = "https://github.com/rosenpass/rosenpass"
readme = "../readme.md"
[[bench]]
name = "handshake"
harness = false
[dependencies]
anyhow = { version = "1.0.52", features = ["backtrace"] }
base64 = "0.13.0"
clap = { version = "3.0.0", features = ["yaml"] }
static_assertions = "1.1.0"
memoffset = "0.6.5"
libsodium-sys-stable = { version = "1.19.26", features = ["use-pkg-config"] }
oqs-sys = { version = "0.7.1", default-features = false, features = ['classic_mceliece', 'kyber'] }
lazy_static = "1.4.0"
thiserror = "1.0.38"
paste = "1.0.11"
log = { version = "0.4.17", optional = true }
env_logger = { version = "0.10.0", optional = true }
[dev-dependencies]
criterion = "0.3.5"
test_bin = "0.4.0"
[features]
default = ["log", "env_logger"]

View File

@@ -11,9 +11,6 @@ DESCRIPTION
These keys can then be passed to various services such as wireguard or other vpn services
as pre-shared-keys to achieve security against attackers with quantum computers.
This is a research project and quantum computers are not thought to become practical in less than ten years.
If you are not specifically tasked with developing post-quantum secure systems, you probably do not need this tool.
COMMANDS
keygen private-key <file-path> public-key <file-path>
@@ -35,11 +32,11 @@ COMMANDS
You must either specify the outfile or wireguard output option.
endpoint <ip>[:<port>]
Specifies the address where the peer can be reached. This will be automatically updated after the first sucessfull
Specifies the address where the peer can be reached. This will be automatically updated after the first successful
key exchange with the peer. If this is unspecified, the peer must initiate the connection.
preshared-key <file-path>
You may specifie a pre-shared key which will be mixied into the final secret.
You may specify a pre-shared key which will be mixed into the final secret.
outfile <file-path>
You may specify a file to write the exchanged keys to. If this option is specified, {0} will

352
rp
View File

@@ -1,352 +0,0 @@
#!/usr/bin/env bash
set -e
# String formatting subsystem
formatting_init() {
endl=$'\n'
}
enquote() {
while (( $# > 1 )); do
printf "%q " "${1}"; shift
done
if (( $# == 1 )); then
printf "%q" "${1}"; shift
fi
}
multiline() {
# shellcheck disable=SC1004
echo "${1} " | awk '
function pm(a, b, l) {
return length(a) > l \
&& length(b) > l \
&& substr(a, 1, l+1) == substr(b, 1, l+1) \
? pm(a, b, l+1) : l;
}
!started && $0 !~ /^[ \t]*$/ {
started=1
match($0, /^[ \t]*/)
prefix=substr($0, 1, RLENGTH)
}
started {
print(substr($0, 1 + pm($0, prefix)));
}
'
}
dbg() {
echo >&2 "$@"
}
# Cleanup subsystem (sigterm)
cleanup_init() {
cleanup_actions=()
trap cleanup_apply exit
}
cleanup_apply() {
local f
for f in "${cleanup_actions[@]}"; do
eval "${f}"
done
}
cleanup() {
cleanup_actions+=("$(multiline "${1}")")
}
# Transactional execution subsystem
frag_init() {
explain=0
frag_transaction=()
frag "
#! /bin/bash
set -e"
}
frag_apply() {
local f
for f in "${frag_transaction[@]}"; do
if (( explain == 1 )); then
dbg "${f}"
fi
eval "${f}"
done
}
frag() {
frag_transaction+=("$(multiline "${1}")")
}
frag_append() {
local len; len="${#frag_transaction[@]}"
frag_transaction=("${frag_transaction[@]:0:len-1}" "${frag_transaction[len-1]}${1}")
}
frag_append_esc() {
frag_append " \\${endl}${1}"
}
# Usage documentation subsystem
usage_init() {
usagestack=("${script}")
}
usage_snap() {
echo "${#usagestack}"
}
usage_restore() {
local n; n="${1}"
dbg REST "${1}"
usagestack=("${usagestack[@]:0:n-2}")
}
usage() {
dbg "Usage: ${usagestack[*]}"
}
fatal() {
dbg "FATAL: $*"
usage
exit 1
}
genkey() {
usagestack+=("PRIVATE_KEYS_DIR")
local skdir
skdir="${1%/}"; shift || fatal "Required positional argument: PRIVATE_KEYS_DIR"
while (( $# > 0 )); do
local arg; arg="$1"; shift
case "${arg}" in
-h | -help | --help | help) usage; return 0 ;;
*) fatal "Unknown option ${arg}";;
esac
done
if test -e "${skdir}"; then
fatal "PRIVATE_KEYS_DIR \"${skdir}\" already exists"
fi
frag "
umask 077
mkdir -p $(enquote "${skdir}")
wg genkey > $(enquote "${skdir}"/wgsk)
$(enquote "${binary}") keygen \\
private-key $(enquote "${skdir}"/pqsk) \\
public-key $(enquote "${skdir}"/pqpk)"
}
pubkey() {
usagestack+=("PRIVATE_KEYS_DIR" "PUBLIC_KEYS_DIR")
local skdir pkdir
skdir="${1%/}"; shift || fatal "Required positional argument: PRIVATE_KEYS_DIR"
pkdir="${1%/}"; shift || fatal "Required positional argument: PUBLIC_KEYS_DIR"
while (( $# > 0 )); do
local arg; arg="$1"; shift
case "${arg}" in
-h | -help | --help | help) usage; exit 0;;
*) fatal "Unknown option ${arg}";;
esac
done
if test -e "${pkdir}"; then
fatal "PUBLIC_KEYS_DIR \"${pkdir}\" already exists"
fi
frag "
mkdir -p $(enquote "${pkdir}")
wg pubkey < $(enquote "${skdir}"/wgsk) > $(enquote "${pkdir}/wgpk")
cp $(enquote "${skdir}"/pqpk) $(enquote "${pkdir}/pqpk")"
}
exchange() {
usagestack+=("PRIVATE_KEYS_DIR" "[dev <device>]" "[listen <ip>:<port>]" "[peer PUBLIC_KEYS_DIR [endpoint <ip>:<port>] [persistent-keepalive <interval>] [allowed-ips <ip1>/<cidr1>[,<ip2>/<cidr2>]...]]...")
local skdir dev lport
dev="${project_name}0"
skdir="${1%/}"; shift || fatal "Required positional argument: PRIVATE_KEYS_DIR"
while (( $# > 0 )); do
local arg; arg="$1"; shift
case "${arg}" in
dev) dev="${1}"; shift || fatal "dev option requires parameter";;
peer) set -- "peer" "$@"; break;; # Parsed down below
listen)
local listen; listen="${1}";
lip="${listen%:*}";
lport="${listen/*:/}";
if [[ "$lip" = "$lport" ]]; then
lip="[0::0]"
fi
shift;;
-h | -help | --help | help) usage; return 0;;
*) fatal "Unknown option ${arg}";;
esac
done
if (( $# == 0 )); then
fatal "Needs at least one peer specified"
fi
frag "
# Create the Wireguard interface
ip link add dev $(enquote "${dev}") type wireguard || true"
cleanup "
ip link del dev $(enquote "${dev}") || true"
frag "
ip link set dev $(enquote "${dev}") up"
frag "
# Deploy the classic wireguard private key
wg set $(enquote "${dev}") private-key $(enquote "${skdir}/wgsk")"
if test -n "${lport}"; then
frag_append "listen-port $(enquote "$(( lport + 1 ))")"
fi
frag "
# Launch the post quantum wireguard exchange daemon
$(enquote "${binary}") exchange"
if (( verbose == 1 )); then
frag_append "verbose"
fi
frag_append_esc " private-key $(enquote "${skdir}/pqsk")"
frag_append_esc " public-key $(enquote "${skdir}/pqpk")"
if test -n "${lport}"; then
frag_append_esc " listen $(enquote "${lip}:${lport}")"
fi
usagestack+=("peer" "PUBLIC_KEYS_DIR endpoint IP:PORT")
while (( $# > 0 )); do
shift; # Skip "peer" argument
local peerdir ip port keepalive allowedips
peerdir="${1%/}"; shift || fatal "Required peer argument: PUBLIC_KEYS_DIR"
while (( $# > 0 )); do
local arg; arg="$1"; shift
case "${arg}" in
peer) set -- "peer" "$@"; break;; # Next peer
endpoint) ip="${1%:*}"; port="${1/*:/}"; shift;;
persistent-keepalive) keepalive="${1}"; shift;;
allowed-ips) allowedips="${1}"; shift;;
-h | -help | --help | help) usage; return 0;;
*) fatal "Unknown option ${arg}";;
esac
done
# Public key
frag_append_esc " peer public-key $(enquote "${peerdir}/pqpk")"
# PSK
local pskfile; pskfile="${peerdir}/psk"
if test -f "${pskfile}"; then
frag_append_esc " preshared-key $(enquote "${pskfile}")"
fi
if test -n "${ip}"; then
frag_append_esc " endpoint $(enquote "${ip}:${port}")"
fi
frag_append_esc " wireguard $(enquote "${dev}") $(enquote "$(cat "${peerdir}/wgpk")")"
if test -n "${ip}"; then
frag_append_esc " endpoint $(enquote "${ip}:$(( port + 1 ))")"
fi
if test -n "${keepalive}"; then
frag_append_esc " persistent-keepalive $(enquote "${keepalive}")"
fi
if test -n "${allowedips}"; then
frag_append_esc " allowed-ips $(enquote "${allowedips}")"
fi
done
}
find_rosenpass_binary() {
local binary; binary=""
if [[ -n "${gitdir}" ]]; then
# If rp is run from the git repo, use the newest build artifact
binary=$(
find "${gitdir}/result/bin/${project_name}" \
"${gitdir}"/target/{release,debug}/"${project_name}" \
-printf "%T@ %p\n" 2>/dev/null \
| sort -nr \
| awk 'NR==1 { print($2) }'
)
elif [[ -n "${nixdir}" ]]; then
# If rp is run from nix, use the nix-installed rosenpass version
binary="${nixdir}/bin/${project_name}"
fi
if [[ -z "${binary}" ]]; then
binary="${project_name}"
fi
echo "${binary}"
}
main() {
formatting_init
cleanup_init
usage_init
frag_init
project_name="rosenpass"
verbose=0
scriptdir="$(dirname "${script}")"
gitdir="$(git -C "${scriptdir}" rev-parse --show-toplevel 2>/dev/null)" || true
nixdir="$(readlink -f result/bin/rp | grep -Pio '^/nix/store/[^/]+(?=/bin/[^/]+)')" || true
binary="$(find_rosenpass_binary)"
# Parse command
usagestack+=("[explain]" "[verbose]" "genkey|pubkey|exchange" "[ARGS]...")
local cmd
while (( $# > 0 )); do
local arg; arg="$1"; shift
case "${arg}" in
genkey|pubkey|exchange) cmd="${arg}"; break;;
explain) explain=1;;
verbose) verbose=1;;
-h | -help | --help | help) usage; return 0 ;;
*) fatal "Unknown command ${arg}";;
esac
done
test -n "${cmd}" || fatal "No command supplied"
usagestack=("${script}")
# Execute command
usagestack+=("${cmd}")
"${cmd}" "$@"
usagestack=("${script}")
# Apply transaction
frag_apply
}
script="$0"
main "$@"

13
rp/Cargo.toml Normal file
View File

@@ -0,0 +1,13 @@
[package]
name = "rp"
version = "0.1.0"
edition = "2021"
authors = ["wucke13 <wucke13@gmail.com>", "Karolin Varner <karo@cupdev.net>"]
license = "MIT OR Apache-2.0"
description = "Build post-quantum-secure VPNs with WireGuard!"
homepage = "https://rosenpass.eu/"
repository = "https://github.com/rosenpass/rosenpass"
readme = "../readme.md"
[dependencies]
clap = { version = "4.1.8", features = ["derive"] }

55
rp/src/main.rs Normal file
View File

@@ -0,0 +1,55 @@
use std::path::PathBuf;
use clap::{Parser, Subcommand};
// Usage: ../rp-old [explain] [verbose] genkey|pubkey|exchange [ARGS]...
/// Simple program to greet a person
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Cli {
/// Explain what is done
#[arg(short, long)]
explain: bool,
/// Be verbose about what's going on
#[arg(short, long)]
verbose: bool,
#[command(subcommand)]
command: Command,
}
/// Doc comment
#[derive(Subcommand, Debug)]
// #[command(PARENT CMD ATTRIBUTE)]
enum Command {
/// Generate a keypair
// --- Requirements ---
// requires wireguard
// should not exist before
// should be dir after
// should contain three files after pqpk, pqsk, wgsk
Genkey {
private_keys_dir: PathBuf,
},
/// Generate public keys
// --- Requirements ---
// requires wireguard
// requires private_keys_dir to exist
// should create public_keys_dir
// should copy pqpk from private_ to public_keys_dir
// should generate wgpk to public_keys_dir
Pubkey {
private_keys_dir: PathBuf,
public_keys_dir: PathBuf,
},
Exchange {},
}
fn main() {
let args = Cli::parse();
println!("{args:#?}");
}