distant_net/common/
key.rs

1use std::fmt;
2use std::str::FromStr;
3
4use derive_more::{Display, Error};
5use rand::rngs::OsRng;
6use rand::RngCore;
7
8#[derive(Debug, Display, Error)]
9pub struct SecretKeyError;
10
11impl From<SecretKeyError> for std::io::Error {
12    fn from(_: SecretKeyError) -> Self {
13        std::io::Error::new(
14            std::io::ErrorKind::InvalidData,
15            "not valid secret key format",
16        )
17    }
18}
19
20/// Represents a 16-byte (128-bit) secret key
21pub type SecretKey16 = SecretKey<16>;
22
23/// Represents a 24-byte (192-bit) secret key
24pub type SecretKey24 = SecretKey<24>;
25
26/// Represents a 32-byte (256-bit) secret key
27pub type SecretKey32 = SecretKey<32>;
28
29/// Represents a secret key used with transport encryption and authentication
30#[derive(Clone, PartialEq, Eq)]
31pub struct SecretKey<const N: usize>([u8; N]);
32
33impl<const N: usize> fmt::Debug for SecretKey<N> {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        f.debug_tuple("SecretKey")
36            .field(&"**OMITTED**".to_string())
37            .finish()
38    }
39}
40
41impl<const N: usize> Default for SecretKey<N> {
42    /// Creates a new secret key of the size `N`
43    ///
44    /// ### Panic
45    ///
46    /// Will panic if `N` is less than 1 or greater than `isize::MAX`
47    fn default() -> Self {
48        Self::generate().unwrap()
49    }
50}
51
52impl<const N: usize> SecretKey<N> {
53    /// Returns byte slice to the key's bytes
54    pub fn unprotected_as_bytes(&self) -> &[u8] {
55        &self.0
56    }
57
58    /// Returns reference to array of key's bytes
59    pub fn unprotected_as_byte_array(&self) -> &[u8; N] {
60        &self.0
61    }
62
63    /// Consumes the secret key and returns the array of key's bytes
64    pub fn unprotected_into_byte_array(self) -> [u8; N] {
65        self.0
66    }
67
68    /// Consumes the secret key and returns the key's bytes as a [`HeapSecretKey`]
69    pub fn into_heap_secret_key(self) -> HeapSecretKey {
70        HeapSecretKey(self.0.to_vec())
71    }
72
73    /// Returns the length of the key
74    #[allow(clippy::len_without_is_empty)]
75    pub fn len(&self) -> usize {
76        N
77    }
78
79    /// Generates a new secret key, returning success if key created or
80    /// failing if the desired key length is not between 1 and `isize::MAX`
81    pub fn generate() -> Result<Self, SecretKeyError> {
82        // Limitation described in https://github.com/orion-rs/orion/issues/130
83        if N < 1 || N > (isize::MAX as usize) {
84            return Err(SecretKeyError);
85        }
86
87        let mut key = [0; N];
88        OsRng.fill_bytes(&mut key);
89
90        Ok(Self(key))
91    }
92
93    /// Creates the key from the given byte slice, returning success if key created
94    /// or failing if the byte slice does not match the desired key length
95    pub fn from_slice(slice: &[u8]) -> Result<Self, SecretKeyError> {
96        if slice.len() != N {
97            return Err(SecretKeyError);
98        }
99
100        let mut value = [0u8; N];
101        value[..N].copy_from_slice(slice);
102
103        Ok(Self(value))
104    }
105}
106
107impl<const N: usize> From<[u8; N]> for SecretKey<N> {
108    fn from(arr: [u8; N]) -> Self {
109        Self(arr)
110    }
111}
112
113impl<const N: usize> FromStr for SecretKey<N> {
114    type Err = SecretKeyError;
115
116    /// Parse a str of hex as an N-byte secret key
117    fn from_str(s: &str) -> Result<Self, Self::Err> {
118        let bytes = hex::decode(s).map_err(|_| SecretKeyError)?;
119        Self::from_slice(&bytes)
120    }
121}
122
123impl<const N: usize> fmt::Display for SecretKey<N> {
124    /// Display an N-byte secret key as a hex string
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        write!(f, "{}", hex::encode(self.unprotected_as_bytes()))
127    }
128}
129
130/// Represents a secret key used with transport encryption and authentication that is stored on the
131/// heap
132#[derive(Clone, PartialEq, Eq)]
133pub struct HeapSecretKey(Vec<u8>);
134
135impl fmt::Debug for HeapSecretKey {
136    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137        f.debug_tuple("HeapSecretKey")
138            .field(&"**OMITTED**".to_string())
139            .finish()
140    }
141}
142
143impl HeapSecretKey {
144    /// Returns byte slice to the key's bytes
145    pub fn unprotected_as_bytes(&self) -> &[u8] {
146        &self.0
147    }
148
149    /// Consumes the secret key and returns the key's bytes
150    pub fn unprotected_into_bytes(self) -> Vec<u8> {
151        self.0.to_vec()
152    }
153
154    /// Returns the length of the key
155    #[allow(clippy::len_without_is_empty)]
156    pub fn len(&self) -> usize {
157        self.0.len()
158    }
159
160    /// Generates a random key of `n` bytes in length.
161    ///
162    /// ### Note
163    ///
164    /// Will return an error if `n` < 1 or `n` > `isize::MAX`.
165    pub fn generate(n: usize) -> Result<Self, SecretKeyError> {
166        // Limitation described in https://github.com/orion-rs/orion/issues/130
167        if n < 1 || n > (isize::MAX as usize) {
168            return Err(SecretKeyError);
169        }
170
171        let mut key = Vec::new();
172        let mut buf = [0; 32];
173
174        // Continually generate a chunk of bytes and extend our key until we've reached
175        // the appropriate length
176        while key.len() < n {
177            OsRng.fill_bytes(&mut buf);
178            key.extend_from_slice(&buf[..std::cmp::min(n - key.len(), 32)]);
179        }
180
181        Ok(Self(key))
182    }
183}
184
185impl From<Vec<u8>> for HeapSecretKey {
186    fn from(bytes: Vec<u8>) -> Self {
187        Self(bytes)
188    }
189}
190
191impl<const N: usize> From<[u8; N]> for HeapSecretKey {
192    fn from(arr: [u8; N]) -> Self {
193        Self::from(arr.to_vec())
194    }
195}
196
197impl<const N: usize> From<SecretKey<N>> for HeapSecretKey {
198    fn from(key: SecretKey<N>) -> Self {
199        key.into_heap_secret_key()
200    }
201}
202
203impl FromStr for HeapSecretKey {
204    type Err = SecretKeyError;
205
206    /// Parse a str of hex as secret key on heap
207    fn from_str(s: &str) -> Result<Self, Self::Err> {
208        Ok(Self(hex::decode(s).map_err(|_| SecretKeyError)?))
209    }
210}
211
212impl fmt::Display for HeapSecretKey {
213    /// Display an N-byte secret key as a hex string
214    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215        write!(f, "{}", hex::encode(self.unprotected_as_bytes()))
216    }
217}
218
219impl<const N: usize> PartialEq<[u8; N]> for HeapSecretKey {
220    fn eq(&self, other: &[u8; N]) -> bool {
221        self.0.eq(other)
222    }
223}
224
225impl<const N: usize> PartialEq<HeapSecretKey> for [u8; N] {
226    fn eq(&self, other: &HeapSecretKey) -> bool {
227        other.eq(self)
228    }
229}
230
231impl<const N: usize> PartialEq<HeapSecretKey> for &[u8; N] {
232    fn eq(&self, other: &HeapSecretKey) -> bool {
233        other.eq(*self)
234    }
235}
236
237impl PartialEq<[u8]> for HeapSecretKey {
238    fn eq(&self, other: &[u8]) -> bool {
239        self.0.eq(other)
240    }
241}
242
243impl PartialEq<HeapSecretKey> for [u8] {
244    fn eq(&self, other: &HeapSecretKey) -> bool {
245        other.eq(self)
246    }
247}
248
249impl PartialEq<HeapSecretKey> for &[u8] {
250    fn eq(&self, other: &HeapSecretKey) -> bool {
251        other.eq(*self)
252    }
253}
254
255impl PartialEq<String> for HeapSecretKey {
256    fn eq(&self, other: &String) -> bool {
257        self.0.eq(other.as_bytes())
258    }
259}
260
261impl PartialEq<HeapSecretKey> for String {
262    fn eq(&self, other: &HeapSecretKey) -> bool {
263        other.eq(self)
264    }
265}
266
267impl PartialEq<HeapSecretKey> for &String {
268    fn eq(&self, other: &HeapSecretKey) -> bool {
269        other.eq(*self)
270    }
271}
272
273impl PartialEq<str> for HeapSecretKey {
274    fn eq(&self, other: &str) -> bool {
275        self.0.eq(other.as_bytes())
276    }
277}
278
279impl PartialEq<HeapSecretKey> for str {
280    fn eq(&self, other: &HeapSecretKey) -> bool {
281        other.eq(self)
282    }
283}
284
285impl PartialEq<HeapSecretKey> for &str {
286    fn eq(&self, other: &HeapSecretKey) -> bool {
287        other.eq(*self)
288    }
289}
290
291#[cfg(test)]
292mod tests {
293    use test_log::test;
294
295    use super::*;
296
297    #[test]
298    fn secret_key_should_be_able_to_be_generated() {
299        SecretKey::<0>::generate().unwrap_err();
300
301        let key = SecretKey::<1>::generate().unwrap();
302        assert_eq!(key.len(), 1);
303
304        // NOTE: We aren't going to validate generating isize::MAX or +1 of that size because it
305        //       takes a lot of time to do so
306        let key = SecretKey::<100>::generate().unwrap();
307        assert_eq!(key.len(), 100);
308    }
309
310    #[test]
311    fn heap_secret_key_should_be_able_to_be_generated() {
312        HeapSecretKey::generate(0).unwrap_err();
313
314        let key = HeapSecretKey::generate(1).unwrap();
315        assert_eq!(key.len(), 1);
316
317        // NOTE: We aren't going to validate generating isize::MAX or +1 of that size because it
318        //       takes a lot of time to do so
319        let key = HeapSecretKey::generate(100).unwrap();
320        assert_eq!(key.len(), 100);
321    }
322}