This commit is contained in:
Jan Winkelmann (keks)
2025-02-21 14:56:35 +01:00
parent 2ddd1488b3
commit 44e46895aa
19 changed files with 310 additions and 126 deletions

View File

@@ -1,7 +1,11 @@
pub trait KeyedHash<const KEY_LEN: usize, const HASH_LEN: usize> { pub trait KeyedHash<const KEY_LEN: usize, const HASH_LEN: usize> {
type Error; type Error;
fn keyed_hash(key: &[u8; KEY_LEN], data: &[u8], out: &mut [u8; HASH_LEN]) -> Result<(), Self::Error>; fn keyed_hash(
key: &[u8; KEY_LEN],
data: &[u8],
out: &mut [u8; HASH_LEN],
) -> Result<(), Self::Error>;
} }
pub trait KeyedHashInstance<const KEY_LEN: usize, const HASH_LEN: usize> { pub trait KeyedHashInstance<const KEY_LEN: usize, const HASH_LEN: usize> {
@@ -9,5 +13,10 @@ pub trait KeyedHashInstance<const KEY_LEN: usize, const HASH_LEN: usize> {
type OutputType; type OutputType;
type Error; type Error;
fn keyed_hash(&self, key: &[u8; KEY_LEN], data: &[u8], out: &mut [u8; HASH_LEN]) -> Result<(), Self::Error>; fn keyed_hash(
} &self,
key: &[u8; KEY_LEN],
data: &[u8],
out: &mut [u8; HASH_LEN],
) -> Result<(), Self::Error>;
}

View File

@@ -4,9 +4,9 @@ use rosenpass_to::To;
use crate::keyed_hash as hash; use crate::keyed_hash as hash;
use crate::subtle::either_hash::EitherShakeOrBlake;
pub use hash::KEY_LEN; pub use hash::KEY_LEN;
use rosenpass_cipher_traits::KeyedHashInstance; use rosenpass_cipher_traits::KeyedHashInstance;
use crate::subtle::either_hash::EitherShakeOrBlake;
/// ///
///```rust ///```rust
@@ -125,7 +125,11 @@ impl SecretHashDomain {
/// as the content for the new [SecretHashDomain]. /// as the content for the new [SecretHashDomain].
/// Both `k` and `d` have to be exactly [KEY_LEN] bytes in length. /// Both `k` and `d` have to be exactly [KEY_LEN] bytes in length.
/// TODO: docu /// TODO: docu
pub fn invoke_primitive(k: &[u8], d: &[u8], hash_choice: EitherShakeOrBlake) -> Result<SecretHashDomain> { pub fn invoke_primitive(
k: &[u8],
d: &[u8],
hash_choice: EitherShakeOrBlake,
) -> Result<SecretHashDomain> {
let mut new_secret_key = Secret::zero(); let mut new_secret_key = Secret::zero();
hash_choice.keyed_hash(k.try_into()?, d, new_secret_key.secret_mut())?; hash_choice.keyed_hash(k.try_into()?, d, new_secret_key.secret_mut())?;
let mut r = SecretHashDomain(new_secret_key, hash_choice); let mut r = SecretHashDomain(new_secret_key, hash_choice);

View File

@@ -1,18 +1,22 @@
use rosenpass_cipher_traits::{KeyedHash, KeyedHashInstance};
use anyhow::Result;
use crate::subtle::hash_functions::keyed_shake256::SHAKE256Core; use crate::subtle::hash_functions::keyed_shake256::SHAKE256Core;
use crate::subtle::incorrect_hmac_blake2b::Blake2bCore; use crate::subtle::incorrect_hmac_blake2b::Blake2bCore;
use anyhow::Result;
use rosenpass_cipher_traits::{KeyedHash, KeyedHashInstance};
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub enum EitherHash<const KEY_LEN: usize, const HASH_LEN: usize, Error, pub enum EitherHash<
const KEY_LEN: usize,
const HASH_LEN: usize,
Error,
L: KeyedHash<KEY_LEN, HASH_LEN, Error = Error>, L: KeyedHash<KEY_LEN, HASH_LEN, Error = Error>,
R: KeyedHash<KEY_LEN, HASH_LEN, Error = Error>> R: KeyedHash<KEY_LEN, HASH_LEN, Error = Error>,
{ > {
Left(L), Left(L),
Right(R), Right(R),
} }
impl<const KEY_LEN: usize, const HASH_LEN: usize, Error, L, R> KeyedHashInstance<KEY_LEN, HASH_LEN> for EitherHash<KEY_LEN, HASH_LEN, Error, L, R> impl<const KEY_LEN: usize, const HASH_LEN: usize, Error, L, R> KeyedHashInstance<KEY_LEN, HASH_LEN>
for EitherHash<KEY_LEN, HASH_LEN, Error, L, R>
where where
L: KeyedHash<KEY_LEN, HASH_LEN, Error = Error>, L: KeyedHash<KEY_LEN, HASH_LEN, Error = Error>,
R: KeyedHash<KEY_LEN, HASH_LEN, Error = Error>, R: KeyedHash<KEY_LEN, HASH_LEN, Error = Error>,
@@ -21,7 +25,12 @@ where
type OutputType = [u8; HASH_LEN]; type OutputType = [u8; HASH_LEN];
type Error = Error; type Error = Error;
fn keyed_hash(&self, key: &[u8; KEY_LEN], data: &[u8], out: &mut [u8; HASH_LEN]) -> Result<(), Self::Error> { fn keyed_hash(
&self,
key: &[u8; KEY_LEN],
data: &[u8],
out: &mut [u8; HASH_LEN],
) -> Result<(), Self::Error> {
match self { match self {
Self::Left(_) => L::keyed_hash(key, data, out), Self::Left(_) => L::keyed_hash(key, data, out),
Self::Right(_) => R::keyed_hash(key, data, out), Self::Right(_) => R::keyed_hash(key, data, out),

View File

@@ -1,8 +1,8 @@
use anyhow::ensure; use anyhow::ensure;
use zeroize::Zeroizing;
use rosenpass_cipher_traits::KeyedHash; use rosenpass_cipher_traits::KeyedHash;
use rosenpass_constant_time::xor; use rosenpass_constant_time::xor;
use rosenpass_to::{ops::copy_slice, with_destination, To}; use rosenpass_to::{ops::copy_slice, with_destination, To};
use zeroize::Zeroizing;
use crate::subtle::hash_functions::blake2b; use crate::subtle::hash_functions::blake2b;
use crate::subtle::hash_functions::infer_keyed_hash::InferKeyedHash; use crate::subtle::hash_functions::infer_keyed_hash::InferKeyedHash;

View File

@@ -1,6 +1,6 @@
use std::marker::PhantomData;
use anyhow::Result; use anyhow::Result;
use rosenpass_cipher_traits::{KeyedHash, KeyedHashInstance}; use rosenpass_cipher_traits::{KeyedHash, KeyedHashInstance};
use std::marker::PhantomData;
/// This is a helper to allow for type parameter inference when calling functions /// This is a helper to allow for type parameter inference when calling functions
/// that need a [KeyedHash]. /// that need a [KeyedHash].
@@ -19,11 +19,13 @@ impl<Static, const KEY_LEN: usize, const HASH_LEN: usize> InferKeyedHash<Static,
where where
Static: KeyedHash<KEY_LEN, HASH_LEN, Error = anyhow::Error>, Static: KeyedHash<KEY_LEN, HASH_LEN, Error = anyhow::Error>,
{ {
pub const KEY_LEN : usize = KEY_LEN; pub const KEY_LEN: usize = KEY_LEN;
pub const HASH_LEN: usize = HASH_LEN; pub const HASH_LEN: usize = HASH_LEN;
pub const fn new() -> Self { pub const fn new() -> Self {
Self { _phantom_keyed_hasher: PhantomData } Self {
_phantom_keyed_hasher: PhantomData,
}
} }
/// This just forwards to [KeyedHash::keyed_hash] of the type parameter `Static` /// This just forwards to [KeyedHash::keyed_hash] of the type parameter `Static`
@@ -45,7 +47,12 @@ where
} }
} }
impl<const KEY_LEN: usize, const HASH_LEN: usize, Static: KeyedHash<KEY_LEN, HASH_LEN, Error = anyhow::Error>> KeyedHashInstance<KEY_LEN, HASH_LEN> for InferKeyedHash<Static, KEY_LEN, HASH_LEN> { impl<
const KEY_LEN: usize,
const HASH_LEN: usize,
Static: KeyedHash<KEY_LEN, HASH_LEN, Error = anyhow::Error>,
> KeyedHashInstance<KEY_LEN, HASH_LEN> for InferKeyedHash<Static, KEY_LEN, HASH_LEN>
{
type KeyType = [u8; KEY_LEN]; type KeyType = [u8; KEY_LEN];
type OutputType = [u8; HASH_LEN]; type OutputType = [u8; HASH_LEN];
type Error = anyhow::Error; type Error = anyhow::Error;
@@ -57,7 +64,8 @@ impl<const KEY_LEN: usize, const HASH_LEN: usize, Static: KeyedHash<KEY_LEN, HAS
/// Helper traits ///////////////////////////////////////////// /// Helper traits /////////////////////////////////////////////
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Default for InferKeyedHash<Static, KEY_LEN, OUT_LEN> impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Default
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
where where
Static: KeyedHash<KEY_LEN, OUT_LEN, Error = anyhow::Error>, Static: KeyedHash<KEY_LEN, OUT_LEN, Error = anyhow::Error>,
{ {
@@ -66,7 +74,8 @@ where
} }
} }
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Clone for InferKeyedHash<Static, KEY_LEN, OUT_LEN> impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Clone
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
where where
Static: KeyedHash<KEY_LEN, OUT_LEN, Error = anyhow::Error>, Static: KeyedHash<KEY_LEN, OUT_LEN, Error = anyhow::Error>,
{ {
@@ -75,7 +84,8 @@ where
} }
} }
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Copy for InferKeyedHash<Static, KEY_LEN, OUT_LEN> impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Copy
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
where where
Static: KeyedHash<KEY_LEN, OUT_LEN, Error = anyhow::Error>, Static: KeyedHash<KEY_LEN, OUT_LEN, Error = anyhow::Error>,
{ {

View File

@@ -1,13 +1,15 @@
use crate::subtle::hash_functions::infer_keyed_hash::InferKeyedHash;
use anyhow::ensure; use anyhow::ensure;
use rosenpass_cipher_traits::KeyedHash;
use sha3::digest::{ExtendableOutput, Update, XofReader}; use sha3::digest::{ExtendableOutput, Update, XofReader};
use sha3::Shake256; use sha3::Shake256;
use rosenpass_cipher_traits::KeyedHash;
use crate::subtle::hash_functions::infer_keyed_hash::InferKeyedHash;
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct SHAKE256Core<const KEY_LEN: usize, const HASH_LEN: usize>; pub struct SHAKE256Core<const KEY_LEN: usize, const HASH_LEN: usize>;
impl<const KEY_LEN: usize, const HASH_LEN: usize> KeyedHash<KEY_LEN, HASH_LEN> for SHAKE256Core<KEY_LEN, HASH_LEN> { impl<const KEY_LEN: usize, const HASH_LEN: usize> KeyedHash<KEY_LEN, HASH_LEN>
for SHAKE256Core<KEY_LEN, HASH_LEN>
{
type Error = anyhow::Error; type Error = anyhow::Error;
/// TODO: Rework test /// TODO: Rework test
@@ -36,7 +38,11 @@ impl<const KEY_LEN: usize, const HASH_LEN: usize> KeyedHash<KEY_LEN, HASH_LEN> f
/// 108, 50, 224, 48, 19, 197, 253, 105, 136, 95, 34, 95, 203, 149, 192, 124, 223, 243, 87]; /// 108, 50, 224, 48, 19, 197, 253, 105, 136, 95, 34, 95, 203, 149, 192, 124, 223, 243, 87];
/// # assert_eq!(hash_data, expected_hash); /// # assert_eq!(hash_data, expected_hash);
/// ``` /// ```
fn keyed_hash(key: &[u8; KEY_LEN], data: &[u8], out: &mut [u8; HASH_LEN]) -> Result<(), Self::Error> { fn keyed_hash(
key: &[u8; KEY_LEN],
data: &[u8],
out: &mut [u8; HASH_LEN],
) -> Result<(), Self::Error> {
// Since SHAKE256 is a XOF, we fix the output length manually to what is required for the // Since SHAKE256 is a XOF, we fix the output length manually to what is required for the
// protocol. // protocol.
ensure!(out.len() == HASH_LEN); ensure!(out.len() == HASH_LEN);
@@ -59,7 +65,6 @@ impl<const KEY_LEN: usize, const HASH_LEN: usize> KeyedHash<KEY_LEN, HASH_LEN> f
} }
} }
impl<const KEY_LEN: usize, const HASH_LEN: usize> SHAKE256Core<KEY_LEN, HASH_LEN> { impl<const KEY_LEN: usize, const HASH_LEN: usize> SHAKE256Core<KEY_LEN, HASH_LEN> {
pub fn new() -> Self { pub fn new() -> Self {
Self Self
@@ -83,7 +88,7 @@ impl<const KEY_LEN: usize, const HASH_LEN: usize> SHAKE256Core<KEY_LEN, HASH_LEN
/// # assert_eq!(hash_data, expected_hash); /// # assert_eq!(hash_data, expected_hash);
/// ``` /// ```
pub type SHAKE256<const KEY_LEN: usize, const HASH_LEN: usize> = pub type SHAKE256<const KEY_LEN: usize, const HASH_LEN: usize> =
InferKeyedHash<SHAKE256Core<KEY_LEN, HASH_LEN>, KEY_LEN, HASH_LEN>; InferKeyedHash<SHAKE256Core<KEY_LEN, HASH_LEN>, KEY_LEN, HASH_LEN>;
/// TODO: Documentation and more interesting test /// TODO: Documentation and more interesting test
/// ```rust /// ```rust
@@ -102,4 +107,3 @@ InferKeyedHash<SHAKE256Core<KEY_LEN, HASH_LEN>, KEY_LEN, HASH_LEN>;
/// # assert_eq!(hash_data, expected_hash); /// # assert_eq!(hash_data, expected_hash);
/// ``` /// ```
pub type SHAKE256_32 = SHAKE256<32, 32>; pub type SHAKE256_32 = SHAKE256<32, 32>;

View File

@@ -1,4 +1,4 @@
pub mod blake2b; pub mod blake2b;
pub mod incorrect_hmac_blake2b; pub mod incorrect_hmac_blake2b;
mod infer_keyed_hash;
pub mod keyed_shake256; pub mod keyed_shake256;
mod infer_keyed_hash;

View File

@@ -8,8 +8,8 @@
pub mod chacha20poly1305_ietf; pub mod chacha20poly1305_ietf;
#[cfg(feature = "experiment_libcrux")] #[cfg(feature = "experiment_libcrux")]
pub mod chacha20poly1305_ietf_libcrux; pub mod chacha20poly1305_ietf_libcrux;
pub mod xchacha20poly1305_ietf;
mod hash_functions;
pub mod either_hash; pub mod either_hash;
mod hash_functions;
pub mod xchacha20poly1305_ietf;
pub use hash_functions::{blake2b, incorrect_hmac_blake2b, keyed_shake256}; pub use hash_functions::{blake2b, incorrect_hmac_blake2b, keyed_shake256};

1
initial Submodule

Submodule initial added at f1122f1f62

View File

@@ -1,5 +1,7 @@
use anyhow::Result; use anyhow::Result;
use rosenpass::protocol::{CryptoServer, HandleMsgResult, MsgBuf, PeerPtr, ProtocolVersion, SPk, SSk, SymKey}; use rosenpass::protocol::{
CryptoServer, HandleMsgResult, MsgBuf, PeerPtr, ProtocolVersion, SPk, SSk, SymKey,
};
use std::ops::DerefMut; use std::ops::DerefMut;
use rosenpass_cipher_traits::Kem; use rosenpass_cipher_traits::Kem;

View File

@@ -42,6 +42,7 @@ use std::slice;
use std::time::Duration; use std::time::Duration;
use std::time::Instant; use std::time::Instant;
use crate::config::ProtocolVersion;
use crate::protocol::BuildCryptoServer; use crate::protocol::BuildCryptoServer;
use crate::protocol::HostIdentification; use crate::protocol::HostIdentification;
use crate::{ use crate::{
@@ -50,7 +51,6 @@ use crate::{
}; };
use rosenpass_util::attempt; use rosenpass_util::attempt;
use rosenpass_util::b64::B64Display; use rosenpass_util::b64::B64Display;
use crate::config::ProtocolVersion;
/// The maximum size of a base64 encoded symmetric key (estimate) /// The maximum size of a base64 encoded symmetric key (estimate)
pub const MAX_B64_KEY_SIZE: usize = 32 * 5 / 3; pub const MAX_B64_KEY_SIZE: usize = 32 * 5 / 3;
@@ -1043,7 +1043,7 @@ impl AppServer {
outfile: Option<PathBuf>, outfile: Option<PathBuf>,
broker_peer: Option<BrokerPeer>, broker_peer: Option<BrokerPeer>,
hostname: Option<String>, hostname: Option<String>,
protocol_version: ProtocolVersion protocol_version: ProtocolVersion,
) -> anyhow::Result<AppPeerPtr> { ) -> anyhow::Result<AppPeerPtr> {
let PeerPtr(pn) = match &mut self.crypto_site { let PeerPtr(pn) = match &mut self.crypto_site {
ConstructionSite::Void => bail!("Crypto server construction site is void"), ConstructionSite::Void => bail!("Crypto server construction site is void"),

View File

@@ -1,10 +1,10 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use heck::ToShoutySnakeCase; use heck::ToShoutySnakeCase;
use rosenpass_ciphers::{hash_domain::HashDomain, KEY_LEN};
use rosenpass_ciphers::subtle::either_hash::EitherShakeOrBlake; use rosenpass_ciphers::subtle::either_hash::EitherShakeOrBlake;
use rosenpass_ciphers::subtle::incorrect_hmac_blake2b::Blake2bCore; use rosenpass_ciphers::subtle::incorrect_hmac_blake2b::Blake2bCore;
use rosenpass_ciphers::subtle::keyed_shake256::SHAKE256Core; use rosenpass_ciphers::subtle::keyed_shake256::SHAKE256Core;
use rosenpass_ciphers::{hash_domain::HashDomain, KEY_LEN};
/// Recursively calculate a concrete hash value for an API message type /// Recursively calculate a concrete hash value for an API message type
fn calculate_hash_value(hd: HashDomain, values: &[&str]) -> Result<[u8; KEY_LEN]> { fn calculate_hash_value(hd: HashDomain, values: &[&str]) -> Result<[u8; KEY_LEN]> {

View File

@@ -103,7 +103,7 @@ macro_rules! hash_domain {
/// used in various places in the rosenpass protocol. /// used in various places in the rosenpass protocol.
/// ///
/// This is generally used to create further hash-domains for specific purposes. See /// This is generally used to create further hash-domains for specific purposes. See
/// ///
/// TODO: Update documentation /// TODO: Update documentation
/// ///
/// # Examples /// # Examples
@@ -114,10 +114,11 @@ macro_rules! hash_domain {
pub fn protocol(hash_choice: EitherShakeOrBlake) -> Result<HashDomain> { pub fn protocol(hash_choice: EitherShakeOrBlake) -> Result<HashDomain> {
// TODO: Update this string that is mixed in? // TODO: Update this string that is mixed in?
match hash_choice { match hash_choice {
EitherShakeOrBlake::Left(SHAKE256Core) => HashDomain::zero(hash_choice).mix("Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 SHAKE256".as_bytes()), EitherShakeOrBlake::Left(SHAKE256Core) => HashDomain::zero(hash_choice)
EitherShakeOrBlake::Right(Blake2bCore) => HashDomain::zero(hash_choice).mix("Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 Blake2b".as_bytes()), .mix("Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 SHAKE256".as_bytes()),
EitherShakeOrBlake::Right(Blake2bCore) => HashDomain::zero(hash_choice)
.mix("Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 Blake2b".as_bytes()),
} }
} }
hash_domain_ns!( hash_domain_ns!(

View File

@@ -1,11 +1,11 @@
use super::{CryptoServer, PeerPtr, SPk, SSk, SymKey};
use crate::config::ProtocolVersion;
use rosenpass_util::{ use rosenpass_util::{
build::Build, build::Build,
mem::{DiscardResultExt, SwapWithDefaultExt}, mem::{DiscardResultExt, SwapWithDefaultExt},
result::ensure_or, result::ensure_or,
}; };
use thiserror::Error; use thiserror::Error;
use crate::config::ProtocolVersion;
use super::{CryptoServer, PeerPtr, SPk, SSk, SymKey};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
/// A pair of matching public/secret keys used to launch the crypto server. /// A pair of matching public/secret keys used to launch the crypto server.
@@ -187,7 +187,15 @@ impl Build<CryptoServer> for BuildCryptoServer {
let mut srv = CryptoServer::new(sk, pk); let mut srv = CryptoServer::new(sk, pk);
for (idx, PeerParams { psk, pk , protocol_version}) in self.peers.into_iter().enumerate() { for (
idx,
PeerParams {
psk,
pk,
protocol_version,
},
) in self.peers.into_iter().enumerate()
{
let PeerPtr(idx2) = srv.add_peer(psk, pk, protocol_version.into())?; let PeerPtr(idx2) = srv.add_peer(psk, pk, protocol_version.into())?;
assert!(idx == idx2, "Peer id changed during CryptoServer construction from {idx} to {idx2}. This is a developer error.") assert!(idx == idx2, "Peer id changed during CryptoServer construction from {idx} to {idx2}. This is a developer error.")
} }
@@ -337,14 +345,28 @@ impl BuildCryptoServer {
/// assert_eq!(peer.spkt, public_key); /// assert_eq!(peer.spkt, public_key);
/// assert_eq!(peer_psk.secret(), pre_shared_key.secret()); /// assert_eq!(peer_psk.secret(), pre_shared_key.secret());
/// ``` /// ```
pub fn with_added_peer(&mut self, psk: Option<SymKey>, pk: SPk, protocol_version: ProtocolVersion) -> &mut Self { pub fn with_added_peer(
&mut self,
psk: Option<SymKey>,
pk: SPk,
protocol_version: ProtocolVersion,
) -> &mut Self {
// TODO: Check here already whether peer was already added // TODO: Check here already whether peer was already added
self.peers.push(PeerParams { psk, pk, protocol_version }); self.peers.push(PeerParams {
psk,
pk,
protocol_version,
});
self self
} }
/// Add a new entry to the list of registered peers, with or without a pre-shared key. /// Add a new entry to the list of registered peers, with or without a pre-shared key.
pub fn add_peer(&mut self, psk: Option<SymKey>, pk: SPk, protocol_version: ProtocolVersion) -> PeerPtr { pub fn add_peer(
&mut self,
psk: Option<SymKey>,
pk: SPk,
protocol_version: ProtocolVersion,
) -> PeerPtr {
let id = PeerPtr(self.peers.len()); let id = PeerPtr(self.peers.len());
self.with_added_peer(psk, pk, protocol_version); self.with_added_peer(psk, pk, protocol_version);
id id

View File

@@ -19,11 +19,15 @@ use std::{
use anyhow::{bail, ensure, Context, Result}; use anyhow::{bail, ensure, Context, Result};
use rand::Fill as Randomize; use rand::Fill as Randomize;
use crate::{hash_domains, msgs::*, RosenpassError};
use memoffset::span_of; use memoffset::span_of;
use rosenpass_cipher_traits::Kem; use rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::hash_domain::{SecretHashDomain, SecretHashDomainNamespace}; use rosenpass_ciphers::hash_domain::{SecretHashDomain, SecretHashDomainNamespace};
use rosenpass_ciphers::kem::{EphemeralKem, StaticKem}; use rosenpass_ciphers::kem::{EphemeralKem, StaticKem};
use rosenpass_ciphers::keyed_hash; use rosenpass_ciphers::keyed_hash;
use rosenpass_ciphers::subtle::either_hash::EitherShakeOrBlake;
use rosenpass_ciphers::subtle::incorrect_hmac_blake2b::Blake2bCore;
use rosenpass_ciphers::subtle::keyed_shake256::SHAKE256Core;
use rosenpass_ciphers::{aead, xaead, KEY_LEN}; use rosenpass_ciphers::{aead, xaead, KEY_LEN};
use rosenpass_constant_time as constant_time; use rosenpass_constant_time as constant_time;
use rosenpass_secret_memory::{Public, PublicBox, Secret}; use rosenpass_secret_memory::{Public, PublicBox, Secret};
@@ -33,10 +37,6 @@ use rosenpass_util::functional::ApplyExt;
use rosenpass_util::mem::DiscardResultExt; use rosenpass_util::mem::DiscardResultExt;
use rosenpass_util::{cat, mem::cpy_min, time::Timebase}; use rosenpass_util::{cat, mem::cpy_min, time::Timebase};
use zerocopy::{AsBytes, FromBytes, Ref}; use zerocopy::{AsBytes, FromBytes, Ref};
use rosenpass_ciphers::subtle::either_hash::{EitherShakeOrBlake};
use rosenpass_ciphers::subtle::incorrect_hmac_blake2b::Blake2bCore;
use rosenpass_ciphers::subtle::keyed_shake256::SHAKE256Core;
use crate::{hash_domains, msgs::*, RosenpassError};
// CONSTANTS & SETTINGS ////////////////////////// // CONSTANTS & SETTINGS //////////////////////////
@@ -369,7 +369,7 @@ pub enum IndexKey {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ProtocolVersion { pub enum ProtocolVersion {
V02, V02,
V03 V03,
} }
impl ProtocolVersion { impl ProtocolVersion {
@@ -1434,7 +1434,7 @@ impl CryptoServer {
} }
/// Add a peer with an optional pre shared key (`psk`) and its public key (`pk`) /// Add a peer with an optional pre shared key (`psk`) and its public key (`pk`)
/// ///
/// TODO: Adapt documentation /// TODO: Adapt documentation
/// ///
/// ``` /// ```
@@ -1460,7 +1460,12 @@ impl CryptoServer {
/// ///
/// Ok::<(), anyhow::Error>(()) /// Ok::<(), anyhow::Error>(())
/// ``` /// ```
pub fn add_peer(&mut self, psk: Option<SymKey>, pk: SPk, protocol_version: ProtocolVersion) -> Result<PeerPtr> { pub fn add_peer(
&mut self,
psk: Option<SymKey>,
pk: SPk,
protocol_version: ProtocolVersion,
) -> Result<PeerPtr> {
let peer = Peer { let peer = Peer {
psk: psk.unwrap_or_else(SymKey::zero), psk: psk.unwrap_or_else(SymKey::zero),
spkt: pk, spkt: pk,
@@ -2306,7 +2311,7 @@ impl CryptoServer {
log::debug!("Rx {:?}, processing", msg_type); log::debug!("Rx {:?}, processing", msg_type);
let mut msg_out = truncating_cast_into::<Envelope<RespHello>>(tx_buf)?; let mut msg_out = truncating_cast_into::<Envelope<RespHello>>(tx_buf)?;
let peer = match msg_type { let peer = match msg_type {
Ok(MsgType::InitHello) => { Ok(MsgType::InitHello) => {
let msg_in: Ref<&[u8], Envelope<InitHello>> = let msg_in: Ref<&[u8], Envelope<InitHello>> =
@@ -2314,23 +2319,31 @@ impl CryptoServer {
// At this point, we do not know the hash functon used by the peer, thus we try both, // At this point, we do not know the hash functon used by the peer, thus we try both,
// with a preference for SHAKE256. // with a preference for SHAKE256.
let peer_shake256 = self.handle_init_hello(&msg_in.payload, &mut msg_out.payload, EitherShakeOrBlake::Left(SHAKE256Core)); let peer_shake256 = self.handle_init_hello(
&msg_in.payload,
&mut msg_out.payload,
EitherShakeOrBlake::Left(SHAKE256Core),
);
let (peer, peer_hash_choice) = match peer_shake256 { let (peer, peer_hash_choice) = match peer_shake256 {
Ok(peer ) => (peer, EitherShakeOrBlake::Left(SHAKE256Core)), Ok(peer) => (peer, EitherShakeOrBlake::Left(SHAKE256Core)),
Err(_) => { Err(_) => {
let peer_blake2b = self.handle_init_hello(&msg_in.payload, &mut msg_out.payload, EitherShakeOrBlake::Right(Blake2bCore)); let peer_blake2b = self.handle_init_hello(
&msg_in.payload,
&mut msg_out.payload,
EitherShakeOrBlake::Right(Blake2bCore),
);
match peer_blake2b { match peer_blake2b {
Ok(peer) => (peer, EitherShakeOrBlake::Right(Blake2bCore)), Ok(peer) => (peer, EitherShakeOrBlake::Right(Blake2bCore)),
Err(_) => bail!("No valid hash function found for InitHello") Err(_) => bail!("No valid hash function found for InitHello"),
} }
} }
}; };
// Now, we make sure that the hash function used by the peer is the same as the one // Now, we make sure that the hash function used by the peer is the same as the one
// that is specified in the local configuration. // that is specified in the local configuration.
self.verify_hash_choice_match(peer, peer_hash_choice.clone())?; self.verify_hash_choice_match(peer, peer_hash_choice.clone())?;
ensure!(msg_in.check_seal(self, peer_hash_choice)?, seal_broken); ensure!(msg_in.check_seal(self, peer_hash_choice)?, seal_broken);
len = self.seal_and_commit_msg(peer, MsgType::RespHello, &mut msg_out)?; len = self.seal_and_commit_msg(peer, MsgType::RespHello, &mut msg_out)?;
peer peer
} }
@@ -2340,8 +2353,11 @@ impl CryptoServer {
let mut msg_out = truncating_cast_into::<Envelope<InitConf>>(tx_buf)?; let mut msg_out = truncating_cast_into::<Envelope<InitConf>>(tx_buf)?;
let peer = self.handle_resp_hello(&msg_in.payload, &mut msg_out.payload)?; let peer = self.handle_resp_hello(&msg_in.payload, &mut msg_out.payload)?;
ensure!(msg_in.check_seal(self, peer.get(self).protocol_version.shake_or_blake())?, seal_broken); ensure!(
msg_in.check_seal(self, peer.get(self).protocol_version.shake_or_blake())?,
seal_broken
);
len = self.seal_and_commit_msg(peer, MsgType::InitConf, &mut msg_out)?; len = self.seal_and_commit_msg(peer, MsgType::InitConf, &mut msg_out)?;
peer.hs() peer.hs()
.store_msg_for_retransmission(self, &msg_out.as_bytes()[..len])?; .store_msg_for_retransmission(self, &msg_out.as_bytes()[..len])?;
@@ -2351,7 +2367,6 @@ impl CryptoServer {
Ok(MsgType::InitConf) => { Ok(MsgType::InitConf) => {
let msg_in: Ref<&[u8], Envelope<InitConf>> = let msg_in: Ref<&[u8], Envelope<InitConf>> =
Ref::new(rx_buf).ok_or(RosenpassError::BufferSizeMismatch)?; Ref::new(rx_buf).ok_or(RosenpassError::BufferSizeMismatch)?;
let mut msg_out = truncating_cast_into::<Envelope<EmptyData>>(tx_buf)?; let mut msg_out = truncating_cast_into::<Envelope<EmptyData>>(tx_buf)?;
@@ -2360,7 +2375,13 @@ impl CryptoServer {
// Cached response; copy out of cache // Cached response; copy out of cache
Some(cached) => { Some(cached) => {
let peer = cached.peer(); let peer = cached.peer();
ensure!(msg_in.check_seal(self, peer.get(self).protocol_version.shake_or_blake())?, seal_broken); ensure!(
msg_in.check_seal(
self,
peer.get(self).protocol_version.shake_or_blake()
)?,
seal_broken
);
let cached = cached let cached = cached
.get(self) .get(self)
.map(|v| v.response.borrow()) .map(|v| v.response.borrow())
@@ -2374,14 +2395,22 @@ impl CryptoServer {
None => { None => {
// At this point, we do not know the hash functon used by the peer, thus we try both, // At this point, we do not know the hash functon used by the peer, thus we try both,
// with a preference for SHAKE256. // with a preference for SHAKE256.
let peer_shake256 = self.handle_init_conf(&msg_in.payload, &mut msg_out.payload, EitherShakeOrBlake::Left(SHAKE256Core)); let peer_shake256 = self.handle_init_conf(
&msg_in.payload,
&mut msg_out.payload,
EitherShakeOrBlake::Left(SHAKE256Core),
);
let (peer, peer_hash_choice) = match peer_shake256 { let (peer, peer_hash_choice) = match peer_shake256 {
Ok(peer) => (peer, EitherShakeOrBlake::Left(SHAKE256Core)), Ok(peer) => (peer, EitherShakeOrBlake::Left(SHAKE256Core)),
Err(_) => { Err(_) => {
let peer_blake2b = self.handle_init_conf(&msg_in.payload, &mut msg_out.payload, EitherShakeOrBlake::Right(Blake2bCore)); let peer_blake2b = self.handle_init_conf(
&msg_in.payload,
&mut msg_out.payload,
EitherShakeOrBlake::Right(Blake2bCore),
);
match peer_blake2b { match peer_blake2b {
Ok(peer) => (peer, EitherShakeOrBlake::Right(Blake2bCore)), Ok(peer) => (peer, EitherShakeOrBlake::Right(Blake2bCore)),
Err(_) => bail!("No valid hash function found for InitHello") Err(_) => bail!("No valid hash function found for InitHello"),
} }
} }
}; };
@@ -2389,7 +2418,7 @@ impl CryptoServer {
// that is specified in the local configuration. // that is specified in the local configuration.
self.verify_hash_choice_match(peer, peer_hash_choice.clone())?; self.verify_hash_choice_match(peer, peer_hash_choice.clone())?;
ensure!(msg_in.check_seal(self, peer_hash_choice)?, seal_broken); ensure!(msg_in.check_seal(self, peer_hash_choice)?, seal_broken);
KnownInitConfResponsePtr::insert_for_request_msg( KnownInitConfResponsePtr::insert_for_request_msg(
self, self,
peer, peer,
@@ -2428,9 +2457,13 @@ impl CryptoServer {
resp: if len == 0 { None } else { Some(len) }, resp: if len == 0 { None } else { Some(len) },
}) })
} }
/// TODO documentation /// TODO documentation
fn verify_hash_choice_match(&self, peer: PeerPtr, peer_hash_choice: EitherShakeOrBlake) -> Result<()> { fn verify_hash_choice_match(
&self,
peer: PeerPtr,
peer_hash_choice: EitherShakeOrBlake,
) -> Result<()> {
match peer.get(self).protocol_version.shake_or_blake() { match peer.get(self).protocol_version.shake_or_blake() {
EitherShakeOrBlake::Left(SHAKE256Core) => match peer_hash_choice { EitherShakeOrBlake::Left(SHAKE256Core) => match peer_hash_choice {
EitherShakeOrBlake::Left(SHAKE256Core) => Ok(()), EitherShakeOrBlake::Left(SHAKE256Core) => Ok(()),
@@ -2439,7 +2472,7 @@ impl CryptoServer {
EitherShakeOrBlake::Right(Blake2bCore) => match peer_hash_choice { EitherShakeOrBlake::Right(Blake2bCore) => match peer_hash_choice {
EitherShakeOrBlake::Left(SHAKE256Core) => bail!("Hash function mismatch"), EitherShakeOrBlake::Left(SHAKE256Core) => bail!("Hash function mismatch"),
EitherShakeOrBlake::Right(Blake2bCore) => Ok(()), EitherShakeOrBlake::Right(Blake2bCore) => Ok(()),
} },
} }
} }
@@ -3209,7 +3242,11 @@ where
M: AsBytes + FromBytes, M: AsBytes + FromBytes,
{ {
/// Internal business logic: Check the message authentication code produced by [Self::seal] /// Internal business logic: Check the message authentication code produced by [Self::seal]
pub fn check_seal(&self, srv: &CryptoServer, shake_or_blake: EitherShakeOrBlake) -> Result<bool> { pub fn check_seal(
&self,
srv: &CryptoServer,
shake_or_blake: EitherShakeOrBlake,
) -> Result<bool> {
let expected = hash_domains::mac(shake_or_blake)? let expected = hash_domains::mac(shake_or_blake)?
.mix(srv.spkm.deref())? .mix(srv.spkm.deref())?
.mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?; .mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?;
@@ -3257,21 +3294,31 @@ impl HandshakeState {
/// Initialize the handshake state with the responder public key and the protocol domain /// Initialize the handshake state with the responder public key and the protocol domain
/// separator /// separator
pub fn init(&mut self, spkr: &[u8]) -> Result<&mut Self> { pub fn init(&mut self, spkr: &[u8]) -> Result<&mut Self> {
self.ck = hash_domains::ckinit(self.ck.shake_or_blake().clone())?.turn_secret().mix(spkr)?.dup(); self.ck = hash_domains::ckinit(self.ck.shake_or_blake().clone())?
.turn_secret()
.mix(spkr)?
.dup();
Ok(self) Ok(self)
} }
/// Mix some data into the chaining key. This is used for mixing cryptographic keys and public /// Mix some data into the chaining key. This is used for mixing cryptographic keys and public
/// data alike into the chaining key /// data alike into the chaining key
pub fn mix(&mut self, a: &[u8]) -> Result<&mut Self> { pub fn mix(&mut self, a: &[u8]) -> Result<&mut Self> {
self.ck = self.ck.mix(&hash_domains::mix(self.ck.shake_or_blake().clone())?)?.mix(a)?.dup(); self.ck = self
.ck
.mix(&hash_domains::mix(self.ck.shake_or_blake().clone())?)?
.mix(a)?
.dup();
Ok(self) Ok(self)
} }
/// Encrypt some data with a value derived from the current chaining key and mix that data /// Encrypt some data with a value derived from the current chaining key and mix that data
/// into the protocol state. /// into the protocol state.
pub fn encrypt_and_mix(&mut self, ct: &mut [u8], pt: &[u8]) -> Result<&mut Self> { pub fn encrypt_and_mix(&mut self, ct: &mut [u8], pt: &[u8]) -> Result<&mut Self> {
let k = self.ck.mix(&hash_domains::hs_enc(self.ck.shake_or_blake().clone())?)?.into_secret(); let k = self
.ck
.mix(&hash_domains::hs_enc(self.ck.shake_or_blake().clone())?)?
.into_secret();
aead::encrypt(ct, k.secret(), &[0u8; aead::NONCE_LEN], &[], pt)?; aead::encrypt(ct, k.secret(), &[0u8; aead::NONCE_LEN], &[], pt)?;
self.mix(ct) self.mix(ct)
} }
@@ -3281,7 +3328,10 @@ impl HandshakeState {
/// Makes sure that the same values are mixed into the chaining that where mixed in on the /// Makes sure that the same values are mixed into the chaining that where mixed in on the
/// sender side. /// sender side.
pub fn decrypt_and_mix(&mut self, pt: &mut [u8], ct: &[u8]) -> Result<&mut Self> { pub fn decrypt_and_mix(&mut self, pt: &mut [u8], ct: &[u8]) -> Result<&mut Self> {
let k = self.ck.mix(&hash_domains::hs_enc(self.ck.shake_or_blake().clone())?)?.into_secret(); let k = self
.ck
.mix(&hash_domains::hs_enc(self.ck.shake_or_blake().clone())?)?
.into_secret();
aead::decrypt(pt, k.secret(), &[0u8; aead::NONCE_LEN], &[], ct)?; aead::decrypt(pt, k.secret(), &[0u8; aead::NONCE_LEN], &[], ct)?;
self.mix(ct) self.mix(ct)
} }
@@ -3373,7 +3423,7 @@ impl HandshakeState {
biscuit_ct: &[u8], biscuit_ct: &[u8],
sidi: SessionId, sidi: SessionId,
sidr: SessionId, sidr: SessionId,
shake_or_blake: EitherShakeOrBlake shake_or_blake: EitherShakeOrBlake,
) -> Result<(PeerPtr, BiscuitId, HandshakeState)> { ) -> Result<(PeerPtr, BiscuitId, HandshakeState)> {
// The first bit of the biscuit indicates which biscuit key was used // The first bit of the biscuit indicates which biscuit key was used
let bk = BiscuitKeyPtr(((biscuit_ct[0] & 0b1000_0000) >> 7) as usize); let bk = BiscuitKeyPtr(((biscuit_ct[0] & 0b1000_0000) >> 7) as usize);
@@ -3404,7 +3454,11 @@ impl HandshakeState {
.find_peer(pid) // TODO: FindPeer should return a Result<()> .find_peer(pid) // TODO: FindPeer should return a Result<()>
.with_context(|| format!("Could not decode biscuit for peer {pid:?}: No such peer."))?; .with_context(|| format!("Could not decode biscuit for peer {pid:?}: No such peer."))?;
let ck = SecretHashDomain::danger_from_secret(Secret::from_slice(&biscuit.ck), peer.get(srv).protocol_version.shake_or_blake()).dup(); let ck = SecretHashDomain::danger_from_secret(
Secret::from_slice(&biscuit.ck),
peer.get(srv).protocol_version.shake_or_blake(),
)
.dup();
// Reconstruct the handshake state // Reconstruct the handshake state
let mut hs = Self { sidi, sidr, ck }; let mut hs = Self { sidi, sidr, ck };
hs.mix(biscuit_ct)?; hs.mix(biscuit_ct)?;
@@ -3417,10 +3471,19 @@ impl HandshakeState {
/// This called by either party. /// This called by either party.
/// ///
/// `role` indicates whether the local peer was an initiator or responder in the handshake. /// `role` indicates whether the local peer was an initiator or responder in the handshake.
pub fn enter_live(self, srv: &CryptoServer, role: HandshakeRole, either_shake_or_blake: EitherShakeOrBlake) -> Result<Session> { pub fn enter_live(
self,
srv: &CryptoServer,
role: HandshakeRole,
either_shake_or_blake: EitherShakeOrBlake,
) -> Result<Session> {
let HandshakeState { ck, sidi, sidr } = self; let HandshakeState { ck, sidi, sidr } = self;
let tki = ck.mix(&hash_domains::ini_enc(either_shake_or_blake.clone())?)?.into_secret(); let tki = ck
let tkr = ck.mix(&hash_domains::res_enc(either_shake_or_blake)?)?.into_secret(); .mix(&hash_domains::ini_enc(either_shake_or_blake.clone())?)?
.into_secret();
let tkr = ck
.mix(&hash_domains::res_enc(either_shake_or_blake)?)?
.into_secret();
let created_at = srv.timebase.now(); let created_at = srv.timebase.now();
let (ntx, nrx) = (0, 0); let (ntx, nrx) = (0, 0);
let (mysid, peersid, ktx, krx) = match role { let (mysid, peersid, ktx, krx) = match role {
@@ -3458,7 +3521,12 @@ impl CryptoServer {
.get(self) .get(self)
.as_ref() .as_ref()
.with_context(|| format!("No current session for peer {:?}", peer))?; .with_context(|| format!("No current session for peer {:?}", peer))?;
Ok(session.ck.mix(&hash_domains::osk(peer.get(self).protocol_version.shake_or_blake())?)?.into_secret()) Ok(session
.ck
.mix(&hash_domains::osk(
peer.get(self).protocol_version.shake_or_blake(),
)?)?
.into_secret())
} }
} }
@@ -3466,7 +3534,10 @@ impl CryptoServer {
/// Core cryptographic protocol implementation: Kicks of the handshake /// Core cryptographic protocol implementation: Kicks of the handshake
/// on the initiator side, producing the InitHello message. /// on the initiator side, producing the InitHello message.
pub fn handle_initiation(&mut self, peer: PeerPtr, ih: &mut InitHello) -> Result<PeerPtr> { pub fn handle_initiation(&mut self, peer: PeerPtr, ih: &mut InitHello) -> Result<PeerPtr> {
let mut hs = InitiatorHandshake::zero_with_timestamp(self, peer.get(self).protocol_version.shake_or_blake()); let mut hs = InitiatorHandshake::zero_with_timestamp(
self,
peer.get(self).protocol_version.shake_or_blake(),
);
// IHI1 // IHI1
hs.core.init(peer.get(self).spkt.deref())?; hs.core.init(peer.get(self).spkt.deref())?;
@@ -3490,8 +3561,11 @@ impl CryptoServer {
)?; )?;
// IHI6 // IHI6
hs.core hs.core.encrypt_and_mix(
.encrypt_and_mix(ih.pidic.as_mut_slice(), self.pidm(peer.get(self).protocol_version.shake_or_blake())?.as_ref())?; ih.pidic.as_mut_slice(),
self.pidm(peer.get(self).protocol_version.shake_or_blake())?
.as_ref(),
)?;
// IHI7 // IHI7
hs.core hs.core
@@ -3510,7 +3584,12 @@ impl CryptoServer {
/// Core cryptographic protocol implementation: Parses an [InitHello] message and produces a /// Core cryptographic protocol implementation: Parses an [InitHello] message and produces a
/// [RespHello] message on the responder side. /// [RespHello] message on the responder side.
/// TODO: Document Hash Functon usage /// TODO: Document Hash Functon usage
pub fn handle_init_hello(&mut self, ih: &InitHello, rh: &mut RespHello, shake_or_blake: EitherShakeOrBlake) -> Result<PeerPtr> { pub fn handle_init_hello(
&mut self,
ih: &InitHello,
rh: &mut RespHello,
shake_or_blake: EitherShakeOrBlake,
) -> Result<PeerPtr> {
let mut core = HandshakeState::zero(shake_or_blake); let mut core = HandshakeState::zero(shake_or_blake);
core.sidi = SessionId::from_slice(&ih.sidi); core.sidi = SessionId::from_slice(&ih.sidi);
@@ -3655,8 +3734,14 @@ impl CryptoServer {
// we still need it for InitConf message retransmission to function. // we still need it for InitConf message retransmission to function.
// ICI7 // ICI7
peer.session() peer.session().insert(
.insert(self, core.enter_live(self, HandshakeRole::Initiator, peer.get(self).protocol_version.shake_or_blake())?)?; self,
core.enter_live(
self,
HandshakeRole::Initiator,
peer.get(self).protocol_version.shake_or_blake(),
)?,
)?;
hs_mut!().core.erase(); hs_mut!().core.erase();
hs_mut!().next = HandshakeStateMachine::RespConf; hs_mut!().next = HandshakeStateMachine::RespConf;
@@ -3669,7 +3754,12 @@ impl CryptoServer {
/// This concludes the handshake on the cryptographic level; the [EmptyData] message is just /// This concludes the handshake on the cryptographic level; the [EmptyData] message is just
/// an acknowledgement message telling the initiator to stop performing retransmissions. /// an acknowledgement message telling the initiator to stop performing retransmissions.
/// TODO: documentation /// TODO: documentation
pub fn handle_init_conf(&mut self, ic: &InitConf, rc: &mut EmptyData, shake_or_blake: EitherShakeOrBlake) -> Result<PeerPtr> { pub fn handle_init_conf(
&mut self,
ic: &InitConf,
rc: &mut EmptyData,
shake_or_blake: EitherShakeOrBlake,
) -> Result<PeerPtr> {
// (peer, bn) ← LoadBiscuit(InitConf.biscuit) // (peer, bn) ← LoadBiscuit(InitConf.biscuit)
// ICR1 // ICR1
let (peer, biscuit_no, mut core) = HandshakeState::load_biscuit( let (peer, biscuit_no, mut core) = HandshakeState::load_biscuit(
@@ -3702,8 +3792,14 @@ impl CryptoServer {
peer.get_mut(self).biscuit_used = biscuit_no; peer.get_mut(self).biscuit_used = biscuit_no;
// ICR7 // ICR7
peer.session() peer.session().insert(
.insert(self, core.enter_live(self, HandshakeRole::Responder, peer.get(self).protocol_version.shake_or_blake())?)?; self,
core.enter_live(
self,
HandshakeRole::Responder,
peer.get(self).protocol_version.shake_or_blake(),
)?,
)?;
// TODO: This should be part of the protocol specification. // TODO: This should be part of the protocol specification.
// Abort any ongoing handshake from initiator role // Abort any ongoing handshake from initiator role
peer.hs().take(self); peer.hs().take(self);
@@ -3751,13 +3847,20 @@ impl CryptoServer {
/// message then terminates the handshake. /// message then terminates the handshake.
/// ///
/// The EmptyData message is just there to tell the initiator to abort retransmissions. /// The EmptyData message is just there to tell the initiator to abort retransmissions.
pub fn handle_resp_conf(&mut self, msg_in: &Ref<&[u8], Envelope<EmptyData>>, seal_broken: String) -> Result<PeerPtr> { pub fn handle_resp_conf(
&mut self,
msg_in: &Ref<&[u8], Envelope<EmptyData>>,
seal_broken: String,
) -> Result<PeerPtr> {
let rc: &EmptyData = &msg_in.payload; let rc: &EmptyData = &msg_in.payload;
let sid = SessionId::from_slice(&rc.sid); let sid = SessionId::from_slice(&rc.sid);
let hs = self let hs = self
.lookup_handshake(sid) .lookup_handshake(sid)
.with_context(|| format!("Got RespConf packet for non-existent session {sid:?}"))?; .with_context(|| format!("Got RespConf packet for non-existent session {sid:?}"))?;
ensure!(msg_in.check_seal(self, hs.peer().get(self).protocol_version.shake_or_blake())?, seal_broken); ensure!(
msg_in.check_seal(self, hs.peer().get(self).protocol_version.shake_or_blake())?,
seal_broken
);
let ses = hs.peer().session(); let ses = hs.peer().session();
let exp = hs.get(self).as_ref().map(|h| h.next); let exp = hs.get(self).as_ref().map(|h| h.next);
@@ -3840,7 +3943,9 @@ impl CryptoServer {
}?; }?;
let spkt = peer.get(self).spkt.deref(); let spkt = peer.get(self).spkt.deref();
let cookie_key = hash_domains::cookie_key(EitherShakeOrBlake::Left(SHAKE256Core))?.mix(spkt)?.into_value(); let cookie_key = hash_domains::cookie_key(EitherShakeOrBlake::Left(SHAKE256Core))?
.mix(spkt)?
.into_value();
let cookie_value = peer.cv().update_mut(self).unwrap(); let cookie_value = peer.cv().update_mut(self).unwrap();
xaead::decrypt(cookie_value, &cookie_key, &mac, &cr.inner.cookie_encrypted)?; xaead::decrypt(cookie_value, &cookie_key, &mac, &cr.inner.cookie_encrypted)?;
@@ -3969,7 +4074,6 @@ mod test {
handles_incorrect_size_messages(ProtocolVersion::V03) handles_incorrect_size_messages(ProtocolVersion::V03)
} }
/// Ensure that the protocol implementation can deal with truncated /// Ensure that the protocol implementation can deal with truncated
/// messages and with overlong messages. /// messages and with overlong messages.
/// ///
@@ -4268,20 +4372,21 @@ mod test {
assert_eq!(PeerPtr(0).cv().lifecycle(&a), Lifecycle::Young); assert_eq!(PeerPtr(0).cv().lifecycle(&a), Lifecycle::Young);
let expected_cookie_value = hash_domains::cookie_value(protocol_version.shake_or_blake()) let expected_cookie_value =
.unwrap() hash_domains::cookie_value(protocol_version.shake_or_blake())
.mix( .unwrap()
b.active_or_retired_cookie_secrets()[0] .mix(
.unwrap() b.active_or_retired_cookie_secrets()[0]
.get(&b) .unwrap()
.value .get(&b)
.secret(), .value
) .secret(),
.unwrap() )
.mix(ip_addr_port_a.encode()) .unwrap()
.unwrap() .mix(ip_addr_port_a.encode())
.into_value()[..16] .unwrap()
.to_vec(); .into_value()[..16]
.to_vec();
assert_eq!( assert_eq!(
PeerPtr(0).cv().get(&a).map(|x| &x.value.secret()[..]), PeerPtr(0).cv().get(&a).map(|x| &x.value.secret()[..]),
@@ -4331,7 +4436,9 @@ mod test {
cookie_reply_mechanism_initiator_bails_on_message_under_load(ProtocolVersion::V03) cookie_reply_mechanism_initiator_bails_on_message_under_load(ProtocolVersion::V03)
} }
fn cookie_reply_mechanism_initiator_bails_on_message_under_load(protocol_version: ProtocolVersion) { fn cookie_reply_mechanism_initiator_bails_on_message_under_load(
protocol_version: ProtocolVersion,
) {
setup_logging(); setup_logging();
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets(); rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
stacker::grow(8 * 1024 * 1024, || { stacker::grow(8 * 1024 * 1024, || {
@@ -4409,10 +4516,7 @@ mod test {
Ok((sk, pk)) Ok((sk, pk))
} }
fn proc_initiation( fn proc_initiation(srv: &mut CryptoServer, peer: PeerPtr) -> Result<Envelope<InitHello>> {
srv: &mut CryptoServer,
peer: PeerPtr,
) -> Result<Envelope<InitHello>> {
let mut buf = MsgBuf::zero(); let mut buf = MsgBuf::zero();
srv.initiate_handshake(peer, buf.as_mut_slice())? srv.initiate_handshake(peer, buf.as_mut_slice())?
.discard_result(); .discard_result();
@@ -4482,8 +4586,12 @@ mod test {
assert!(res.is_err()); assert!(res.is_err());
} }
// we this as a closure in orer to use the protocol_version variable in it. // we this as a closure in orer to use the protocol_version variable in it.
let check_retransmission = |srv: &mut CryptoServer, ic: &Envelope<InitConf>, ic_broken: &Envelope<InitConf>, rc: &Envelope<EmptyData>| -> Result<()> { let check_retransmission = |srv: &mut CryptoServer,
ic: &Envelope<InitConf>,
ic_broken: &Envelope<InitConf>,
rc: &Envelope<EmptyData>|
-> Result<()> {
// Processing the same RespHello package again leads to retransmission (i.e. exactly the // Processing the same RespHello package again leads to retransmission (i.e. exactly the
// same output) // same output)
let rc_dup = proc_init_conf(srv, ic)?; let rc_dup = proc_init_conf(srv, ic)?;
@@ -4492,7 +4600,11 @@ mod test {
// Though if we directly call handle_resp_hello() we get an error since // Though if we directly call handle_resp_hello() we get an error since
// retransmission is not being handled by the cryptographic code // retransmission is not being handled by the cryptographic code
let mut discard_resp_conf = EmptyData::new_zeroed(); let mut discard_resp_conf = EmptyData::new_zeroed();
let res = srv.handle_init_conf(&ic.payload, &mut discard_resp_conf, protocol_version.clone().shake_or_blake()); let res = srv.handle_init_conf(
&ic.payload,
&mut discard_resp_conf,
protocol_version.clone().shake_or_blake(),
);
assert!(res.is_err()); assert!(res.is_err());
// Obviously, a broken InitConf message should still be rejected // Obviously, a broken InitConf message should still be rejected

View File

@@ -14,6 +14,8 @@ use rosenpass::api::{
self, add_listen_socket_response_status, add_psk_broker_response_status, self, add_listen_socket_response_status, add_psk_broker_response_status,
supply_keypair_response_status, supply_keypair_response_status,
}; };
use rosenpass::config::ProtocolVersion;
use rosenpass::protocol::SymKey;
use rosenpass_util::{ use rosenpass_util::{
b64::B64Display, b64::B64Display,
file::LoadValueB64, file::LoadValueB64,
@@ -26,8 +28,6 @@ use rosenpass_util::{
use std::os::fd::{AsFd, AsRawFd}; use std::os::fd::{AsFd, AsRawFd};
use tempfile::TempDir; use tempfile::TempDir;
use zerocopy::AsBytes; use zerocopy::AsBytes;
use rosenpass::config::ProtocolVersion;
use rosenpass::protocol::SymKey;
struct KillChild(std::process::Child); struct KillChild(std::process::Child);

View File

@@ -16,8 +16,8 @@ use rosenpass_util::{mem::DiscardResultExt, zerocopy::ZerocopySliceExt};
use tempfile::TempDir; use tempfile::TempDir;
use zerocopy::AsBytes; use zerocopy::AsBytes;
use rosenpass::protocol::SymKey;
use rosenpass::config::ProtocolVersion; use rosenpass::config::ProtocolVersion;
use rosenpass::protocol::SymKey;
struct KillChild(std::process::Child); struct KillChild(std::process::Child);
@@ -46,7 +46,6 @@ fn api_integration_test_v03() -> anyhow::Result<()> {
api_integration_test(ProtocolVersion::V03) api_integration_test(ProtocolVersion::V03)
} }
fn api_integration_test(protocol_version: ProtocolVersion) -> anyhow::Result<()> { fn api_integration_test(protocol_version: ProtocolVersion) -> anyhow::Result<()> {
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets(); rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();

View File

@@ -9,11 +9,11 @@ use std::{
}; };
use anyhow::ensure; use anyhow::ensure;
use rosenpass::config::ProtocolVersion;
use rosenpass::{ use rosenpass::{
app_server::{ipv4_any_binding, ipv6_any_binding, AppServer, AppServerTest, MAX_B64_KEY_SIZE}, app_server::{ipv4_any_binding, ipv6_any_binding, AppServer, AppServerTest, MAX_B64_KEY_SIZE},
protocol::{SPk, SSk, SymKey}, protocol::{SPk, SSk, SymKey},
}; };
use rosenpass::config::ProtocolVersion;
use rosenpass_cipher_traits::Kem; use rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::kem::StaticKem; use rosenpass_ciphers::kem::StaticKem;
use rosenpass_secret_memory::Secret; use rosenpass_secret_memory::Secret;
@@ -66,8 +66,14 @@ fn key_exchange_with_app_server(protocol_version: ProtocolVersion) -> anyhow::Re
let outfile = Some(osk); let outfile = Some(osk);
let port = otr_port; let port = otr_port;
let hostname = is_client.then(|| format!("[::1]:{port}")); let hostname = is_client.then(|| format!("[::1]:{port}"));
srv.app_srv srv.app_srv.add_peer(
.add_peer(psk, pk, outfile, broker_peer, hostname, protocol_version.clone())?; psk,
pk,
outfile,
broker_peer,
hostname,
protocol_version.clone(),
)?;
srv.app_srv.event_loop() srv.app_srv.event_loop()
}) })

View File

@@ -9,7 +9,10 @@ use rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::kem::StaticKem; use rosenpass_ciphers::kem::StaticKem;
use rosenpass_util::result::OkExt; use rosenpass_util::result::OkExt;
use rosenpass::protocol::{testutils::time_travel_forward, CryptoServer, HostIdentification, MsgBuf, PeerPtr, PollResult, ProtocolVersion, SPk, SSk, SymKey, Timing, UNENDING}; use rosenpass::protocol::{
testutils::time_travel_forward, CryptoServer, HostIdentification, MsgBuf, PeerPtr, PollResult,
ProtocolVersion, SPk, SSk, SymKey, Timing, UNENDING,
};
// TODO: Most of the utility functions in here should probably be moved to // TODO: Most of the utility functions in here should probably be moved to
// rosenpass::protocol::testutils; // rosenpass::protocol::testutils;
@@ -94,7 +97,9 @@ fn test_successful_exchange_under_packet_loss_v03() -> anyhow::Result<()> {
test_successful_exchange_under_packet_loss(ProtocolVersion::V03) test_successful_exchange_under_packet_loss(ProtocolVersion::V03)
} }
fn test_successful_exchange_under_packet_loss(protocol_version: ProtocolVersion) -> anyhow::Result<()> { fn test_successful_exchange_under_packet_loss(
protocol_version: ProtocolVersion,
) -> anyhow::Result<()> {
// Set security policy for storing secrets; choose the one that is faster for testing // Set security policy for storing secrets; choose the one that is faster for testing
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets(); rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();