aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMathias Hall-Andersen <mathias@hall-andersen.dk>2019-08-30 19:46:00 +0200
committerMathias Hall-Andersen <mathias@hall-andersen.dk>2019-08-30 19:46:00 +0200
commit0520b28ac2d1918db4bd19d551448b8471cbb65a (patch)
tree36d17f524beb400ae89069be354738c22d67d00d /src
parentJoin with worker threads on device drop (diff)
downloadwireguard-rs-0520b28ac2d1918db4bd19d551448b8471cbb65a.tar.xz
wireguard-rs-0520b28ac2d1918db4bd19d551448b8471cbb65a.zip
Move to RustCrypto AEAD crate for handshake
Diffstat (limited to 'src')
-rw-r--r--src/handshake/macs.rs78
-rw-r--r--src/handshake/messages.rs65
-rw-r--r--src/handshake/noise.rs112
-rw-r--r--src/main.rs3
4 files changed, 98 insertions, 160 deletions
diff --git a/src/handshake/macs.rs b/src/handshake/macs.rs
index 5773f3d..516b9dc 100644
--- a/src/handshake/macs.rs
+++ b/src/handshake/macs.rs
@@ -1,14 +1,20 @@
+use generic_array::GenericArray;
use lazy_static::lazy_static;
use rand::{CryptoRng, RngCore};
use spin::RwLock;
use std::time::{Duration, Instant};
-use blake2::Blake2s;
-use sodiumoxide::crypto::aead::xchacha20poly1305_ietf;
-use subtle::ConstantTimeEq;
+// types to coalesce into bytes
+use std::net::SocketAddr;
use x25519_dalek::PublicKey;
-use std::net::SocketAddr;
+// AEAD
+use aead::{Aead, NewAead, Payload};
+use chacha20poly1305::XChaCha20Poly1305;
+
+// MAC
+use blake2::Blake2s;
+use subtle::ConstantTimeEq;
use super::messages::{CookieReply, MacsFooter, TYPE_COOKIE_REPLY};
use super::types::HandshakeError;
@@ -19,6 +25,7 @@ const LABEL_COOKIE: &[u8] = b"cookie--";
const SIZE_COOKIE: usize = 16;
const SIZE_SECRET: usize = 32;
const SIZE_MAC: usize = 16; // blake2s-mac128
+const SIZE_TAG: usize = 16; // xchacha20poly1305 tag
lazy_static! {
pub static ref COOKIE_UPDATE_INTERVAL: Duration = Duration::new(120, 0);
@@ -51,41 +58,28 @@ macro_rules! MAC {
}
macro_rules! XSEAL {
- ($key:expr, $nonce:expr, $ad:expr, $pt:expr, $ct:expr, $tag:expr) => {{
- let s_key = xchacha20poly1305_ietf::Key::from_slice($key).unwrap();
- let s_nonce = xchacha20poly1305_ietf::Nonce::from_slice($nonce).unwrap();
-
- debug_assert_eq!($tag.len(), xchacha20poly1305_ietf::TAGBYTES);
- debug_assert_eq!($pt.len(), $ct.len());
-
- $ct.copy_from_slice($pt);
- let tag = xchacha20poly1305_ietf::seal_detached(
- $ct,
- if $ad.len() == 0 { None } else { Some($ad) },
- &s_nonce,
- &s_key,
- );
- $tag.copy_from_slice(tag.as_ref());
+ ($key:expr, $nonce:expr, $ad:expr, $pt:expr, $ct:expr) => {{
+ let ct = XChaCha20Poly1305::new(*GenericArray::from_slice($key))
+ .encrypt(
+ GenericArray::from_slice($nonce),
+ Payload { msg: $pt, aad: $ad },
+ )
+ .unwrap();
+ debug_assert_eq!(ct.len(), $pt.len() + SIZE_TAG);
+ $ct.copy_from_slice(&ct);
}};
}
macro_rules! XOPEN {
- ($key:expr, $nonce:expr, $ad:expr, $pt:expr, $ct:expr, $tag:expr) => {{
- let s_key = xchacha20poly1305_ietf::Key::from_slice($key).unwrap();
- let s_nonce = xchacha20poly1305_ietf::Nonce::from_slice($nonce).unwrap();
- let s_tag = xchacha20poly1305_ietf::Tag::from_slice($tag).unwrap();
-
- debug_assert_eq!($pt.len(), $ct.len());
-
- $pt.copy_from_slice($ct);
- xchacha20poly1305_ietf::open_detached(
- $pt,
- if $ad.len() == 0 { None } else { Some($ad) },
- &s_tag,
- &s_nonce,
- &s_key,
- )
- .map_err(|_| HandshakeError::DecryptionFailure)
+ ($key:expr, $nonce:expr, $ad:expr, $pt:expr, $ct:expr) => {{
+ debug_assert_eq!($ct.len(), $pt.len() + SIZE_TAG);
+ XChaCha20Poly1305::new(*GenericArray::from_slice($key))
+ .decrypt(
+ GenericArray::from_slice($nonce),
+ Payload { msg: $ct, aad: $ad },
+ )
+ .map_err(|_| HandshakeError::DecryptionFailure)
+ .map(|pt| $pt.copy_from_slice(&pt))
}};
}
@@ -151,12 +145,11 @@ impl Generator {
let mac1 = self.last_mac1.ok_or(HandshakeError::InvalidState)?;
let mut tau = [0u8; SIZE_COOKIE];
XOPEN!(
- &self.cookie_key, // key
- &reply.f_nonce, // nonce
- &mac1, // ad
- &mut tau, // pt
- &reply.f_cookie, // ct
- &reply.f_cookie_tag // tag
+ &self.cookie_key, // key
+ &reply.f_nonce, // nonce
+ &mac1, // ad
+ &mut tau, // pt
+ &reply.f_cookie // ct || tag
)?;
self.cookie = Some(Cookie {
birth: Instant::now(),
@@ -260,8 +253,7 @@ impl Validator {
&msg.f_nonce, // nonce
&macs.f_mac1, // ad
&self.get_set_tau(rng, &src), // pt
- &mut msg.f_cookie, // ct
- &mut msg.f_cookie_tag // tagf
+ &mut msg.f_cookie // ct || tag
);
}
diff --git a/src/handshake/messages.rs b/src/handshake/messages.rs
index d068f26..6dca413 100644
--- a/src/handshake/messages.rs
+++ b/src/handshake/messages.rs
@@ -16,6 +16,7 @@ const SIZE_TAG: usize = 16; // poly1305 tag
const SIZE_XNONCE: usize = 24; // xchacha20 nonce
const SIZE_COOKIE: usize = 16; //
const SIZE_X25519_POINT: usize = 32; // x25519 public key
+const SIZE_TIMESTAMP: usize = 12;
pub const TYPE_INITIATION: u8 = 1;
pub const TYPE_RESPONSE: u8 = 2;
@@ -43,8 +44,7 @@ pub struct CookieReply {
pub f_type: U32<LittleEndian>,
pub f_receiver: U32<LittleEndian>,
pub f_nonce: [u8; SIZE_XNONCE],
- pub f_cookie: [u8; SIZE_COOKIE],
- pub f_cookie_tag: [u8; SIZE_TAG],
+ pub f_cookie: [u8; SIZE_COOKIE + SIZE_TAG],
}
/* Inner sub-messages */
@@ -62,10 +62,8 @@ pub struct NoiseInitiation {
pub f_type: U32<LittleEndian>,
pub f_sender: U32<LittleEndian>,
pub f_ephemeral: [u8; SIZE_X25519_POINT],
- pub f_static: [u8; SIZE_X25519_POINT],
- pub f_static_tag: [u8; SIZE_TAG],
- pub f_timestamp: timestamp::TAI64N,
- pub f_timestamp_tag: [u8; SIZE_TAG],
+ pub f_static: [u8; SIZE_X25519_POINT + SIZE_TAG],
+ pub f_timestamp: [u8; SIZE_TIMESTAMP + SIZE_TAG],
}
#[repr(packed)]
@@ -75,7 +73,7 @@ pub struct NoiseResponse {
pub f_sender: U32<LittleEndian>,
pub f_receiver: U32<LittleEndian>,
pub f_ephemeral: [u8; SIZE_X25519_POINT],
- pub f_empty_tag: [u8; SIZE_TAG],
+ pub f_empty: [u8; SIZE_TAG],
}
/* Zero copy parsing of handshake messages */
@@ -145,8 +143,7 @@ impl Default for CookieReply {
f_type: <U32<LittleEndian>>::new(TYPE_COOKIE_REPLY as u32),
f_receiver: <U32<LittleEndian>>::ZERO,
f_nonce: [0u8; SIZE_XNONCE],
- f_cookie: [0u8; SIZE_COOKIE],
- f_cookie_tag: [0u8; SIZE_TAG],
+ f_cookie: [0u8; SIZE_COOKIE + SIZE_TAG],
}
}
}
@@ -164,13 +161,10 @@ impl Default for NoiseInitiation {
fn default() -> Self {
Self {
f_type: <U32<LittleEndian>>::new(TYPE_INITIATION as u32),
-
f_sender: <U32<LittleEndian>>::ZERO,
f_ephemeral: [0u8; SIZE_X25519_POINT],
- f_static: [0u8; SIZE_X25519_POINT],
- f_static_tag: [0u8; SIZE_TAG],
- f_timestamp: timestamp::ZERO,
- f_timestamp_tag: [0u8; SIZE_TAG],
+ f_static: [0u8; SIZE_X25519_POINT + SIZE_TAG],
+ f_timestamp: [0u8; SIZE_TIMESTAMP + SIZE_TAG],
}
}
}
@@ -182,7 +176,7 @@ impl Default for NoiseResponse {
f_sender: <U32<LittleEndian>>::ZERO,
f_receiver: <U32<LittleEndian>>::ZERO,
f_ephemeral: [0u8; SIZE_X25519_POINT],
- f_empty_tag: [0u8; SIZE_TAG],
+ f_empty: [0u8; SIZE_TAG],
}
}
}
@@ -208,12 +202,11 @@ impl fmt::Debug for CookieReply {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
- "CookieReply {{ type = {}, receiver = {}, nonce = {}, cookie = {}|{} }}",
+ "CookieReply {{ type = {}, receiver = {}, nonce = {}, cookie = {} }}",
self.f_type,
self.f_receiver,
- hex::encode(self.f_nonce),
- hex::encode(self.f_cookie),
- hex::encode(self.f_cookie_tag)
+ hex::encode(&self.f_nonce[..]),
+ hex::encode(&self.f_cookie[..]),
)
}
}
@@ -222,14 +215,12 @@ impl fmt::Debug for CookieReply {
impl fmt::Debug for NoiseInitiation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,
- "NoiseInitiation {{ type = {}, sender = {}, ephemeral = {}, static = {}|{}, timestamp = {}|{} }}",
+ "NoiseInitiation {{ type = {}, sender = {}, ephemeral = {}, static = {}, timestamp = {} }}",
self.f_type.get(),
self.f_sender.get(),
- hex::encode(self.f_ephemeral),
- hex::encode(self.f_static),
- hex::encode(self.f_static_tag),
- hex::encode(self.f_timestamp),
- hex::encode(self.f_timestamp_tag)
+ hex::encode(&self.f_ephemeral[..]),
+ hex::encode(&self.f_static[..]),
+ hex::encode(&self.f_timestamp[..]),
)
}
}
@@ -242,8 +233,8 @@ impl fmt::Debug for NoiseResponse {
self.f_type,
self.f_sender,
self.f_receiver,
- hex::encode(self.f_ephemeral),
- hex::encode(self.f_empty_tag)
+ hex::encode(&self.f_ephemeral[..]),
+ hex::encode(&self.f_empty[..])
)
}
}
@@ -254,8 +245,8 @@ impl fmt::Debug for MacsFooter {
write!(
f,
"Macs {{ mac1 = {}, mac2 = {} }}",
- hex::encode(self.f_mac1),
- hex::encode(self.f_mac2)
+ hex::encode(&self.f_mac1[..]),
+ hex::encode(&self.f_mac2[..])
)
}
}
@@ -306,7 +297,7 @@ mod tests {
0xde, 0x1e, 0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67, 0xea, 0x89, 0x45, 0x44,
0x13, 0x56, 0x52, 0x1f,
];
- msg.noise.f_empty_tag = [
+ msg.noise.f_empty = [
0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05,
0x2f, 0xde,
];
@@ -337,18 +328,12 @@ mod tests {
msg.noise.f_static = [
0xdc, 0x33, 0x90, 0x15, 0x8f, 0x82, 0x3e, 0x06, 0x44, 0xa0, 0xde, 0x4c, 0x15, 0x6c,
0x5d, 0xa4, 0x65, 0x99, 0xf6, 0x6c, 0xa1, 0x14, 0x77, 0xf9, 0xeb, 0x6a, 0xec, 0xc3,
- 0x3c, 0xda, 0x47, 0xe1,
- ];
- msg.noise.f_static_tag = [
- 0x45, 0xac, 0x8d, 0x43, 0xea, 0x1b, 0x2f, 0x02, 0x45, 0x5d, 0x86, 0x37, 0xee, 0x83,
- 0x6b, 0x42,
+ 0x3c, 0xda, 0x47, 0xe1, 0x45, 0xac, 0x8d, 0x43, 0xea, 0x1b, 0x2f, 0x02, 0x45, 0x5d,
+ 0x86, 0x37, 0xee, 0x83, 0x6b, 0x42,
];
msg.noise.f_timestamp = [
- 0x4f, 0x1c, 0x60, 0xec, 0x0e, 0xf6, 0x36, 0xf0, 0x78, 0x28, 0x57, 0x42,
- ];
- msg.noise.f_timestamp_tag = [
- 0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05,
- 0x2f, 0xde,
+ 0x4f, 0x1c, 0x60, 0xec, 0x0e, 0xf6, 0x36, 0xf0, 0x78, 0x28, 0x57, 0x42, 0x60, 0x0e,
+ 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde,
];
msg.macs.f_mac1 = [
0xf2, 0xad, 0x40, 0xb5, 0xf7, 0xde, 0x77, 0x35, 0x89, 0x19, 0xb7, 0x5c, 0xf9, 0x54,
diff --git a/src/handshake/noise.rs b/src/handshake/noise.rs
index 8e8f517..8efe4aa 100644
--- a/src/handshake/noise.rs
+++ b/src/handshake/noise.rs
@@ -6,13 +6,14 @@ use x25519_dalek::StaticSecret;
use blake2::Blake2s;
use hmac::Hmac;
-// AEAD (from libsodium)
-use sodiumoxide::crypto::aead::chacha20poly1305;
+// AEAD
+use aead::{Aead, NewAead, Payload};
+use chacha20poly1305::ChaCha20Poly1305;
use rand::{CryptoRng, RngCore};
use generic_array::typenum::*;
-use generic_array::GenericArray;
+use generic_array::*;
use super::device::Device;
use super::messages::{NoiseInitiation, NoiseResponse};
@@ -36,6 +37,7 @@ type TemporaryState = (u32, PublicKey, GenericArray<u8, U32>, GenericArray<u8, U
const SIZE_CK: usize = 32;
const SIZE_HS: usize = 32;
const SIZE_NONCE: usize = 8;
+const SIZE_TAG: usize = 16;
// C := Hash(Construction)
const INITIAL_CK: [u8; SIZE_CK] = [
@@ -49,7 +51,7 @@ const INITIAL_HS: [u8; SIZE_HS] = [
0x2d, 0x9c, 0x6c, 0x66, 0x22, 0x93, 0xe8, 0xb7, 0x0e, 0xe1, 0x9c, 0x65, 0xba, 0x07, 0x9e, 0xf3,
];
-const ZERO_NONCE: [u8; SIZE_NONCE] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
+const ZERO_NONCE: [u8; 12] = [0u8; 12];
macro_rules! HASH {
( $($input:expr),* ) => {{
@@ -101,52 +103,20 @@ macro_rules! KDF3 {
}
macro_rules! SEAL {
- ($key:expr, $ad:expr, $pt:expr, $ct:expr, $tag:expr) => {{
- // create annoying nonce and key objects
- let s_nonce = chacha20poly1305::Nonce::from_slice(&ZERO_NONCE).unwrap();
- let s_key = chacha20poly1305::Key::from_slice($key).unwrap();
-
- // type annontate the ct and pt arguments
- let pt: &[u8] = $pt;
- let ct: &mut [u8] = $ct;
-
- // basic sanity checks
- debug_assert_eq!(pt.len(), ct.len());
- debug_assert_eq!($tag.len(), chacha20poly1305::TAGBYTES);
-
- // encrypt
- ct.copy_from_slice(pt);
- let tag = chacha20poly1305::seal_detached(
- ct,
- if $ad.len() == 0 { None } else { Some($ad) },
- &s_nonce,
- &s_key,
- );
- $tag.copy_from_slice(tag.as_ref());
+ ($key:expr, $ad:expr, $pt:expr, $ct:expr) => {{
+ let ct = ChaCha20Poly1305::new(*GenericArray::from_slice($key))
+ .encrypt(&ZERO_NONCE.into(), Payload { msg: $pt, aad: $ad })
+ .unwrap();
+ $ct.copy_from_slice(&ct);
}};
}
macro_rules! OPEN {
- ($key:expr, $ad:expr, $pt:expr, $ct:expr, $tag:expr) => {{
- // create annoying nonce and key objects
- let s_nonce = chacha20poly1305::Nonce::from_slice(&ZERO_NONCE).unwrap();
- let s_key = chacha20poly1305::Key::from_slice($key).unwrap();
- let s_tag = chacha20poly1305::Tag::from_slice($tag).unwrap();
-
- // type annontate the ct and pt arguments
- let pt: &mut [u8] = $pt;
- let ct: &[u8] = $ct;
-
- // decrypt
- pt.copy_from_slice(ct);
- chacha20poly1305::open_detached(
- pt,
- if $ad.len() == 0 { None } else { Some($ad) },
- &s_tag,
- &s_nonce,
- &s_key,
- )
- .map_err(|_| HandshakeError::DecryptionFailure)
+ ($key:expr, $ad:expr, $pt:expr, $ct:expr) => {{
+ ChaCha20Poly1305::new(*GenericArray::from_slice($key))
+ .decrypt(&ZERO_NONCE.into(), Payload { msg: $ct, aad: $ad })
+ .map_err(|_| HandshakeError::DecryptionFailure)
+ .map(|pt| $pt.copy_from_slice(&pt))
}};
}
@@ -275,15 +245,14 @@ pub fn create_initiation<T: Copy, R: RngCore + CryptoRng>(
SEAL!(
&key,
- &hs, // ad
- device.pk.as_bytes(), // pt
- &mut msg.f_static, // ct
- &mut msg.f_static_tag // tag
+ &hs, // ad
+ device.pk.as_bytes(), // pt
+ &mut msg.f_static // ct || tag
);
// H := Hash(H || msg.static)
- let hs = HASH!(&hs, &msg.f_static, &msg.f_static_tag);
+ let hs = HASH!(&hs, &msg.f_static[..]);
// (C, k) := Kdf2(C, DH(S_priv, S_pub))
@@ -293,15 +262,14 @@ pub fn create_initiation<T: Copy, R: RngCore + CryptoRng>(
SEAL!(
&key,
- &hs, // ad
- &timestamp::now(), // pt
- &mut msg.f_timestamp, // ct
- &mut msg.f_timestamp_tag // tag
+ &hs, // ad
+ &timestamp::now(), // pt
+ &mut msg.f_timestamp // ct || tag
);
// H := Hash(H || msg.timestamp)
- let hs = HASH!(&hs, &msg.f_timestamp, &msg.f_timestamp_tag);
+ let hs = HASH!(&hs, &msg.f_timestamp);
// update state of peer
@@ -344,17 +312,16 @@ pub fn consume_initiation<'a, T: Copy>(
OPEN!(
&key,
- &hs, // ad
- &mut pk, // pt
- &msg.f_static, // ct
- &msg.f_static_tag // tag
+ &hs, // ad
+ &mut pk, // pt
+ &msg.f_static // ct || tag
)?;
let peer = device.lookup_pk(&PublicKey::from(pk))?;
// H := Hash(H || msg.static)
- let hs = HASH!(&hs, &msg.f_static, &msg.f_static_tag);
+ let hs = HASH!(&hs, &msg.f_static[..]);
// (C, k) := Kdf2(C, DH(S_priv, S_pub))
@@ -366,10 +333,9 @@ pub fn consume_initiation<'a, T: Copy>(
OPEN!(
&key,
- &hs, // ad
- &mut ts, // pt
- &msg.f_timestamp, // ct
- &msg.f_timestamp_tag // tag
+ &hs, // ad
+ &mut ts, // pt
+ &msg.f_timestamp // ct || tag
)?;
// check and update timestamp
@@ -378,7 +344,7 @@ pub fn consume_initiation<'a, T: Copy>(
// H := Hash(H || msg.timestamp)
- let hs = HASH!(&hs, &msg.f_timestamp, &msg.f_timestamp_tag);
+ let hs = HASH!(&hs, &msg.f_timestamp);
// return state (to create response)
@@ -437,10 +403,9 @@ pub fn create_response<T: Copy, R: RngCore + CryptoRng>(
SEAL!(
&key,
- &hs, // ad
- &[], // pt
- &mut [], // ct
- &mut msg.f_empty_tag // tag
+ &hs, // ad
+ &[], // pt
+ &mut msg.f_empty // \epsilon || tag
);
/* not strictly needed
@@ -515,10 +480,9 @@ pub fn consume_response<T: Copy>(
OPEN!(
&key,
- &hs, // ad
- &mut [], // pt
- &[], // ct
- &msg.f_empty_tag // tag
+ &hs, // ad
+ &mut [], // pt
+ &msg.f_empty // \epsilon || tag
)?;
// derive key-pair
diff --git a/src/main.rs b/src/main.rs
index fc1a26a..600e144 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -13,7 +13,6 @@ use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
-use sodiumoxide;
use types::{Bind, KeyPair};
struct Test {}
@@ -71,8 +70,6 @@ struct PeerTimer {
fn main() {
let runner = Runner::new(Duration::from_millis(100), 1000, 1024);
- // choose optimal crypto implementations for platform
- sodiumoxide::init().unwrap();
{
let router = router::Device::new(
4,