mirror of
https://github.com/rosenpass/rosenpass.git
synced 2026-02-27 22:13:12 -08:00
Compare commits
1 Commits
v0.1.2-rc.
...
dev/redo-r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3131441b68 |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -865,7 +865,7 @@ checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rosenpass"
|
name = "rosenpass"
|
||||||
version = "0.1.2-rc.4"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rosenpass"
|
name = "rosenpass"
|
||||||
version = "0.1.2-rc.4"
|
version = "0.1.1"
|
||||||
authors = ["Karolin Varner <karo@cupdev.net>", "wucke13 <wucke13@gmail.com>"]
|
authors = ["Karolin Varner <karo@cupdev.net>", "wucke13 <wucke13@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|||||||
105
doc/rosenpass.1
105
doc/rosenpass.1
@@ -1,105 +0,0 @@
|
|||||||
.Dd $Mdocdate$
|
|
||||||
.Dt ROSENPASS 1
|
|
||||||
.Os
|
|
||||||
.Sh NAME
|
|
||||||
.Nm rosenpass
|
|
||||||
.Nd builds post-quantum-secure VPNs
|
|
||||||
.Sh SYNOPSIS
|
|
||||||
.Nm
|
|
||||||
.Op COMMAND
|
|
||||||
.Op Ar OPTIONS ...
|
|
||||||
.Op Ar ARGS ...
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
.Nm
|
|
||||||
performs cryptographic key exchanges that are secure against quantum-computers
|
|
||||||
and outputs the keys.
|
|
||||||
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.
|
|
||||||
.Pp
|
|
||||||
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.
|
|
||||||
.Ss COMMANDS
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It Ar keygen private-key <file-path> public-key <file-path>
|
|
||||||
Generate a keypair to use in the exchange command later.
|
|
||||||
Send the public-key file to your communication partner and keep the private-key
|
|
||||||
file secret!
|
|
||||||
.It Ar exchange private-key <file-path> public-key <file-path> [ OPTIONS ] PEERS
|
|
||||||
Start a process to exchange keys with the specified peers.
|
|
||||||
You should specify at least one peer.
|
|
||||||
.Pp
|
|
||||||
It's
|
|
||||||
.Ar OPTIONS
|
|
||||||
are as follows:
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It Ar listen <ip>[:<port>]
|
|
||||||
Instructs
|
|
||||||
.Nm
|
|
||||||
to listen on the specified interface and port.
|
|
||||||
By default
|
|
||||||
.Nm
|
|
||||||
will listen on all interfaces and select a random port.
|
|
||||||
.It Ar verbose
|
|
||||||
Extra logging.
|
|
||||||
.El
|
|
||||||
.El
|
|
||||||
.Ss PEER
|
|
||||||
Each
|
|
||||||
.Ar PEER
|
|
||||||
is defined as follows:
|
|
||||||
.Qq peer public-key <file-path> [endpoint <ip>[:<port>]] [preshared-key <file-path>] [outfile <file-path>] [wireguard <dev> <peer> <extra_params>]
|
|
||||||
.Pp
|
|
||||||
Providing a
|
|
||||||
.Ar PEER
|
|
||||||
instructs
|
|
||||||
.Nm
|
|
||||||
to exchange keys with the given peer and write the resulting PSK into the given
|
|
||||||
output file.
|
|
||||||
You must either specify the outfile or wireguard output option.
|
|
||||||
.Pp
|
|
||||||
The parameters of
|
|
||||||
.Ar PEER
|
|
||||||
are as follows:
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It Ar endpoint <ip>[:<port>]
|
|
||||||
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.
|
|
||||||
.It Ar preshared-key <file-path>
|
|
||||||
You may specify a pre-shared key which will be mixed into the final secret.
|
|
||||||
.It Ar outfile <file-path>
|
|
||||||
You may specify a file to write the exchanged keys to.
|
|
||||||
If this option is specified,
|
|
||||||
.Nm
|
|
||||||
will write a notification to standard out every time the key is updated.
|
|
||||||
.It Ar wireguard <dev> <peer> <extra_params>
|
|
||||||
This allows you to directly specify a wireguard peer to deploy the
|
|
||||||
pre-shared-key to.
|
|
||||||
You may specify extra parameters you would pass to
|
|
||||||
.Qq wg set
|
|
||||||
besides the preshared-key parameter which is used by
|
|
||||||
.Nm .
|
|
||||||
This makes it possible to add peers entirely from
|
|
||||||
.Nm .
|
|
||||||
.El
|
|
||||||
.Sh EXIT STATUS
|
|
||||||
.Ex -std
|
|
||||||
.Sh SEE ALSO
|
|
||||||
.Xr rp 1 ,
|
|
||||||
.Xr wg 1
|
|
||||||
.Sh STANDARDS
|
|
||||||
This tool is the reference implementation of the Rosenpass protocol, written
|
|
||||||
by Karolin Varner, Benjamin Lipp, Wanja Zaeske, and Lisa Schmidt.
|
|
||||||
.Sh AUTHORS
|
|
||||||
Rosenpass was created by Karolin Varner, Benjamin Lipp, Wanja Zaeske,
|
|
||||||
Marei Peischl, Stephan Ajuvo, and Lisa Schmidt.
|
|
||||||
.Pp
|
|
||||||
This manual page was written by
|
|
||||||
.An Emil Engler
|
|
||||||
.Sh BUGS
|
|
||||||
The bugs are tracked at
|
|
||||||
.Lk https://github.com/rosenpass/rosenpass/issues .
|
|
||||||
@@ -90,6 +90,7 @@ pub const RTX_BUFFER_SIZE: usize = max_usize(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/// A type for time, e.g. for backoff before re-tries
|
/// A type for time, e.g. for backoff before re-tries
|
||||||
|
// TODO replace by core::time::Duration
|
||||||
pub type Timing = f64;
|
pub type Timing = f64;
|
||||||
|
|
||||||
/// Before Common Era (or more practically: Definitely so old it needs refreshing)
|
/// Before Common Era (or more practically: Definitely so old it needs refreshing)
|
||||||
@@ -209,6 +210,7 @@ pub struct Peer {
|
|||||||
pub session: Option<Session>,
|
pub session: Option<Session>,
|
||||||
pub handshake: Option<InitiatorHandshake>,
|
pub handshake: Option<InitiatorHandshake>,
|
||||||
pub initiation_requested: bool,
|
pub initiation_requested: bool,
|
||||||
|
pub th: TransmissionHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Peer {
|
impl Peer {
|
||||||
@@ -220,6 +222,7 @@ impl Peer {
|
|||||||
session: None,
|
session: None,
|
||||||
initiation_requested: false,
|
initiation_requested: false,
|
||||||
handshake: None,
|
handshake: None,
|
||||||
|
th: TransmissionHandler::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,6 +283,36 @@ pub struct InitiatorHandshake {
|
|||||||
pub tx_buf: MsgBuf,
|
pub tx_buf: MsgBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TransmissionHandler {
|
||||||
|
// when to attempt the first transmission
|
||||||
|
tx_at: Timing,
|
||||||
|
|
||||||
|
// average interval between transmission and subsequent retransmissions
|
||||||
|
tx_interval: Timing,
|
||||||
|
|
||||||
|
// how often to attemp (re-) transmission
|
||||||
|
tx_count: u8,
|
||||||
|
|
||||||
|
// length of message in `tx_buf`
|
||||||
|
tx_len: usize,
|
||||||
|
|
||||||
|
// buffer for the message
|
||||||
|
tx_buf: MsgBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TransmissionHandler {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
tx_at: 0.0,
|
||||||
|
tx_interval: 1.0,
|
||||||
|
tx_count: 0,
|
||||||
|
tx_len: 0,
|
||||||
|
tx_buf: Public::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
// Metadata
|
// Metadata
|
||||||
@@ -460,10 +493,10 @@ impl CryptoServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub fn pidm(&self) -> Result<PeerId> {
|
pub fn pidm(spkm: &[u8]) -> Result<PeerId> {
|
||||||
Ok(Public::new(
|
Ok(Public::new(
|
||||||
lprf::peerid()?
|
lprf::peerid()?
|
||||||
.mix(self.spkm.secret())?
|
.mix(spkm)?
|
||||||
.into_value()))
|
.into_value()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,6 +517,7 @@ impl CryptoServer {
|
|||||||
session: None,
|
session: None,
|
||||||
handshake: None,
|
handshake: None,
|
||||||
initiation_requested: false,
|
initiation_requested: false,
|
||||||
|
th: TransmissionHandler::default(),
|
||||||
};
|
};
|
||||||
let peerid = peer.pidt()?;
|
let peerid = peer.pidt()?;
|
||||||
let peerno = self.peers.len();
|
let peerno = self.peers.len();
|
||||||
@@ -586,6 +620,7 @@ impl Peer {
|
|||||||
session: None,
|
session: None,
|
||||||
handshake: None,
|
handshake: None,
|
||||||
initiation_requested: false,
|
initiation_requested: false,
|
||||||
|
th: TransmissionHandler::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -725,7 +760,15 @@ impl CryptoServer {
|
|||||||
// TODO remove unecessary copying between global tx_buf and per-peer buf
|
// TODO remove unecessary copying between global tx_buf and per-peer buf
|
||||||
// TODO move retransmission storage to io server
|
// TODO move retransmission storage to io server
|
||||||
pub fn initiate_handshake(&mut self, peer: PeerPtr, tx_buf: &mut [u8]) -> Result<usize> {
|
pub fn initiate_handshake(&mut self, peer: PeerPtr, tx_buf: &mut [u8]) -> Result<usize> {
|
||||||
let mut msg = tx_buf.envelope::<InitHello<()>>()?; // Envelope::<InitHello>::default(); // TODO
|
let mut msg = tx_buf.envelope::<InitHello<()>>()?;
|
||||||
|
// Envelope::<InitHello>::default(); // TODO
|
||||||
|
// let mut msg = peer
|
||||||
|
// .get_mut(self)
|
||||||
|
// .th
|
||||||
|
// .tx_buf
|
||||||
|
// .as_mut_slice()
|
||||||
|
// .envelope::<InitHello<()>>()?;
|
||||||
|
|
||||||
self.handle_initiation(peer, msg.payload_mut().init_hello()?)?;
|
self.handle_initiation(peer, msg.payload_mut().init_hello()?)?;
|
||||||
let len = self.seal_and_commit_msg(peer, MsgType::InitHello, msg)?;
|
let len = self.seal_and_commit_msg(peer, MsgType::InitHello, msg)?;
|
||||||
peer.hs()
|
peer.hs()
|
||||||
@@ -781,7 +824,6 @@ impl CryptoServer {
|
|||||||
Ok(MsgType::InitHello) => {
|
Ok(MsgType::InitHello) => {
|
||||||
let msg_in = rx_buf.envelope::<InitHello<&[u8]>>()?;
|
let msg_in = rx_buf.envelope::<InitHello<&[u8]>>()?;
|
||||||
ensure!(msg_in.check_seal(self)?, seal_broken);
|
ensure!(msg_in.check_seal(self)?, seal_broken);
|
||||||
|
|
||||||
let mut msg_out = tx_buf.envelope::<RespHello<&mut [u8]>>()?;
|
let mut msg_out = tx_buf.envelope::<RespHello<&mut [u8]>>()?;
|
||||||
let peer = self.handle_init_hello(
|
let peer = self.handle_init_hello(
|
||||||
msg_in.payload().init_hello()?,
|
msg_in.payload().init_hello()?,
|
||||||
@@ -916,6 +958,9 @@ pub enum PollResult {
|
|||||||
DeleteKey(PeerPtr),
|
DeleteKey(PeerPtr),
|
||||||
SendInitiation(PeerPtr),
|
SendInitiation(PeerPtr),
|
||||||
SendRetransmission(PeerPtr),
|
SendRetransmission(PeerPtr),
|
||||||
|
// Transmit(PeerPtr),
|
||||||
|
// /// implicitly respond to peerptr with msg in scratch_buf
|
||||||
|
// Respond
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PollResult {
|
impl Default for PollResult {
|
||||||
@@ -1394,13 +1439,18 @@ impl CryptoServer {
|
|||||||
/// established primitives
|
/// established primitives
|
||||||
pub fn handle_initiation(
|
pub fn handle_initiation(
|
||||||
&mut self,
|
&mut self,
|
||||||
peer: PeerPtr,
|
peer_ptr: PeerPtr,
|
||||||
mut ih: InitHello<&mut [u8]>,
|
_ih: InitHello<&mut [u8]>,
|
||||||
) -> Result<PeerPtr> {
|
) -> Result<PeerPtr> {
|
||||||
let mut hs = InitiatorHandshake::zero_with_timestamp(self);
|
let mut hs = InitiatorHandshake::zero_with_timestamp(self);
|
||||||
|
let peer = &mut self.peers[peer_ptr.0];
|
||||||
|
let mut tx_buf = peer.th.tx_buf;
|
||||||
|
let mut msg = tx_buf.as_mut_slice().envelope::<InitHello<()>>()?;
|
||||||
|
peer.th.tx_len = msg.all_bytes().len();
|
||||||
|
let mut ih = msg.payload_mut().init_hello()?;
|
||||||
|
|
||||||
// IHI1
|
// IHI1
|
||||||
hs.core.init(peer.get(self).spkt.secret())?;
|
hs.core.init(peer.spkt.secret())?;
|
||||||
|
|
||||||
// IHI2
|
// IHI2
|
||||||
hs.core.sidi.randomize();
|
hs.core.sidi.randomize();
|
||||||
@@ -1417,25 +1467,23 @@ impl CryptoServer {
|
|||||||
hs.core
|
hs.core
|
||||||
.encaps_and_mix::<StaticKEM, { StaticKEM::SHK_LEN }>(
|
.encaps_and_mix::<StaticKEM, { StaticKEM::SHK_LEN }>(
|
||||||
ih.sctr_mut(),
|
ih.sctr_mut(),
|
||||||
peer.get(self).spkt.secret(),
|
peer.spkt.secret(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// IHI6
|
// IHI6
|
||||||
hs.core
|
hs.core
|
||||||
.encrypt_and_mix(ih.pidic_mut(), self.pidm()?.as_ref())?;
|
.encrypt_and_mix(ih.pidic_mut(), Self::pidm(self.spkm.secret())?.as_ref())?;
|
||||||
|
|
||||||
// IHI7
|
// IHI7
|
||||||
hs.core
|
hs.core.mix(self.spkm.secret())?.mix(peer.psk.secret())?;
|
||||||
.mix(self.spkm.secret())?
|
|
||||||
.mix(peer.get(self).psk.secret())?;
|
|
||||||
|
|
||||||
// IHI8
|
// IHI8
|
||||||
hs.core.encrypt_and_mix(ih.auth_mut(), &NOTHING)?;
|
hs.core.encrypt_and_mix(ih.auth_mut(), &NOTHING)?;
|
||||||
|
|
||||||
// Update the handshake hash last (not changing any state on prior error
|
// Update the handshake hash last (not changing any state on prior error
|
||||||
peer.hs().insert(self, hs)?;
|
peer.handshake.insert(hs);
|
||||||
|
|
||||||
Ok(peer)
|
Ok(peer_ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_init_hello(
|
pub fn handle_init_hello(
|
||||||
@@ -1475,6 +1523,8 @@ impl CryptoServer {
|
|||||||
// IHR8
|
// IHR8
|
||||||
core.decrypt_and_mix(&mut [0u8; 0], ih.auth())?;
|
core.decrypt_and_mix(&mut [0u8; 0], ih.auth())?;
|
||||||
|
|
||||||
|
// TODO access this peers transmission_handler, bind it as `rh`
|
||||||
|
|
||||||
// RHR1
|
// RHR1
|
||||||
core.sidr.randomize();
|
core.sidr.randomize();
|
||||||
rh.sidi_mut().copy_from_slice(core.sidi.as_ref());
|
rh.sidi_mut().copy_from_slice(core.sidi.as_ref());
|
||||||
|
|||||||
Reference in New Issue
Block a user