noise-protocol-0.1.4/.cargo_vcs_info.json0000644000000001540000000000100140120ustar { "git": { "sha1": "66538c336f56f4a0917b8de1fd4b258ef70002d5" }, "path_in_vcs": "noise-protocol" }noise-protocol-0.1.4/Cargo.toml0000644000000016540000000000100120160ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "noise-protocol" version = "0.1.4" authors = [ "trevp", "Guanhao Yin ", ] description = "Noise Protocol Framework implementation." readme = "README.md" keywords = ["noise"] categories = ["cryptography"] license = "Unlicense" repository = "https://github.com/sopium/noise-rust" [dependencies.arrayvec] version = "0.7.2" default-features = false [features] default = ["use_std"] use_alloc = [] use_std = [] noise-protocol-0.1.4/Cargo.toml.orig000064400000000000000000000007251046102023000154750ustar 00000000000000[package] edition = "2018" authors = ["trevp", "Guanhao Yin "] license = "Unlicense" name = "noise-protocol" readme = "README.md" repository = "https://github.com/sopium/noise-rust" version = "0.1.4" description = "Noise Protocol Framework implementation." keywords = ["noise"] categories = ["cryptography"] [dependencies] arrayvec = { version = "0.7.2", default-features = false } [features] default = ["use_std"] use_std = [] use_alloc = [] noise-protocol-0.1.4/README.md000064400000000000000000000037201046102023000140630ustar 00000000000000# Noise-Rust [![Crates.io](https://img.shields.io/crates/v/noise-protocol.svg)](https://crates.io/crates/noise-protocol) [![Docs.rs](https://docs.rs/noise-protocol/badge.svg)](https://docs.rs/noise-protocol) [![Build Status](https://travis-ci.org/sopium/noise-rust.svg?branch=master)](https://travis-ci.org/sopium/noise-rust) Implementation of the [Noise Protocol Framework](http://noiseprotocol.org) in Rust. ## Status Revision 34 is implemented. Test vectors from [cacophony](https://github.com/centromere/cacophony) and [snow](https://github.com/mcginty/snow) are successfully verified. ## Philosophy * Simple: straightforward implementation, small amount of code, almost no dependencies, supports `no_std`. Feature `use_alloc` can optionallly be used as an alternative to std. * Fast: static dispatch, no heap allocation necessary. * Unopinionated: flexible, primitive API, does not dictate how it should be used. ## Documentation * [noise-protocol](https://docs.rs/noise-protocol) * [noise-rust-crypto](https://docs.rs/noise-rust-crypto) ## Crates This repository contains several crates. The `noise-protocol` crate contains the abstract implementation of the protocol framework. `noise-rust-crypto` provides concrete implementations of the needed crypto primitives. It is a wrapper for `x25519-dalek` and [RustCrypto](`https://github.com/RustCrypto`) crates. The following table shows what primitives each of these crates supports: | | X25519 | AES-256-GCM | Chacha20-Poly1305 | SHA-256 | SHA-512 | BLAKE2s | BLAKE2b | |-------------|:------:|:-----------:|:-----------------:|:-------:|:-------:|:-------:|:-------:| | rust-crypto | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | You can also plug in other primitive implementations by implementing the `DH`, `Cipher` and `Hash` traits. ## `no_std` usage The `noise-protocol` crate supports `no_std`, if default features are disabled. ## License Unlicense. noise-protocol-0.1.4/src/cipherstate.rs000064400000000000000000000060351046102023000162560ustar 00000000000000use crate::traits::{Cipher, U8Array}; #[cfg(feature = "use_alloc")] use alloc::vec::Vec; /// A `CipherState` can encrypt and decrypt data. /// /// Mostly like `CipherState` in the spec, but must be created with a key. /// /// # Panics /// /// Encryption and decryption methods will panic if nonce reaches maximum u64, i.e., 2 ^ 64 - 1. pub struct CipherState { key: C::Key, n: u64, } impl Clone for CipherState where C: Cipher, { fn clone(&self) -> Self { Self { key: self.key.clone(), n: self.n, } } } impl CipherState where C: Cipher, { /// Name of cipher, e.g. “ChaChaPoly”. pub fn name() -> &'static str { C::name() } /// Create a new `CipherState` with a `key` and a nonce `n`. pub fn new(key: &[u8], n: u64) -> Self { CipherState { key: C::Key::from_slice(key), n, } } /// Rekey. Set our key to `REKEY(old key)`. pub fn rekey(&mut self) { self.key = C::rekey(&self.key); } /// AEAD encryption. pub fn encrypt_ad(&mut self, authtext: &[u8], plaintext: &[u8], out: &mut [u8]) { C::encrypt(&self.key, self.n, authtext, plaintext, out); // This will fail when n == 2 ^ 64 - 1, complying to the spec. self.n = self.n.checked_add(1).unwrap(); } /// AEAD decryption. pub fn decrypt_ad( &mut self, authtext: &[u8], ciphertext: &[u8], out: &mut [u8], ) -> Result<(), ()> { C::decrypt(&self.key, self.n, authtext, ciphertext, out)?; self.n = self.n.checked_add(1).unwrap(); Ok(()) } /// Encryption. pub fn encrypt(&mut self, plaintext: &[u8], out: &mut [u8]) { self.encrypt_ad(&[0u8; 0], plaintext, out) } /// Encryption, returns ciphertext as `Vec`. #[cfg(any(feature = "use_std", feature = "use_alloc"))] pub fn encrypt_vec(&mut self, plaintext: &[u8]) -> Vec { let mut out = vec![0u8; plaintext.len() + 16]; self.encrypt(plaintext, &mut out); out } /// Decryption. pub fn decrypt(&mut self, ciphertext: &[u8], out: &mut [u8]) -> Result<(), ()> { self.decrypt_ad(&[0u8; 0], ciphertext, out) } /// Decryption, returns plaintext as `Vec`. #[cfg(any(feature = "use_std", feature = "use_alloc"))] pub fn decrypt_vec(&mut self, ciphertext: &[u8]) -> Result, ()> { if ciphertext.len() < 16 { return Err(()); } let mut out = vec![0u8; ciphertext.len() - 16]; self.decrypt(ciphertext, &mut out)?; Ok(out) } /// Get the next value of `n`. Could be used to decide on whether to re-key, etc. pub fn get_next_n(&self) -> u64 { self.n } /// Get underlying cipher and nonce. /// /// This is useful for e.g. WireGuard. Because packets may be lost or arrive out of order, /// they would likely want to deal with nonces themselves. pub fn extract(self) -> (C::Key, u64) { (self.key, self.n) } } noise-protocol-0.1.4/src/handshakepattern.rs000064400000000000000000000256251046102023000172750ustar 00000000000000//! Handshake patterns. use arrayvec::ArrayVec; /// A token in noise message patterns. #[allow(missing_docs)] #[derive(Copy, Clone)] pub enum Token { E, S, EE, ES, SE, SS, PSK, } use self::Token::*; /// Noise handshake pattern. #[derive(Clone)] pub struct HandshakePattern { pre_i: ArrayVec, pre_r: ArrayVec, msg_patterns: ArrayVec, 8>, name: &'static str, } impl HandshakePattern { /// Construct a new HandshakePattern from pre-message patterns, message patterns and name. /// /// # Pattern validity /// /// It is the caller's responlity to ensure that the pattern is *valid*. /// /// # Panics /// /// If any of the patterns are too long (longer than 8 tokens). /// /// Or if the number of patterns are too large (larger than 8). pub fn new( pre_i: &[Token], pre_r: &[Token], msg_patterns: &[&[Token]], name: &'static str, ) -> Self { HandshakePattern { pre_i: pre_i.iter().cloned().collect(), pre_r: pre_r.iter().cloned().collect(), msg_patterns: msg_patterns .iter() .map(|p| p.iter().cloned().collect()) .collect(), name, } } /// Get initiator pre-messages. pub fn get_pre_i(&self) -> &[Token] { &self.pre_i } /// Get responder pre-messages. pub fn get_pre_r(&self) -> &[Token] { &self.pre_r } /// Get message patterns. pub fn get_message_pattern(&self, i: usize) -> &[Token] { &self.msg_patterns[i] } /// Get number of message patterns. pub fn get_message_patterns_len(&self) -> usize { self.msg_patterns.len() } /// Get pattern name. pub fn get_name(&self) -> &'static str { self.name } /// Whether there are any psk tokens in this pattern. pub fn has_psk(&self) -> bool { self.msg_patterns.iter().any(|m| { m.iter().any(|m| match m { Token::PSK => true, _ => false, }) }) } /// Whether the pattern is a one-way pattern. pub fn is_one_way(&self) -> bool { self.msg_patterns.len() == 1 } fn with_psks(&self, poses: &[usize], new_name: &'static str) -> HandshakePattern { let mut new_msg_patterns = self.msg_patterns.clone(); for pos in poses { if *pos == 0usize { new_msg_patterns[0].insert(0, PSK); } else { new_msg_patterns[pos - 1].push(PSK); } } HandshakePattern { pre_i: self.pre_i.clone(), pre_r: self.pre_r.clone(), msg_patterns: new_msg_patterns, name: new_name, } } } macro_rules! vec { () => { ArrayVec::new() }; ( $( $x:expr ),* ) => { { let mut temp_vec = ArrayVec::new(); $( temp_vec.push($x); )* temp_vec } }; } /// The `Noise_N` pattern. pub fn noise_n() -> HandshakePattern { HandshakePattern { pre_i: vec![], pre_r: vec![S], msg_patterns: vec![vec![E, ES]], name: "N", } } /// The `Noise_K` pattern. pub fn noise_k() -> HandshakePattern { HandshakePattern { pre_i: vec![S], pre_r: vec![S], msg_patterns: vec![vec![E, ES, SS]], name: "K", } } /// The `Noise_X` pattern. pub fn noise_x() -> HandshakePattern { HandshakePattern { pre_i: vec![], pre_r: vec![S], msg_patterns: vec![vec![E, ES, S, SS]], name: "X", } } /// The `Noise_NN` pattern. pub fn noise_nn() -> HandshakePattern { HandshakePattern { pre_i: vec![], pre_r: vec![], msg_patterns: vec![vec![E], vec![E, EE]], name: "NN", } } /// The `Noise_NK` pattern. pub fn noise_nk() -> HandshakePattern { HandshakePattern { pre_i: vec![], pre_r: vec![S], msg_patterns: vec![vec![E, ES], vec![E, EE]], name: "NK", } } /// The `Noise_NX` pattern. pub fn noise_nx() -> HandshakePattern { HandshakePattern { pre_i: vec![], pre_r: vec![], msg_patterns: vec![vec![E], vec![E, EE, S, ES]], name: "NX", } } /// The `Noise_XN` pattern. pub fn noise_xn() -> HandshakePattern { HandshakePattern { pre_i: vec![], pre_r: vec![], msg_patterns: vec![vec![E], vec![E, EE], vec![S, SE]], name: "XN", } } /// The `Noise_XK` pattern. pub fn noise_xk() -> HandshakePattern { HandshakePattern { pre_i: vec![], pre_r: vec![S], msg_patterns: vec![vec![E, ES], vec![E, EE], vec![S, SE]], name: "XK", } } /// The `Noise_XX` pattern. pub fn noise_xx() -> HandshakePattern { HandshakePattern { pre_i: vec![], pre_r: vec![], msg_patterns: vec![vec![E], vec![E, EE, S, ES], vec![S, SE]], name: "XX", } } /// The `Noise_KN` pattern. pub fn noise_kn() -> HandshakePattern { HandshakePattern { pre_i: vec![S], pre_r: vec![], msg_patterns: vec![vec![E], vec![E, EE, SE]], name: "KN", } } /// The `Noise_KK` pattern. pub fn noise_kk() -> HandshakePattern { HandshakePattern { pre_i: vec![S], pre_r: vec![S], msg_patterns: vec![vec![E, ES, SS], vec![E, EE, SE]], name: "KK", } } /// The `Noise_KX` pattern. pub fn noise_kx() -> HandshakePattern { HandshakePattern { pre_i: vec![S], pre_r: vec![], msg_patterns: vec![vec![E], vec![E, EE, SE, S, ES]], name: "KX", } } /// The `Noise_IN` pattern. pub fn noise_in() -> HandshakePattern { HandshakePattern { pre_i: vec![], pre_r: vec![], msg_patterns: vec![vec![E, S], vec![E, EE, SE]], name: "IN", } } /// The `Noise_IK` pattern. pub fn noise_ik() -> HandshakePattern { HandshakePattern { pre_i: vec![], pre_r: vec![S], msg_patterns: vec![vec![E, ES, S, SS], vec![E, EE, SE]], name: "IK", } } /// The `Noise_IX` pattern. pub fn noise_ix() -> HandshakePattern { HandshakePattern { pre_i: vec![], pre_r: vec![], msg_patterns: vec![vec![E, S], vec![E, EE, SE, S, ES]], name: "IX", } } /// The `Noise_XXfallback` pattern. /// /// Something that is used in noise pipes. pub fn noise_xx_fallback() -> HandshakePattern { HandshakePattern { pre_i: vec![], pre_r: vec![E], msg_patterns: vec![vec![E, EE, S, SE], vec![S, ES]], name: "XXfallback", } } // PSK Patterns. /// The `Noise_Npsk0` pattern. pub fn noise_n_psk0() -> HandshakePattern { noise_n().with_psks(&[0], "Npsk0") } /// The `Noise_Kpsk0` pattern. pub fn noise_k_psk0() -> HandshakePattern { noise_k().with_psks(&[0], "Kpsk0") } /// The `Noise_Xpsk1` pattern. pub fn noise_x_psk1() -> HandshakePattern { noise_x().with_psks(&[1], "Xpsk1") } /// The `Noise_NNpsk0` pattern. pub fn noise_nn_psk0() -> HandshakePattern { noise_nn().with_psks(&[0], "NNpsk0") } /// The `Noise_NNpsk2` pattern. pub fn noise_nn_psk2() -> HandshakePattern { noise_nn().with_psks(&[2], "NNpsk2") } /// The `Noise_NKpsk0` pattern. pub fn noise_nk_psk0() -> HandshakePattern { noise_nk().with_psks(&[0], "NKpsk0") } /// The `Noise_NKpsk2` pattern. pub fn noise_nk_psk2() -> HandshakePattern { noise_nk().with_psks(&[2], "NKpsk2") } /// The `Noise_NXpsk2` pattern. pub fn noise_nx_psk2() -> HandshakePattern { noise_nx().with_psks(&[2], "NXpsk2") } /// The `Noise_XNpsk3` pattern. pub fn noise_xn_psk3() -> HandshakePattern { noise_xn().with_psks(&[3], "XNpsk3") } /// The `Noise_XKpsk3` pattern. pub fn noise_xk_psk3() -> HandshakePattern { noise_xk().with_psks(&[3], "XKpsk3") } /// The `Noise_XXpsk3` pattern. pub fn noise_xx_psk3() -> HandshakePattern { noise_xx().with_psks(&[3], "XXpsk3") } /// The `Noise_KNpsk0` pattern. pub fn noise_kn_psk0() -> HandshakePattern { noise_kn().with_psks(&[0], "KNpsk0") } /// The `Noise_KNpsk2` pattern. pub fn noise_kn_psk2() -> HandshakePattern { noise_kn().with_psks(&[2], "KNpsk2") } /// The `Noise_KKpsk0` pattern. pub fn noise_kk_psk0() -> HandshakePattern { noise_kk().with_psks(&[0], "KKpsk0") } /// The `Noise_KKpsk2` pattern. pub fn noise_kk_psk2() -> HandshakePattern { noise_kk().with_psks(&[2], "KKpsk2") } /// The `Noise_KXpsk2` pattern. pub fn noise_kx_psk2() -> HandshakePattern { noise_kx().with_psks(&[2], "KXpsk2") } /// The `Noise_INpsk1` pattern. pub fn noise_in_psk1() -> HandshakePattern { noise_in().with_psks(&[1], "INpsk1") } /// The `Noise_INpsk2` pattern. pub fn noise_in_psk2() -> HandshakePattern { noise_in().with_psks(&[2], "INpsk2") } /// The `Noise_IKpsk1` pattern. pub fn noise_ik_psk1() -> HandshakePattern { noise_ik().with_psks(&[1], "IKpsk1") } /// The `Noise_IKpsk2` pattern. pub fn noise_ik_psk2() -> HandshakePattern { noise_ik().with_psks(&[2], "IKpsk2") } /// The `Noise_IXpsk2` pattern. pub fn noise_ix_psk2() -> HandshakePattern { noise_ix().with_psks(&[2], "IXpsk2") } /// The `Noise_NNpsk0+psk2` pattern. pub fn noise_nn_psk0_psk2() -> HandshakePattern { noise_nn().with_psks(&[0, 2], "NNpsk0+psk2") } /// The `Noise_NXpsk0+psk1+psk2` pattern. pub fn noise_nx_psk0_psk1_psk2() -> HandshakePattern { noise_nx().with_psks(&[0, 1, 2], "NXpsk0+psk1+psk2") } /// The `Noise_XNpsk1+psk3` pattern. pub fn noise_xn_psk1_psk3() -> HandshakePattern { noise_xn().with_psks(&[1, 3], "XNpsk1+psk3") } /// The `Noise_XKpsk0+psk3` pattern. pub fn noise_xk_psk0_psk3() -> HandshakePattern { noise_xk().with_psks(&[0, 3], "XKpsk0+psk3") } /// The `Noise_KNpsk1+psk2` pattern. pub fn noise_kn_psk1_psk2() -> HandshakePattern { noise_kn().with_psks(&[1, 2], "KNpsk1+psk2") } /// The `Noise_KKpsk0+psk2` pattern pub fn noise_kk_psk0_psk2() -> HandshakePattern { noise_kk().with_psks(&[0, 2], "KKpsk0+psk2") } /// The `Noise_INpsk1+psk2` pattern. pub fn noise_in_psk1_psk2() -> HandshakePattern { noise_in().with_psks(&[1, 2], "INpsk1+psk2") } /// The `Noise_IKpsk0+psk2` pattern. pub fn noise_ik_psk0_psk2() -> HandshakePattern { noise_ik().with_psks(&[0, 2], "IKpsk0+psk2") } /// The `Noise_IXpsk0+psk2` pattern. pub fn noise_ix_psk0_psk2() -> HandshakePattern { noise_ix().with_psks(&[0, 2], "IXpsk0+psk2") } /// The `Noise_XXpsk0+psk1` pattern. pub fn noise_xx_psk0_psk1() -> HandshakePattern { noise_xx().with_psks(&[0, 1], "XXpsk0+psk1") } /// The `Noise_XXpsk0+psk2` pattern. pub fn noise_xx_psk0_psk2() -> HandshakePattern { noise_xx().with_psks(&[0, 2], "XXpsk0+psk2") } /// The `Noise_XXpsk0+psk3` pattern. pub fn noise_xx_psk0_psk3() -> HandshakePattern { noise_xx().with_psks(&[0, 3], "XXpsk0+psk3") } /// The `Noise_XXpsk0+psk1+psk2+psk3` pattern. pub fn noise_xx_psk0_psk1_psk2_psk3() -> HandshakePattern { noise_xx().with_psks(&[0, 1, 2, 3], "XXpsk0+psk1+psk2+psk3") } noise-protocol-0.1.4/src/handshakestate.rs000064400000000000000000000456571046102023000167470ustar 00000000000000use crate::cipherstate::CipherState; use crate::handshakepattern::{HandshakePattern, Token}; use crate::symmetricstate::SymmetricState; use crate::traits::{Cipher, Hash, U8Array, DH}; use arrayvec::{ArrayString, ArrayVec}; use core::fmt::{Display, Error as FmtError, Formatter, Write}; #[cfg(feature = "use_alloc")] use alloc::vec::Vec; /// Noise handshake state. pub struct HandshakeState { symmetric: SymmetricState, s: Option, e: Option, rs: Option, re: Option, is_initiator: bool, pattern: HandshakePattern, message_index: usize, pattern_has_psk: bool, psks: ArrayVec<[u8; 32], 4>, } impl Clone for HandshakeState where D: DH, C: Cipher, H: Hash, { fn clone(&self) -> Self { Self { symmetric: self.symmetric.clone(), s: self.s.as_ref().map(U8Array::clone), e: self.e.as_ref().map(U8Array::clone), rs: self.rs.as_ref().map(U8Array::clone), re: self.re.as_ref().map(U8Array::clone), is_initiator: self.is_initiator, pattern: self.pattern.clone(), message_index: self.message_index, pattern_has_psk: self.pattern_has_psk, psks: self.psks.clone(), } } } impl HandshakeState where D: DH, C: Cipher, H: Hash, { /// Get protocol name, e.g. Noise_IK_25519_ChaChaPoly_BLAKE2s. fn get_name(pattern_name: &str) -> ArrayString<256> { let mut ret = ArrayString::new(); write!( &mut ret, "Noise_{}_{}_{}_{}", pattern_name, D::name(), C::name(), H::name() ) .unwrap(); ret } /// Initialize a handshake state. /// /// If `e` is [`None`], a new ephemeral key will be generated if necessary /// when [`write_message`](HandshakeState::write_message). /// /// # Setting Explicit Ephemeral Key /// /// An explicit `e` should only be specified for testing purposes, or in /// fallback patterns. If you do pass in an explicit `e`, [`HandshakeState`] /// will use it as is and will not generate new ephemeral keys in /// [`write_message`](HandshakeState::write_message). pub fn new

