vitaminc_encrypt/
key.rs

1use aws_lc_rs::aead::UnboundKey;
2use vitaminc_aead::{Cipher, Decrypt, Encrypt, IntoAad, LocalCipherText, Unspecified};
3use vitaminc_protected::{Controlled, Protected};
4use vitaminc_random::{Generatable, RandomError, SafeRand};
5
6/// 256-bit key type for use with symmetric encryption algorithms like AES-256-GCM.
7/// Vitaminc does not support smaller key sizes to ensure quantum security and compatibility with AWS-LC.
8// SAFETY: Safe to implement Debug because the inner type is Protected, which does not leak sensitive data.
9#[derive(Debug)]
10#[cfg_attr(test, derive(Clone))]
11pub struct Key(Protected<[u8; 32]>);
12
13impl Key {
14    pub(crate) fn as_unbound(&self) -> Result<UnboundKey, Unspecified> {
15        UnboundKey::new(&aws_lc_rs::aead::AES_256_GCM, self.0.risky_ref()).map_err(|_| Unspecified)
16    }
17}
18
19impl From<[u8; 32]> for Key {
20    fn from(key: [u8; 32]) -> Self {
21        Self(Protected::new(key))
22    }
23}
24
25impl Generatable for Key {
26    fn random(rng: &mut SafeRand) -> Result<Self, RandomError> {
27        Generatable::random(rng).map(Self)
28    }
29}
30
31pub struct EncryptedKey(LocalCipherText);
32
33impl Encrypt for Key {
34    type Encrypted = EncryptedKey;
35
36    fn encrypt_with_aad<'a, C, A>(self, cipher: &C, aad: A) -> Result<Self::Encrypted, Unspecified>
37    where
38        C: Cipher,
39        A: IntoAad<'a>,
40    {
41        self.0.encrypt_with_aad(cipher, aad).map(EncryptedKey)
42    }
43}
44
45impl Decrypt for Key {
46    type Encrypted = EncryptedKey;
47
48    fn decrypt_with_aad<'a, C, A>(
49        encrypted: Self::Encrypted,
50        cipher: &C,
51        aad: A,
52    ) -> Result<Self, Unspecified>
53    where
54        C: Cipher,
55        A: IntoAad<'a>,
56    {
57        Decrypt::decrypt_with_aad(encrypted.0, cipher, aad).map(Self)
58    }
59}
60
61#[cfg(test)]
62pub(crate) mod tests {
63    use super::*;
64    use quickcheck::Arbitrary;
65
66    fn gen_array(g: &mut quickcheck::Gen) -> [u8; 32] {
67        let mut array = [0u8; 32];
68        for byte in array.iter_mut() {
69            *byte = u8::arbitrary(g);
70        }
71        array
72    }
73
74    impl quickcheck::Arbitrary for Key {
75        fn arbitrary(g: &mut quickcheck::Gen) -> Self {
76            let key = gen_array(g);
77            Self(Protected::new(key))
78        }
79    }
80
81    /// A pair of keys that are guaranteed to be different when generated.
82    #[derive(Clone, Debug)]
83    pub(crate) struct DifferingKeyPair(pub Key, pub Key);
84
85    #[cfg(test)]
86    impl quickcheck::Arbitrary for DifferingKeyPair {
87        fn arbitrary(g: &mut quickcheck::Gen) -> Self {
88            let raw_a = gen_array(g);
89            let mut raw_b = gen_array(g);
90            while raw_a == raw_b {
91                raw_b = gen_array(g);
92            }
93            Self(Key::from(raw_a), Key::from(raw_b))
94        }
95    }
96}