otplus_core/cipher/
root_key.rs1use chacha20poly1305::{aead::{KeyInit, OsRng}, Key, ChaCha20Poly1305};
2use zeroize::Zeroize;
3use serde::{Serialize, Serializer, Deserialize, Deserializer};
4use serde::de::Error;
5use base64::{engine::general_purpose::STANDARD, Engine};
6use serde::ser::SerializeStruct;
7use chrono::Utc;
8
9#[derive(Debug, Clone)]
10pub struct RootKeyMetadata {
11 pub created_at: i64,
12 pub key_length: u32,
13}
14
15impl Serialize for RootKeyMetadata {
16 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
17 where
18 S: Serializer,
19 {
20 let mut state = serializer.serialize_struct("RootKeyMetadata", 2)?;
21 state.serialize_field("created_at", &self.created_at)?;
22 state.serialize_field("key_length", &self.key_length)?;
23 state.end()
24 }
25}
26
27impl<'de> Deserialize<'de> for RootKeyMetadata {
28 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
29 where
30 D: Deserializer<'de>,
31 {
32 #[derive(Deserialize)]
33 struct RootKeyMetadataHelper {
34 created_at: i64,
35 key_length: u32,
36 }
37
38 let helper = RootKeyMetadataHelper::deserialize(deserializer)?;
39 Ok(Self { created_at: helper.created_at, key_length: helper.key_length })
40 }
41}
42
43#[derive(Debug, Clone)]
44pub struct RootKey {
45 pub value: Key,
46 pub metadata: RootKeyMetadata,
47}
48
49impl Serialize for RootKey {
50 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
51 where
52 S: Serializer,
53 {
54 let mut state = serializer.serialize_struct("RootKey", 2)?;
55 state.serialize_field("value", &STANDARD.encode(&self.value.as_slice()))?;
56 state.serialize_field("metadata", &self.metadata)?;
57 state.end()
58 }
59}
60
61impl<'de> Deserialize<'de> for RootKey {
62 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
63 where
64 D: Deserializer<'de>,
65 {
66 #[derive(Deserialize)]
67 struct RootKeyHelper {
68 value: String,
69 metadata: RootKeyMetadata,
70 }
71
72 let helper = RootKeyHelper::deserialize(deserializer)?;
73 let key = STANDARD.decode(&helper.value)
74 .map_err(|e| Error::custom(e.to_string()))?;
75
76 if key.len() != 32 {
77 return Err(Error::custom("Invalid key length"));
78 }
79
80 Ok(Self { value: Key::from_slice(&key).clone(), metadata: helper.metadata })
81 }
82}
83
84impl Drop for RootKey {
85 fn drop(&mut self) {
86 self.value.as_mut_slice().zeroize();
87 }
88}
89
90impl Default for RootKey {
91 fn default() -> Self {
92 let mut os_rng = OsRng::default();
93 let value = ChaCha20Poly1305::generate_key(&mut os_rng);
94 Self { value, metadata: RootKeyMetadata { created_at: Utc::now().timestamp_millis(), key_length: 32 } }
95 }
96}
97
98#[cfg(test)]
99mod root_key_tests {
100 use super::*;
101
102 #[test]
103 fn test_data_key_default() {
104 let dek = RootKey::default();
105 assert_eq!(dek.value.as_slice().len(), 32);
106 assert_eq!(dek.metadata.key_length, 32);
107 }
108
109 #[test]
110 fn test_data_key_serialize_deserialize() {
111 let dek = RootKey::default();
112 let serialized = serde_json::to_string(&dek).unwrap();
113 println!("Serialized: {}", serialized);
114 let deserialized: RootKey = serde_json::from_str(&serialized).unwrap();
115 println!("Deserialized: {:?}", deserialized);
116 }
117}