( pattern: HandshakePattern, is_initiator: bool, prologue: P, s: Option, e: Option, rs: Option, re: Option, ) -> Self where P: AsRef<[u8]>, { let mut symmetric = SymmetricState::new(Self::get_name(pattern.get_name()).as_bytes()); let pattern_has_psk = pattern.has_psk(); // Mix in prologue. symmetric.mix_hash(prologue.as_ref()); // Mix in static keys known ahead of time. for t in pattern.get_pre_i() { match *t { Token::S => { if is_initiator { symmetric.mix_hash(D::pubkey(s.as_ref().unwrap()).as_slice()); } else { symmetric.mix_hash(rs.as_ref().unwrap().as_slice()); } } _ => panic!("Unexpected token in pre message"), } } for t in pattern.get_pre_r() { match *t { Token::S => { if is_initiator { symmetric.mix_hash(rs.as_ref().unwrap().as_slice()); } else { symmetric.mix_hash(D::pubkey(s.as_ref().unwrap()).as_slice()); } } Token::E => { if is_initiator { let re = re.as_ref().unwrap().as_slice(); symmetric.mix_hash(re); if pattern_has_psk { symmetric.mix_key(re); } } else { let e = D::pubkey(e.as_ref().unwrap()); symmetric.mix_hash(e.as_slice()); if pattern_has_psk { symmetric.mix_key(e.as_slice()); } } } _ => panic!("Unexpected token in pre message"), } } HandshakeState { symmetric, s, e, rs, re, is_initiator, pattern, message_index: 0, pattern_has_psk, psks: ArrayVec::new(), } } /// Calculate the size overhead of the next message. /// /// # Panics /// /// If these is no more message to read/write, i.e., if the handshake is /// already completed. pub fn get_next_message_overhead(&self) -> usize { let m = self.pattern.get_message_pattern(self.message_index); let mut overhead = 0; let mut has_key = self.symmetric.has_key(); for &t in m { match t { Token::E => { overhead += D::Pubkey::len(); if self.pattern_has_psk { has_key = true; } } Token::S => { overhead += D::Pubkey::len(); if has_key { overhead += 16; } } _ => { has_key = true; } } } if has_key { overhead += 16 } overhead } /// Like [`write_message`](HandshakeState::write_message), but returns a [`Vec`]. #[cfg(any(feature = "use_std", feature = "use_alloc"))] pub fn write_message_vec(&mut self, payload: &[u8]) -> Result, Error> { let mut out = vec![0u8; payload.len() + self.get_next_message_overhead()]; self.write_message(payload, &mut out)?; Ok(out) } /// Takes a payload and write the generated handshake message to /// `out`. /// /// # Error Kinds /// /// - [DH](ErrorKind::DH): DH operation failed. /// - [NeedPSK](ErrorKind::NeedPSK): A PSK token is encountered but none is available. /// /// # Panics /// /// * If a required static key is not set. /// /// * If `out.len() != payload.len() + self.get_next_message_overhead()`. /// /// * If it is not our turn to write. /// /// * If the handshake has already completed. pub fn write_message(&mut self, payload: &[u8], out: &mut [u8]) -> Result<(), Error> { debug_assert_eq!(out.len(), payload.len() + self.get_next_message_overhead()); // Check that it is our turn to send. assert!(self.message_index % 2 == if self.is_initiator { 0 } else { 1 }); // Get the message pattern. let m = self.pattern.get_message_pattern(self.message_index); self.message_index += 1; let mut cur: usize = 0; // Process tokens. for t in m { match *t { Token::E => { if self.e.is_none() { self.e = Some(D::genkey()); } let e_pk = D::pubkey(self.e.as_ref().unwrap()); self.symmetric.mix_hash(e_pk.as_slice()); if self.pattern_has_psk { self.symmetric.mix_key(e_pk.as_slice()); } out[cur..cur + D::Pubkey::len()].copy_from_slice(e_pk.as_slice()); cur += D::Pubkey::len(); } Token::S => { let len = if self.symmetric.has_key() { D::Pubkey::len() + 16 } else { D::Pubkey::len() }; let encrypted_s_out = &mut out[cur..cur + len]; self.symmetric.encrypt_and_hash( D::pubkey(self.s.as_ref().unwrap()).as_slice(), encrypted_s_out, ); cur += len; } Token::PSK => { if let Some(psk) = self.psks.pop_at(0) { self.symmetric.mix_key_and_hash(&psk); } else { return Err(Error::need_psk()); } } t => { let dh_result = self.perform_dh(t).map_err(|_| Error::dh())?; self.symmetric.mix_key(dh_result.as_slice()); } } } self.symmetric.encrypt_and_hash(payload, &mut out[cur..]); Ok(()) } /// Takes a handshake message, process it and update our internal /// state, and write the encapsulated payload to `out`. /// /// # Error Kinds /// /// - [DH](ErrorKind::DH): DH operation failed. /// - [NeedPSK](ErrorKind::NeedPSK): A PSK token is encountered but none is /// available. /// - [Decryption](ErrorKind::Decryption): Decryption failed. /// /// # Error Recovery /// /// If [`read_message`](HandshakeState::read_message) fails, the whole /// [`HandshakeState`] may be in invalid state and should not be used to /// read or write any further messages. (But /// [`get_re()`](HandshakeState::get_re) and /// [`get_rs()`](HandshakeState::get_rs) is allowed.) In case error recovery /// is desirable, [`clone`](Clone::clone) the [`HandshakeState`] before /// calling [`read_message`](HandshakeState::read_message). /// /// # Panics /// /// * If `out.len() + self.get_next_message_overhead() != data.len()`. /// /// (Notes that this implies `data.len() >= overhead`.) /// /// * If a required static key is not set. /// /// * If it is not our turn to read. /// /// * If the handshake has already completed. pub fn read_message(&mut self, data: &[u8], out: &mut [u8]) -> Result<(), Error> { debug_assert_eq!(out.len() + self.get_next_message_overhead(), data.len()); assert!(self.message_index % 2 == if self.is_initiator { 1 } else { 0 }); // Get the message pattern. let m = self.pattern.get_message_pattern(self.message_index); self.message_index += 1; let mut data = data; // Consume the next `n` bytes of data. let mut get = |n| { let ret = &data[..n]; data = &data[n..]; ret }; // Process tokens. for t in m { match *t { Token::E => { let re = D::Pubkey::from_slice(get(D::Pubkey::len())); self.symmetric.mix_hash(re.as_slice()); if self.pattern_has_psk { self.symmetric.mix_key(re.as_slice()); } self.re = Some(re); } Token::S => { let temp = get(if self.symmetric.has_key() { D::Pubkey::len() + 16 } else { D::Pubkey::len() }); let mut rs = D::Pubkey::new(); self.symmetric .decrypt_and_hash(temp, rs.as_mut()) .map_err(|_| Error::decryption())?; self.rs = Some(rs); } Token::PSK => { if let Some(psk) = self.psks.pop_at(0) { self.symmetric.mix_key_and_hash(&psk); } else { return Err(Error::need_psk()); } } t => { let dh_result = self.perform_dh(t).map_err(|_| Error::dh())?; self.symmetric.mix_key(dh_result.as_slice()); } } } self.symmetric .decrypt_and_hash(data, out) .map_err(|_| Error::decryption()) } /// Similar to [`read_message`](HandshakeState::read_message), but returns /// result as a [`Vec`]. /// /// In addition to possible errors from /// [`read_message`](HandshakeState::read_message), /// [TooShort](ErrorKind::TooShort) may be returned. #[cfg(any(feature = "use_std", feature = "use_alloc"))] pub fn read_message_vec(&mut self, data: &[u8]) -> Result, Error> { let overhead = self.get_next_message_overhead(); if data.len() < overhead { Err(Error::too_short()) } else { let mut out = vec![0u8; data.len() - overhead]; self.read_message(data, &mut out)?; Ok(out) } } /// Push a PSK to the PSK-queue. /// /// # Panics /// /// If the PSK-queue becomes longer than 4. pub fn push_psk(&mut self, psk: &[u8]) { self.psks.push(U8Array::from_slice(psk)); } /// Whether handshake has completed. pub fn completed(&self) -> bool { self.message_index == self.pattern.get_message_patterns_len() } /// Get handshake hash. Useful for e.g., channel binding. pub fn get_hash(&self) -> &[u8] { self.symmetric.get_hash() } /// Get ciphers that can be used to encrypt/decrypt further messages. The /// first [`CipherState`] is for initiator to responder, and the second for /// responder to initiator. /// /// Should be called after handshake is /// [`completed`](HandshakeState::completed). pub fn get_ciphers(&self) -> (CipherState, CipherState) { self.symmetric.split() } /// Get remote static pubkey, if available. pub fn get_rs(&self) -> Option { self.rs.as_ref().map(U8Array::clone) } /// Get remote semi-ephemeral pubkey. /// /// Returns [`None`](None) if we do not know. /// /// Useful for noise-pipes. pub fn get_re(&self) -> Option { self.re.as_ref().map(U8Array::clone) } /// Get whether this [`HandshakeState`] is created as initiator. pub fn get_is_initiator(&self) -> bool { self.is_initiator } /// Get handshake pattern this [`HandshakeState`] uses. pub fn get_pattern(&self) -> &HandshakePattern { &self.pattern } fn perform_dh(&self, t: Token) -> Result { let dh = |a: Option<&D::Key>, b: Option<&D::Pubkey>| D::dh(a.unwrap(), b.unwrap()); match t { Token::EE => dh(self.e.as_ref(), self.re.as_ref()), Token::ES => { if self.is_initiator { dh(self.e.as_ref(), self.rs.as_ref()) } else { dh(self.s.as_ref(), self.re.as_ref()) } } Token::SE => { if self.is_initiator { dh(self.s.as_ref(), self.re.as_ref()) } else { dh(self.e.as_ref(), self.rs.as_ref()) } } Token::SS => dh(self.s.as_ref(), self.rs.as_ref()), _ => unreachable!(), } } } /// Handshake error. #[derive(Debug)] pub struct Error { kind: ErrorKind, } /// Handshake error kind. #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum ErrorKind { /// A DH operation has failed. DH, /// A PSK is needed, but none is available. NeedPSK, /// Decryption failed. Decryption, /// The message is too short, and impossible to read. TooShort, } impl Error { fn dh() -> Error { Error { kind: ErrorKind::DH, } } fn need_psk() -> Error { Error { kind: ErrorKind::NeedPSK, } } fn decryption() -> Error { Error { kind: ErrorKind::Decryption, } } fn too_short() -> Error { Error { kind: ErrorKind::TooShort, } } /// Error kind. pub fn kind(&self) -> ErrorKind { self.kind } } impl Display for Error { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), FmtError> { write!(fmt, "{:?}", self) } } #[cfg(feature = "use_std")] impl ::std::error::Error for Error { fn description(&self) -> &'static str { match self.kind { ErrorKind::DH => "DH error", ErrorKind::NeedPSK => "Need PSK", ErrorKind::Decryption => "Decryption failed", ErrorKind::TooShort => "Message is too short", } } } /// Builder for `HandshakeState`. pub struct HandshakeStateBuilder<'a, D: DH> { pattern: Option, is_initiator: Option, prologue: Option<&'a [u8]>, s: Option, e: Option, rs: Option, re: Option, } impl<'a, D: DH> Default for HandshakeStateBuilder<'a, D> { fn default() -> Self { HandshakeStateBuilder::new() } } impl<'a, D> HandshakeStateBuilder<'a, D> where D: DH, { /// Create a new [`HandshakeStateBuilder`]. pub fn new() -> Self { HandshakeStateBuilder { pattern: None, is_initiator: None, prologue: None, s: None, e: None, rs: None, re: None, } } /// Set handshake pattern. pub fn set_pattern(&mut self, p: HandshakePattern) -> &mut Self { self.pattern = Some(p); self } /// Set whether the [`HandshakeState`] is initiator. pub fn set_is_initiator(&mut self, is: bool) -> &mut Self { self.is_initiator = Some(is); self } /// Set prologue. pub fn set_prologue(&mut self, prologue: &'a [u8]) -> &mut Self { self.prologue = Some(prologue); self } /// Set ephemeral key. /// /// This is not encouraged and usually not necessary. Cf. /// [`HandshakeState::new()`]. pub fn set_e(&mut self, e: D::Key) -> &mut Self { self.e = Some(e); self } /// Set static key. pub fn set_s(&mut self, s: D::Key) -> &mut Self { self.s = Some(s); self } /// Set peer semi-ephemeral public key. /// /// Usually used in fallback patterns. pub fn set_re(&mut self, re: D::Pubkey) -> &mut Self { self.re = Some(re); self } /// Set peer static public key. pub fn set_rs(&mut self, rs: D::Pubkey) -> &mut Self { self.rs = Some(rs); self } /// Build [`HandshakeState`]. /// /// # Panics /// /// If any of [`set_pattern`](HandshakeStateBuilder::set_pattern), /// [`set_prologue`](HandshakeStateBuilder::set_prologue) or /// [`set_is_initiator`](HandshakeStateBuilder::set_is_initiator) has not /// been called yet. pub fn build_handshake_state(self) -> HandshakeState where C: Cipher, H: Hash, { HandshakeState::new( self.pattern.unwrap(), self.is_initiator.unwrap(), self.prologue.unwrap(), self.s, self.e, self.rs, self.re, ) } } noise-protocol-0.1.4/src/lib.rs000064400000000000000000000026021046102023000145050ustar 00000000000000//! Rust implementation of the [Noise Protocol //! Framework](http://www.noiseprotocol.org/). //! //! # Basic Usage //! //! Initialize a [`HandshakeState`] with [`HandshakeState::new`] or //! [`HandshakeStateBuilder`], call [`HandshakeState::write_message`] and //! [`HandshakeState::read_message`] to complete the handshake, and finally call //! [`HandshakeState::get_ciphers`] to get a pair of [`CipherState`] to //! encrypt/decrypt further transport messages. //! //! # Crypto Primitives //! //! This crate only contains an abstract implementation of the protocol. //! Concrete implementations of the crypto primitives, wrapping around some //! popular libraries, are provided in sibling crates, e.g., `noise-ring`, //! `noise-sodiumoxide` and `noise-rust-crypto`. //! //! Other implementations of the crypto primitives can be easily plugged in by //! implementing the [`DH`], [`Cipher`] and [`Hash`] traits. #![warn(missing_docs)] #![cfg_attr(not(feature = "use_std"), no_std)] mod cipherstate; mod handshakepattern; mod handshakestate; mod symmetricstate; mod traits; #[cfg(feature = "use_alloc")] #[macro_use] extern crate alloc; pub use crate::cipherstate::CipherState; pub use crate::traits::{Cipher, Hash, U8Array, DH}; /// Handshake patterns. pub mod patterns { pub use crate::handshakepattern::*; } pub use crate::handshakestate::{Error, ErrorKind, HandshakeState, HandshakeStateBuilder}; noise-protocol-0.1.4/src/symmetricstate.rs000064400000000000000000000054021046102023000170150ustar 00000000000000use crate::cipherstate::CipherState; use crate::traits::{Cipher, Hash, U8Array}; pub struct SymmetricState { // Instead of `has_key`, use an `Option`. cipherstate: Option>, h: H::Output, ck: H::Output, } impl Clone for SymmetricState where C: Cipher, H: Hash, { fn clone(&self) -> Self { Self { cipherstate: self.cipherstate.clone(), h: self.h.clone(), ck: self.ck.clone(), } } } impl SymmetricState where C: Cipher, H: Hash, { /// Initialize a `SymmetricState` with a handshake name. pub fn new(handshake_name: &[u8]) -> SymmetricState { let mut h = H::Output::new(); if handshake_name.len() <= H::hash_len() { h.as_mut()[..handshake_name.len()].copy_from_slice(handshake_name); } else { h = H::hash(handshake_name); } SymmetricState { cipherstate: None, ck: h.clone(), h, } } pub fn mix_key(&mut self, data: &[u8]) { let (k1, k2) = H::hkdf(self.ck.as_slice(), data); self.ck = k1; self.cipherstate = Some(CipherState::new(&k2.as_slice()[..C::key_len()], 0)); } pub fn mix_hash(&mut self, data: &[u8]) { let mut h: H = Default::default(); h.input(self.h.as_slice()); h.input(data); self.h = h.result(); } pub fn mix_key_and_hash(&mut self, input_key_material: &[u8]) { let (ck, temp_h, temp_k) = H::hkdf3(self.ck.as_slice(), input_key_material); self.ck = ck; self.mix_hash(temp_h.as_slice()); self.cipherstate = Some(CipherState::new(&temp_k.as_slice()[..C::key_len()], 0)); } pub fn has_key(&self) -> bool { self.cipherstate.is_some() } pub fn encrypt_and_hash(&mut self, plaintext: &[u8], out: &mut [u8]) { if let Some(ref mut c) = self.cipherstate { c.encrypt_ad(self.h.as_slice(), plaintext, out); } else { out.copy_from_slice(plaintext); }; self.mix_hash(out); } pub fn decrypt_and_hash(&mut self, data: &[u8], out: &mut [u8]) -> Result<(), ()> { if let Some(ref mut c) = self.cipherstate { c.decrypt_ad(self.h.as_slice(), data, out)?; } else { out.copy_from_slice(data) } self.mix_hash(data); Ok(()) } pub fn split(&self) -> (CipherState, CipherState) { let (k1, k2) = H::hkdf(self.ck.as_slice(), &[]); let c1 = CipherState::new(&k1.as_slice()[..C::key_len()], 0); let c2 = CipherState::new(&k2.as_slice()[..C::key_len()], 0); (c1, c2) } pub fn get_hash(&self) -> &[u8] { self.h.as_slice() } } noise-protocol-0.1.4/src/traits.rs000064400000000000000000000135421046102023000152520ustar 00000000000000/// A trait for fixed size u8 array. // Inspired by ArrayVec and SmallVec, but no unsafe. // Use this trait so that we don't have to use [`Vec`] for some semi-fixed length buffers and // input/output types. pub trait U8Array: Sized { /// Create a new array filled with all zeros. fn new() -> Self; /// Create a new array filled with a same value. fn new_with(_: u8) -> Self; /// Create a new array from a slice. /// /// # Panics /// /// The slice must be of the same length. fn from_slice(_: &[u8]) -> Self; /// Length of the array. fn len() -> usize; /// As slice. fn as_slice(&self) -> &[u8]; /// As mutable slice. fn as_mut(&mut self) -> &mut [u8]; // Cannot just impl [`Clone`], that will conflict with [u8; 32]. /// Clone. fn clone(&self) -> Self { Self::from_slice(self.as_slice()) } } macro_rules! impl_array { ($len:expr) => { impl U8Array for [u8; $len] { fn new() -> Self { [0u8; $len] } fn new_with(x: u8) -> Self { [x; $len] } fn from_slice(data: &[u8]) -> Self { let mut a = [0u8; $len]; a.copy_from_slice(data); a } fn len() -> usize { $len } fn as_slice(&self) -> &[u8] { self } fn as_mut(&mut self) -> &mut [u8] { self } } }; } impl_array!(32); impl_array!(64); impl_array!(128); /// A DH. pub trait DH { /// Type of private key. type Key: U8Array; /// Type of pubkey key. type Pubkey: U8Array; /// Type of output. type Output: U8Array; /// Name of this DH function, e.g., “25519”. fn name() -> &'static str; /// Randomly generate a new private key. fn genkey() -> Self::Key; /// Calculate public key from a private key. fn pubkey(_: &Self::Key) -> Self::Pubkey; /// Perform DH key exchange. fn dh(_: &Self::Key, _: &Self::Pubkey) -> Result; } /// An AEAD. pub trait Cipher { /// Name of this cipher function. fn name() -> &'static str; /// Type of key. type Key: U8Array; /// Length of key. fn key_len() -> usize { Self::Key::len() } /// Length of auth tag. /// /// All ciphers specified in the spec has tag length 16. fn tag_len() -> usize { 16 } /// AEAD encryption. /// /// # Panics /// /// If `out.len() != plaintext.len() + Self::tag_len()` fn encrypt(k: &Self::Key, nonce: u64, ad: &[u8], plaintext: &[u8], out: &mut [u8]); /// AEAD decryption. /// /// # Panics /// /// If `out.len() != ciphertext.len() - Self::tag_len()` fn decrypt( k: &Self::Key, nonce: u64, ad: &[u8], ciphertext: &[u8], out: &mut [u8], ) -> Result<(), ()>; /// Rekey. Returns a new cipher key as a pseudorandom function of `k`. fn rekey(k: &Self::Key) -> Self::Key { // XXX: `k1` is not zeroed. let mut k1 = [0u8; 48]; Self::encrypt(k, 0u64.wrapping_sub(1), &[], &[0; 32], &mut k1); Self::Key::from_slice(&k1[..32]) } } /// A hash function. pub trait Hash: Default { /// Name of the hash function. fn name() -> &'static str; /// Type of a block. type Block: U8Array; /// Type of output. type Output: U8Array; /// Length of block. fn block_len() -> usize { Self::Block::len() } /// Length of hash output, in number of bytes. fn hash_len() -> usize { Self::Output::len() } /// Reset state of hash context. fn reset(&mut self) { *self = Default::default(); } /// Update hash context with some input. fn input(&mut self, data: &[u8]); /// Get hash result. fn result(&mut self) -> Self::Output; /// Calculate hash of some data. fn hash(data: &[u8]) -> Self::Output { let mut h: Self = Default::default(); h.input(data); h.result() } /// Calculate HMAC-THIS-HASH, with some `key` and several messages. fn hmac_many(key: &[u8], data: &[&[u8]]) -> Self::Output { assert!(key.len() <= Self::block_len()); let mut ipad = Self::Block::new_with(0x36u8); let mut opad = Self::Block::new_with(0x5cu8); let ipad = ipad.as_mut(); let opad = opad.as_mut(); for (i, b) in key.iter().enumerate() { ipad[i] ^= b; opad[i] ^= b; } let mut hasher: Self = Default::default(); hasher.input(ipad); for d in data { hasher.input(d); } let inner_output = hasher.result(); hasher.reset(); hasher.input(opad); hasher.input(inner_output.as_slice()); hasher.result() } /// Calculate HMAC-THIS-HASH, with some `key` and a message. fn hmac(key: &[u8], data: &[u8]) -> Self::Output { Self::hmac_many(key, &[data]) } /// Calculate HKDF, as specified in the noise spec. fn hkdf(chaining_key: &[u8], input_key_material: &[u8]) -> (Self::Output, Self::Output) { let temp_key = Self::hmac(chaining_key, input_key_material); let out1 = Self::hmac(temp_key.as_slice(), &[1u8]); let out2 = Self::hmac_many(temp_key.as_slice(), &[out1.as_slice(), &[2u8]]); (out1, out2) } /// Triple output HKDF. fn hkdf3( chaining_key: &[u8], input_key_material: &[u8], ) -> (Self::Output, Self::Output, Self::Output) { let temp_key = Self::hmac(chaining_key, input_key_material); let out1 = Self::hmac(temp_key.as_slice(), &[1u8]); let out2 = Self::hmac_many(temp_key.as_slice(), &[out1.as_slice(), &[2u8]]); let out3 = Self::hmac_many(temp_key.as_slice(), &[out2.as_slice(), &[3u8]]); (out1, out2, out3) } }