refactor: replace lenses library with the zerocopy crate

This commit is contained in:
Aaron Kaiser
2024-02-06 15:33:59 +01:00
committed by Karolin Varner
parent e38a6b8ed4
commit a996b08279
10 changed files with 194 additions and 426 deletions

31
Cargo.lock generated
View File

@@ -1131,7 +1131,6 @@ dependencies = [
"rosenpass-cipher-traits", "rosenpass-cipher-traits",
"rosenpass-ciphers", "rosenpass-ciphers",
"rosenpass-constant-time", "rosenpass-constant-time",
"rosenpass-lenses",
"rosenpass-secret-memory", "rosenpass-secret-memory",
"rosenpass-to", "rosenpass-to",
"rosenpass-util", "rosenpass-util",
@@ -1141,6 +1140,7 @@ dependencies = [
"test_bin", "test_bin",
"thiserror", "thiserror",
"toml", "toml",
"zerocopy",
] ]
[[package]] [[package]]
@@ -1185,14 +1185,6 @@ dependencies = [
"stacker", "stacker",
] ]
[[package]]
name = "rosenpass-lenses"
version = "0.1.0"
dependencies = [
"paste",
"thiserror",
]
[[package]] [[package]]
name = "rosenpass-oqs" name = "rosenpass-oqs"
version = "0.1.0" version = "0.1.0"
@@ -1848,6 +1840,27 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "zerocopy"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "zeroize" name = "zeroize"
version = "1.7.0" version = "1.7.0"

View File

