use core::mem::size_of;
use zerocopy::{AsBytes, FromBytes};
use zeroize::Zeroize;
#[cfg(all(feature = "dalek", not(feature = "force_sodium")))]
use crate::dalek::secretbox as sb;
#[cfg(all(
feature = "sodium",
any(feature = "force_sodium", not(feature = "dalek"))
))]
use crate::sodium::secretbox as sb;
#[derive(AsBytes, FromBytes, Clone, Zeroize)]
#[repr(C)]
#[zeroize(drop)]
pub struct Key(pub [u8; 32]);
impl Key {
pub const SIZE: usize = size_of::<Self>();
pub fn from_slice(s: &[u8]) -> Option<Self> {
if s.len() == Self::SIZE {
let mut out = Self([0; Self::SIZE]);
out.0.copy_from_slice(s);
Some(out)
} else {
None
}
}
#[cfg(feature = "rand")]
pub fn generate_with_rng<R>(r: &mut R) -> Key
where
R: rand::CryptoRng + rand::RngCore,
{
let mut buf = [0; Key::SIZE];
r.fill_bytes(&mut buf);
Key(buf)
}
#[cfg(all(feature = "getrandom", not(feature = "sodium")))]
pub fn generate() -> Key {
Key::generate_with_rng(&mut rand::rngs::OsRng {})
}
#[allow(missing_docs)]
#[cfg(feature = "sodium")]
pub fn generate() -> Key {
crate::sodium::secretbox::generate_key()
}
}
#[cfg(any(feature = "sodium", feature = "dalek"))]
impl Key {
pub fn seal(&self, msg: &mut [u8], n: &Nonce) -> Hmac {
sb::seal(self, msg, n)
}
#[must_use]
pub fn open(&self, c: &mut [u8], hmac: &Hmac, n: &Nonce) -> bool {
sb::open(self, c, hmac, n)
}
#[must_use]
pub fn open_attached_into(&self, input: &[u8], n: &Nonce, mut out: &mut [u8]) -> bool {
let (h, c) = input.split_at(Hmac::SIZE);
let hmac = Hmac::from_slice(h).unwrap();
out.copy_from_slice(c);
self.open(&mut out, &hmac, n)
}
pub fn seal_attached_into(&self, msg: &[u8], nonce: &Nonce, out: &mut [u8]) {
assert!(out.len() >= msg.len() + Hmac::SIZE);
let (h, mut c) = out.split_at_mut(Hmac::SIZE);
c.copy_from_slice(msg);
let hmac = self.seal(&mut c, nonce);
h.copy_from_slice(hmac.as_bytes());
}
}
#[derive(AsBytes, FromBytes, Copy, Clone)]
#[repr(C)]
pub struct Nonce(pub [u8; 24]);
impl Nonce {
pub const SIZE: usize = size_of::<Self>();
pub fn zero() -> Nonce {
Nonce([0; 24])
}
#[cfg(all(feature = "getrandom", not(feature = "sodium")))]
pub fn generate() -> Nonce {
Nonce::generate_with_rng(&mut rand::rngs::OsRng {})
}
#[allow(missing_docs)]
#[cfg(feature = "sodium")]
pub fn generate() -> Nonce {
crate::sodium::secretbox::generate_nonce()
}
#[cfg(feature = "rand")]
pub fn generate_with_rng<R>(r: &mut R) -> Nonce
where
R: rand::CryptoRng + rand::RngCore,
{
let mut buf = [0; Nonce::SIZE];
r.fill_bytes(&mut buf);
Nonce(buf)
}
pub fn from_slice(s: &[u8]) -> Option<Self> {
if s.len() == Self::SIZE {
let mut out = Self([0; Self::SIZE]);
out.0.copy_from_slice(s);
Some(out)
} else {
None
}
}
}
#[derive(Copy, Clone, AsBytes, FromBytes)]
#[repr(C)]
pub struct Hmac(pub [u8; 16]);
impl Hmac {
pub const SIZE: usize = size_of::<Self>();
pub fn from_slice(s: &[u8]) -> Option<Self> {
if s.len() == Self::SIZE {
let mut out = Self([0; Self::SIZE]);
out.0.copy_from_slice(s);
Some(out)
} else {
None
}
}
}