Formatting

This commit is contained in:
Mathias Hall-Andersen
2019-07-25 22:04:35 +02:00
parent 27f8fd8e34
commit 43b56dfb58
7 changed files with 328 additions and 383 deletions

View File

@@ -7,35 +7,38 @@ use rand::rngs::OsRng;
use x25519_dalek::PublicKey;
use x25519_dalek::StaticSecret;
use crate::noise;
use crate::messages;
use crate::types::*;
use crate::noise;
use crate::peer::Peer;
use crate::types::*;
pub struct Device<T> {
pub sk : StaticSecret, // static secret key
pub pk : PublicKey, // static public key
peers : Vec<Peer<T>>, // peer index -> state
pk_map : HashMap<[u8; 32], usize>, // public key -> peer index
id_map : RwLock<HashMap<u32, usize>> // receive ids -> peer index
pub sk: StaticSecret, // static secret key
pub pk: PublicKey, // static public key
peers: Vec<Peer<T>>, // peer index -> state
pk_map: HashMap<[u8; 32], usize>, // public key -> peer index
id_map: RwLock<HashMap<u32, usize>>, // receive ids -> peer index
}
/* A mutable reference to the device needs to be held during configuration.
* Wrapping the device in a RwLock enables peer config after "configuration time"
*/
impl <T>Device<T> where T : Copy {
impl<T> Device<T>
where
T: Copy,
{
/// Initialize a new handshake state machine
///
/// # Arguments
///
/// * `sk` - x25519 scalar representing the local private key
pub fn new(sk : StaticSecret) -> Device<T> {
pub fn new(sk: StaticSecret) -> Device<T> {
Device {
pk : PublicKey::from(&sk),
sk : sk,
peers : vec![],
pk_map : HashMap::new(),
id_map : RwLock::new(HashMap::new())
pk: PublicKey::from(&sk),
sk: sk,
peers: vec![],
pk_map: HashMap::new(),
id_map: RwLock::new(HashMap::new()),
}
}
@@ -46,7 +49,7 @@ impl <T>Device<T> where T : Copy {
///
/// * `pk` - The public key to add
/// * `identifier` - Associated identifier which can be used to distinguish the peers
pub fn add(&mut self, pk : PublicKey, identifier : T) -> Result<(), ConfigError> {
pub fn add(&mut self, pk: PublicKey, identifier: T) -> Result<(), ConfigError> {
// check that the pk is not added twice
if let Some(_) = self.pk_map.get(pk.as_bytes()) {
@@ -56,7 +59,9 @@ impl <T>Device<T> where T : Copy {
// check that the pk is not that of the device
if *self.pk.as_bytes() == *pk.as_bytes() {
return Err(ConfigError::new("Public key corresponds to secret key of interface"));
return Err(ConfigError::new(
"Public key corresponds to secret key of interface",
));
}
// map : pk -> new index
@@ -66,9 +71,8 @@ impl <T>Device<T> where T : Copy {
// map : new index -> peer
self.peers.push(Peer::new(
idx, identifier, pk, self.sk.diffie_hellman(&pk)
));
self.peers
.push(Peer::new(idx, identifier, pk, self.sk.diffie_hellman(&pk)));
Ok(())
}
@@ -83,7 +87,7 @@ impl <T>Device<T> where T : Copy {
/// # Returns
///
/// The call might fail if the public key is not found
pub fn psk(&mut self, pk : PublicKey, psk : Option<Psk>) -> Result<(), ConfigError> {
pub fn psk(&mut self, pk: PublicKey, psk: Option<Psk>) -> Result<(), ConfigError> {
match self.pk_map.get(pk.as_bytes()) {
Some(&idx) => {
let peer = &mut self.peers[idx];
@@ -92,8 +96,8 @@ impl <T>Device<T> where T : Copy {
None => [0u8; 32],
};
Ok(())
},
_ => Err(ConfigError::new("No such public key"))
}
_ => Err(ConfigError::new("No such public key")),
}
}
@@ -102,8 +106,8 @@ impl <T>Device<T> where T : Copy {
/// # Arguments
///
/// * `id` - The (sender) id to release
pub fn release(&self, id : u32) {
let mut m =self.id_map.write();
pub fn release(&self, id: u32) {
let mut m = self.id_map.write();
debug_assert!(m.contains_key(&id), "Releasing id not allocated");
m.remove(&id);
}
@@ -113,7 +117,7 @@ impl <T>Device<T> where T : Copy {
/// # Arguments
///
/// * `pk` - Public key of peer to initiate handshake for
pub fn begin(&self, pk : &PublicKey) -> Result<Vec<u8>, HandshakeError> {
pub fn begin(&self, pk: &PublicKey) -> Result<Vec<u8>, HandshakeError> {
match self.pk_map.get(pk.as_bytes()) {
None => Err(HandshakeError::UnknownPublicKey),
Some(&idx) => {
@@ -129,7 +133,7 @@ impl <T>Device<T> where T : Copy {
/// # Arguments
///
/// * `msg` - Byte slice containing the message (untrusted input)
pub fn process(&self, msg : &[u8]) -> Result<Output<T>, HandshakeError> {
pub fn process(&self, msg: &[u8]) -> Result<Output<T>, HandshakeError> {
match msg.get(0) {
Some(&messages::TYPE_INITIATION) => {
// consume the initiation
@@ -143,37 +147,36 @@ impl <T>Device<T> where T : Copy {
self.release(sender);
e
})
},
Some(&messages::TYPE_RESPONSE) =>
noise::consume_response(self, msg),
_ => Err(HandshakeError::InvalidMessageFormat)
}
Some(&messages::TYPE_RESPONSE) => noise::consume_response(self, msg),
_ => Err(HandshakeError::InvalidMessageFormat),
}
}
// Internal function
//
// Return the peer associated with the public key
pub(crate) fn lookup_pk(&self, pk : &PublicKey) -> Result<&Peer<T>, HandshakeError> {
pub(crate) fn lookup_pk(&self, pk: &PublicKey) -> Result<&Peer<T>, HandshakeError> {
match self.pk_map.get(pk.as_bytes()) {
Some(&idx) => Ok(&self.peers[idx]),
_ => Err(HandshakeError::UnknownPublicKey)
_ => Err(HandshakeError::UnknownPublicKey),
}
}
// Internal function
//
// Return the peer currently associated with the receiver identifier
pub(crate) fn lookup_id(&self, id : u32) -> Result<&Peer<T>, HandshakeError> {
pub(crate) fn lookup_id(&self, id: u32) -> Result<&Peer<T>, HandshakeError> {
match self.id_map.read().get(&id) {
Some(&idx) => Ok(&self.peers[idx]),
_ => Err(HandshakeError::UnknownReceiverId)
_ => Err(HandshakeError::UnknownReceiverId),
}
}
// Internal function
//
// Allocated a new receiver identifier for the peer index
fn allocate(&self, idx : usize) -> u32 {
fn allocate(&self, idx: usize) -> u32 {
let mut rng = OsRng::new().unwrap();
loop {
@@ -181,7 +184,7 @@ impl <T>Device<T> where T : Copy {
// check membership with read lock
if self.id_map.read().contains_key(&id) {
continue
continue;
}
// take write lock and add index
@@ -196,8 +199,8 @@ impl <T>Device<T> where T : Copy {
#[cfg(test)]
mod tests {
use hex;
use super::*;
use hex;
use messages::*;
use std::convert::TryFrom;
@@ -224,7 +227,6 @@ mod tests {
// do a few handshakes
for i in 0..10 {
println!("handshake : {}", i);
// create initiation

View File

@@ -1,9 +1,9 @@
mod types;
mod noise;
mod messages;
mod peer;
mod device;
mod messages;
mod noise;
mod peer;
mod timestamp;
mod types;
// publicly exposed interface

View File

@@ -1,15 +1,15 @@
use hex;
use std::mem;
use std::fmt;
use std::convert::TryFrom;
use crate::types::*;
use hex;
use std::convert::TryFrom;
use std::fmt;
use std::mem;
const SIZE_TAG : usize = 16;
const SIZE_X25519_POINT : usize = 32;
const SIZE_TIMESTAMP : usize = 12;
const SIZE_TAG: usize = 16;
const SIZE_X25519_POINT: usize = 32;
const SIZE_TIMESTAMP: usize = 12;
pub const TYPE_INITIATION : u8 = 1;
pub const TYPE_RESPONSE : u8 = 2;
pub const TYPE_INITIATION: u8 = 1;
pub const TYPE_RESPONSE: u8 = 2;
/* Functions related to the packing / unpacking of
* the fixed-sized noise handshake messages.
@@ -20,21 +20,19 @@ pub const TYPE_RESPONSE : u8 = 2;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct Initiation {
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 : [u8; SIZE_TIMESTAMP],
pub f_timestamp_tag : [u8; SIZE_TAG],
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: [u8; SIZE_TIMESTAMP],
pub f_timestamp_tag: [u8; SIZE_TAG],
}
impl TryFrom<&[u8]> for Initiation {
type Error = HandshakeError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
// check length of slice matches message
if value.len() != mem::size_of::<Self>() {
@@ -44,7 +42,7 @@ impl TryFrom<&[u8]> for Initiation {
// create owned copy
let mut owned = [0u8; mem::size_of::<Self>()];
let mut msg : Self;
let mut msg: Self;
owned.copy_from_slice(value);
// cast to Initiation
@@ -76,10 +74,8 @@ impl Into<Vec<u8>> for Initiation {
msg.f_sender = msg.f_sender.to_le();
// cast to array
let array : [u8; mem::size_of::<Self>()];
unsafe {
array = mem::transmute::<Self, [u8; mem::size_of::<Self>()]>(msg)
};
let array: [u8; mem::size_of::<Self>()];
unsafe { array = mem::transmute::<Self, [u8; mem::size_of::<Self>()]>(msg) };
array.to_vec()
}
@@ -88,13 +84,13 @@ impl Into<Vec<u8>> for Initiation {
impl Default for Initiation {
fn default() -> Self {
Self {
f_type : TYPE_INITIATION as u32,
f_sender : 0,
f_ephemeral : [0u8; SIZE_X25519_POINT],
f_static : [0u8; SIZE_X25519_POINT],
f_static_tag : [0u8; SIZE_TAG],
f_timestamp : [0u8; SIZE_TIMESTAMP],
f_timestamp_tag : [0u8; SIZE_TAG]
f_type: TYPE_INITIATION as u32,
f_sender: 0,
f_ephemeral: [0u8; SIZE_X25519_POINT],
f_static: [0u8; SIZE_X25519_POINT],
f_static_tag: [0u8; SIZE_TAG],
f_timestamp: [0u8; SIZE_TIMESTAMP],
f_timestamp_tag: [0u8; SIZE_TAG],
}
}
}
@@ -117,13 +113,13 @@ impl fmt::Debug for Initiation {
#[cfg(test)]
impl PartialEq for Initiation {
fn eq(&self, other: &Self) -> bool {
self.f_type == other.f_type &&
self.f_sender == other.f_sender &&
self.f_ephemeral[..] == other.f_ephemeral[..] &&
self.f_static[..] == other.f_static[..] &&
self.f_static_tag[..] == other.f_static_tag[..] &&
self.f_timestamp[..] == other.f_timestamp &&
self.f_timestamp_tag[..] == other.f_timestamp_tag
self.f_type == other.f_type
&& self.f_sender == other.f_sender
&& self.f_ephemeral[..] == other.f_ephemeral[..]
&& self.f_static[..] == other.f_static[..]
&& self.f_static_tag[..] == other.f_static_tag[..]
&& self.f_timestamp[..] == other.f_timestamp
&& self.f_timestamp_tag[..] == other.f_timestamp_tag
}
}
@@ -133,19 +129,17 @@ impl Eq for Initiation {}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct Response {
f_type : u32,
pub f_sender : u32,
pub f_receiver : u32,
pub f_ephemeral : [u8; SIZE_X25519_POINT],
pub f_empty_tag : [u8; SIZE_TAG],
f_type: u32,
pub f_sender: u32,
pub f_receiver: u32,
pub f_ephemeral: [u8; SIZE_X25519_POINT],
pub f_empty_tag: [u8; SIZE_TAG],
}
impl TryFrom<&[u8]> for Response {
type Error = HandshakeError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
// check length of slice matches message
if value.len() != mem::size_of::<Self>() {
@@ -155,7 +149,7 @@ impl TryFrom<&[u8]> for Response {
// create owned copy
let mut owned = [0u8; mem::size_of::<Self>()];
let mut msg : Self;
let mut msg: Self;
owned.copy_from_slice(value);
// cast to MessageResponse
@@ -189,10 +183,8 @@ impl Into<Vec<u8>> for Response {
msg.f_receiver = msg.f_receiver.to_le();
// cast to array
let array : [u8; mem::size_of::<Self>()];
unsafe {
array = mem::transmute::<Self, [u8; mem::size_of::<Self>()]>(msg)
};
let array: [u8; mem::size_of::<Self>()];
unsafe { array = mem::transmute::<Self, [u8; mem::size_of::<Self>()]>(msg) };
array.to_vec()
}
@@ -201,11 +193,11 @@ impl Into<Vec<u8>> for Response {
impl Default for Response {
fn default() -> Self {
Self {
f_type : TYPE_RESPONSE as u32,
f_sender : 0,
f_receiver : 0,
f_ephemeral : [0u8; SIZE_X25519_POINT],
f_empty_tag : [0u8; SIZE_TAG]
f_type: TYPE_RESPONSE as u32,
f_sender: 0,
f_receiver: 0,
f_ephemeral: [0u8; SIZE_X25519_POINT],
f_empty_tag: [0u8; SIZE_TAG],
}
}
}
@@ -226,11 +218,11 @@ impl fmt::Debug for Response {
#[cfg(test)]
impl PartialEq for Response {
fn eq(&self, other: &Self) -> bool {
self.f_type == other.f_type &&
self.f_sender == other.f_sender &&
self.f_receiver == other.f_receiver &&
self.f_ephemeral == other.f_ephemeral &&
self.f_empty_tag == other.f_empty_tag
self.f_type == other.f_type
&& self.f_sender == other.f_sender
&& self.f_receiver == other.f_receiver
&& self.f_ephemeral == other.f_ephemeral
&& self.f_empty_tag == other.f_empty_tag
}
}
@@ -240,57 +232,53 @@ mod tests {
#[test]
fn message_response_identity() {
let mut msg : Response = Default::default();
let mut msg: Response = Default::default();
msg.f_sender = 146252;
msg.f_receiver = 554442;
msg.f_ephemeral = [
0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51,
0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c, 0xde, 0x1e,
0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67,
0xea, 0x89, 0x45, 0x44, 0x13, 0x56, 0x52, 0x1f
0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51, 0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c,
0xde, 0x1e, 0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67, 0xea, 0x89, 0x45, 0x44,
0x13, 0x56, 0x52, 0x1f,
];
msg.f_empty_tag = [
0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05,
0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde
0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05,
0x2f, 0xde,
];
let buf : Vec<u8> = msg.into();
let msg_p : Response = Response::try_from(&buf[..]).unwrap();
let buf: Vec<u8> = msg.into();
let msg_p: Response = Response::try_from(&buf[..]).unwrap();
assert_eq!(msg, msg_p);
}
#[test]
fn message_initiate_identity() {
let mut msg : Initiation = Default::default();
let mut msg: Initiation = Default::default();
msg.f_sender = 575757;
msg.f_ephemeral = [
0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51,
0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c, 0xde, 0x1e,
0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67,
0xea, 0x89, 0x45, 0x44, 0x13, 0x56, 0x52, 0x1f
0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51, 0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c,
0xde, 0x1e, 0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67, 0xea, 0x89, 0x45, 0x44,
0x13, 0x56, 0x52, 0x1f,
];
msg.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
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.f_static_tag = [
0x45, 0xac, 0x8d, 0x43, 0xea, 0x1b, 0x2f, 0x02,
0x45, 0x5d, 0x86, 0x37, 0xee, 0x83, 0x6b, 0x42
0x45, 0xac, 0x8d, 0x43, 0xea, 0x1b, 0x2f, 0x02, 0x45, 0x5d, 0x86, 0x37, 0xee, 0x83,
0x6b, 0x42,
];
msg.f_timestamp = [
0x4f, 0x1c, 0x60, 0xec, 0x0e, 0xf6, 0x36, 0xf0,
0x78, 0x28, 0x57, 0x42
0x4f, 0x1c, 0x60, 0xec, 0x0e, 0xf6, 0x36, 0xf0, 0x78, 0x28, 0x57, 0x42,
];
msg.f_timestamp_tag = [
0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05,
0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde
0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05,
0x2f, 0xde,
];
let buf : Vec<u8> = msg.into();
let buf: Vec<u8> = msg.into();
assert_eq!(msg, Initiation::try_from(&buf[..]).unwrap());
}
}

View File

@@ -5,23 +5,23 @@ use x25519_dalek::PublicKey;
use x25519_dalek::StaticSecret;
// HASH & MAC
use hmac::{Mac, Hmac};
use blake2::{Blake2s, Digest};
use blake2::Blake2s;
use hmac::Hmac;
// AEAD
use crypto::aead::{AeadDecryptor, AeadEncryptor};
use crypto::chacha20poly1305::ChaCha20Poly1305;
use crypto::aead::{AeadEncryptor,AeadDecryptor};
use rand::rngs::OsRng;
use generic_array::typenum::*;
use generic_array::GenericArray;
use crate::types::*;
use crate::peer::{State, Peer};
use crate::device::Device;
use crate::messages::{Initiation, Response};
use crate::peer::{Peer, State};
use crate::timestamp;
use crate::types::*;
// HMAC hasher (generic construction)
@@ -31,144 +31,97 @@ type HMACBlake2s = Hmac<Blake2s>;
type TemporaryState = (u32, PublicKey, GenericArray<u8, U32>, GenericArray<u8, U32>);
const SIZE_CK : usize = 32;
const SIZE_HS : usize = 32;
const SIZE_NONCE : usize = 8;
const SIZE_CK: usize = 32;
const SIZE_HS: usize = 32;
const SIZE_NONCE: usize = 8;
// C := Hash(Construction)
const INITIAL_CK : [u8; SIZE_CK] = [
0x60, 0xe2, 0x6d, 0xae, 0xf3, 0x27, 0xef, 0xc0,
0x2e, 0xc3, 0x35, 0xe2, 0xa0, 0x25, 0xd2, 0xd0,
0x16, 0xeb, 0x42, 0x06, 0xf8, 0x72, 0x77, 0xf5,
0x2d, 0x38, 0xd1, 0x98, 0x8b, 0x78, 0xcd, 0x36
const INITIAL_CK: [u8; SIZE_CK] = [
0x60, 0xe2, 0x6d, 0xae, 0xf3, 0x27, 0xef, 0xc0, 0x2e, 0xc3, 0x35, 0xe2, 0xa0, 0x25, 0xd2, 0xd0,
0x16, 0xeb, 0x42, 0x06, 0xf8, 0x72, 0x77, 0xf5, 0x2d, 0x38, 0xd1, 0x98, 0x8b, 0x78, 0xcd, 0x36,
];
// H := Hash(C || Identifier)
const INITIAL_HS : [u8; SIZE_HS] = [
0x22, 0x11, 0xb3, 0x61, 0x08, 0x1a, 0xc5, 0x66,
0x69, 0x12, 0x43, 0xdb, 0x45, 0x8a, 0xd5, 0x32,
0x2d, 0x9c, 0x6c, 0x66, 0x22, 0x93, 0xe8, 0xb7,
0x0e, 0xe1, 0x9c, 0x65, 0xba, 0x07, 0x9e, 0xf3
const INITIAL_HS: [u8; SIZE_HS] = [
0x22, 0x11, 0xb3, 0x61, 0x08, 0x1a, 0xc5, 0x66, 0x69, 0x12, 0x43, 0xdb, 0x45, 0x8a, 0xd5, 0x32,
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; SIZE_NONCE] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
macro_rules! HASH {
($input1:expr) => {
{
let mut hsh = <Blake2s as Digest>::new();
Digest::input(&mut hsh, $input1);
Digest::result(hsh)
}
};
($input1:expr, $input2:expr) => {
{
let mut hsh = <Blake2s as Digest>::new();
Digest::input(&mut hsh, $input1);
Digest::input(&mut hsh, $input2);
Digest::result(hsh)
}
};
($input1:expr, $input2:expr, $input3:expr) => {
{
let mut hsh = <Blake2s as Digest>::new();
Digest::input(&mut hsh, $input1);
Digest::input(&mut hsh, $input2);
Digest::input(&mut hsh, $input3);
Digest::result(hsh)
}
};
( $($input:expr),* ) => {{
use blake2::Digest;
let mut hsh = Blake2s::new();
$(
hsh.input($input);
)*
hsh.result()
}};
}
macro_rules! HMAC {
($key:expr, $input1:expr) => {
{
// let mut mac = HMACBlake2s::new($key);
let mut mac = HMACBlake2s::new_varkey($key).unwrap();
mac.input($input1);
mac.result().code()
}
};
($key:expr, $input1:expr, $input2:expr) => {
{
let mut mac = HMACBlake2s::new_varkey($key).unwrap();
mac.input($input1);
mac.input($input2);
mac.result().code()
}
};
($key:expr, $($input:expr),*) => {{
use hmac::Mac;
let mut mac = HMACBlake2s::new_varkey($key).unwrap();
$(
mac.input($input);
)*
mac.result().code()
}};
}
macro_rules! KDF1 {
($ck:expr, $input:expr) => {
{
let t0 = HMAC!($ck, $input);
let t1 = HMAC!(&t0, &[0x1]);
t1
}
}
($ck:expr, $input:expr) => {{
let t0 = HMAC!($ck, $input);
let t1 = HMAC!(&t0, &[0x1]);
t1
}};
}
macro_rules! KDF2 {
($ck:expr, $input:expr) => {
{
let t0 = HMAC!($ck, $input);
let t1 = HMAC!(&t0, &[0x1]);
let t2 = HMAC!(&t0, &t1, &[0x2]);
(t1, t2)
}
}
($ck:expr, $input:expr) => {{
let t0 = HMAC!($ck, $input);
let t1 = HMAC!(&t0, &[0x1]);
let t2 = HMAC!(&t0, &t1, &[0x2]);
(t1, t2)
}};
}
macro_rules! KDF3 {
($ck:expr, $input:expr) => {
{
let t0 = HMAC!($ck, $input);
let t1 = HMAC!(&t0, &[0x1]);
let t2 = HMAC!(&t0, &t1, &[0x2]);
let t3 = HMAC!(&t0, &t2, &[0x3]);
(t1, t2, t3)
}
}
($ck:expr, $input:expr) => {{
let t0 = HMAC!($ck, $input);
let t1 = HMAC!(&t0, &[0x1]);
let t2 = HMAC!(&t0, &t1, &[0x2]);
let t3 = HMAC!(&t0, &t2, &[0x3]);
(t1, t2, t3)
}};
}
macro_rules! SEAL {
($key:expr, $aead:expr, $pt:expr, $ct:expr, $tag:expr) => {
{
let mut aead = ChaCha20Poly1305::new($key, &ZERO_NONCE, $aead);
aead.encrypt(
$pt,
$ct,
$tag
);
}
}
($key:expr, $aead:expr, $pt:expr, $ct:expr, $tag:expr) => {{
let mut aead = ChaCha20Poly1305::new($key, &ZERO_NONCE, $aead);
aead.encrypt($pt, $ct, $tag);
}};
}
macro_rules! OPEN {
($key:expr, $aead:expr, $pt:expr, $ct:expr, $tag:expr) => {
{
let mut aead = ChaCha20Poly1305::new($key, &ZERO_NONCE, $aead);
if !aead.decrypt($ct, $pt, $tag) {
Err(HandshakeError::DecryptionFailure)
} else {
Ok(())
}
($key:expr, $aead:expr, $pt:expr, $ct:expr, $tag:expr) => {{
let mut aead = ChaCha20Poly1305::new($key, &ZERO_NONCE, $aead);
if !aead.decrypt($ct, $pt, $tag) {
Err(HandshakeError::DecryptionFailure)
} else {
Ok(())
}
}
}};
}
#[cfg(test)]
mod tests {
use super::*;
const IDENTIFIER : &[u8] = b"WireGuard v1 zx2c4 Jason@zx2c4.com";
const CONSTRUCTION : &[u8] = b"Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
const IDENTIFIER: &[u8] = b"WireGuard v1 zx2c4 Jason@zx2c4.com";
const CONSTRUCTION: &[u8] = b"Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s";
#[test]
fn precomputed_chain_key() {
@@ -177,21 +130,17 @@ mod tests {
#[test]
fn precomputed_hash() {
assert_eq!(
INITIAL_HS[..],
HASH!(INITIAL_CK, IDENTIFIER)[..]
);
assert_eq!(INITIAL_HS[..], HASH!(INITIAL_CK, IDENTIFIER)[..]);
}
}
pub fn create_initiation<T : Copy>(
device : &Device<T>,
peer : &Peer<T>,
sender : u32
pub fn create_initiation<T: Copy>(
device: &Device<T>,
peer: &Peer<T>,
sender: u32,
) -> Result<Vec<u8>, HandshakeError> {
let mut rng = OsRng::new().unwrap();
let mut msg : Initiation = Default::default();
let mut msg: Initiation = Default::default();
// initialize state
@@ -226,10 +175,10 @@ pub fn create_initiation<T : Copy>(
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
&mut msg.f_static_tag // tag
);
// H := Hash(H || msg.static)
@@ -244,10 +193,10 @@ pub fn create_initiation<T : Copy>(
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
&mut msg.f_timestamp_tag // tag
);
// H := Hash(H || msg.timestamp)
@@ -256,18 +205,22 @@ pub fn create_initiation<T : Copy>(
// update state of peer
peer.set_state(State::InitiationSent{hs, ck, eph_sk, sender});
peer.set_state(State::InitiationSent {
hs,
ck,
eph_sk,
sender,
});
// return message as vector
Ok(Initiation::into(msg))
}
pub fn consume_initiation<'a, T : Copy>(
device : &'a Device<T>,
msg : &[u8]
pub fn consume_initiation<'a, T: Copy>(
device: &'a Device<T>,
msg: &[u8],
) -> Result<(&'a Peer<T>, TemporaryState), HandshakeError> {
// parse message
let msg = Initiation::try_from(msg)?;
@@ -289,10 +242,7 @@ pub fn consume_initiation<'a, T : Copy>(
// (C, k) := Kdf2(C, DH(E_priv, S_pub))
let eph_r_pk = PublicKey::from(msg.f_ephemeral);
let (ck, key) = KDF2!(
&ck,
device.sk.diffie_hellman(&eph_r_pk).as_bytes()
);
let (ck, key) = KDF2!(&ck, device.sk.diffie_hellman(&eph_r_pk).as_bytes());
// msg.static := Aead(k, 0, S_pub, H)
@@ -300,10 +250,10 @@ 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
&msg.f_static_tag // tag
)?;
let peer = device.lookup_pk(&PublicKey::from(pk))?;
@@ -322,10 +272,10 @@ 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
&msg.f_timestamp_tag // tag
)?;
// check and update timestamp
@@ -341,14 +291,13 @@ pub fn consume_initiation<'a, T : Copy>(
Ok((peer, (msg.f_sender, eph_r_pk, hs, ck)))
}
pub fn create_response<T : Copy>(
peer : &Peer<T>,
sender : u32, // sending identifier
state : TemporaryState // state from "consume_initiation"
pub fn create_response<T: Copy>(
peer: &Peer<T>,
sender: u32, // sending identifier
state: TemporaryState, // state from "consume_initiation"
) -> Result<Output<T>, HandshakeError> {
let mut rng = OsRng::new().unwrap();
let mut msg : Response = Default::default();
let mut msg: Response = Default::default();
let (receiver, eph_r_pk, hs, ck) = state;
@@ -392,10 +341,10 @@ pub fn create_response<T : Copy>(
SEAL!(
&key,
&hs, // ad
&[], // pt
&mut [], // ct
&mut msg.f_empty_tag // tag
&hs, // ad
&[], // pt
&mut [], // ct
&mut msg.f_empty_tag // tag
);
/* not strictly needed
@@ -413,22 +362,24 @@ pub fn create_response<T : Copy>(
Ok((
peer.identifier,
Some(Response::into(msg)),
Some(KeyPair{
confirmed : false,
send : Key{
id : sender,
key : key_send.into()
Some(KeyPair {
confirmed: false,
send: Key {
id: sender,
key: key_send.into(),
},
recv : Key{
id : receiver,
key : key_recv.into()
}
})
recv: Key {
id: receiver,
key: key_recv.into(),
},
}),
))
}
pub fn consume_response<T : Copy>(device : &Device<T>, msg : &[u8]) -> Result<Output<T>, HandshakeError> {
pub fn consume_response<T: Copy>(
device: &Device<T>,
msg: &[u8],
) -> Result<Output<T>, HandshakeError> {
// parse message
let msg = Response::try_from(msg)?;
@@ -438,7 +389,12 @@ pub fn consume_response<T : Copy>(device : &Device<T>, msg : &[u8]) -> Result<Ou
let peer = device.lookup_id(msg.f_receiver)?;
let (hs, ck, sender, eph_sk) = match peer.get_state() {
State::Reset => Err(HandshakeError::InvalidState),
State::InitiationSent{hs, ck, sender, eph_sk} => Ok((hs, ck, sender, eph_sk))
State::InitiationSent {
hs,
ck,
sender,
eph_sk,
} => Ok((hs, ck, sender, eph_sk)),
}?;
// C := Kdf1(C, E_pub)
@@ -470,10 +426,10 @@ pub fn consume_response<T : Copy>(device : &Device<T>, msg : &[u8]) -> Result<Ou
OPEN!(
&key,
&hs, // ad
&mut [], // pt
&[], // ct
&msg.f_empty_tag // tag
&hs, // ad
&mut [], // pt
&[], // ct
&msg.f_empty_tag // tag
)?;
// derive key-pair
@@ -485,16 +441,16 @@ pub fn consume_response<T : Copy>(device : &Device<T>, msg : &[u8]) -> Result<Ou
Ok((
peer.identifier,
None,
Some(KeyPair{
confirmed : true,
send : Key{
id : sender,
key : key_send.into()
Some(KeyPair {
confirmed: true,
send: Key {
id: sender,
key: key_send.into(),
},
recv : Key{
id : msg.f_sender,
key : key_recv.into()
}
})
recv: Key {
id: msg.f_sender,
key: key_recv.into(),
},
}),
))
}

View File

@@ -4,12 +4,12 @@ use generic_array::typenum::U32;
use generic_array::GenericArray;
use x25519_dalek::PublicKey;
use x25519_dalek::StaticSecret;
use x25519_dalek::SharedSecret;
use x25519_dalek::StaticSecret;
use crate::types::*;
use crate::timestamp;
use crate::device::Device;
use crate::timestamp;
use crate::types::*;
/* Represents the recomputation and state of a peer.
*
@@ -18,28 +18,28 @@ use crate::device::Device;
pub struct Peer<T> {
// external identifier
pub(crate) identifier : T,
pub(crate) identifier: T,
// internal identifier
pub(crate) idx : usize,
pub(crate) idx: usize,
// mutable state
state : Mutex<State>,
timestamp : Mutex<Option<timestamp::TAI64N>>,
state: Mutex<State>,
timestamp: Mutex<Option<timestamp::TAI64N>>,
// constant state
pub(crate) pk : PublicKey, // public key of peer
pub(crate) ss : SharedSecret, // precomputed DH(static, static)
pub(crate) psk : Psk // psk of peer
pub(crate) pk: PublicKey, // public key of peer
pub(crate) ss: SharedSecret, // precomputed DH(static, static)
pub(crate) psk: Psk, // psk of peer
}
pub enum State {
Reset,
InitiationSent{
sender : u32, // assigned sender id
eph_sk : StaticSecret,
hs : GenericArray<u8, U32>,
ck : GenericArray<u8, U32>
InitiationSent {
sender: u32, // assigned sender id
eph_sk: StaticSecret,
hs: GenericArray<u8, U32>,
ck: GenericArray<u8, U32>,
},
}
@@ -47,32 +47,39 @@ impl Clone for State {
fn clone(&self) -> State {
match self {
State::Reset => State::Reset,
State::InitiationSent{sender, eph_sk, hs, ck} =>
State::InitiationSent{
sender : *sender,
eph_sk : StaticSecret::from(eph_sk.to_bytes()),
hs : *hs,
ck : *ck
}
State::InitiationSent {
sender,
eph_sk,
hs,
ck,
} => State::InitiationSent {
sender: *sender,
eph_sk: StaticSecret::from(eph_sk.to_bytes()),
hs: *hs,
ck: *ck,
},
}
}
}
impl <T>Peer<T> where T : Copy {
impl<T> Peer<T>
where
T: Copy,
{
pub fn new(
idx : usize,
identifier : T, // external identifier
pk : PublicKey, // public key of peer
ss : SharedSecret // precomputed DH(static, static)
idx: usize,
identifier: T, // external identifier
pk: PublicKey, // public key of peer
ss: SharedSecret, // precomputed DH(static, static)
) -> Self {
Self {
idx : idx,
identifier : identifier,
state : Mutex::new(State::Reset),
timestamp : Mutex::new(None),
pk : pk,
ss : ss,
psk : [0u8; 32]
idx: idx,
identifier: identifier,
state: Mutex::new(State::Reset),
timestamp: Mutex::new(None),
pk: pk,
ss: ss,
psk: [0u8; 32],
}
}
@@ -87,10 +94,7 @@ impl <T>Peer<T> where T : Copy {
///
/// # Arguments
///
pub fn set_state(
&self,
state_new : State
) {
pub fn set_state(&self, state_new: State) {
*self.state.lock() = state_new;
}
@@ -102,29 +106,28 @@ impl <T>Peer<T> where T : Copy {
/// * ts_new - The associated timestamp
pub fn check_timestamp(
&self,
device : &Device<T>,
timestamp_new : &timestamp::TAI64N
device: &Device<T>,
timestamp_new: &timestamp::TAI64N,
) -> Result<(), HandshakeError> {
let mut state = self.state.lock();
let mut timestamp = self.timestamp.lock();
let update = match *timestamp {
None => true,
Some(timestamp_old) => if timestamp::compare(&timestamp_old, &timestamp_new) {
true
} else {
false
Some(timestamp_old) => {
if timestamp::compare(&timestamp_old, &timestamp_new) {
true
} else {
false
}
}
};
if update {
// release existing identifier
match *state {
State::InitiationSent{sender, ..} => {
device.release(sender)
},
_ => ()
State::InitiationSent { sender, .. } => device.release(sender),
_ => (),
}
// reset state and update timestamp

View File

@@ -1,6 +1,6 @@
use std::time::{SystemTime, UNIX_EPOCH};
const TAI64_EPOCH : u64 = 0x4000000000000000;
const TAI64_EPOCH: u64 = 0x4000000000000000;
pub type TAI64N = [u8; 12];
@@ -10,8 +10,8 @@ pub fn zero() -> TAI64N {
pub fn now() -> TAI64N {
// get system time as duration
let sysnow = SystemTime::now();
let delta = sysnow.duration_since(UNIX_EPOCH).unwrap();
let sysnow = SystemTime::now();
let delta = sysnow.duration_since(UNIX_EPOCH).unwrap();
// convert to tai64n
let tai64_secs = delta.as_secs() + TAI64_EPOCH;
@@ -24,7 +24,7 @@ pub fn now() -> TAI64N {
res
}
pub fn compare(old : &TAI64N, new : &TAI64N) -> bool {
pub fn compare(old: &TAI64N, new: &TAI64N) -> bool {
for i in 0..12 {
if new[i] > old[i] {
return true;

View File

@@ -1,5 +1,5 @@
use std::fmt;
use std::error::Error;
use std::fmt;
// config error
@@ -7,7 +7,7 @@ use std::error::Error;
pub struct ConfigError(String);
impl ConfigError {
pub fn new(s : &str) -> Self {
pub fn new(s: &str) -> Self {
ConfigError(s.to_string())
}
}
@@ -37,24 +37,20 @@ pub enum HandshakeError {
UnknownReceiverId,
InvalidMessageFormat,
OldTimestamp,
InvalidState
InvalidState,
}
impl fmt::Display for HandshakeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
HandshakeError::DecryptionFailure =>
write!(f, "Failed to AEAD:OPEN"),
HandshakeError::UnknownPublicKey =>
write!(f, "Unknown public key"),
HandshakeError::UnknownReceiverId =>
write!(f, "Receiver id not allocated to any handshake"),
HandshakeError::InvalidMessageFormat =>
write!(f, "Invalid handshake message format"),
HandshakeError::OldTimestamp =>
write!(f, "Timestamp is less/equal to the newest"),
HandshakeError::InvalidState =>
write!(f, "Message does not apply to handshake state")
HandshakeError::DecryptionFailure => write!(f, "Failed to AEAD:OPEN"),
HandshakeError::UnknownPublicKey => write!(f, "Unknown public key"),
HandshakeError::UnknownReceiverId => {
write!(f, "Receiver id not allocated to any handshake")
}
HandshakeError::InvalidMessageFormat => write!(f, "Invalid handshake message format"),
HandshakeError::OldTimestamp => write!(f, "Timestamp is less/equal to the newest"),
HandshakeError::InvalidState => write!(f, "Message does not apply to handshake state"),
}
}
}
@@ -73,8 +69,8 @@ impl Error for HandshakeError {
#[derive(Debug)]
pub struct Key {
pub key : [u8; 32],
pub id : u32
pub key: [u8; 32],
pub id: u32,
}
#[cfg(test)]
@@ -86,16 +82,16 @@ impl PartialEq for Key {
#[derive(Debug)]
pub struct KeyPair {
pub confirmed : bool, // has the key-pair been confirmed?
pub send : Key, // key for outbound messages
pub recv : Key // key for inbound messages
pub confirmed: bool, // has the key-pair been confirmed?
pub send: Key, // key for outbound messages
pub recv: Key, // key for inbound messages
}
pub type Output<T> = (
T, // external identifier associated with peer
// (e.g. a reference or vector index)
T, // external identifier associated with peer
// (e.g. a reference or vector index)
Option<Vec<u8>>, // message to send
Option<KeyPair> // resulting key-pair of successful handshake
Option<KeyPair>, // resulting key-pair of successful handshake
);
// preshared key