1use crate::{
2 error::Result, AsymmetricCryptoKey, CryptoError, EncString, KeyDecryptable, KeyEncryptable,
3 SymmetricCryptoKey, UnsignedSharedKey,
4};
5
6#[derive(Debug)]
11pub struct DeviceKey(SymmetricCryptoKey);
12
13#[derive(Debug)]
14#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
15pub struct TrustDeviceResponse {
16 pub device_key: String,
18 pub protected_user_key: UnsignedSharedKey,
20 pub protected_device_private_key: EncString,
22 pub protected_device_public_key: EncString,
24}
25
26impl DeviceKey {
27 pub fn trust_device(user_key: &SymmetricCryptoKey) -> Result<TrustDeviceResponse> {
32 let mut rng = rand::thread_rng();
33 let device_key = DeviceKey(SymmetricCryptoKey::make_aes256_cbc_hmac_key());
34
35 let device_private_key = AsymmetricCryptoKey::generate(&mut rng);
36
37 let protected_user_key =
38 UnsignedSharedKey::encapsulate_key_unsigned(user_key, &device_private_key)?;
39
40 let protected_device_public_key = device_private_key
41 .to_public_der()?
42 .encrypt_with_key(user_key)?;
43
44 let protected_device_private_key = device_private_key
45 .to_der()?
46 .encrypt_with_key(&device_key.0)?;
47
48 Ok(TrustDeviceResponse {
49 device_key: device_key.to_base64(),
50 protected_user_key,
51 protected_device_private_key,
52 protected_device_public_key,
53 })
54 }
55
56 pub fn decrypt_user_key(
58 &self,
59 protected_device_private_key: EncString,
60 protected_user_key: UnsignedSharedKey,
61 ) -> Result<SymmetricCryptoKey> {
62 let device_private_key: Vec<u8> = protected_device_private_key.decrypt_with_key(&self.0)?;
63 let device_private_key = AsymmetricCryptoKey::from_der(&device_private_key)?;
64
65 let user_key: SymmetricCryptoKey =
66 protected_user_key.decapsulate_key_unsigned(&device_private_key)?;
67 Ok(user_key)
68 }
69
70 fn to_base64(&self) -> String {
71 self.0.to_base64()
72 }
73}
74
75impl TryFrom<String> for DeviceKey {
76 type Error = CryptoError;
77
78 fn try_from(value: String) -> Result<Self, Self::Error> {
79 SymmetricCryptoKey::try_from(value).map(DeviceKey)
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use crate::derive_symmetric_key;
87
88 #[test]
89 fn test_trust_device() {
90 let key = SymmetricCryptoKey::Aes256CbcHmacKey(derive_symmetric_key("test"));
91
92 let result = DeviceKey::trust_device(&key).unwrap();
93
94 let device_key = DeviceKey::try_from(result.device_key).unwrap();
95 let decrypted = device_key
96 .decrypt_user_key(
97 result.protected_device_private_key,
98 result.protected_user_key,
99 )
100 .unwrap();
101
102 assert_eq!(key, decrypted);
103 assert_eq!(key, decrypted);
104 }
105
106 #[test]
107 fn test_decrypt_user_key() {
108 let user_key: &mut [u8] = &mut [
110 109, 128, 172, 147, 206, 123, 134, 95, 16, 36, 155, 113, 201, 18, 186, 230, 216, 212,
111 173, 188, 74, 11, 134, 131, 137, 242, 105, 178, 105, 126, 52, 139, 248, 91, 215, 21,
112 128, 91, 226, 222, 165, 67, 251, 34, 83, 81, 77, 147, 225, 76, 13, 41, 102, 45, 183,
113 218, 106, 89, 254, 208, 251, 101, 130, 10,
114 ];
115 let user_key = SymmetricCryptoKey::try_from(user_key).unwrap();
116
117 let key_data: &mut [u8] = &mut [
118 114, 235, 60, 115, 172, 156, 203, 145, 195, 130, 215, 250, 88, 146, 215, 230, 12, 109,
119 245, 222, 54, 217, 255, 211, 221, 105, 230, 236, 65, 52, 209, 133, 76, 208, 113, 254,
120 194, 216, 156, 19, 230, 62, 32, 93, 87, 7, 144, 156, 117, 142, 250, 32, 182, 118, 187,
121 8, 247, 7, 203, 201, 65, 147, 206, 247,
122 ];
123 let device_key = DeviceKey(key_data.try_into().unwrap());
124
125 let protected_user_key: UnsignedSharedKey = "4.f+VbbacRhO2q4MOUSdt1AIjQ2FuLAvg4aDxJMXAh3VxvbmUADj8Ct/R7XEpPUqApmbRS566jS0eRVy8Sk08ogoCdj1IFN9VsIky2i2X1WHK1fUnr3UBmXE3tl2NPBbx56U+h73S2jNTSyet2W18Jg2q7/w8KIhR3J41QrG9aGoOTN93to3hb5W4z6rdrSI0e7GkizbwcIA0NH7Z1JyAhrjPm9+tjRjg060YbEbGaWTAOkZWfgbLjr8bY455DteO2xxG139cOx7EBo66N+YhjsLi0ozkeUyPQkoWBdKMcQllS7jCfB4fDyJA05ALTbk74syKkvqFxqwmQbg+aVn+dcw==".parse().unwrap();
126
127 let protected_device_private_key: EncString = "2.GyQfUYWW6Byy4UV5icFLxg==|EMiU7OTF79N6tfv3+YUs5zJhBAgqv6sa5YCoPl6yAETh7Tfk+JmbeizxXFPj5Q1X/tcVpDZl/3fGcxtnIxg1YtvDFn7j8uPnoApOWhCKmwcvJSIkt+qvX3lELNBwZXozSiy7PbQ0JbCMe2d4MkimR5k8+lE9FB3208yYK7nOJhlrsUCnOekCYEU9/4NCMA8tz8SpITx/MN4JJ1TQ/KjPJYLt+3JNUxK47QlgREWQvyVzCRt7ZGtcgIJ/U1qycAWMpEg9NkuV8j5QRA1S7VBsA6qliJwys5+dmTuIOmOMwdKFZDc4ZvWoRkPp2TSJBu7L8sSAgU6mmDWac8iQ+9Ka/drdfwYLrH8GAZvURk79tSpRrT7+PAFe2QdUtliUIyiqkh8iJVjZube4hRnEsRuX9V9b+UdtAr6zAj7mugO/VAu5T9J38V79V2ohG3NtXysDeKLXpAlkhjllWXeq/wret2fD4WiwqEDj0G2A/PY3F3OziIgp0UKc00AfqrPq8OVK3A+aowwVqdYadgxyoVCKWJ8unJeAXG7MrMQ9tHpzF6COoaEy7Wwoc17qko33zazwLZbfAjB4oc8Ea26jRKnJZP56sVZAjOSQQMziAsA08MRaa/DQhgRea1+Ygba0gMft8Dww8anN2gQBveTZRBWyqXYgN3U0Ity5gNauT8RnFk9faqVFt2Qxnp0JgJ+PsqEt5Hn4avBRZQQ7o8VvPnxYLDKFe3I2m6HFYFWRhOGeDYxexIuaiF2iIAYFVUmnDuWpgnUiL4XJ3KHDsjkPzcV3z4D2Knr/El2VVXve8jhDjETfovmmN28+i2e29PXvKIymTskMFpFCQPc7wBY/Id7pmgb3SujKYNpkAS2sByDoRir0my49DDGfta0dENssJhFd3x+87fZbEj3cMiikg2pBwpTLgmfIUa5cVZU2s8JZ9wu7gaioYzvX+elHa3EHLcnEUoJTtSf9kjb+Nbq4ktMgYAO2wIC96t1LvmqK4Qn2cOdw5QNlRqALhqe5V31kyIcwRMK0AyIoOPhnSqtpYdFiR3LDTvZA8dU0vSsuchCwHNMeRUtKvdzN/tk+oeznyY/mpakUESN501lEKd/QFLtJZsDZTtNlcA8fU3kDtws4ZIMR0O5+PFmgQFSU8OMobf9ClUzy/wHTvYGyDuSwbOoPeS955QKkUKXCNMj33yrPr+ioHQ1BNwLX3VmMF4bNRBY/vr+CG0/EZi0Gwl0kyHGl0yWEtpQuu+/PaROJeOraWy5D1UoZZhY4n0zJZBt1eg3FZ2rhKv4gdUc50nZpeNWE8pIqZ6RQ7qPJuqfF1Z+G73iOSnLYCHDiiFmhD5ivf9IGkTAcWcBsQ/2wcSj9bFJr4DrKfsbQ4CkSWICWVn/W+InKkO6BTsBbYmvte5SvbaN+UOtiUSkHLBCCr8273VNgcB/hgtbUires3noxYZJxoczr+i7vdlEgQnWEKrpo0CifsFxGwYS3Yy2K79iwvDMaLPDf73zLSbuoUl6602F2Mzcjnals67f+gSpaDvWt7Kg9c/ZfGjq8oNxVaXJnX3gSDsO+fhwVAtnDApL+tL8cFfxGerW4KGi9/74woH+C3MMIViBtNnrpEuvxUW97Dg5nd40oGDeyi/q+8HdcxkneyFY=|JYdol19Yi+n1r7M+06EwK5JCi2s/CWqKui2Cy6hEb3k=".parse().unwrap();
128
129 let decrypted = device_key
130 .decrypt_user_key(protected_device_private_key, protected_user_key)
131 .unwrap();
132
133 assert_eq!(decrypted, user_key);
134 }
135}