mirror of
https://github.com/rosenpass/rosenpass.git
synced 2026-02-28 14:33:37 -08:00
Move static KEM public key to new PublicBox struct
This commit is contained in:
committed by
kat watson
parent
bdad414c90
commit
a18658847c
@@ -6,7 +6,7 @@ use rosenpass_secret_memory::file::StoreSecret;
|
|||||||
use rosenpass_secret_memory::{
|
use rosenpass_secret_memory::{
|
||||||
secret_policy_try_use_memfd_secrets, secret_policy_use_only_malloc_secrets,
|
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::{
|
use rosenpass_wireguard_broker::brokers::native_unix::{
|
||||||
NativeUnixBroker, NativeUnixBrokerConfigBaseBuilder, NativeUnixBrokerConfigBaseBuilderError,
|
NativeUnixBroker, NativeUnixBrokerConfigBaseBuilder, NativeUnixBrokerConfigBaseBuilderError,
|
||||||
};
|
};
|
||||||
@@ -370,7 +370,7 @@ impl CliCommand {
|
|||||||
fn generate_and_save_keypair(secret_key: PathBuf, public_key: PathBuf) -> anyhow::Result<()> {
|
fn generate_and_save_keypair(secret_key: PathBuf, public_key: PathBuf) -> anyhow::Result<()> {
|
||||||
let mut ssk = crate::protocol::SSk::random();
|
let mut ssk = crate::protocol::SSk::random();
|
||||||
let mut spk = crate::protocol::SPk::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)?;
|
ssk.store_secret(secret_key)?;
|
||||||
spk.store(public_key)
|
spk.store(public_key)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,11 +32,11 @@
|
|||||||
//!
|
//!
|
||||||
//! // initialize secret and public key for peer a ...
|
//! // initialize secret and public key for peer a ...
|
||||||
//! let (mut peer_a_sk, mut peer_a_pk) = (SSk::zero(), SPk::zero());
|
//! 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
|
//! // ... and for peer b
|
||||||
//! let (mut peer_b_sk, mut peer_b_pk) = (SSk::zero(), SPk::zero());
|
//! 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
|
//! // initialize server and a pre-shared key
|
||||||
//! let psk = SymKey::random();
|
//! let psk = SymKey::random();
|
||||||
@@ -88,7 +88,7 @@ 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_secret_memory::{Public, Secret};
|
use rosenpass_secret_memory::{Public, PublicBox, 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 zerocopy::{AsBytes, FromBytes, Ref};
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ pub fn has_happened(ev: Timing, now: Timing) -> bool {
|
|||||||
|
|
||||||
// DATA STRUCTURES & BASIC TRAITS & ACCESSORS ////
|
// 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 SSk = Secret<{ StaticKem::SK_LEN }>;
|
||||||
pub type EPk = Public<{ EphemeralKem::PK_LEN }>;
|
pub type EPk = Public<{ EphemeralKem::PK_LEN }>;
|
||||||
pub type ESk = Secret<{ EphemeralKem::SK_LEN }>;
|
pub type ESk = Secret<{ EphemeralKem::SK_LEN }>;
|
||||||
@@ -548,7 +548,7 @@ impl CryptoServer {
|
|||||||
pub fn pidm(&self) -> Result<PeerId> {
|
pub fn pidm(&self) -> Result<PeerId> {
|
||||||
Ok(Public::new(
|
Ok(Public::new(
|
||||||
hash_domains::peerid()?
|
hash_domains::peerid()?
|
||||||
.mix(self.spkm.secret())?
|
.mix(&*self.spkm)?
|
||||||
.into_value()))
|
.into_value()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,7 +708,7 @@ impl Peer {
|
|||||||
pub fn pidt(&self) -> Result<PeerId> {
|
pub fn pidt(&self) -> Result<PeerId> {
|
||||||
Ok(Public::new(
|
Ok(Public::new(
|
||||||
hash_domains::peerid()?
|
hash_domains::peerid()?
|
||||||
.mix(self.spkt.secret())?
|
.mix(&*self.spkt)?
|
||||||
.into_value()))
|
.into_value()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1016,9 +1016,7 @@ impl CryptoServer {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let cookie_value = active_cookie_value.unwrap();
|
let cookie_value = active_cookie_value.unwrap();
|
||||||
let cookie_key = hash_domains::cookie_key()?
|
let cookie_key = hash_domains::cookie_key()?.mix(&*self.spkm)?.into_value();
|
||||||
.mix(self.spkm.secret())?
|
|
||||||
.into_value();
|
|
||||||
|
|
||||||
let mut msg_out = truncating_cast_into::<CookieReply>(tx_buf)?;
|
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
|
/// Calculate the message authentication code (`mac`) and also append cookie value
|
||||||
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)?
|
||||||
.mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?;
|
.mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?;
|
||||||
self.mac.copy_from_slice(mac.into_value()[..16].as_ref());
|
self.mac.copy_from_slice(mac.into_value()[..16].as_ref());
|
||||||
self.seal_cookie(peer, srv)?;
|
self.seal_cookie(peer, srv)?;
|
||||||
@@ -1536,7 +1534,7 @@ where
|
|||||||
/// 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)?
|
||||||
.mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?;
|
.mix(&self.as_bytes()[span_of!(Self, msg_type..mac)])?;
|
||||||
Ok(constant_time::memcmp(
|
Ok(constant_time::memcmp(
|
||||||
&self.mac,
|
&self.mac,
|
||||||
@@ -1641,7 +1639,7 @@ impl HandshakeState {
|
|||||||
|
|
||||||
// calculate ad contents
|
// calculate ad contents
|
||||||
let ad = hash_domains::biscuit_ad()?
|
let ad = hash_domains::biscuit_ad()?
|
||||||
.mix(srv.spkm.secret())?
|
.mix(&*srv.spkm)?
|
||||||
.mix(self.sidi.as_slice())?
|
.mix(self.sidi.as_slice())?
|
||||||
.mix(self.sidr.as_slice())?
|
.mix(self.sidr.as_slice())?
|
||||||
.into_value();
|
.into_value();
|
||||||
@@ -1676,7 +1674,7 @@ impl HandshakeState {
|
|||||||
|
|
||||||
// Calculate additional data fields
|
// Calculate additional data fields
|
||||||
let ad = hash_domains::biscuit_ad()?
|
let ad = hash_domains::biscuit_ad()?
|
||||||
.mix(srv.spkm.secret())?
|
.mix(&*srv.spkm)?
|
||||||
.mix(sidi.as_slice())?
|
.mix(sidi.as_slice())?
|
||||||
.mix(sidr.as_slice())?
|
.mix(sidr.as_slice())?
|
||||||
.into_value();
|
.into_value();
|
||||||
@@ -1763,7 +1761,7 @@ impl CryptoServer {
|
|||||||
let mut hs = InitiatorHandshake::zero_with_timestamp(self);
|
let mut hs = InitiatorHandshake::zero_with_timestamp(self);
|
||||||
|
|
||||||
// IHI1
|
// IHI1
|
||||||
hs.core.init(peer.get(self).spkt.secret())?;
|
hs.core.init(&*peer.get(self).spkt)?;
|
||||||
|
|
||||||
// IHI2
|
// IHI2
|
||||||
hs.core.sidi.randomize();
|
hs.core.sidi.randomize();
|
||||||
@@ -1780,7 +1778,7 @@ impl CryptoServer {
|
|||||||
hs.core
|
hs.core
|
||||||
.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
|
.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
|
||||||
ih.sctr.as_mut_slice(),
|
ih.sctr.as_mut_slice(),
|
||||||
peer.get(self).spkt.secret(),
|
&*peer.get(self).spkt,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// IHI6
|
// IHI6
|
||||||
@@ -1788,9 +1786,7 @@ impl CryptoServer {
|
|||||||
.encrypt_and_mix(ih.pidic.as_mut_slice(), self.pidm()?.as_ref())?;
|
.encrypt_and_mix(ih.pidic.as_mut_slice(), self.pidm()?.as_ref())?;
|
||||||
|
|
||||||
// IHI7
|
// IHI7
|
||||||
hs.core
|
hs.core.mix(&*self.spkm)?.mix(peer.get(self).psk.secret())?;
|
||||||
.mix(self.spkm.secret())?
|
|
||||||
.mix(peer.get(self).psk.secret())?;
|
|
||||||
|
|
||||||
// IHI8
|
// IHI8
|
||||||
hs.core.encrypt_and_mix(ih.auth.as_mut_slice(), &[])?;
|
hs.core.encrypt_and_mix(ih.auth.as_mut_slice(), &[])?;
|
||||||
@@ -1807,7 +1803,7 @@ impl CryptoServer {
|
|||||||
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)?;
|
||||||
|
|
||||||
// IHR4
|
// IHR4
|
||||||
core.mix(&ih.sidi)?.mix(&ih.epki)?;
|
core.mix(&ih.sidi)?.mix(&ih.epki)?;
|
||||||
@@ -1815,7 +1811,7 @@ impl CryptoServer {
|
|||||||
// 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,
|
||||||
&ih.sctr,
|
&ih.sctr,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -1828,7 +1824,7 @@ impl CryptoServer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// IHR7
|
// IHR7
|
||||||
core.mix(peer.get(self).spkt.secret())?
|
core.mix(&*peer.get(self).spkt)?
|
||||||
.mix(peer.get(self).psk.secret())?;
|
.mix(peer.get(self).psk.secret())?;
|
||||||
|
|
||||||
// IHR8
|
// IHR8
|
||||||
@@ -1848,7 +1844,7 @@ impl CryptoServer {
|
|||||||
// RHR5
|
// RHR5
|
||||||
core.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
|
core.encaps_and_mix::<StaticKem, { StaticKem::SHK_LEN }>(
|
||||||
&mut rh.scti,
|
&mut rh.scti,
|
||||||
peer.get(self).spkt.secret(),
|
&*peer.get(self).spkt,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// RHR6
|
// RHR6
|
||||||
@@ -1916,7 +1912,7 @@ impl CryptoServer {
|
|||||||
// 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,
|
||||||
&rh.scti,
|
&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_key = hash_domains::cookie_key()?.mix(spkt)?.into_value();
|
||||||
let cookie_value = peer.cv().update_mut(self).unwrap();
|
let cookie_value = peer.cv().update_mut(self).unwrap();
|
||||||
|
|
||||||
@@ -2255,7 +2251,7 @@ mod test {
|
|||||||
fn keygen() -> Result<(SSk, SPk)> {
|
fn keygen() -> Result<(SSk, SPk)> {
|
||||||
// TODO: Copied from the benchmark; deduplicate
|
// TODO: Copied from the benchmark; deduplicate
|
||||||
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
|
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))
|
Ok((sk, pk))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use rosenpass_util::file::{LoadValueB64, StoreValueB64};
|
use rosenpass_util::file::{LoadValueB64, StoreValue, StoreValueB64};
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
use rosenpass::protocol::{SPk, SSk};
|
use rosenpass::protocol::{SPk, SSk};
|
||||||
@@ -56,8 +56,8 @@ pub fn genkey(private_keys_dir: &Path) -> Result<()> {
|
|||||||
if !pqsk_path.exists() && !pqpk_path.exists() {
|
if !pqsk_path.exists() && !pqpk_path.exists() {
|
||||||
let mut pqsk = SSk::random();
|
let mut pqsk = SSk::random();
|
||||||
let mut pqpk = SPk::random();
|
let mut pqpk = SPk::random();
|
||||||
StaticKem::keygen(pqsk.secret_mut(), pqpk.secret_mut())?;
|
StaticKem::keygen(pqsk.secret_mut(), &mut *pqpk)?;
|
||||||
pqpk.store_secret(pqpk_path)?;
|
pqpk.store(pqpk_path)?;
|
||||||
pqsk.store_secret(pqsk_path)?;
|
pqsk.store_secret(pqsk_path)?;
|
||||||
} else {
|
} else {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ pub mod alloc;
|
|||||||
|
|
||||||
mod public;
|
mod public;
|
||||||
pub use crate::public::Public;
|
pub use crate::public::Public;
|
||||||
|
pub use crate::public::PublicBox;
|
||||||
|
|
||||||
mod secret;
|
mod secret;
|
||||||
pub use crate::secret::Secret;
|
pub use crate::secret::Secret;
|
||||||
|
|||||||
@@ -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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user