1
use zbus::zvariant;
2
use zeroize::{Zeroize, ZeroizeOnDrop};
3

            
4
use crate::{crypto, file};
5

            
6
/// Cryptographic key material.
7
///
8
/// File-keyring APIs accept already-derived values constructed with
9
/// [`Self::new`]. Key bytes are redacted from [`Debug`](std::fmt::Debug)
10
/// output.
11
#[derive(Zeroize, ZeroizeOnDrop)]
12
pub struct Key {
13
    key: Vec<u8>,
14
    #[zeroize(skip)]
15
    strength: Result<(), file::WeakKeyError>,
16
}
17

            
18
impl std::fmt::Debug for Key {
19
2
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20
2
        write!(
21
            f,
22
            "Key {{ key: [REDACTED], strength: {:?} }}",
23
            self.strength
24
        )
25
    }
26
}
27

            
28
impl AsRef<[u8]> for Key {
29
29
    fn as_ref(&self) -> &[u8] {
30
33
        self.key.as_slice()
31
    }
32
}
33

            
34
impl AsMut<[u8]> for Key {
35
41
    fn as_mut(&mut self) -> &mut [u8] {
36
36
        &mut self.key
37
    }
38
}
39

            
40
impl Key {
41
    /// Construct a key from bytes.
42
    ///
43
    /// The key's source strength is unknown. File-keyring APIs accept an
44
    /// exact-length value as direct key material, so callers are responsible
45
    /// for supplying sufficient entropy.
46
24
    pub const fn new(key: Vec<u8>) -> Self {
47
26
        Self::new_with_strength(key, Err(file::WeakKeyError::StrengthUnknown))
48
    }
49

            
50
23
    pub(crate) const fn check_strength(&self) -> Result<(), file::WeakKeyError> {
51
24
        self.strength
52
    }
53

            
54
35
    pub(crate) const fn new_with_strength(
55
        key: Vec<u8>,
56
        strength: Result<(), file::WeakKeyError>,
57
    ) -> Self {
58
        Self { key, strength }
59
    }
60

            
61
2
    pub(crate) fn validate_file_key(&self) -> Result<(), file::Error> {
62
2
        let expected = crypto::key_len();
63
4
        if self.key.len() == expected {
64
2
            Ok(())
65
        } else {
66
2
            Err(file::Error::InvalidKeyLength {
67
                expected,
68
2
                actual: self.key.len(),
69
            })
70
        }
71
    }
72

            
73
2
    pub(crate) fn into_file_key(mut self) -> Result<Self, file::Error> {
74
4
        self.validate_file_key()?;
75
4
        if matches!(self.strength, Err(file::WeakKeyError::StrengthUnknown)) {
76
2
            self.strength = Ok(());
77
        }
78
2
        Ok(self)
79
    }
80

            
81
22
    pub fn generate_private_key() -> Result<Self, crypto::Error> {
82
23
        Ok(Self::new(crypto::generate_private_key()?.to_vec()))
83
    }
84

            
85
19
    pub fn generate_public_key(private_key: &Self) -> Result<Self, crypto::Error> {
86
21
        Ok(Self::new(crypto::generate_public_key(private_key)?))
87
    }
88

            
89
19
    pub fn generate_aes_key(
90
        private_key: &Self,
91
        server_public_key: &Self,
92
    ) -> Result<Self, crypto::Error> {
93
21
        Ok(Self::new(
94
43
            crypto::generate_aes_key(private_key, server_public_key)?.to_vec(),
95
        ))
96
    }
97
}
98

            
99
impl From<Key> for zvariant::Value<'static> {
100
19
    fn from(key: Key) -> Self {
101
19
        let mut key = key;
102
19
        let inner: Vec<u8> = std::mem::take(&mut key.key);
103
19
        zvariant::Array::from(inner).into()
104
    }
105
}
106

            
107
impl From<Key> for zvariant::OwnedValue {
108
20
    fn from(key: Key) -> Self {
109
19
        zvariant::Value::from(key).try_into_owned().unwrap()
110
    }
111
}
112

            
113
impl TryFrom<zvariant::Value<'_>> for Key {
114
    type Error = zvariant::Error;
115

            
116
18
    fn try_from(value: zvariant::Value<'_>) -> Result<Self, Self::Error> {
117
19
        Ok(Key::new(value.try_into()?))
118
    }
