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,23 +7,26 @@ use rand::rngs::OsRng;
use x25519_dalek::PublicKey; use x25519_dalek::PublicKey;
use x25519_dalek::StaticSecret; use x25519_dalek::StaticSecret;
use crate::noise;
use crate::messages; use crate::messages;
use crate::types::*; use crate::noise;
use crate::peer::Peer; use crate::peer::Peer;
use crate::types::*;
pub struct Device<T> { pub struct Device<T> {
pub sk: StaticSecret, // static secret key pub sk: StaticSecret, // static secret key
pub pk: PublicKey, // static public key pub pk: PublicKey, // static public key
peers: Vec<Peer<T>>, // peer index -> state peers: Vec<Peer<T>>, // peer index -> state
pk_map: HashMap<[u8; 32], usize>, // public key -> peer index pk_map: HashMap<[u8; 32], usize>, // public key -> peer index
id_map : RwLock<HashMap<u32, usize>> // receive ids -> peer index id_map: RwLock<HashMap<u32, usize>>, // receive ids -> peer index
} }
/* A mutable reference to the device needs to be held during configuration. /* A mutable reference to the device needs to be held during configuration.
* Wrapping the device in a RwLock enables peer config after "configuration time" * 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 /// Initialize a new handshake state machine
/// ///
/// # Arguments /// # Arguments
@@ -35,7 +38,7 @@ impl <T>Device<T> where T : Copy {
sk: sk, sk: sk,
peers: vec![], peers: vec![],
pk_map: HashMap::new(), pk_map: HashMap::new(),
id_map : RwLock::new(HashMap::new()) id_map: RwLock::new(HashMap::new()),
} }
} }
@@ -56,7 +59,9 @@ impl <T>Device<T> where T : Copy {
// check that the pk is not that of the device // check that the pk is not that of the device
if *self.pk.as_bytes() == *pk.as_bytes() { 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 // map : pk -> new index
@@ -66,9 +71,8 @@ impl <T>Device<T> where T : Copy {
// map : new index -> peer // map : new index -> peer
self.peers.push(Peer::new( self.peers
idx, identifier, pk, self.sk.diffie_hellman(&pk) .push(Peer::new(idx, identifier, pk, self.sk.diffie_hellman(&pk)));
));
Ok(()) Ok(())
} }
@@ -92,8 +96,8 @@ impl <T>Device<T> where T : Copy {
None => [0u8; 32], None => [0u8; 32],
}; };
Ok(()) Ok(())
}, }
_ => Err(ConfigError::new("No such public key")) _ => Err(ConfigError::new("No such public key")),
} }
} }
@@ -143,10 +147,9 @@ impl <T>Device<T> where T : Copy {
self.release(sender); self.release(sender);
e e
}) })
}, }
Some(&messages::TYPE_RESPONSE) => Some(&messages::TYPE_RESPONSE) => noise::consume_response(self, msg),
noise::consume_response(self, msg), _ => Err(HandshakeError::InvalidMessageFormat),
_ => Err(HandshakeError::InvalidMessageFormat)
} }
} }
@@ -156,7 +159,7 @@ impl <T>Device<T> where T : Copy {
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()) { match self.pk_map.get(pk.as_bytes()) {
Some(&idx) => Ok(&self.peers[idx]), Some(&idx) => Ok(&self.peers[idx]),
_ => Err(HandshakeError::UnknownPublicKey) _ => Err(HandshakeError::UnknownPublicKey),
} }
} }
@@ -166,7 +169,7 @@ impl <T>Device<T> where T : Copy {
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) { match self.id_map.read().get(&id) {
Some(&idx) => Ok(&self.peers[idx]), Some(&idx) => Ok(&self.peers[idx]),
_ => Err(HandshakeError::UnknownReceiverId) _ => Err(HandshakeError::UnknownReceiverId),
} }
} }
@@ -181,7 +184,7 @@ impl <T>Device<T> where T : Copy {
// check membership with read lock // check membership with read lock
if self.id_map.read().contains_key(&id) { if self.id_map.read().contains_key(&id) {
continue continue;
} }
// take write lock and add index // take write lock and add index
@@ -196,8 +199,8 @@ impl <T>Device<T> where T : Copy {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use hex;
use super::*; use super::*;
use hex;
use messages::*; use messages::*;
use std::convert::TryFrom; use std::convert::TryFrom;
@@ -224,7 +227,6 @@ mod tests {
// do a few handshakes // do a few handshakes
for i in 0..10 { for i in 0..10 {
println!("handshake : {}", i); println!("handshake : {}", i);
// create initiation // create initiation

View File

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

View File

@@ -1,8 +1,8 @@
use hex;
use std::mem;
use std::fmt;
use std::convert::TryFrom;
use crate::types::*; use crate::types::*;
use hex;
use std::convert::TryFrom;
use std::fmt;
use std::mem;
const SIZE_TAG: usize = 16; const SIZE_TAG: usize = 16;
const SIZE_X25519_POINT: usize = 32; const SIZE_X25519_POINT: usize = 32;
@@ -30,11 +30,9 @@ pub struct Initiation {
} }
impl TryFrom<&[u8]> for Initiation { impl TryFrom<&[u8]> for Initiation {
type Error = HandshakeError; type Error = HandshakeError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> { fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
// check length of slice matches message // check length of slice matches message
if value.len() != mem::size_of::<Self>() { if value.len() != mem::size_of::<Self>() {
@@ -77,9 +75,7 @@ impl Into<Vec<u8>> for Initiation {
// cast to array // cast to array
let array: [u8; mem::size_of::<Self>()]; let array: [u8; mem::size_of::<Self>()];
unsafe { unsafe { array = mem::transmute::<Self, [u8; mem::size_of::<Self>()]>(msg) };
array = mem::transmute::<Self, [u8; mem::size_of::<Self>()]>(msg)
};
array.to_vec() array.to_vec()
} }
@@ -94,7 +90,7 @@ impl Default for Initiation {
f_static: [0u8; SIZE_X25519_POINT], f_static: [0u8; SIZE_X25519_POINT],
f_static_tag: [0u8; SIZE_TAG], f_static_tag: [0u8; SIZE_TAG],
f_timestamp: [0u8; SIZE_TIMESTAMP], f_timestamp: [0u8; SIZE_TIMESTAMP],
f_timestamp_tag : [0u8; SIZE_TAG] f_timestamp_tag: [0u8; SIZE_TAG],
} }
} }
} }
@@ -117,13 +113,13 @@ impl fmt::Debug for Initiation {
#[cfg(test)] #[cfg(test)]
impl PartialEq for Initiation { impl PartialEq for Initiation {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.f_type == other.f_type && self.f_type == other.f_type
self.f_sender == other.f_sender && && self.f_sender == other.f_sender
self.f_ephemeral[..] == other.f_ephemeral[..] && && self.f_ephemeral[..] == other.f_ephemeral[..]
self.f_static[..] == other.f_static[..] && && self.f_static[..] == other.f_static[..]
self.f_static_tag[..] == other.f_static_tag[..] && && self.f_static_tag[..] == other.f_static_tag[..]
self.f_timestamp[..] == other.f_timestamp && && self.f_timestamp[..] == other.f_timestamp
self.f_timestamp_tag[..] == other.f_timestamp_tag && self.f_timestamp_tag[..] == other.f_timestamp_tag
} }
} }
@@ -141,11 +137,9 @@ pub struct Response {
} }
impl TryFrom<&[u8]> for Response { impl TryFrom<&[u8]> for Response {
type Error = HandshakeError; type Error = HandshakeError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> { fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
// check length of slice matches message // check length of slice matches message
if value.len() != mem::size_of::<Self>() { if value.len() != mem::size_of::<Self>() {
@@ -190,9 +184,7 @@ impl Into<Vec<u8>> for Response {
// cast to array // cast to array
let array: [u8; mem::size_of::<Self>()]; let array: [u8; mem::size_of::<Self>()];
unsafe { unsafe { array = mem::transmute::<Self, [u8; mem::size_of::<Self>()]>(msg) };
array = mem::transmute::<Self, [u8; mem::size_of::<Self>()]>(msg)
};
array.to_vec() array.to_vec()
} }
@@ -205,7 +197,7 @@ impl Default for Response {
f_sender: 0, f_sender: 0,
f_receiver: 0, f_receiver: 0,
f_ephemeral: [0u8; SIZE_X25519_POINT], f_ephemeral: [0u8; SIZE_X25519_POINT],
f_empty_tag : [0u8; SIZE_TAG] f_empty_tag: [0u8; SIZE_TAG],
} }
} }
} }
@@ -226,11 +218,11 @@ impl fmt::Debug for Response {
#[cfg(test)] #[cfg(test)]
impl PartialEq for Response { impl PartialEq for Response {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.f_type == other.f_type && self.f_type == other.f_type
self.f_sender == other.f_sender && && self.f_sender == other.f_sender
self.f_receiver == other.f_receiver && && self.f_receiver == other.f_receiver
self.f_ephemeral == other.f_ephemeral && && self.f_ephemeral == other.f_ephemeral
self.f_empty_tag == other.f_empty_tag && self.f_empty_tag == other.f_empty_tag
} }
} }
@@ -245,14 +237,13 @@ mod tests {
msg.f_sender = 146252; msg.f_sender = 146252;
msg.f_receiver = 554442; msg.f_receiver = 554442;
msg.f_ephemeral = [ msg.f_ephemeral = [
0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51, 0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51, 0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c,
0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c, 0xde, 0x1e, 0xde, 0x1e, 0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67, 0xea, 0x89, 0x45, 0x44,
0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67, 0x13, 0x56, 0x52, 0x1f,
0xea, 0x89, 0x45, 0x44, 0x13, 0x56, 0x52, 0x1f
]; ];
msg.f_empty_tag = [ msg.f_empty_tag = [
0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, 0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05,
0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde 0x2f, 0xde,
]; ];
let buf: Vec<u8> = msg.into(); let buf: Vec<u8> = msg.into();
@@ -266,28 +257,25 @@ mod tests {
msg.f_sender = 575757; msg.f_sender = 575757;
msg.f_ephemeral = [ msg.f_ephemeral = [
0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51, 0xc1, 0x66, 0x0a, 0x0c, 0xdc, 0x0f, 0x6c, 0x51, 0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c,
0x0f, 0xc2, 0xcc, 0x51, 0x52, 0x0c, 0xde, 0x1e, 0xde, 0x1e, 0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67, 0xea, 0x89, 0x45, 0x44,
0xf7, 0xf1, 0xca, 0x90, 0x86, 0x72, 0xad, 0x67, 0x13, 0x56, 0x52, 0x1f,
0xea, 0x89, 0x45, 0x44, 0x13, 0x56, 0x52, 0x1f
]; ];
msg.f_static = [ msg.f_static = [
0xdc, 0x33, 0x90, 0x15, 0x8f, 0x82, 0x3e, 0x06, 0xdc, 0x33, 0x90, 0x15, 0x8f, 0x82, 0x3e, 0x06, 0x44, 0xa0, 0xde, 0x4c, 0x15, 0x6c,
0x44, 0xa0, 0xde, 0x4c, 0x15, 0x6c, 0x5d, 0xa4, 0x5d, 0xa4, 0x65, 0x99, 0xf6, 0x6c, 0xa1, 0x14, 0x77, 0xf9, 0xeb, 0x6a, 0xec, 0xc3,
0x65, 0x99, 0xf6, 0x6c, 0xa1, 0x14, 0x77, 0xf9, 0x3c, 0xda, 0x47, 0xe1,
0xeb, 0x6a, 0xec, 0xc3, 0x3c, 0xda, 0x47, 0xe1
]; ];
msg.f_static_tag = [ msg.f_static_tag = [
0x45, 0xac, 0x8d, 0x43, 0xea, 0x1b, 0x2f, 0x02, 0x45, 0xac, 0x8d, 0x43, 0xea, 0x1b, 0x2f, 0x02, 0x45, 0x5d, 0x86, 0x37, 0xee, 0x83,
0x45, 0x5d, 0x86, 0x37, 0xee, 0x83, 0x6b, 0x42 0x6b, 0x42,
]; ];
msg.f_timestamp = [ msg.f_timestamp = [
0x4f, 0x1c, 0x60, 0xec, 0x0e, 0xf6, 0x36, 0xf0, 0x4f, 0x1c, 0x60, 0xec, 0x0e, 0xf6, 0x36, 0xf0, 0x78, 0x28, 0x57, 0x42,
0x78, 0x28, 0x57, 0x42
]; ];
msg.f_timestamp_tag = [ msg.f_timestamp_tag = [
0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, 0x60, 0x0e, 0x1e, 0x95, 0x41, 0x6b, 0x52, 0x05, 0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05,
0xa2, 0x09, 0xe1, 0xbf, 0x40, 0x05, 0x2f, 0xde 0x2f, 0xde,
]; ];
let buf: Vec<u8> = msg.into(); let buf: Vec<u8> = msg.into();

View File

@@ -5,23 +5,23 @@ use x25519_dalek::PublicKey;
use x25519_dalek::StaticSecret; use x25519_dalek::StaticSecret;
// HASH & MAC // HASH & MAC
use hmac::{Mac, Hmac}; use blake2::Blake2s;
use blake2::{Blake2s, Digest}; use hmac::Hmac;
// AEAD // AEAD
use crypto::aead::{AeadDecryptor, AeadEncryptor};
use crypto::chacha20poly1305::ChaCha20Poly1305; use crypto::chacha20poly1305::ChaCha20Poly1305;
use crypto::aead::{AeadEncryptor,AeadDecryptor};
use rand::rngs::OsRng; use rand::rngs::OsRng;
use generic_array::typenum::*; use generic_array::typenum::*;
use generic_array::GenericArray; use generic_array::GenericArray;
use crate::types::*;
use crate::peer::{State, Peer};
use crate::device::Device; use crate::device::Device;
use crate::messages::{Initiation, Response}; use crate::messages::{Initiation, Response};
use crate::peer::{Peer, State};
use crate::timestamp; use crate::timestamp;
use crate::types::*;
// HMAC hasher (generic construction) // HMAC hasher (generic construction)
@@ -37,130 +37,83 @@ const SIZE_NONCE : usize = 8;
// C := Hash(Construction) // C := Hash(Construction)
const INITIAL_CK: [u8; SIZE_CK] = [ const INITIAL_CK: [u8; SIZE_CK] = [
0x60, 0xe2, 0x6d, 0xae, 0xf3, 0x27, 0xef, 0xc0, 0x60, 0xe2, 0x6d, 0xae, 0xf3, 0x27, 0xef, 0xc0, 0x2e, 0xc3, 0x35, 0xe2, 0xa0, 0x25, 0xd2, 0xd0,
0x2e, 0xc3, 0x35, 0xe2, 0xa0, 0x25, 0xd2, 0xd0, 0x16, 0xeb, 0x42, 0x06, 0xf8, 0x72, 0x77, 0xf5, 0x2d, 0x38, 0xd1, 0x98, 0x8b, 0x78, 0xcd, 0x36,
0x16, 0xeb, 0x42, 0x06, 0xf8, 0x72, 0x77, 0xf5,
0x2d, 0x38, 0xd1, 0x98, 0x8b, 0x78, 0xcd, 0x36
]; ];
// H := Hash(C || Identifier) // H := Hash(C || Identifier)
const INITIAL_HS: [u8; SIZE_HS] = [ const INITIAL_HS: [u8; SIZE_HS] = [
0x22, 0x11, 0xb3, 0x61, 0x08, 0x1a, 0xc5, 0x66, 0x22, 0x11, 0xb3, 0x61, 0x08, 0x1a, 0xc5, 0x66, 0x69, 0x12, 0x43, 0xdb, 0x45, 0x8a, 0xd5, 0x32,
0x69, 0x12, 0x43, 0xdb, 0x45, 0x8a, 0xd5, 0x32, 0x2d, 0x9c, 0x6c, 0x66, 0x22, 0x93, 0xe8, 0xb7, 0x0e, 0xe1, 0x9c, 0x65, 0xba, 0x07, 0x9e, 0xf3,
0x2d, 0x9c, 0x6c, 0x66, 0x22, 0x93, 0xe8, 0xb7,
0x0e, 0xe1, 0x9c, 0x65, 0xba, 0x07, 0x9e, 0xf3
]; ];
const ZERO_NONCE : [u8; SIZE_NONCE] = [ const ZERO_NONCE: [u8; SIZE_NONCE] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
];
macro_rules! HASH { macro_rules! HASH {
($input1:expr) => { ( $($input:expr),* ) => {{
{ use blake2::Digest;
let mut hsh = <Blake2s as Digest>::new(); let mut hsh = Blake2s::new();
Digest::input(&mut hsh, $input1); $(
Digest::result(hsh) hsh.input($input);
} )*
}; hsh.result()
}};
($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)
}
};
} }
macro_rules! HMAC { macro_rules! HMAC {
($key:expr, $input1:expr) => { ($key:expr, $($input:expr),*) => {{
{ use hmac::Mac;
// let mut mac = HMACBlake2s::new($key);
let mut mac = HMACBlake2s::new_varkey($key).unwrap(); let mut mac = HMACBlake2s::new_varkey($key).unwrap();
mac.input($input1); $(
mac.input($input);
)*
mac.result().code() 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()
}
};
} }
macro_rules! KDF1 { macro_rules! KDF1 {
($ck:expr, $input:expr) => { ($ck:expr, $input:expr) => {{
{
let t0 = HMAC!($ck, $input); let t0 = HMAC!($ck, $input);
let t1 = HMAC!(&t0, &[0x1]); let t1 = HMAC!(&t0, &[0x1]);
t1 t1
} }};
}
} }
macro_rules! KDF2 { macro_rules! KDF2 {
($ck:expr, $input:expr) => { ($ck:expr, $input:expr) => {{
{
let t0 = HMAC!($ck, $input); let t0 = HMAC!($ck, $input);
let t1 = HMAC!(&t0, &[0x1]); let t1 = HMAC!(&t0, &[0x1]);
let t2 = HMAC!(&t0, &t1, &[0x2]); let t2 = HMAC!(&t0, &t1, &[0x2]);
(t1, t2) (t1, t2)
} }};
}
} }
macro_rules! KDF3 { macro_rules! KDF3 {
($ck:expr, $input:expr) => { ($ck:expr, $input:expr) => {{
{
let t0 = HMAC!($ck, $input); let t0 = HMAC!($ck, $input);
let t1 = HMAC!(&t0, &[0x1]); let t1 = HMAC!(&t0, &[0x1]);
let t2 = HMAC!(&t0, &t1, &[0x2]); let t2 = HMAC!(&t0, &t1, &[0x2]);
let t3 = HMAC!(&t0, &t2, &[0x3]); let t3 = HMAC!(&t0, &t2, &[0x3]);
(t1, t2, t3) (t1, t2, t3)
} }};
}
} }
macro_rules! SEAL { macro_rules! SEAL {
($key:expr, $aead:expr, $pt:expr, $ct:expr, $tag:expr) => { ($key:expr, $aead:expr, $pt:expr, $ct:expr, $tag:expr) => {{
{
let mut aead = ChaCha20Poly1305::new($key, &ZERO_NONCE, $aead); let mut aead = ChaCha20Poly1305::new($key, &ZERO_NONCE, $aead);
aead.encrypt( aead.encrypt($pt, $ct, $tag);
$pt, }};
$ct,
$tag
);
}
}
} }
macro_rules! OPEN { macro_rules! OPEN {
($key:expr, $aead:expr, $pt:expr, $ct:expr, $tag:expr) => { ($key:expr, $aead:expr, $pt:expr, $ct:expr, $tag:expr) => {{
{
let mut aead = ChaCha20Poly1305::new($key, &ZERO_NONCE, $aead); let mut aead = ChaCha20Poly1305::new($key, &ZERO_NONCE, $aead);
if !aead.decrypt($ct, $pt, $tag) { if !aead.decrypt($ct, $pt, $tag) {
Err(HandshakeError::DecryptionFailure) Err(HandshakeError::DecryptionFailure)
} else { } else {
Ok(()) Ok(())
} }
} }};
}
} }
#[cfg(test)] #[cfg(test)]
@@ -177,19 +130,15 @@ mod tests {
#[test] #[test]
fn precomputed_hash() { fn precomputed_hash() {
assert_eq!( assert_eq!(INITIAL_HS[..], HASH!(INITIAL_CK, IDENTIFIER)[..]);
INITIAL_HS[..],
HASH!(INITIAL_CK, IDENTIFIER)[..]
);
} }
} }
pub fn create_initiation<T: Copy>( pub fn create_initiation<T: Copy>(
device: &Device<T>, device: &Device<T>,
peer: &Peer<T>, peer: &Peer<T>,
sender : u32 sender: u32,
) -> Result<Vec<u8>, HandshakeError> { ) -> Result<Vec<u8>, HandshakeError> {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
let mut msg: Initiation = Default::default(); let mut msg: Initiation = Default::default();
@@ -256,7 +205,12 @@ pub fn create_initiation<T : Copy>(
// update state of peer // 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 // return message as vector
@@ -265,9 +219,8 @@ pub fn create_initiation<T : Copy>(
pub fn consume_initiation<'a, T: Copy>( pub fn consume_initiation<'a, T: Copy>(
device: &'a Device<T>, device: &'a Device<T>,
msg : &[u8] msg: &[u8],
) -> Result<(&'a Peer<T>, TemporaryState), HandshakeError> { ) -> Result<(&'a Peer<T>, TemporaryState), HandshakeError> {
// parse message // parse message
let msg = Initiation::try_from(msg)?; 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)) // (C, k) := Kdf2(C, DH(E_priv, S_pub))
let eph_r_pk = PublicKey::from(msg.f_ephemeral); let eph_r_pk = PublicKey::from(msg.f_ephemeral);
let (ck, key) = KDF2!( let (ck, key) = KDF2!(&ck, device.sk.diffie_hellman(&eph_r_pk).as_bytes());
&ck,
device.sk.diffie_hellman(&eph_r_pk).as_bytes()
);
// msg.static := Aead(k, 0, S_pub, H) // msg.static := Aead(k, 0, S_pub, H)
@@ -344,9 +294,8 @@ pub fn consume_initiation<'a, T : Copy>(
pub fn create_response<T: Copy>( pub fn create_response<T: Copy>(
peer: &Peer<T>, peer: &Peer<T>,
sender: u32, // sending identifier sender: u32, // sending identifier
state : TemporaryState // state from "consume_initiation" state: TemporaryState, // state from "consume_initiation"
) -> Result<Output<T>, HandshakeError> { ) -> Result<Output<T>, HandshakeError> {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
let mut msg: Response = Default::default(); let mut msg: Response = Default::default();
@@ -417,18 +366,20 @@ pub fn create_response<T : Copy>(
confirmed: false, confirmed: false,
send: Key { send: Key {
id: sender, id: sender,
key : key_send.into() key: key_send.into(),
}, },
recv: Key { recv: Key {
id: receiver, id: receiver,
key : key_recv.into() 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 // parse message
let msg = Response::try_from(msg)?; 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 peer = device.lookup_id(msg.f_receiver)?;
let (hs, ck, sender, eph_sk) = match peer.get_state() { let (hs, ck, sender, eph_sk) = match peer.get_state() {
State::Reset => Err(HandshakeError::InvalidState), 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) // C := Kdf1(C, E_pub)
@@ -489,12 +445,12 @@ pub fn consume_response<T : Copy>(device : &Device<T>, msg : &[u8]) -> Result<Ou
confirmed: true, confirmed: true,
send: Key { send: Key {
id: sender, id: sender,
key : key_send.into() key: key_send.into(),
}, },
recv: Key { recv: Key {
id: msg.f_sender, id: msg.f_sender,
key : key_recv.into() key: key_recv.into(),
} },
}) }),
)) ))
} }

View File

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

View File

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