@@ -11,7 +11,6 @@ members = [
"to", "to",
"fuzz", "fuzz",
"secret-memory", "secret-memory",
"lenses",
] ]
default-members = [ default-members = [
@@ -31,7 +30,6 @@ rosenpass-ciphers = { path = "ciphers" }
rosenpass-to = { path = "to" } rosenpass-to = { path = "to" }
rosenpass-secret-memory = { path = "secret-memory" } rosenpass-secret-memory = { path = "secret-memory" }
rosenpass-oqs = { path = "oqs" } rosenpass-oqs = { path = "oqs" }
rosenpass-lenses = { path = "lenses" }
criterion = "0.4.0" criterion = "0.4.0"
test_bin = "0.4.0" test_bin = "0.4.0"
libfuzzer-sys = "0.4" libfuzzer-sys = "0.4"
@@ -59,3 +57,4 @@ mio = { version = "0.8.9", features = ["net", "os-poll"] }
oqs-sys = { version = "0.8", default-features = false, features = ['classic_mceliece', 'kyber'] } oqs-sys = { version = "0.8", default-features = false, features = ['classic_mceliece', 'kyber'] }
blake2 = "0.10.6" blake2 = "0.10.6"
chacha20poly1305 = { version = "0.10.1", default-features = false, features = [ "std", "heapless" ] } chacha20poly1305 = { version = "0.10.1", default-features = false, features = [ "std", "heapless" ] }
zerocopy = { version = "0.7.32", features = ["derive"] }

View File

@@ -112,9 +112,9 @@
# suitable Rust toolchain # suitable Rust toolchain
toolchain = with inputs.fenix.packages.${system}; combine [ toolchain = with inputs.fenix.packages.${system}; combine [
stable.cargo latest.cargo
stable.rustc latest.rustc
targets.${target}.stable.rust-std targets.${target}.latest.rust-std
]; ];
# naersk with a custom toolchain # naersk with a custom toolchain

View File

@@ -1,16 +0,0 @@
[package]
name = "rosenpass-lenses"
version = "0.1.0"
authors = ["Karolin Varner <karo@cupdev.net>", "wucke13 <wucke13@gmail.com>"]
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Rosenpass internal library for parsing binary data securely"
homepage = "https://rosenpass.eu/"
repository = "https://github.com/rosenpass/rosenpass"
readme = "readme.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
paste = { workspace = true }
thiserror = { workspace = true }

View File

@@ -1,3 +0,0 @@
# Rosenpass internal binary parsing library
This is an internal library; no guarantee is made about its API at this point in time.

View File

@@ -1,206 +0,0 @@
use std::result::Result;
/// Common trait shared by all Lenses
pub trait LenseView {
const LEN: usize;
}
/// Error during lense creation
#[derive(thiserror::Error, Debug, Eq, PartialEq, Clone)]
pub enum LenseError {
#[error("buffer size mismatch")]
BufferSizeMismatch,
}
pub type LenseResult<T> = Result<T, LenseError>;
impl LenseError {
pub fn ensure_exact_buffer_size(len: usize, required: usize) -> LenseResult<()> {
(len == required)
.then_some(())
.ok_or(LenseError::BufferSizeMismatch)
}
pub fn ensure_sufficient_buffer_size(len: usize, required: usize) -> LenseResult<()> {
(len >= required)
.then_some(())
.ok_or(LenseError::BufferSizeMismatch)
}
}
/// A macro to create data lenses.
#[macro_export]
macro_rules! lense(
// prefix @ offset ; optional meta ; field name : field length, ...
(token_muncher_ref @ $offset:expr ; $( $attr:meta )* ; $field:ident : $len:expr $(, $( $tail:tt )+ )?) => {
::paste::paste!{
#[allow(rustdoc::broken_intra_doc_links)]
$( #[ $attr ] )*
///
#[doc = lense!(maybe_docstring_link $len)]
/// bytes long
pub fn $field(&self) -> &__ContainerType::Output {
&self.0[$offset .. $offset + $len]
}
/// The bytes until the
#[doc = lense!(maybe_docstring_link Self::$field)]
/// field
pub fn [< until_ $field >](&self) -> &__ContainerType::Output {
&self.0[0 .. $offset]
}
// if the tail exits, consume it as well
$(
lense!{token_muncher_ref @ $offset + $len ; $( $tail )+ }
)?
}
};
// prefix @ offset ; optional meta ; field name : field length, ...
(token_muncher_mut @ $offset:expr ; $( $attr:meta )* ; $field:ident : $len:expr $(, $( $tail:tt )+ )?) => {
::paste::paste!{
#[allow(rustdoc::broken_intra_doc_links)]
$( #[ $attr ] )*
///
#[doc = lense!(maybe_docstring_link $len)]
/// bytes long
pub fn [< $field _mut >](&mut self) -> &mut __ContainerType::Output {
&mut self.0[$offset .. $offset + $len]
}
// if the tail exits, consume it as well
$(
lense!{token_muncher_mut @ $offset + $len ; $( $tail )+ }
)?
}
};
// switch that yields literals unchanged, but creates docstring links to
// constants
// TODO the doc string link doesn't work if $x is taken from a generic,
(maybe_docstring_link $x:literal) => (stringify!($x));
(maybe_docstring_link $x:expr) => (stringify!([$x]));
// struct name < optional generics > := optional doc string field name : field length, ...
($type:ident $( < $( $generic:ident ),+ > )? := $( $( #[ $attr:meta ] )* $field:ident : $len:expr ),+) => (::paste::paste!{
#[allow(rustdoc::broken_intra_doc_links)]
/// A data lense to manipulate byte slices.
///
//// # Fields
///
$(
/// - `
#[doc = stringify!($field)]
/// `:
#[doc = lense!(maybe_docstring_link $len)]
/// bytes
)+
pub struct $type<__ContainerType $(, $( $generic ),+ )? > (
__ContainerType,
// The phantom data is required, since all generics declared on a
// type need to be used on the type.
// https://doc.rust-lang.org/stable/error_codes/E0392.html
$( $( ::core::marker::PhantomData<$generic> ),+ )?
);
impl<__ContainerType $(, $( $generic: LenseView ),+ )? > $type<__ContainerType $(, $( $generic ),+ )? >{
$(
/// Size in bytes of the field `
#[doc = !($field)]
/// `
pub const fn [< $field _len >]() -> usize{
$len
}
)+
/// Verify that `len` exactly holds [Self]
pub fn check_size(len: usize) -> ::rosenpass_lenses::LenseResult<()> {
::rosenpass_lenses::LenseError::ensure_exact_buffer_size(len, $( $len + )+ 0)
}
}
// read-only accessor functions
impl<'a, __ContainerType $(, $( $generic: LenseView ),+ )?> $type<&'a __ContainerType $(, $( $generic ),+ )?>
where
__ContainerType: std::ops::Index<std::ops::Range<usize>> + ?Sized,
{
lense!{token_muncher_ref @ 0 ; $( $( $attr )* ; $field : $len ),+ }
/// View into all bytes belonging to this Lense
pub fn all_bytes(&self) -> &__ContainerType::Output {
&self.0[0..Self::LEN]
}
}
// mutable accessor functions
impl<'a, __ContainerType $(, $( $generic: LenseView ),+ )?> $type<&'a mut __ContainerType $(, $( $generic ),+ )?>
where
__ContainerType: std::ops::IndexMut<std::ops::Range<usize>> + ?Sized,
{
lense!{token_muncher_ref @ 0 ; $( $( $attr )* ; $field : $len ),+ }
lense!{token_muncher_mut @ 0 ; $( $( $attr )* ; $field : $len ),+ }
/// View into all bytes belonging to this Lense
pub fn all_bytes(&self) -> &__ContainerType::Output {
&self.0[0..Self::LEN]
}
/// View into all bytes belonging to this Lense
pub fn all_bytes_mut(&mut self) -> &mut __ContainerType::Output {
&mut self.0[0..Self::LEN]
}
}
// lense trait, allowing us to know the implementing lenses size
impl<__ContainerType $(, $( $generic: LenseView ),+ )? > LenseView for $type<__ContainerType $(, $( $generic ),+ )? >{
/// Number of bytes required to store this type in binary format
const LEN: usize = $( $len + )+ 0;
}
/// Extension trait to allow checked creation of a lense over
/// some byte slice that contains a
#[doc = lense!(maybe_docstring_link $type)]
pub trait [< $type Ext >] {
type __ContainerType;
/// Create a lense to the byte slice
fn [< $type:snake >] $(< $($generic : LenseView),* >)? (self) -> ::rosenpass_lenses::LenseResult< $type<Self::__ContainerType, $( $($generic),+ )? >>;
/// Create a lense to the byte slice, automatically truncating oversized buffers
fn [< $type:snake _ truncating >] $(< $($generic : LenseView),* >)? (self) -> ::rosenpass_lenses::LenseResult< $type<Self::__ContainerType, $( $($generic),+ )? >>;
}
impl<'a> [< $type Ext >] for &'a [u8] {
type __ContainerType = &'a [u8];
fn [< $type:snake >] $(< $($generic : LenseView),* >)? (self) -> ::rosenpass_lenses::LenseResult< $type<Self::__ContainerType, $( $($generic),+ )? >> {
$type::<Self::__ContainerType, $( $($generic),+ )? >::check_size(self.len())?;
Ok($type ( self, $( $( ::core::marker::PhantomData::<$generic> ),+ )? ))
}
fn [< $type:snake _ truncating >] $(< $($generic : LenseView),* >)? (self) -> ::rosenpass_lenses::LenseResult< $type<Self::__ContainerType, $( $($generic),+ )? >> {
let required_size = $( $len + )+ 0;
::rosenpass_lenses::LenseError::ensure_sufficient_buffer_size(self.len(), required_size)?;
[< $type Ext >]::[< $type:snake >](&self[..required_size])
}
}
impl<'a> [< $type Ext >] for &'a mut [u8] {
type __ContainerType = &'a mut [u8];
fn [< $type:snake >] $(< $($generic : LenseView),* >)? (self) -> ::rosenpass_lenses::LenseResult< $type<Self::__ContainerType, $( $($generic),+ )? >> {
$type::<Self::__ContainerType, $( $($generic),+ )? >::check_size(self.len())?;
Ok($type ( self, $( $( ::core::marker::PhantomData::<$generic> ),+ )? ))
}
fn [< $type:snake _ truncating >] $(< $($generic : LenseView),* >)? (self) -> ::rosenpass_lenses::LenseResult< $type<Self::__ContainerType, $( $($generic),+ )? >> {
let required_size = $( $len + )+ 0;
::rosenpass_lenses::LenseError::ensure_sufficient_buffer_size(self.len(), required_size)?;
[< $type Ext >]::[< $type:snake >](&mut self[..required_size])
}
}
});
);

View File

@@ -20,7 +20,6 @@ rosenpass-ciphers = { workspace = true }
rosenpass-cipher-traits = { workspace = true } rosenpass-cipher-traits = { workspace = true }
rosenpass-to = { workspace = true } rosenpass-to = { workspace = true }
rosenpass-secret-memory = { workspace = true } rosenpass-secret-memory = { workspace = true }
rosenpass-lenses = { workspace = true }
anyhow = { workspace = true } anyhow = { workspace = true }
static_assertions = { workspace = true } static_assertions = { workspace = true }
memoffset = { workspace = true } memoffset = { workspace = true }
@@ -33,6 +32,7 @@ toml = { workspace = true }
clap = { workspace = true } clap = { workspace = true }
mio = { workspace = true } mio = { workspace = true }
rand = { workspace = true } rand = { workspace = true }
zerocopy = { workspace = true }
[build-dependencies] [build-dependencies]
anyhow = { workspace = true } anyhow = { workspace = true }

View File

@@ -1,4 +1,4 @@
use rosenpass_lenses::LenseError; #![feature(offset_of)]
pub mod app_server; pub mod app_server;
pub mod cli; pub mod cli;
@@ -15,10 +15,3 @@ pub enum RosenpassError {
InvalidMessageType(u8), InvalidMessageType(u8),
} }
impl From<LenseError> for RosenpassError {
fn from(value: LenseError) -> Self {
match value {
LenseError::BufferSizeMismatch => RosenpassError::BufferSizeMismatch,
}
}
}

View File

@@ -6,129 +6,111 @@
//! always serialized instance of the data in question. This is closely related //! always serialized instance of the data in question. This is closely related
//! to the concept of lenses in function programming; more on that here: //! to the concept of lenses in function programming; more on that here:
//! [https://sinusoid.es/misc/lager/lenses.pdf](https://sinusoid.es/misc/lager/lenses.pdf) //! [https://sinusoid.es/misc/lager/lenses.pdf](https://sinusoid.es/misc/lager/lenses.pdf)
//! //! To achieve this we utilize the zerocopy library.
//! # Example
//!
//! The following example uses the [`lense` macro](rosenpass_lenses::lense) to create a lense that
//! might be useful when dealing with UDP headers.
//!
//! ```
//! use rosenpass_lenses::{lense, LenseView};
//! use rosenpass::RosenpassError;
//! # fn main() -> Result<(), RosenpassError> {
//!
//! lense! {UdpDatagramHeader :=
//! source_port: 2,
//! dest_port: 2,
//! length: 2,
//! checksum: 2
//! }
//!
//! let mut buf = [0u8; 8];
//!
//! // read-only lense, no check of size:
//! let lense = UdpDatagramHeader(&buf);
//! assert_eq!(lense.checksum(), &[0, 0]);
//!
//! // mutable lense, runtime check of size
//! let mut lense = buf.as_mut().udp_datagram_header()?;
//! lense.source_port_mut().copy_from_slice(&53u16.to_be_bytes()); // some DNS, anyone?
//!
//! // the original buffer is still available
//! assert_eq!(buf, [0, 53, 0, 0, 0, 0, 0, 0]);
//!
//! // read-only lense, runtime check of size
//! let lense = buf.as_ref().udp_datagram_header()?;
//! assert_eq!(lense.source_port(), &[0, 53]);
//! # Ok(())
//! # }
//! ```
use super::RosenpassError; use super::RosenpassError;
use std::mem::size_of;
use rosenpass_cipher_traits::Kem; use rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::kem::{EphemeralKem, StaticKem}; use rosenpass_ciphers::kem::{EphemeralKem, StaticKem};
use rosenpass_ciphers::{aead, xaead, KEY_LEN}; use rosenpass_ciphers::{aead, xaead, KEY_LEN};
use rosenpass_lenses::{lense, LenseView}; use zerocopy::{AsBytes, FromBytes, FromZeroes};
// Macro magic //////////////////////////////////////////////////////////////// // Macro magic ////////////////////////////////////////////////////////////////
lense! { Envelope<M> :=
#[repr(packed)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct Envelope<M: AsBytes + FromBytes> {
/// [MsgType] of this message /// [MsgType] of this message
msg_type: 1, pub msg_type: u8,
/// Reserved for future use /// Reserved for future use
reserved: 3, pub reserved: [u8; 3],
/// The actual Paylod /// The actual Paylod
payload: M::LEN, pub payload: M,
/// Message Authentication Code (mac) over all bytes until (exclusive) /// Message Authentication Code (mac) over all bytes until (exclusive)
/// `mac` itself /// `mac` itself
mac: 16, pub mac: [u8; 16],
/// Currently unused, TODO: do something with this /// Currently unused, TODO: do something with this
cookie: 16 pub cookie: [u8; 16]
} }
lense! { InitHello := #[repr(packed)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct InitHello {
/// Randomly generated connection id /// Randomly generated connection id
sidi: 4, pub sidi: [u8; 4],
/// Kyber 512 Ephemeral Public Key /// Kyber 512 Ephemeral Public Key
epki: EphemeralKem::PK_LEN, pub epki: [u8; EphemeralKem::PK_LEN],
/// Classic McEliece Ciphertext /// Classic McEliece Ciphertext
sctr: StaticKem::CT_LEN, pub sctr: [u8; StaticKem::CT_LEN],
/// Encryped: 16 byte hash of McEliece initiator static key /// Encryped: 16 byte hash of McEliece initiator static key
pidic: aead::TAG_LEN + 32, pub pidic: [u8; aead::TAG_LEN + 32],
/// Encrypted TAI64N Time Stamp (against replay attacks) /// Encrypted TAI64N Time Stamp (against replay attacks)
auth: aead::TAG_LEN pub auth: [u8; aead::TAG_LEN],
} }
lense! { RespHello := #[repr(packed)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct RespHello {
/// Randomly generated connection id /// Randomly generated connection id
sidr: 4, pub sidr: [u8; 4],
/// Copied from InitHello /// Copied from InitHello
sidi: 4, pub sidi: [u8; 4],
/// Kyber 512 Ephemeral Ciphertext /// Kyber 512 Ephemeral Ciphertext
ecti: EphemeralKem::CT_LEN, pub ecti: [u8; EphemeralKem::CT_LEN],
/// Classic McEliece Ciphertext /// Classic McEliece Ciphertext
scti: StaticKem::CT_LEN, pub scti: [u8; StaticKem::CT_LEN],
/// Empty encrypted message (just an auth tag) /// Empty encrypted message (just an auth tag)
auth: aead::TAG_LEN, pub auth: [u8; aead::TAG_LEN],
/// Responders handshake state in encrypted form /// Responders handshake state in encrypted form
biscuit: BISCUIT_CT_LEN pub biscuit: [u8; BISCUIT_CT_LEN],
} }
lense! { InitConf := #[repr(packed)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct InitConf {
/// Copied from InitHello /// Copied from InitHello
sidi: 4, pub sidi: [u8; 4],
/// Copied from RespHello /// Copied from RespHello
sidr: 4, pub sidr: [u8; 4],
/// Responders handshake state in encrypted form /// Responders handshake state in encrypted form
biscuit: BISCUIT_CT_LEN, pub biscuit: [u8; BISCUIT_CT_LEN],
/// Empty encrypted message (just an auth tag) /// Empty encrypted message (just an auth tag)
auth: aead::TAG_LEN pub auth: [u8; aead::TAG_LEN]
} }
lense! { EmptyData := #[repr(packed)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct EmptyData {
/// Copied from RespHello /// Copied from RespHello
sid: 4, pub sid: [u8; 4],
/// Nonce /// Nonce
ctr: 8, pub ctr: [u8; 8],
/// Empty encrypted message (just an auth tag) /// Empty encrypted message (just an auth tag)
auth: aead::TAG_LEN pub auth: [u8; aead::TAG_LEN]
} }
lense! { Biscuit := #[repr(packed)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct Biscuit {
/// H(spki) Ident ifies the initiator /// H(spki) Ident ifies the initiator
pidi: KEY_LEN, pub pidi: [u8; KEY_LEN],
/// The biscuit number (replay protection) /// The biscuit number (replay protection)
biscuit_no: 12, pub biscuit_no: [u8; 12],
/// Chaining key /// Chaining key
ck: KEY_LEN pub ck: [u8; KEY_LEN]
} }
lense! { DataMsg := #[repr(packed)]
dummy: 4 #[derive(AsBytes, FromBytes, FromZeroes)]
pub struct DataMsg {
pub dummy: [u8; 4]
} }
lense! { CookieReply := #[repr(packed)]
dummy: 4 #[derive(AsBytes, FromBytes, FromZeroes)]
pub struct CookieReply {
pub dummy: [u8; 4]
} }
// Traits ///////////////////////////////////////////////////////////////////// // Traits /////////////////////////////////////////////////////////////////////
@@ -178,7 +160,7 @@ impl TryFrom<u8> for MsgType {
} }
/// length in bytes of an unencrypted Biscuit (plain text) /// length in bytes of an unencrypted Biscuit (plain text)
pub const BISCUIT_PT_LEN: usize = Biscuit::<()>::LEN; pub const BISCUIT_PT_LEN: usize = size_of::<Biscuit>();
/// Length in bytes of an encrypted Biscuit (cipher text) /// Length in bytes of an encrypted Biscuit (cipher text)
pub const BISCUIT_CT_LEN: usize = BISCUIT_PT_LEN + xaead::NONCE_LEN + xaead::TAG_LEN; pub const BISCUIT_CT_LEN: usize = BISCUIT_PT_LEN + xaead::NONCE_LEN + xaead::TAG_LEN;

