Better seperation and introduction of timestamp
This commit is contained in:
@@ -9,6 +9,7 @@ use x25519_dalek::StaticSecret;
|
|||||||
|
|
||||||
use crate::noise;
|
use crate::noise;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
use crate::peer::Peer;
|
||||||
|
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
pub sk : StaticSecret, // static secret key
|
pub sk : StaticSecret, // static secret key
|
||||||
@@ -62,12 +63,10 @@ impl Device {
|
|||||||
|
|
||||||
// map : new index -> peer
|
// map : new index -> peer
|
||||||
|
|
||||||
self.peers.push(Peer {
|
self.peers.push(Peer::new(
|
||||||
state : Mutex::new(State::Reset{ts : None}),
|
pk,
|
||||||
pk : pk,
|
self.sk.diffie_hellman(&pk)
|
||||||
ss : self.sk.diffie_hellman(&pk),
|
));
|
||||||
psk : [0u8; 32]
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
mod types;
|
mod types;
|
||||||
mod noise;
|
mod noise;
|
||||||
mod messages;
|
mod messages;
|
||||||
|
mod peer;
|
||||||
mod device;
|
mod device;
|
||||||
mod timestamp;
|
mod timestamp;
|
||||||
|
|||||||
30
src/noise.rs
30
src/noise.rs
@@ -13,6 +13,7 @@ use crypto::aead::{AeadEncryptor,AeadDecryptor};
|
|||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
|
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
use crate::peer::{State, Peer};
|
||||||
use crate::device::Device;
|
use crate::device::Device;
|
||||||
use crate::messages;
|
use crate::messages;
|
||||||
use crate::timestamp;
|
use crate::timestamp;
|
||||||
@@ -166,25 +167,31 @@ pub fn create_initiation(
|
|||||||
msg.f_sender = id;
|
msg.f_sender = id;
|
||||||
|
|
||||||
// (E_priv, E_pub) := DH-Generate()
|
// (E_priv, E_pub) := DH-Generate()
|
||||||
|
|
||||||
let sk = StaticSecret::new(&mut rng);
|
let sk = StaticSecret::new(&mut rng);
|
||||||
let pk = PublicKey::from(&sk);
|
let pk = PublicKey::from(&sk);
|
||||||
|
|
||||||
// C := Kdf(C, E_pub)
|
// C := Kdf(C, E_pub)
|
||||||
|
|
||||||
let ck = KDF1!(&ck, pk.as_bytes());
|
let ck = KDF1!(&ck, pk.as_bytes());
|
||||||
|
|
||||||
// msg.ephemeral := E_pub
|
// msg.ephemeral := E_pub
|
||||||
|
|
||||||
msg.f_ephemeral = *pk.as_bytes();
|
msg.f_ephemeral = *pk.as_bytes();
|
||||||
|
|
||||||
// H := HASH(H, msg.ephemeral)
|
// H := HASH(H, msg.ephemeral)
|
||||||
|
|
||||||
let hs = HASH!(&hs, msg.f_ephemeral);
|
let hs = HASH!(&hs, msg.f_ephemeral);
|
||||||
|
|
||||||
// (C, k) := Kdf2(C, DH(E_priv, S_pub))
|
// (C, k) := Kdf2(C, DH(E_priv, S_pub))
|
||||||
|
|
||||||
let (ck, key) = KDF2!(
|
let (ck, key) = KDF2!(
|
||||||
&ck,
|
&ck,
|
||||||
sk.diffie_hellman(&peer.pk).as_bytes()
|
sk.diffie_hellman(&peer.pk).as_bytes()
|
||||||
);
|
);
|
||||||
|
|
||||||
// msg.static := Aead(k, 0, S_pub, H)
|
// msg.static := Aead(k, 0, S_pub, H)
|
||||||
|
|
||||||
SEAL!(
|
SEAL!(
|
||||||
&key,
|
&key,
|
||||||
&hs, // ad
|
&hs, // ad
|
||||||
@@ -194,39 +201,44 @@ pub fn create_initiation(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// H := Hash(H || msg.static)
|
// H := Hash(H || msg.static)
|
||||||
|
|
||||||
let hs = HASH!(&hs, &msg.f_static, &msg.f_static_tag);
|
let hs = HASH!(&hs, &msg.f_static, &msg.f_static_tag);
|
||||||
|
|
||||||
// (C, k) := Kdf2(C, DH(S_priv, S_pub))
|
// (C, k) := Kdf2(C, DH(S_priv, S_pub))
|
||||||
|
|
||||||
let (ck, key) = KDF2!(
|
let (ck, key) = KDF2!(
|
||||||
&ck,
|
&ck,
|
||||||
peer.ss.as_bytes() // precomputed
|
peer.ss.as_bytes() // precomputed static-static
|
||||||
);
|
);
|
||||||
|
|
||||||
// msg.timestamp := Aead(k, 0, Timestamp(), H)
|
// msg.timestamp := Aead(k, 0, Timestamp(), H)
|
||||||
|
|
||||||
SEAL!(
|
SEAL!(
|
||||||
&key,
|
&key,
|
||||||
&hs, // ad
|
&hs, // ad
|
||||||
×tamp::new(), // pt
|
×tamp::now(), // pt
|
||||||
&mut msg.f_timestamp, // ct
|
&mut msg.f_timestamp, // ct
|
||||||
&mut msg.f_timestamp_tag // tag
|
&mut msg.f_timestamp_tag // tag
|
||||||
);
|
);
|
||||||
|
|
||||||
// H := Hash(H || msg.timestamp)
|
// H := Hash(H || msg.timestamp)
|
||||||
|
|
||||||
let hs = HASH!(&hs, &msg.f_timestamp, &msg.f_timestamp_tag);
|
let hs = HASH!(&hs, &msg.f_timestamp, &msg.f_timestamp_tag);
|
||||||
|
|
||||||
// mutate state of peer
|
// update state of peer
|
||||||
|
|
||||||
let mut st = peer.state.lock().unwrap();
|
peer.set_state(
|
||||||
*st = State::InitiationSent{
|
State::InitiationSent{
|
||||||
hs : hs,
|
hs : hs,
|
||||||
ck : ck
|
ck : ck
|
||||||
};
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// return message as vector
|
// return message as vector
|
||||||
|
|
||||||
Ok(messages::Initiation::into(msg))
|
Ok(messages::Initiation::into(msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_initiation(peer : &Peer) -> Result<Output, ()> {
|
pub fn process_initiation(device : &Device, peer : &Peer) -> Result<Output, ()> {
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
|
|||||||
99
src/peer.rs
Normal file
99
src/peer.rs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
use generic_array::typenum::U32;
|
||||||
|
use generic_array::GenericArray;
|
||||||
|
|
||||||
|
use x25519_dalek::PublicKey;
|
||||||
|
use x25519_dalek::SharedSecret;
|
||||||
|
|
||||||
|
use crate::types::*;
|
||||||
|
use crate::timestamp;
|
||||||
|
|
||||||
|
pub struct Peer {
|
||||||
|
// mutable state
|
||||||
|
state : Mutex<State>,
|
||||||
|
timestamp : Mutex<Option<timestamp::TAI64N>>,
|
||||||
|
|
||||||
|
// constant state
|
||||||
|
pub pk : PublicKey, // public key of peer
|
||||||
|
pub ss : SharedSecret, // precomputed DH(static, static)
|
||||||
|
pub psk : Psk // psk of peer
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub enum State {
|
||||||
|
Reset,
|
||||||
|
InitiationSent{
|
||||||
|
hs : GenericArray<u8, U32>,
|
||||||
|
ck : GenericArray<u8, U32>
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Peer {
|
||||||
|
pub fn new(
|
||||||
|
pk : PublicKey, // public key of peer
|
||||||
|
ss : SharedSecret // precomputed DH(static, static)
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
state : Mutex::new(State::Reset),
|
||||||
|
timestamp : Mutex::new(None),
|
||||||
|
pk : pk,
|
||||||
|
ss : ss,
|
||||||
|
psk : [0u8; 32]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the state of the peer
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
pub fn get_state(&self) -> State {
|
||||||
|
*self.state.lock().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the state of the peer unconditionally
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
pub fn set_state(
|
||||||
|
&self,
|
||||||
|
state_new : State
|
||||||
|
) {
|
||||||
|
let mut state = self.state.lock().unwrap();
|
||||||
|
*state = state_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the mutable state of the peer conditioned on the timestamp being newer
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * st_new - The updated state of the peer
|
||||||
|
/// * ts_new - The associated timestamp
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A Boolean indicating if the state was updated
|
||||||
|
pub fn set_state_timestamp(
|
||||||
|
&self,
|
||||||
|
state_new : State,
|
||||||
|
timestamp_new : ×tamp::TAI64N
|
||||||
|
) -> bool {
|
||||||
|
let mut state = self.state.lock().unwrap();
|
||||||
|
let mut timestamp = self.timestamp.lock().unwrap();
|
||||||
|
match *timestamp {
|
||||||
|
None => {
|
||||||
|
// no prior timestamp know
|
||||||
|
*state = state_new;
|
||||||
|
*timestamp = Some(*timestamp_new);
|
||||||
|
true
|
||||||
|
},
|
||||||
|
Some(timestamp_old) => if timestamp::compare(×tamp_old, ×tamp_new) {
|
||||||
|
// new timestamp is strictly greater
|
||||||
|
*state = state_new;
|
||||||
|
*timestamp = Some(*timestamp_new);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,14 @@
|
|||||||
pub type TAI64N = [u8; 12];
|
pub type TAI64N = [u8; 12];
|
||||||
|
|
||||||
pub fn new() -> TAI64N {
|
pub fn now() -> TAI64N {
|
||||||
[0u8; 12] // TODO
|
[0u8; 12] // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compare(old : &TAI64N, new : &TAI64N) -> bool {
|
||||||
|
for i in 0..12 {
|
||||||
|
if new[i] > old[i] {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
23
src/types.rs
23
src/types.rs
@@ -1,13 +1,9 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Mutex;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use x25519_dalek::PublicKey;
|
use x25519_dalek::PublicKey;
|
||||||
use x25519_dalek::SharedSecret;
|
use x25519_dalek::SharedSecret;
|
||||||
|
|
||||||
use generic_array::typenum::U32;
|
|
||||||
use generic_array::GenericArray;
|
|
||||||
|
|
||||||
use crate::timestamp;
|
use crate::timestamp;
|
||||||
|
|
||||||
// config error
|
// config error
|
||||||
@@ -86,22 +82,3 @@ pub struct Output (
|
|||||||
|
|
||||||
pub type Psk = [u8; 32];
|
pub type Psk = [u8; 32];
|
||||||
|
|
||||||
pub struct Peer {
|
|
||||||
// mutable state
|
|
||||||
pub state : Mutex<State>,
|
|
||||||
|
|
||||||
// constant state
|
|
||||||
pub pk : PublicKey, // public key of peer
|
|
||||||
pub ss : SharedSecret, // precomputed DH(static, static)
|
|
||||||
pub psk : Psk // psk of peer
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum State {
|
|
||||||
Reset{
|
|
||||||
ts : Option<timestamp::TAI64N>
|
|
||||||
},
|
|
||||||
InitiationSent{
|
|
||||||
hs : GenericArray<u8, U32>,
|
|
||||||
ck : GenericArray<u8, U32>
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user