1use core::mem::size_of;
3use zerocopy::{AsBytes, FromBytes};
4use zeroize::Zeroize;
5
6#[cfg(all(feature = "dalek", not(feature = "force_sodium")))]
7use crate::dalek::secretbox as sb;
8#[cfg(all(
9 feature = "sodium",
10 any(feature = "force_sodium", not(feature = "dalek"))
11))]
12use crate::sodium::secretbox as sb;
13
14#[derive(AsBytes, FromBytes, Clone, Zeroize)]
18#[repr(C)]
19#[zeroize(drop)]
20pub struct Key(pub [u8; 32]);
21impl Key {
22 pub const SIZE: usize = size_of::<Self>();
24
25 pub fn from_slice(s: &[u8]) -> Option<Self> {
29 if s.len() == Self::SIZE {
30 let mut out = Self([0; Self::SIZE]);
31 out.0.copy_from_slice(s);
32 Some(out)
33 } else {
34 None
35 }
36 }
37
38 #[cfg(feature = "rand")]
41 pub fn generate_with_rng<R>(r: &mut R) -> Key
42 where
43 R: rand::CryptoRng + rand::RngCore,
44 {
45 let mut buf = [0; Key::SIZE];
46 r.fill_bytes(&mut buf);
47 Key(buf)
48 }
49
50 #[cfg(all(feature = "getrandom", not(feature = "sodium")))]
52 pub fn generate() -> Key {
53 Key::generate_with_rng(&mut rand::rngs::OsRng {})
54 }
55
56 #[allow(missing_docs)]
57 #[cfg(feature = "sodium")]
58 pub fn generate() -> Key {
59 crate::sodium::secretbox::generate_key()
60 }
61}
62
63#[cfg(any(feature = "sodium", feature = "dalek"))]
64impl Key {
65 pub fn seal(&self, msg: &mut [u8], n: &Nonce) -> Hmac {
67 sb::seal(self, msg, n)
68 }
69
70 #[must_use]
72 pub fn open(&self, c: &mut [u8], hmac: &Hmac, n: &Nonce) -> bool {
73 sb::open(self, c, hmac, n)
74 }
75
76 #[must_use]
86 pub fn open_attached_into(&self, input: &[u8], n: &Nonce, mut out: &mut [u8]) -> bool {
87 let (h, c) = input.split_at(Hmac::SIZE);
88 let hmac = Hmac::from_slice(h).unwrap();
89 out.copy_from_slice(c);
90 self.open(&mut out, &hmac, n)
91 }
92
93 pub fn seal_attached_into(&self, msg: &[u8], nonce: &Nonce, out: &mut [u8]) {
98 assert!(out.len() >= msg.len() + Hmac::SIZE);
99
100 let (h, mut c) = out.split_at_mut(Hmac::SIZE);
101 c.copy_from_slice(msg);
102 let hmac = self.seal(&mut c, nonce);
103 h.copy_from_slice(hmac.as_bytes());
104 }
105}
106
107#[derive(AsBytes, FromBytes, Copy, Clone)]
110#[repr(C)]
111pub struct Nonce(pub [u8; 24]);
112impl Nonce {
113 pub const SIZE: usize = size_of::<Self>();
115
116 pub fn zero() -> Nonce {
119 Nonce([0; 24])
120 }
121
122 #[cfg(all(feature = "getrandom", not(feature = "sodium")))]
124 pub fn generate() -> Nonce {
125 Nonce::generate_with_rng(&mut rand::rngs::OsRng {})
126 }
127
128 #[allow(missing_docs)]
129 #[cfg(feature = "sodium")]
130 pub fn generate() -> Nonce {
131 crate::sodium::secretbox::generate_nonce()
132 }
133
134 #[cfg(feature = "rand")]
137 pub fn generate_with_rng<R>(r: &mut R) -> Nonce
138 where
139 R: rand::CryptoRng + rand::RngCore,
140 {
141 let mut buf = [0; Nonce::SIZE];
142 r.fill_bytes(&mut buf);
143 Nonce(buf)
144 }
145
146 pub fn from_slice(s: &[u8]) -> Option<Self> {
150 if s.len() == Self::SIZE {
151 let mut out = Self([0; Self::SIZE]);
152 out.0.copy_from_slice(s);
153 Some(out)
154 } else {
155 None
156 }
157 }
158}
159
160#[derive(Copy, Clone, AsBytes, FromBytes)]
162#[repr(C)]
163pub struct Hmac(pub [u8; 16]);
164impl Hmac {
165 pub const SIZE: usize = size_of::<Self>();
167
168 pub fn from_slice(s: &[u8]) -> Option<Self> {
172 if s.len() == Self::SIZE {
173 let mut out = Self([0; Self::SIZE]);
174 out.0.copy_from_slice(s);
175 Some(out)
176 } else {
177 None
178 }
179 }
180}