View File

@@ -70,6 +70,7 @@ use std::collections::hash_map::{
HashMap, HashMap,
}; };
use std::convert::Infallible; use std::convert::Infallible;
use std::mem::{size_of,offset_of};
use anyhow::{bail, ensure, Context, Result}; use anyhow::{bail, ensure, Context, Result};
@@ -78,18 +79,18 @@ use rosenpass_ciphers::hash_domain::{SecretHashDomain, SecretHashDomainNamespace
use rosenpass_ciphers::kem::{EphemeralKem, StaticKem}; use rosenpass_ciphers::kem::{EphemeralKem, StaticKem};
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_lenses::LenseView;
use rosenpass_secret_memory::{Public, Secret}; use rosenpass_secret_memory::{Public, Secret};
use rosenpass_util::{cat, mem::cpy_min, ord::max_usize, time::Timebase}; use rosenpass_util::{cat, mem::cpy_min, ord::max_usize, time::Timebase};
use zerocopy::{AsBytes, FromBytes, Ref};
use crate::{hash_domains, msgs::*}; use crate::{hash_domains, msgs::*, RosenpassError};
// CONSTANTS & SETTINGS ////////////////////////// // CONSTANTS & SETTINGS //////////////////////////
/// Size required to fit any message in binary form /// Size required to fit any message in binary form
pub const RTX_BUFFER_SIZE: usize = max_usize( pub const RTX_BUFFER_SIZE: usize = max_usize(
<Envelope<(), InitHello<()>> as LenseView>::LEN, size_of::<Envelope<InitHello>>(),
<Envelope<(), InitConf<()>> as LenseView>::LEN, size_of::<Envelope<InitConf>>()
); );
/// A type for time, e.g. for backoff before re-tries /// A type for time, e.g. for backoff before re-tries
@@ -739,11 +740,12 @@ impl CryptoServer {
// TODO remove unnecessary copying between global tx_buf and per-peer buf // TODO remove unnecessary copying between global tx_buf and per-peer buf
// TODO move retransmission storage to io server // TODO move retransmission storage to io server
pub fn initiate_handshake(&mut self, peer: PeerPtr, tx_buf: &mut [u8]) -> Result<usize> { pub fn initiate_handshake(&mut self, peer: PeerPtr, tx_buf: &mut [u8]) -> Result<usize> {
let mut msg = tx_buf.envelope_truncating::<InitHello<()>>()?; // Envelope::<InitHello>::default(); // TODO // Envelope::<InitHello>::default(); // TODO
self.handle_initiation(peer, msg.payload_mut().init_hello()?)?; let mut msg = truncating_cast_into::<Envelope<InitHello>>(tx_buf)?;
let len = self.seal_and_commit_msg(peer, MsgType::InitHello, msg)?; self.handle_initiation(peer, &mut msg.payload)?;
let len = self.seal_and_commit_msg(peer, MsgType::InitHello, &mut msg)?;
peer.hs() peer.hs()
.store_msg_for_retransmission(self, &tx_buf[..len])?; .store_msg_for_retransmission(self, &msg.as_bytes()[..len])?;
Ok(len) Ok(len)
} }
} }
@@ -793,50 +795,50 @@ impl CryptoServer {
let peer = match rx_buf[0].try_into() { let peer = match rx_buf[0].try_into() {
Ok(MsgType::InitHello) => { Ok(MsgType::InitHello) => {
let msg_in = rx_buf.envelope::<InitHello<&[u8]>>()?; let msg_in: Ref<&[u8], Envelope<InitHello>> = Ref::new(rx_buf).ok_or(RosenpassError::BufferSizeMismatch)?;
ensure!(msg_in.check_seal(self)?, seal_broken); ensure!(msg_in.check_seal(self)?, seal_broken);
let mut msg_out = tx_buf.envelope_truncating::<RespHello<&mut [u8]>>()?; let mut msg_out = truncating_cast_into::<Envelope<RespHello>>(tx_buf)?;
let peer = self.handle_init_hello( let peer = self.handle_init_hello(
msg_in.payload().init_hello()?, &msg_in.payload,
msg_out.payload_mut().resp_hello()?, &mut msg_out.payload,
)?; )?;
len = self.seal_and_commit_msg(peer, MsgType::RespHello, msg_out)?; len = self.seal_and_commit_msg(peer, MsgType::RespHello, &mut msg_out)?;
peer peer
} }
Ok(MsgType::RespHello) => { Ok(MsgType::RespHello) => {
let msg_in = rx_buf.envelope::<RespHello<&[u8]>>()?; let msg_in: Ref<&[u8], Envelope<RespHello>> = Ref::new(rx_buf).ok_or(RosenpassError::BufferSizeMismatch)?;
ensure!(msg_in.check_seal(self)?, seal_broken); ensure!(msg_in.check_seal(self)?, seal_broken);
let mut msg_out = tx_buf.envelope_truncating::<InitConf<&mut [u8]>>()?; let mut msg_out = truncating_cast_into::<Envelope<InitConf>>(tx_buf)?;
let peer = self.handle_resp_hello( let peer = self.handle_resp_hello(
msg_in.payload().resp_hello()?, &msg_in.payload,
msg_out.payload_mut().init_conf()?, &mut msg_out.payload,
)?; )?;
len = self.seal_and_commit_msg(peer, MsgType::InitConf, msg_out)?; len = self.seal_and_commit_msg(peer, MsgType::InitConf, &mut msg_out)?;
peer.hs() peer.hs()
.store_msg_for_retransmission(self, &tx_buf[..len])?; .store_msg_for_retransmission(self, &msg_out.as_bytes()[..len])?;
exchanged = true; exchanged = true;
peer peer
} }
Ok(MsgType::InitConf) => { Ok(MsgType::InitConf) => {
let msg_in = rx_buf.envelope::<InitConf<&[u8]>>()?; let msg_in: Ref<&[u8], Envelope<InitConf>> = Ref::new(rx_buf).ok_or(RosenpassError::BufferSizeMismatch)?;
ensure!(msg_in.check_seal(self)?, seal_broken); ensure!(msg_in.check_seal(self)?, seal_broken);
let mut msg_out = tx_buf.envelope_truncating::<EmptyData<&mut [u8]>>()?; let mut msg_out = truncating_cast_into::<Envelope<EmptyData>>(tx_buf)?;
let peer = self.handle_init_conf( let peer = self.handle_init_conf(
msg_in.payload().init_conf()?, &msg_in.payload,
msg_out.payload_mut().empty_data()?, &mut msg_out.payload,
)?; )?;
len = self.seal_and_commit_msg(peer, MsgType::EmptyData, msg_out)?; len = self.seal_and_commit_msg(peer, MsgType::EmptyData, &mut msg_out)?;
exchanged = true; exchanged = true;
peer peer
} }
Ok(MsgType::EmptyData) => { Ok(MsgType::EmptyData) => {
let msg_in = rx_buf.envelope::<EmptyData<&[u8]>>()?; let msg_in: Ref<&[u8], Envelope<EmptyData>> = Ref::new(rx_buf).ok_or(RosenpassError::BufferSizeMismatch)?;
ensure!(msg_in.check_seal(self)?, seal_broken); ensure!(msg_in.check_seal(self)?, seal_broken);
self.handle_resp_conf(msg_in.payload().empty_data()?)? self.handle_resp_conf(&msg_in.payload)?
} }
Ok(MsgType::DataMsg) => bail!("DataMsg handling not implemented!"), Ok(MsgType::DataMsg) => bail!("DataMsg handling not implemented!"),
Ok(MsgType::CookieReply) => bail!("CookieReply handling not implemented!"), Ok(MsgType::CookieReply) => bail!("CookieReply handling not implemented!"),
@@ -856,15 +858,15 @@ impl CryptoServer {
/// ///
/// The message type is explicitly required here because it is very easy to /// The message type is explicitly required here because it is very easy to
/// forget setting that, which creates subtle but far ranging errors. /// forget setting that, which creates subtle but far ranging errors.
pub fn seal_and_commit_msg<M: LenseView>( pub fn seal_and_commit_msg<M: AsBytes + FromBytes>(
&mut self, &mut self,
peer: PeerPtr, peer: PeerPtr,
msg_type: MsgType, msg_type: MsgType,
mut msg: Envelope<&mut [u8], M>, msg: &mut Ref<&mut [u8], Envelope<M>>,
) -> Result<usize> { ) -> Result<usize> {
msg.msg_type_mut()[0] = msg_type as u8; msg.msg_type = msg_type as u8;
msg.seal(peer, self)?; msg.seal(peer, self)?;
Ok(<Envelope<(), M> as LenseView>::LEN) Ok(size_of::<Envelope<M>>())
} }
} }
@@ -1170,32 +1172,32 @@ impl IniHsPtr {
// CRYPTO/HANDSHAKE HANDLING ///////////////////// // CRYPTO/HANDSHAKE HANDLING /////////////////////
impl<M> Envelope<&mut [u8], M> impl<M> Envelope<M>
where where
M: LenseView, M: AsBytes + FromBytes,
{ {
/// Calculate the message authentication code (`mac`) /// Calculate the message authentication code (`mac`)
pub fn seal(&mut self, peer: PeerPtr, srv: &CryptoServer) -> Result<()> { pub fn seal(&mut self, peer: PeerPtr, srv: &CryptoServer) -> Result<()> {
let mac = hash_domains::mac()? let mac = hash_domains::mac()?
.mix(peer.get(srv).spkt.secret())? .mix(peer.get(srv).spkt.secret())?
.mix(self.until_mac())?; .mix(&self.as_bytes()[..offset_of!(Self, mac)])?;
self.mac_mut() self.mac
.copy_from_slice(mac.into_value()[..16].as_ref()); .copy_from_slice(mac.into_value()[..16].as_ref());
Ok(()) Ok(())
} }
} }
impl<M> Envelope<&[u8], M> impl<M> Envelope<M>
where where
M: LenseView, M: AsBytes + FromBytes,
{ {
/// Check the message authentication code /// Check the message authentication code
pub fn check_seal(&self, srv: &CryptoServer) -> Result<bool> { pub fn check_seal(&self, srv: &CryptoServer) -> Result<bool> {
let expected = hash_domains::mac()? let expected = hash_domains::mac()?
.mix(srv.spkm.secret())? .mix(srv.spkm.secret())?
.mix(self.until_mac())?; .mix(&self.as_bytes()[..offset_of!(Self, mac)])?;
Ok(constant_time::memcmp( Ok(constant_time::memcmp(
self.mac(), &self.mac,
&expected.into_value()[..16], &expected.into_value()[..16],
)) ))
} }
@@ -1282,15 +1284,15 @@ impl HandshakeState {
biscuit_ct: &mut [u8], biscuit_ct: &mut [u8],
) -> Result<&mut Self> { ) -> Result<&mut Self> {
let mut biscuit = Secret::<BISCUIT_PT_LEN>::zero(); // pt buffer let mut biscuit = Secret::<BISCUIT_PT_LEN>::zero(); // pt buffer
let mut biscuit = (&mut biscuit.secret_mut()[..]).biscuit()?; // lens view let mut biscuit: Ref<&mut [u8], Biscuit> = Ref::new(biscuit.secret_mut().as_mut_slice()).unwrap();
// calculate pt contents // calculate pt contents
biscuit biscuit
.pidi_mut() .pidi
.copy_from_slice(peer.get(srv).pidt()?.as_slice()); .copy_from_slice(peer.get(srv).pidt()?.as_slice());
biscuit.biscuit_no_mut().copy_from_slice(&*srv.biscuit_ctr); biscuit.biscuit_no.copy_from_slice(&*srv.biscuit_ctr);
biscuit biscuit
.ck_mut() .ck
.copy_from_slice(self.ck.clone().danger_into_secret().secret()); .copy_from_slice(self.ck.clone().danger_into_secret().secret());
// calculate ad contents // calculate ad contents
@@ -1311,7 +1313,7 @@ impl HandshakeState {
n[0] |= (bk.0 as u8 & 0x1) << 7; n[0] |= (bk.0 as u8 & 0x1) << 7;
let k = bk.get(srv).key.secret(); let k = bk.get(srv).key.secret();
let pt = biscuit.all_bytes(); let pt = biscuit.as_bytes();
xaead::encrypt(biscuit_ct, k, &*n, &ad, pt)?; xaead::encrypt(biscuit_ct, k, &*n, &ad, pt)?;
self.mix(biscuit_ct) self.mix(biscuit_ct)
@@ -1337,18 +1339,18 @@ impl HandshakeState {
// Allocate and decrypt the biscuit data // Allocate and decrypt the biscuit data
let mut biscuit = Secret::<BISCUIT_PT_LEN>::zero(); // pt buf let mut biscuit = Secret::<BISCUIT_PT_LEN>::zero(); // pt buf
let mut biscuit = (&mut biscuit.secret_mut()[..]).biscuit()?; // slice let mut biscuit: Ref<&mut [u8], Biscuit> = Ref::new(biscuit.secret_mut().as_mut_slice()).unwrap();
xaead::decrypt( xaead::decrypt(
biscuit.all_bytes_mut(), biscuit.as_bytes_mut(),
bk.get(srv).key.secret(), bk.get(srv).key.secret(),
&ad, &ad,
biscuit_ct, biscuit_ct,
)?; )?;
// Reconstruct the biscuit fields // Reconstruct the biscuit fields
let no = BiscuitId::from_slice(biscuit.biscuit_no()); let no = BiscuitId::from_slice(&biscuit.biscuit_no);
let ck = SecretHashDomain::danger_from_secret(Secret::from_slice(biscuit.ck())).dup(); let ck = SecretHashDomain::danger_from_secret(Secret::from_slice(&biscuit.ck)).dup();
let pid = PeerId::from_slice(biscuit.pidi()); let pid = PeerId::from_slice(&biscuit.pidi);
// Reconstruct the handshake state // Reconstruct the handshake state
let mut hs = Self { sidi, sidr, ck }; let mut hs = Self { sidi, sidr, ck };
@@ -1364,7 +1366,7 @@ impl HandshakeState {
// indicates retransmission // indicates retransmission
// TODO: Handle retransmissions without involving the crypto code // TODO: Handle retransmissions without involving the crypto code
ensure!( ensure!(
constant_time::compare(biscuit.biscuit_no(), &*peer.get(srv).biscuit_used) >= 0, constant_time::compare(&biscuit.biscuit_no, &*peer.get(srv).biscuit_used) >= 0,
"Rejecting biscuit: Outdated biscuit number" "Rejecting biscuit: Outdated biscuit number"
); );
@@ -1415,7 +1417,7 @@ impl CryptoServer {
pub fn handle_initiation( pub fn handle_initiation(
&mut self, &mut self,
peer: PeerPtr, peer: PeerPtr,
mut ih: InitHello<&mut [u8]>, ih: &mut InitHello,
) -> Result<PeerPtr> { ) -> Result<PeerPtr> {
let mut hs = InitiatorHandshake::zero_with_timestamp(self); let mut hs = InitiatorHandshake::zero_with_timestamp(self);
@@ -1424,25 +1426,25 @@ impl CryptoServer {
// IHI2 // IHI2
hs.core.sidi.randomize(); hs.core.sidi.randomize();
ih.sidi_mut().copy_from_slice(&hs.core.sidi.value); ih.sidi.copy_from_slice(&hs.core.sidi.value);
// IHI3 // IHI3
EphemeralKem::keygen(hs.eski.secret_mut(), &mut *hs.epki)?; EphemeralKem::keygen(hs.eski.secret_mut(), &mut *hs.epki)?;
ih.epki_mut().copy_from_slice(&hs.epki.value); ih.epki.copy_from_slice(&hs.epki.value);
// IHI4 // IHI4
hs.core.mix(ih.sidi())?.mix(ih.epki())?; hs.core.mix(ih.sidi.as_slice())?.mix(ih.epki.as_slice())?;
// IHI5 // IHI5
hs.core hs.core
.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>( .encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
ih.sctr_mut(), ih.sctr.as_mut_slice(),
peer.get(self).spkt.secret(), peer.get(self).spkt.secret(),
)?; )?;
// IHI6 // IHI6
hs.core hs.core
.encrypt_and_mix(ih.pidic_mut(), self.pidm()?.as_ref())?; .encrypt_and_mix(ih.pidic.as_mut_slice(), self.pidm()?.as_ref())?;
// IHI7 // IHI7
hs.core hs.core
@@ -1450,7 +1452,7 @@ impl CryptoServer {
.mix(peer.get(self).psk.secret())?; .mix(peer.get(self).psk.secret())?;
// IHI8 // IHI8
hs.core.encrypt_and_mix(ih.auth_mut(), &[])?; hs.core.encrypt_and_mix(ih.auth.as_mut_slice(), &[])?;
// Update the handshake hash last (not changing any state on prior error // Update the handshake hash last (not changing any state on prior error
peer.hs().insert(self, hs)?; peer.hs().insert(self, hs)?;
@@ -1460,30 +1462,30 @@ impl CryptoServer {
pub fn handle_init_hello( pub fn handle_init_hello(
&mut self, &mut self,
ih: InitHello<&[u8]>, ih: &InitHello,
mut rh: RespHello<&mut [u8]>, rh: &mut RespHello,
) -> Result<PeerPtr> { ) -> Result<PeerPtr> {
let mut core = HandshakeState::zero(); let mut core = HandshakeState::zero();
core.sidi = SessionId::from_slice(ih.sidi()); core.sidi = SessionId::from_slice(&ih.sidi);
// IHR1 // IHR1
core.init(self.spkm.secret())?; core.init(self.spkm.secret())?;
// IHR4 // IHR4
core.mix(ih.sidi())?.mix(ih.epki())?; core.mix(&ih.sidi)?.mix(&ih.epki)?;
// IHR5 // IHR5
core.decaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>( core.decaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
self.sskm.secret(), self.sskm.secret(),
self.spkm.secret(), self.spkm.secret(),
ih.sctr(), &ih.sctr,
)?; )?;
// IHR6 // IHR6
let peer = { let peer = {
let mut peerid = PeerId::zero(); let mut peerid = PeerId::zero();
core.decrypt_and_mix(&mut *peerid, ih.pidic())?; core.decrypt_and_mix(&mut *peerid, &ih.pidic)?;
self.find_peer(peerid) self.find_peer(peerid)
.with_context(|| format!("No such peer {peerid:?}."))? .with_context(|| format!("No such peer {peerid:?}."))?
}; };
@@ -1493,46 +1495,46 @@ impl CryptoServer {
.mix(peer.get(self).psk.secret())?; .mix(peer.get(self).psk.secret())?;
// IHR8 // IHR8
core.decrypt_and_mix(&mut [0u8; 0], ih.auth())?; core.decrypt_and_mix(&mut [0u8; 0], &ih.auth)?;
// RHR1 // RHR1
core.sidr.randomize(); core.sidr.randomize();
rh.sidi_mut().copy_from_slice(core.sidi.as_ref()); rh.sidi.copy_from_slice(core.sidi.as_ref());
rh.sidr_mut().copy_from_slice(core.sidr.as_ref()); rh.sidr.copy_from_slice(core.sidr.as_ref());
// RHR3 // RHR3
core.mix(rh.sidr())?.mix(rh.sidi())?; core.mix(&rh.sidr)?.mix(&rh.sidi)?;
// RHR4 // RHR4
core.encaps_and_mix::<EphemeralKem, { EphemeralKem::SHK_LEN }>(rh.ecti_mut(), ih.epki())?; core.encaps_and_mix::<EphemeralKem, { EphemeralKem::SHK_LEN }>(&mut rh.ecti, &ih.epki)?;
// RHR5 // RHR5
core.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>( core.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
rh.scti_mut(), &mut rh.scti,
peer.get(self).spkt.secret(), peer.get(self).spkt.secret(),
)?; )?;
// RHR6 // RHR6
core.store_biscuit(self, peer, rh.biscuit_mut())?; core.store_biscuit(self, peer, &mut rh.biscuit)?;
// RHR7 // RHR7
core.encrypt_and_mix(rh.auth_mut(), &[])?; core.encrypt_and_mix(&mut rh.auth, &[])?;
Ok(peer) Ok(peer)
} }
pub fn handle_resp_hello( pub fn handle_resp_hello(
&mut self, &mut self,
rh: RespHello<&[u8]>, rh: &RespHello,
mut ic: InitConf<&mut [u8]>, ic: &mut InitConf,
) -> Result<PeerPtr> { ) -> Result<PeerPtr> {
// RHI2 // RHI2
let peer = self let peer = self
.lookup_handshake(SessionId::from_slice(rh.sidi())) .lookup_handshake(SessionId::from_slice(&rh.sidi))
.with_context(|| { .with_context(|| {
format!( format!(
"Got RespHello packet for non-existent session {:?}", "Got RespHello packet for non-existent session {:?}",
rh.sidi() rh.sidi
) )
})? })?
.peer(); .peer();
@@ -1557,52 +1559,52 @@ impl CryptoServer {
ensure!( ensure!(
exp == got, exp == got,
"Unexpected package in session {:?}. Expected {:?}, got {:?}.", "Unexpected package in session {:?}. Expected {:?}, got {:?}.",
SessionId::from_slice(rh.sidi()), SessionId::from_slice(&rh.sidi),
exp, exp,
got got
); );
let mut core = hs!().core.clone(); let mut core = hs!().core.clone();
core.sidr.copy_from_slice(rh.sidr()); core.sidr.copy_from_slice(&rh.sidr);
// TODO: decaps_and_mix should take Secret<> directly // TODO: decaps_and_mix should take Secret<> directly
// to save us from the repetitive secret unwrapping // to save us from the repetitive secret unwrapping
// RHI3 // RHI3
core.mix(rh.sidr())?.mix(rh.sidi())?; core.mix(&rh.sidr)?.mix(&rh.sidi)?;
// RHI4 // RHI4
core.decaps_and_mix::<EphemeralKem, { EphemeralKem::SHK_LEN }>( core.decaps_and_mix::<EphemeralKem, { EphemeralKem::SHK_LEN }>(
hs!().eski.secret(), hs!().eski.secret(),
&*hs!().epki, &*hs!().epki,
rh.ecti(), &rh.ecti,
)?; )?;
// RHI5 // RHI5
core.decaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>( core.decaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
self.sskm.secret(), self.sskm.secret(),
self.spkm.secret(), self.spkm.secret(),
rh.scti(), &rh.scti,
)?; )?;
// RHI6 // RHI6
core.mix(rh.biscuit())?; core.mix(&rh.biscuit)?;
// RHI7 // RHI7
core.decrypt_and_mix(&mut [0u8; 0], rh.auth())?; core.decrypt_and_mix(&mut [0u8; 0], &rh.auth)?;
// TODO: We should just authenticate the entire network package up to the auth // TODO: We should just authenticate the entire network package up to the auth
// tag as a pattern instead of mixing in fields separately // tag as a pattern instead of mixing in fields separately
ic.sidi_mut().copy_from_slice(rh.sidi()); ic.sidi.copy_from_slice(&rh.sidi);
ic.sidr_mut().copy_from_slice(rh.sidr()); ic.sidr.copy_from_slice(&rh.sidr);
// ICI3 // ICI3
core.mix(ic.sidi())?.mix(ic.sidr())?; core.mix(&ic.sidi)?.mix(&ic.sidr)?;
ic.biscuit_mut().copy_from_slice(rh.biscuit()); ic.biscuit.copy_from_slice(&rh.biscuit);
// ICI4 // ICI4
core.encrypt_and_mix(ic.auth_mut(), &[])?; core.encrypt_and_mix(&mut ic.auth, &[])?;
// Split() We move the secrets into the session; we do not // Split() We move the secrets into the session; we do not
// delete the InitiatorHandshake, just clear it's secrets because // delete the InitiatorHandshake, just clear it's secrets because
@@ -1619,26 +1621,26 @@ impl CryptoServer {
pub fn handle_init_conf( pub fn handle_init_conf(
&mut self, &mut self,
ic: InitConf<&[u8]>, ic: &InitConf,
mut rc: EmptyData<&mut [u8]>, rc: &mut EmptyData,
) -> Result<PeerPtr> { ) -> 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(
self, self,
ic.biscuit(), &ic.biscuit,
SessionId::from_slice(ic.sidi()), SessionId::from_slice(&ic.sidi),
SessionId::from_slice(ic.sidr()), SessionId::from_slice(&ic.sidr),
)?; )?;
// ICR2 // ICR2
core.encrypt_and_mix(&mut [0u8; aead::TAG_LEN], &[])?; core.encrypt_and_mix(&mut [0u8; aead::TAG_LEN], &[])?;
// ICR3 // ICR3
core.mix(ic.sidi())?.mix(ic.sidr())?; core.mix(&ic.sidi)?.mix(&ic.sidr)?;
// ICR4 // ICR4
core.decrypt_and_mix(&mut [0u8; 0], ic.auth())?; core.decrypt_and_mix(&mut [0u8; 0], &ic.auth)?;
// ICR5 // ICR5
if constant_time::compare(&*biscuit_no, &*peer.get(self).biscuit_used) > 0 { if constant_time::compare(&*biscuit_no, &*peer.get(self).biscuit_used) > 0 {
@@ -1682,19 +1684,19 @@ impl CryptoServer {
.get_mut(self) .get_mut(self)
.as_mut() .as_mut()
.context("Cannot send acknowledgement. No session.")?; .context("Cannot send acknowledgement. No session.")?;
rc.sid_mut().copy_from_slice(&ses.sidt.value); rc.sid.copy_from_slice(&ses.sidt.value);
rc.ctr_mut().copy_from_slice(&ses.txnm.to_le_bytes()); rc.ctr.copy_from_slice(&ses.txnm.to_le_bytes());
ses.txnm += 1; // Increment nonce before encryption, just in case an error is raised ses.txnm += 1; // Increment nonce before encryption, just in case an error is raised
let n = cat!(aead::NONCE_LEN; rc.ctr(), &[0u8; 4]); let n = cat!(aead::NONCE_LEN; &rc.ctr, &[0u8; 4]);
let k = ses.txkm.secret(); let k = ses.txkm.secret();
aead::encrypt(rc.auth_mut(), k, &n, &[], &[])?; // ct, k, n, ad, pt aead::encrypt(&mut rc.auth, k, &n, &[], &[])?; // ct, k, n, ad, pt
Ok(peer) Ok(peer)
} }
pub fn handle_resp_conf(&mut self, rc: EmptyData<&[u8]>) -> Result<PeerPtr> { pub fn handle_resp_conf(&mut self, rc: &EmptyData) -> Result<PeerPtr> {
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:?}"))?;
@@ -1717,16 +1719,16 @@ impl CryptoServer {
})?; })?;
// the unwrap can not fail, because the slice returned by ctr() is // the unwrap can not fail, because the slice returned by ctr() is
// guaranteed to have the correct size // guaranteed to have the correct size
let n = u64::from_le_bytes(rc.ctr().try_into().unwrap()); let n = u64::from_le_bytes(rc.ctr.try_into().unwrap());
ensure!(n >= s.txnt, "Stale nonce"); ensure!(n >= s.txnt, "Stale nonce");
s.txnt = n; s.txnt = n;
aead::decrypt( aead::decrypt(
// pt, k, n, ad, ct // pt, k, n, ad, ct
&mut [0u8; 0], &mut [0u8; 0],
s.txkt.secret(), s.txkt.secret(),
&cat!(aead::NONCE_LEN; rc.ctr(), &[0u8; 4]), &cat!(aead::NONCE_LEN; &rc.ctr, &[0u8; 4]),
&[], &[],
rc.auth(), &rc.auth,
)?; )?;
} }
@@ -1737,6 +1739,10 @@ impl CryptoServer {
} }
} }
fn truncating_cast_into<T: FromBytes>(buf: &mut [u8]) -> Result<Ref<&mut [u8], T>, RosenpassError> {
Ok(Ref::new(&mut buf[..size_of::<T>()]).ok_or(RosenpassError::BufferSizeMismatch)?)
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;