Formatting
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
156
src/messages.rs
156
src/messages.rs
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
318
src/noise.rs
318
src/noise.rs
@@ -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
|
||||
×tamp::now(), // pt
|
||||
&mut msg.f_timestamp, // ct
|
||||
&mut msg.f_timestamp_tag // tag
|
||||
&hs, // ad
|
||||
×tamp::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(),
|
||||
},
|
||||
}),
|
||||
))
|
||||
}
|
||||
|
||||
101
src/peer.rs
101
src/peer.rs
@@ -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 : ×tamp::TAI64N
|
||||
device: &Device<T>,
|
||||
timestamp_new: ×tamp::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(×tamp_old, ×tamp_new) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
Some(timestamp_old) => {
|
||||
if timestamp::compare(×tamp_old, ×tamp_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
|
||||
|
||||
@@ -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;
|
||||
|
||||
42
src/types.rs
42
src/types.rs
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user