summaryrefslogtreecommitdiffstats
path: root/src/noise/noise.rs
diff options
context:
space:
mode:
authorMathias Hall-Andersen <mathias@hall-andersen.dk>2019-07-30 15:28:11 +0200
committerMathias Hall-Andersen <mathias@hall-andersen.dk>2019-07-30 15:28:11 +0200
commit1cfd5aea1aba4b01905414351df13e8f5d4dfb1c (patch)
tree1ddc2d7a08a486676e9cf045f31a1fe0d5714bc5 /src/noise/noise.rs
parentBegin work on MAC field processing (diff)
downloadwireguard-rs-1cfd5aea1aba4b01905414351df13e8f5d4dfb1c.tar.xz
wireguard-rs-1cfd5aea1aba4b01905414351df13e8f5d4dfb1c.zip
Move to nested handshake message structure
Having the nested structure: Handshake Message: Noise part (zerocopy message) MAC footer part (zerocopy message) Greatly simplifies processing the MAC fields, since the MAC footer covers the noise part, which can be accessed as bytes using AsBytes.
Diffstat (limited to 'src/noise/noise.rs')
-rw-r--r--src/noise/noise.rs458
1 files changed, 0 insertions, 458 deletions
diff --git a/src/noise/noise.rs b/src/noise/noise.rs
deleted file mode 100644
index 980f1db..0000000
--- a/src/noise/noise.rs
+++ /dev/null
@@ -1,458 +0,0 @@
-// DH
-use x25519_dalek::PublicKey;
-use x25519_dalek::StaticSecret;
-
-// HASH & MAC
-use blake2::Blake2s;
-use hmac::Hmac;
-
-// AEAD
-use crypto::aead::{AeadDecryptor, AeadEncryptor};
-use crypto::chacha20poly1305::ChaCha20Poly1305;
-
-use rand::rngs::OsRng;
-
-use generic_array::typenum::*;
-use generic_array::GenericArray;
-
-use zerocopy::AsBytes;
-
-use super::device::Device;
-use super::messages::{Initiation, Response};
-use super::peer::{Peer, State};
-use super::timestamp;
-use super::types::*;
-
-use crate::types::{Key, KeyPair};
-
-// HMAC hasher (generic construction)
-
-type HMACBlake2s = Hmac<Blake2s>;
-
-// convenient alias to pass state temporarily into device.rs and back
-
-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;
-
-// 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,
-];
-
-// 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 ZERO_NONCE: [u8; SIZE_NONCE] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
-
-macro_rules! HASH {
- ( $($input:expr),* ) => {{
- use blake2::Digest;
- let mut hsh = Blake2s::new();
- $(
- hsh.input($input);
- )*
- hsh.result()
- }};
-}
-
-macro_rules! HMAC {
- ($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
- }};
-}
-
-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)
- }};
-}
-
-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)
- }};
-}
-
-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);
- }};
-}
-
-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(())
- }
- }};
-}
-
-#[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";
-
- #[test]
- fn precomputed_chain_key() {
- assert_eq!(INITIAL_CK[..], HASH!(CONSTRUCTION)[..]);
- }
-
- #[test]
- fn precomputed_hash() {
- assert_eq!(INITIAL_HS[..], HASH!(INITIAL_CK, IDENTIFIER)[..]);
- }
-}
-
-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();
-
- // initialize state
-
- let ck = INITIAL_CK;
- let hs = INITIAL_HS;
- let hs = HASH!(&hs, peer.pk.as_bytes());
-
- msg.f_sender.set(sender);
-
- // (E_priv, E_pub) := DH-Generate()
-
- let eph_sk = StaticSecret::new(&mut rng);
- let eph_pk = PublicKey::from(&eph_sk);
-
- // C := Kdf(C, E_pub)
-
- let ck = KDF1!(&ck, eph_pk.as_bytes());
-
- // msg.ephemeral := E_pub
-
- msg.f_ephemeral = *eph_pk.as_bytes();
-
- // H := HASH(H, msg.ephemeral)
-
- let hs = HASH!(&hs, msg.f_ephemeral);
-
- // (C, k) := Kdf2(C, DH(E_priv, S_pub))
-
- let (ck, key) = KDF2!(&ck, eph_sk.diffie_hellman(&peer.pk).as_bytes());
-
- // msg.static := Aead(k, 0, S_pub, H)
-
- SEAL!(
- &key,
- &hs, // ad
- device.pk.as_bytes(), // pt
- &mut msg.f_static, // ct
- &mut msg.f_static_tag // tag
- );
-
- // H := Hash(H || msg.static)
-
- let hs = HASH!(&hs, &msg.f_static, &msg.f_static_tag);
-
- // (C, k) := Kdf2(C, DH(S_priv, S_pub))
-
- let (ck, key) = KDF2!(&ck, peer.ss.as_bytes());
-
- // msg.timestamp := Aead(k, 0, Timestamp(), H)
-
- SEAL!(
- &key,
- &hs, // ad
- &timestamp::now(), // pt
- &mut msg.f_timestamp, // ct
- &mut msg.f_timestamp_tag // tag
- );
-
- // H := Hash(H || msg.timestamp)
-
- let hs = HASH!(&hs, &msg.f_timestamp, &msg.f_timestamp_tag);
-
- // update state of peer
-
- peer.set_state(State::InitiationSent {
- hs,
- ck,
- eph_sk,
- sender,
- });
-
- // return message as vector
-
- Ok(msg.as_bytes().to_vec())
-}
-
-pub fn consume_initiation<'a, T: Copy>(
- device: &'a Device<T>,
- msg: &[u8],
-) -> Result<(&'a Peer<T>, TemporaryState), HandshakeError> {
- // parse message
-
- let msg = Initiation::parse(msg)?;
-
- // initialize state
-
- let ck = INITIAL_CK;
- let hs = INITIAL_HS;
- let hs = HASH!(&hs, device.pk.as_bytes());
-
- // C := Kdf(C, E_pub)
-
- let ck = KDF1!(&ck, &msg.f_ephemeral);
-
- // H := HASH(H, msg.ephemeral)
-
- let hs = HASH!(&hs, &msg.f_ephemeral);
-
- // (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());
-
- // msg.static := Aead(k, 0, S_pub, H)
-
- let mut pk = [0u8; 32];
-
- OPEN!(
- &key,
- &hs, // ad
- &mut pk, // pt
- &msg.f_static, // ct
- &msg.f_static_tag // tag
- )?;
-
- let peer = device.lookup_pk(&PublicKey::from(pk))?;
-
- // H := Hash(H || msg.static)
-
- let hs = HASH!(&hs, &msg.f_static, &msg.f_static_tag);
-
- // (C, k) := Kdf2(C, DH(S_priv, S_pub))
-
- let (ck, key) = KDF2!(&ck, peer.ss.as_bytes());
-
- // msg.timestamp := Aead(k, 0, Timestamp(), H)
-
- let mut ts = timestamp::zero();
-
- OPEN!(
- &key,
- &hs, // ad
- &mut ts, // pt
- &msg.f_timestamp, // ct
- &msg.f_timestamp_tag // tag
- )?;
-
- // check and update timestamp
-
- peer.check_timestamp(device, &ts)?;
-
- // H := Hash(H || msg.timestamp)
-
- let hs = HASH!(&hs, &msg.f_timestamp, &msg.f_timestamp_tag);
-
- // return state (to create response)
-
- Ok((peer, (msg.f_sender.get(), eph_r_pk, hs, ck)))
-}
-
-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 (receiver, eph_r_pk, hs, ck) = state;
-
- msg.f_sender.set(sender);
- msg.f_receiver.set(receiver);
-
- // (E_priv, E_pub) := DH-Generate()
-
- let eph_sk = StaticSecret::new(&mut rng);
- let eph_pk = PublicKey::from(&eph_sk);
-
- // C := Kdf1(C, E_pub)
-
- let ck = KDF1!(&ck, eph_pk.as_bytes());
-
- // msg.ephemeral := E_pub
-
- msg.f_ephemeral = *eph_pk.as_bytes();
-
- // H := Hash(H || msg.ephemeral)
-
- let hs = HASH!(&hs, &msg.f_ephemeral);
-
- // C := Kdf1(C, DH(E_priv, E_pub))
-
- let ck = KDF1!(&ck, eph_sk.diffie_hellman(&eph_r_pk).as_bytes());
-
- // C := Kdf1(C, DH(E_priv, S_pub))
-
- let ck = KDF1!(&ck, eph_sk.diffie_hellman(&peer.pk).as_bytes());
-
- // (C, tau, k) := Kdf3(C, Q)
-
- let (ck, tau, key) = KDF3!(&ck, &peer.psk);
-
- // H := Hash(H || tau)
-
- let hs = HASH!(&hs, tau);
-
- // msg.empty := Aead(k, 0, [], H)
-
- SEAL!(
- &key,
- &hs, // ad
- &[], // pt
- &mut [], // ct
- &mut msg.f_empty_tag // tag
- );
-
- /* not strictly needed
- * // H := Hash(H || msg.empty)
- * let hs = HASH!(&hs, &msg.f_empty_tag);
- */
-
- // derive key-pair
- // (verbose code, due to GenericArray -> [u8; 32] conversion)
-
- let (key_recv, key_send) = KDF2!(&ck, &[]);
-
- // return response and unconfirmed key-pair
-
- Ok((
- peer.identifier,
- Some(msg.as_bytes().to_vec()),
- Some(KeyPair {
- confirmed: false,
- send: Key {
- id: sender,
- key: key_send.into(),
- },
- recv: Key {
- id: receiver,
- key: key_recv.into(),
- },
- }),
- ))
-}
-
-pub fn consume_response<T: Copy>(
- device: &Device<T>,
- msg: &[u8],
-) -> Result<Output<T>, HandshakeError> {
- // parse message
-
- let msg = Response::parse(msg)?;
-
- // retrieve peer and associated state
-
- let peer = device.lookup_id(msg.f_receiver.get())?;
- 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)),
- }?;
-
- // C := Kdf1(C, E_pub)
-
- let ck = KDF1!(&ck, &msg.f_ephemeral);
-
- // H := Hash(H || msg.ephemeral)
-
- let hs = HASH!(&hs, &msg.f_ephemeral);
-
- // C := Kdf1(C, DH(E_priv, E_pub))
-
- let eph_r_pk = PublicKey::from(msg.f_ephemeral);
- let ck = KDF1!(&ck, eph_sk.diffie_hellman(&eph_r_pk).as_bytes());
-
- // C := Kdf1(C, DH(E_priv, S_pub))
-
- let ck = KDF1!(&ck, device.sk.diffie_hellman(&eph_r_pk).as_bytes());
-
- // (C, tau, k) := Kdf3(C, Q)
-
- let (ck, tau, key) = KDF3!(&ck, &peer.psk);
-
- // H := Hash(H || tau)
-
- let hs = HASH!(&hs, tau);
-
- // msg.empty := Aead(k, 0, [], H)
-
- OPEN!(
- &key,
- &hs, // ad
- &mut [], // pt
- &[], // ct
- &msg.f_empty_tag // tag
- )?;
-
- // derive key-pair
-
- let (key_send, key_recv) = KDF2!(&ck, &[]);
-
- // return confirmed key-pair
-
- Ok((
- peer.identifier,
- None,
- Some(KeyPair {
- confirmed: true,
- send: Key {
- id: sender,
- key: key_send.into(),
- },
- recv: Key {
- id: msg.f_sender.get(),
- key: key_recv.into(),
- },
- }),
- ))
-}