119
}
120

            
121
impl TryFrom<zvariant::OwnedValue> for Key {
122
    type Error = zvariant::Error;
123

            
124
20
    fn try_from(value: zvariant::OwnedValue) -> Result<Self, Self::Error> {
125
20
        Self::try_from(zvariant::Value::from(value))
126
    }
127
}
128

            
129
#[cfg(test)]
130
mod tests {
131
    use super::*;
132

            
133
    #[test]
134
    fn private_public_pair() {
135
        let private_key = Key::new(vec![
136
            41, 20, 63, 236, 246, 132, 109, 70, 172, 121, 45, 66, 129, 21, 247, 91, 96, 217, 56,
137
            201, 205, 56, 17, 178, 202, 81, 71, 104, 233, 89, 87, 32, 88, 146, 107, 224, 56, 103,
138
            111, 74, 143, 80, 170, 40, 5, 52, 48, 90, 75, 71, 193, 224, 222, 57, 91, 81, 66, 1, 6,
139
            88, 137, 66, 102, 207, 55, 95, 67, 92, 140, 227, 242, 153, 185, 195, 89, 236, 146, 242,
140
            88, 215, 1, 7, 135, 254, 85, 165, 236, 110, 22, 79, 107, 254, 149, 164, 243, 94, 129,
141
            198, 45, 208, 132, 166, 0, 153, 243, 160, 255, 188, 59, 216, 99, 221, 85, 162, 116,
142
            210, 160, 117, 201, 39, 179, 123, 107, 8, 242, 139, 207, 250,
143
        ]);
144
        let server_public_key = Key::new(vec![
145
            50, 233, 76, 88, 47, 206, 235, 107, 9, 232, 98, 14, 188, 214, 209, 77, 35, 66, 109,
146
            119, 24, 191, 120, 90, 242, 198, 240, 115, 200, 66, 51, 180, 8, 164, 89, 9, 229, 31,
147
            160, 31, 156, 101, 169, 60, 63, 247, 37, 255, 75, 198, 62, 235, 50, 29, 221, 245, 29,
148
            248, 140, 209, 62, 215, 2, 137, 82, 77, 248, 242, 56, 176, 118, 183, 124, 74, 26, 133,
149
            188, 47, 31, 141, 232, 194, 92, 18, 69, 3, 56, 153, 42, 9, 143, 81, 197, 159, 200, 197,
150
            221, 74, 186, 157, 158, 36, 74, 125, 11, 234, 33, 2, 5, 36, 206, 248, 155, 157, 145,
151
            159, 238, 19, 185, 194, 134, 3, 195, 198, 60, 100, 159, 31,
152
        ]);
153

            
154
        let expected_public_key = &[
155
            9, 192, 210, 81, 212, 191, 74, 119, 22, 172, 81, 142, 124, 89, 17, 71, 118, 190, 81,
156
            71, 49, 149, 200, 204, 14, 47, 111, 165, 119, 103, 216, 102, 111, 93, 242, 64, 73, 224,
157
            165, 11, 127, 219, 197, 188, 168, 222, 254, 10, 104, 81, 8, 206, 237, 119, 225, 100,
158
            78, 196, 89, 163, 63, 169, 77, 236, 80, 241, 189, 49, 27, 40, 243, 229, 66, 53, 80, 86,
159
            44, 213, 87, 186, 68, 55, 216, 56, 236, 51, 229, 44, 174, 18, 87, 141, 85, 71, 185,
160
            203, 208, 144, 190, 117, 141, 255, 153, 106, 123, 28, 152, 200, 237, 189, 176, 20, 80,
161
            211, 33, 158, 232, 194, 145, 45, 194, 35, 108, 106, 214, 221, 159, 137,
162
        ];
163
        let expected_aes_key = &[
164
            132, 3, 113, 222, 81, 209, 49, 43, 81, 232, 243, 46, 1, 103, 184, 42,
165
        ];
166

            
167
        let public_key = Key::generate_public_key(&private_key);
168
        let aes_key = Key::generate_aes_key(&private_key, &server_public_key);
169

            
170
        assert_eq!(public_key.unwrap().as_ref(), expected_public_key);
171
        assert_eq!(aes_key.unwrap().as_ref(), expected_aes_key);
172
    }
173

            
174
    #[test]
175
    fn key_debug_is_redacted() {
176
        let key = Key::new(vec![1, 2, 3, 4]);
177
        let debug_output = format!("{:?}", key);
178

            
179
        assert!(debug_output.contains("key: [REDACTED]"));
180
        assert!(debug_output.contains("strength:"));
181
    }
182
}