bitwark/
salt.rs

1use std::ops::Deref;
2
3use ring::rand::{SecureRandom, SystemRandom};
4use serde::{Deserialize, Serialize};
5
6use crate::{error::BwError, Generator};
7
8pub trait SaltInfo {
9    fn salt_length() -> usize;
10    fn as_bytes(&self) -> &[u8];
11}
12
13macro_rules! impl_salt {
14    ($name:ident, $length:expr) => {
15        #[derive(Serialize, Deserialize, Debug)]
16        pub struct $name(#[serde(with = "serde_bytes")] [u8; $length]);
17
18        impl Generator for $name {
19            fn generate() -> Result<Self, BwError>
20            where
21                Self: Sized,
22            {
23                let rng = SystemRandom::new();
24                let mut bytes = [0u8; $length];
25                rng.fill(&mut bytes)
26                    .map_err(|_| BwError::FailedSaltGeneration)?;
27                Ok(Self(bytes))
28            }
29        }
30
31        impl SaltInfo for $name {
32            fn salt_length() -> usize {
33                $length
34            }
35
36            fn as_bytes(&self) -> &[u8] {
37                &self.0
38            }
39        }
40
41        impl Deref for $name {
42            type Target = [u8; $length];
43
44            fn deref(&self) -> &Self::Target {
45                &self.0
46            }
47        }
48
49        impl PartialEq for $name {
50            fn eq(&self, other: &Self) -> bool {
51                self.0 == other.0
52            }
53        }
54
55        impl Clone for $name {
56            fn clone(&self) -> Self {
57                $name(self.0.clone())
58            }
59        }
60
61        impl From<$name> for Vec<u8> {
62            fn from(value: $name) -> Self {
63                value.0.to_vec()
64            }
65        }
66
67        impl From<[u8; $length]> for $name {
68            fn from(value: [u8; $length]) -> Self {
69                Self(value)
70            }
71        }
72
73        impl TryFrom<Vec<u8>> for $name {
74            type Error = BwError;
75
76            fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
77                if value.len() != $length {
78                    return Err(BwError::InvalidSaltLength {
79                        expected: $length,
80                        actual: value.len(),
81                    });
82                }
83
84                let mut bytes = [0u8; $length];
85                bytes.copy_from_slice(&value);
86                Ok(Self(bytes))
87            }
88        }
89    };
90}
91
92impl_salt!(Salt128, 128);
93impl_salt!(Salt64, 64);
94impl_salt!(Salt32, 32);
95impl_salt!(Salt16, 16);
96impl_salt!(Salt12, 12);
97
98// Tests --------------------------------------------------------------------------------------
99
100#[cfg(test)]
101mod tests {
102    use crate::{exp::AutoExpiring, Rotation};
103
104    use super::*;
105
106    #[test]
107    fn generate_salt() {
108        let salt = Salt64::generate();
109        assert!(salt.is_ok());
110    }
111
112    #[test]
113    fn generate_different_salt() {
114        let salt1 = Salt64::generate().unwrap();
115        let salt2 = Salt64::generate().unwrap();
116        assert_ne!(*salt1, *salt2);
117    }
118
119    #[test]
120    #[cfg_attr(miri, ignore)]
121    fn generate_expiring_salt() {
122        let mut salt1 = AutoExpiring::<Salt64>::generate(chrono::Duration::seconds(60)).unwrap();
123        let bytes = salt1.clone();
124        salt1.rotate().unwrap();
125        assert_ne!(&*bytes, &*salt1, "Failed to compare");
126    }
127}