From 0520b28ac2d1918db4bd19d551448b8471cbb65a Mon Sep 17 00:00:00 2001 From: Mathias Hall-Andersen Date: Fri, 30 Aug 2019 19:46:00 +0200 Subject: Move to RustCrypto AEAD crate for handshake --- src/handshake/macs.rs | 78 +++++++++++++++----------------- src/handshake/messages.rs | 65 +++++++++++---------------- src/handshake/noise.rs | 112 ++++++++++++++++------------------------------ src/main.rs | 3 -- 4 files changed, 98 insertions(+), 160 deletions(-) (limited to 'src') 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, pub f_receiver: U32, 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, pub f_sender: U32, 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, pub f_receiver: U32, 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: >::new(TYPE_COOKIE_REPLY as u32), f_receiver: >::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: >::new(TYPE_INITIATION as u32), - f_sender: >::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: >::ZERO, f_receiver: >::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, GenericArray {{ @@ -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( 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( SEAL!( &key, - &hs, // ad - ×tamp::now(), // pt - &mut msg.f_timestamp, // ct - &mut msg.f_timestamp_tag // tag + &hs, // ad + ×tamp::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( 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( 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, -- cgit v1.2.3-59-g8ed1b