voided_core/encryption/
key.rs1use crate::{Error, Result};
4use alloc::vec::Vec;
5use rand::RngCore;
6use zeroize::{Zeroize, ZeroizeOnDrop};
7
8#[derive(Clone, Zeroize, ZeroizeOnDrop)]
10pub struct Key([u8; 32]);
11
12impl Key {
13 pub const SIZE: usize = 32;
15
16 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
18 if bytes.len() != Self::SIZE {
19 return Err(Error::InvalidKeyLength {
20 expected: Self::SIZE,
21 actual: bytes.len(),
22 });
23 }
24 let mut key = [0u8; 32];
25 key.copy_from_slice(bytes);
26 Ok(Key(key))
27 }
28
29 pub fn as_bytes(&self) -> &[u8; 32] {
31 &self.0
32 }
33
34 pub fn to_base64(&self) -> String {
36 use base64::{Engine, engine::general_purpose::STANDARD};
37 STANDARD.encode(&self.0)
38 }
39
40 pub fn from_base64(encoded: &str) -> Result<Self> {
42 use base64::{Engine, engine::general_purpose::STANDARD};
43 let bytes = STANDARD.decode(encoded)?;
44 Self::from_bytes(&bytes)
45 }
46}
47
48impl AsRef<[u8]> for Key {
49 fn as_ref(&self) -> &[u8] {
50 &self.0
51 }
52}
53
54impl core::fmt::Debug for Key {
55 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
56 f.debug_struct("Key")
57 .field("length", &Self::SIZE)
58 .finish_non_exhaustive()
59 }
60}
61
62pub fn generate_key() -> Key {
64 let mut key = [0u8; 32];
65 rand::thread_rng().fill_bytes(&mut key);
66 Key(key)
67}
68
69pub fn derive_key_hkdf(
81 input_key_material: &[u8],
82 salt: Option<&[u8]>,
83 info: &[u8],
84) -> Result<Key> {
85 use hkdf::Hkdf;
86 use sha2::Sha256;
87
88 let hk = Hkdf::<Sha256>::new(salt, input_key_material);
89 let mut okm = [0u8; 32];
90
91 hk.expand(info, &mut okm)
92 .map_err(|e| Error::KeyDerivationFailed(e.to_string()))?;
93
94 Ok(Key(okm))
95}
96
97pub fn derive_key_pbkdf2(
109 password: &[u8],
110 salt: &[u8],
111 iterations: u32,
112) -> Result<Key> {
113 use pbkdf2::pbkdf2_hmac;
114 use sha2::Sha256;
115
116 let mut key = [0u8; 32];
117 pbkdf2_hmac::<Sha256>(password, salt, iterations, &mut key);
118
119 Ok(Key(key))
120}
121
122#[allow(dead_code)]
124pub fn generate_salt(length: usize) -> Vec<u8> {
125 let mut salt = vec![0u8; length];
126 rand::thread_rng().fill_bytes(&mut salt);
127 salt
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn test_key_generation() {
136 let key1 = generate_key();
137 let key2 = generate_key();
138
139 assert_ne!(key1.as_bytes(), key2.as_bytes());
141
142 assert_eq!(key1.as_bytes().len(), 32);
144 }
145
146 #[test]
147 fn test_key_base64_roundtrip() {
148 let key = generate_key();
149 let encoded = key.to_base64();
150 let decoded = Key::from_base64(&encoded).unwrap();
151
152 assert_eq!(key.as_bytes(), decoded.as_bytes());
153 }
154
155 #[test]
156 fn test_pbkdf2_derivation() {
157 let password = b"test password";
158 let salt = b"random salt here";
159 let iterations = 1000; let key1 = derive_key_pbkdf2(password, salt, iterations).unwrap();
162 let key2 = derive_key_pbkdf2(password, salt, iterations).unwrap();
163
164 assert_eq!(key1.as_bytes(), key2.as_bytes());
166 }
167
168 #[test]
169 fn test_hkdf_derivation() {
170 let ikm = b"input key material";
171 let salt = b"optional salt";
172 let info = b"context info";
173
174 let key1 = derive_key_hkdf(ikm, Some(salt), info).unwrap();
175 let key2 = derive_key_hkdf(ikm, Some(salt), info).unwrap();
176
177 assert_eq!(key1.as_bytes(), key2.as_bytes());
179 }
180}
181