Move static KEM public key to new PublicBox struct

This commit is contained in:
Katherine Watson
2024-06-16 21:45:48 -07:00
committed by kat watson
parent bdad414c90
commit a18658847c
6 changed files with 177 additions and 31 deletions

View File

@@ -6,7 +6,7 @@ use rosenpass_secret_memory::file::StoreSecret;
use rosenpass_secret_memory::{
secret_policy_try_use_memfd_secrets, secret_policy_use_only_malloc_secrets,
};
use rosenpass_util::file::{LoadValue, LoadValueB64};
use rosenpass_util::file::{LoadValue, LoadValueB64, StoreValue};
use rosenpass_wireguard_broker::brokers::native_unix::{
NativeUnixBroker, NativeUnixBrokerConfigBaseBuilder, NativeUnixBrokerConfigBaseBuilderError,
};
@@ -370,7 +370,7 @@ impl CliCommand {
fn generate_and_save_keypair(secret_key: PathBuf, public_key: PathBuf) -> anyhow::Result<()> {
let mut ssk = crate::protocol::SSk::random();
let mut spk = crate::protocol::SPk::random();
StaticKem::keygen(ssk.secret_mut(), spk.secret_mut())?;
StaticKem::keygen(ssk.secret_mut(), &mut *spk)?;
ssk.store_secret(secret_key)?;
spk.store(public_key)
}

View File

@@ -32,11 +32,11 @@
//!
//! // initialize secret and public key for peer a ...
//! let (mut peer_a_sk, mut peer_a_pk) = (SSk::zero(), SPk::zero());
//! StaticKem::keygen(peer_a_sk.secret_mut(), peer_a_pk.secret_mut())?;
//! StaticKem::keygen(peer_a_sk.secret_mut(), &mut *peer_a_pk)?;
//!
//! // ... and for peer b
//! let (mut peer_b_sk, mut peer_b_pk) = (SSk::zero(), SPk::zero());
//! StaticKem::keygen(peer_b_sk.secret_mut(), peer_b_pk.secret_mut())?;
//! StaticKem::keygen(peer_b_sk.secret_mut(), &mut *peer_b_pk)?;
//!
//! // initialize server and a pre-shared key
//! let psk = SymKey::random();
@@ -88,7 +88,7 @@ use rosenpass_ciphers::hash_domain::{SecretHashDomain, SecretHashDomainNamespace
use rosenpass_ciphers::kem::{EphemeralKem, StaticKem};
use rosenpass_ciphers::{aead, xaead, KEY_LEN};
use rosenpass_constant_time as constant_time;
use rosenpass_secret_memory::{Public, Secret};
use rosenpass_secret_memory::{Public, PublicBox, Secret};
use rosenpass_util::{cat, mem::cpy_min, ord::max_usize, time::Timebase};
use zerocopy::{AsBytes, FromBytes, Ref};
@@ -163,7 +163,7 @@ pub fn has_happened(ev: Timing, now: Timing) -> bool {
// DATA STRUCTURES & BASIC TRAITS & ACCESSORS ////
pub type SPk = Secret<{ StaticKem::PK_LEN }>; // Just Secret<> instead of Public<> so it gets allocated on the heap
pub type SPk = PublicBox<{ StaticKem::PK_LEN }>;
pub type SSk = Secret<{ StaticKem::SK_LEN }>;
pub type EPk = Public<{ EphemeralKem::PK_LEN }>;
pub type ESk = Secret<{ EphemeralKem::SK_LEN }>;
@@ -548,7 +548,7 @@ impl CryptoServer {
pub fn pidm(&self) -> Result<PeerId> {
Ok(Public::new(
hash_domains::peerid()?
.mix(self.spkm.secret())?
.mix(&*self.spkm)?
.into_value()))
}
@@ -708,7 +708,7 @@ impl Peer {
pub fn pidt(&self) -> Result<PeerId> {
Ok(Public::new(
hash_domains::peerid()?
.mix(self.spkt.secret())?
.mix(&*self.spkt)?
.into_value()))
}
}
@@ -1016,9 +1016,7 @@ impl CryptoServer {
);
let cookie_value = active_cookie_value.unwrap();
let cookie_key = hash_domains::cookie_key()?
.mix(self.spkm.secret())?
.into_value();
let cookie_key = hash_domains::cookie_key()?.mix(&*self.spkm)?.into_value();
let mut msg_out = truncating_cast_into::<CookieReply>(tx_buf)?;
@@ -1509,7 +1507,7 @@ where
/// Calculate the message authentication code (`mac`) and also append cookie value
pub fn seal(&mut self, peer: PeerPtr, srv: &CryptoServer) -> Result<()> {
let mac = hash_domains::mac()?
.mix(peer.get(srv).spkt.secret())?
.mix(&*peer.get(srv).spkt)?
.mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?;
self.mac.copy_from_slice(mac.into_value()[..16].as_ref());
self.seal_cookie(peer, srv)?;
@@ -1536,7 +1534,7 @@ where
/// Check the message authentication code
pub fn check_seal(&self, srv: &CryptoServer) -> Result<bool> {
let expected = hash_domains::mac()?
.mix(srv.spkm.secret())?
.mix(&*srv.spkm)?
.mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?;
Ok(constant_time::memcmp(
&self.mac,
@@ -1641,7 +1639,7 @@ impl HandshakeState {
// calculate ad contents
let ad = hash_domains::biscuit_ad()?
.mix(srv.spkm.secret())?
.mix(&*srv.spkm)?
.mix(self.sidi.as_slice())?
.mix(self.sidr.as_slice())?
.into_value();
@@ -1676,7 +1674,7 @@ impl HandshakeState {
// Calculate additional data fields
let ad = hash_domains::biscuit_ad()?
.mix(srv.spkm.secret())?
.mix(&*srv.spkm)?
.mix(sidi.as_slice())?
.mix(sidr.as_slice())?
.into_value();
@@ -1763,7 +1761,7 @@ impl CryptoServer {
let mut hs = InitiatorHandshake::zero_with_timestamp(self);
// IHI1
hs.core.init(peer.get(self).spkt.secret())?;
hs.core.init(&*peer.get(self).spkt)?;
// IHI2
hs.core.sidi.randomize();
@@ -1780,7 +1778,7 @@ impl CryptoServer {
hs.core
.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
ih.sctr.as_mut_slice(),
peer.get(self).spkt.secret(),
&*peer.get(self).spkt,
)?;
// IHI6
@@ -1788,9 +1786,7 @@ impl CryptoServer {
.encrypt_and_mix(ih.pidic.as_mut_slice(), self.pidm()?.as_ref())?;
// IHI7
hs.core
.mix(self.spkm.secret())?
.mix(peer.get(self).psk.secret())?;
hs.core.mix(&*self.spkm)?.mix(peer.get(self).psk.secret())?;
// IHI8
hs.core.encrypt_and_mix(ih.auth.as_mut_slice(), &[])?;
@@ -1807,7 +1803,7 @@ impl CryptoServer {
core.sidi = SessionId::from_slice(&ih.sidi);
// IHR1
core.init(self.spkm.secret())?;
core.init(&*self.spkm)?;
// IHR4
core.mix(&ih.sidi)?.mix(&ih.epki)?;
@@ -1815,7 +1811,7 @@ impl CryptoServer {
// IHR5
core.decaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
self.sskm.secret(),
self.spkm.secret(),
&*self.spkm,
&ih.sctr,
)?;
@@ -1828,7 +1824,7 @@ impl CryptoServer {
};
// IHR7
core.mix(peer.get(self).spkt.secret())?
core.mix(&*peer.get(self).spkt)?
.mix(peer.get(self).psk.secret())?;
// IHR8
@@ -1848,7 +1844,7 @@ impl CryptoServer {
// RHR5
core.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
&mut rh.scti,
peer.get(self).spkt.secret(),
&*peer.get(self).spkt,
)?;
// RHR6
@@ -1916,7 +1912,7 @@ impl CryptoServer {
// RHI5
core.decaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
self.sskm.secret(),
self.spkm.secret(),
&*self.spkm,
&rh.scti,
)?;
@@ -2113,7 +2109,7 @@ impl CryptoServer {
),
}?;
let spkt = peer.get(self).spkt.secret();
let spkt = &*peer.get(self).spkt;
let cookie_key = hash_domains::cookie_key()?.mix(spkt)?.into_value();
let cookie_value = peer.cv().update_mut(self).unwrap();
@@ -2255,7 +2251,7 @@ mod test {
fn keygen() -> Result<(SSk, SPk)> {
// TODO: Copied from the benchmark; deduplicate
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
StaticKem::keygen(sk.secret_mut(), pk.secret_mut())?;
StaticKem::keygen(sk.secret_mut(), &mut *pk)?;
Ok((sk, pk))
}

View File

@@ -5,7 +5,7 @@ use std::{
};
use anyhow::{anyhow, Result};
use rosenpass_util::file::{LoadValueB64, StoreValueB64};
use rosenpass_util::file::{LoadValueB64, StoreValue, StoreValueB64};
use zeroize::Zeroize;
use rosenpass::protocol::{SPk, SSk};
@@ -56,8 +56,8 @@ pub fn genkey(private_keys_dir: &Path) -> Result<()> {
if !pqsk_path.exists() && !pqpk_path.exists() {
let mut pqsk = SSk::random();
let mut pqpk = SPk::random();
StaticKem::keygen(pqsk.secret_mut(), pqpk.secret_mut())?;
pqpk.store_secret(pqpk_path)?;
StaticKem::keygen(pqsk.secret_mut(), &mut *pqpk)?;
pqpk.store(pqpk_path)?;
pqsk.store_secret(pqsk_path)?;
} else {
eprintln!(

View File

@@ -6,6 +6,7 @@ pub mod alloc;
mod public;
pub use crate::public::Public;
pub use crate::public::PublicBox;
mod secret;
pub use crate::secret::Secret;

View File

@@ -277,3 +277,152 @@ mod tests {
}
}
}
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct PublicBox<const N: usize> {
pub inner: Box<Public<N>>,
}
impl<const N: usize> PublicBox<N> {
/// Create a new [Public] from a byte slice
pub fn from_slice(value: &[u8]) -> Self {
copy_slice(value).to_this(Self::zero) // TODO: fix
}
/// Create a new [Public] from a byte array
pub fn new(value: [u8; N]) -> Self {
Self {
inner: Box::new(Public::new(value)),
}
}
/// Create a zero initialized [Public]
pub fn zero() -> Self {
Self {
inner: Box::new(Public::zero()),
}
}
/// Create a random initialized [Public]
pub fn random() -> Self {
mutating(Self::zero(), |r| r.randomize())
}
/// Randomize all bytes in an existing [Public]
pub fn randomize(&mut self) {
(**self).try_fill(&mut crate::rand::rng()).unwrap()
}
}
impl<const N: usize> Randomize for PublicBox<N> {
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), rand::Error> {
(**self).try_fill(rng)
}
}
impl<const N: usize> fmt::Debug for PublicBox<N> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
debug_crypto_array(&**self, fmt)
}
}
impl<const N: usize> Deref for PublicBox<N> {
type Target = [u8; N];
fn deref(&self) -> &[u8; N] {
&*self.inner
}
}
impl<const N: usize> DerefMut for PublicBox<N> {
fn deref_mut(&mut self) -> &mut [u8; N] {
&mut *self.inner
}
}
impl<const N: usize> Borrow<[u8]> for PublicBox<N> {
fn borrow(&self) -> &[u8] {
&**self
}
}
impl<const N: usize> BorrowMut<[u8]> for PublicBox<N> {
fn borrow_mut(&mut self) -> &mut [u8] {
&mut **self
}
}
impl<const N: usize> LoadValue for PublicBox<N> {
type Error = anyhow::Error;
fn load<P: AsRef<Path>>(path: P) -> anyhow::Result<Self> {
let mut v = Self::random();
fopen_r(path)?.read_exact_to_end(&mut *v)?;
Ok(v)
}
}
impl<const N: usize> StoreValue for PublicBox<N> {
type Error = anyhow::Error;
fn store<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
std::fs::write(path, **self)?;
Ok(())
}
}
impl<const N: usize> LoadValueB64 for PublicBox<N> {
type Error = anyhow::Error;
fn load_b64<const F: usize, P: AsRef<Path>>(path: P) -> Result<Self, Self::Error>
where
Self: Sized,
{
let mut f = [0u8; F];
let mut v = PublicBox::zero();
let p = path.as_ref();
let len = fopen_r(p)?
.read_slice_to_end(&mut f)
.with_context(|| format!("Could not load file {p:?}"))?;
b64_decode(&f[0..len], &mut *v)
.with_context(|| format!("Could not decode base64 file {p:?}"))?;
Ok(v)
}
}
impl<const N: usize> StoreValueB64 for PublicBox<N> {
type Error = anyhow::Error;
fn store_b64<const F: usize, P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
let p = path.as_ref();
let mut f = [0u8; F];
let encoded_str = b64_encode(&**self, &mut f)
.with_context(|| format!("Could not encode base64 file {p:?}"))?;
fopen_w(p, Visibility::Public)?
.write_all(encoded_str.as_bytes())
.with_context(|| format!("Could not write file {p:?}"))?;
Ok(())
}
}
impl<const N: usize> StoreValueB64Writer for PublicBox<N> {
type Error = anyhow::Error;
fn store_b64_writer<const F: usize, W: std::io::Write>(
&self,
mut writer: W,
) -> Result<(), Self::Error> {
let mut f = [0u8; F];
let encoded_str =
b64_encode(&**self, &mut f).with_context(|| "Could not encode secret to base64")?;
writer
.write_all(encoded_str.as_bytes())
.with_context(|| "Could not write base64 to writer")?;
Ok(())
}
}