backup_suite/crypto/
key_management.rs1use crate::error::{BackupError, Result};
6use argon2::password_hash::rand_core::{OsRng, RngCore};
7use argon2::password_hash::SaltString;
8use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
9use zeroize::{Zeroize, ZeroizeOnDrop};
10
11#[derive(Clone, Zeroize, ZeroizeOnDrop)]
13pub struct MasterKey {
14 key: [u8; 32],
15}
16
17impl MasterKey {
18 #[must_use]
20 pub fn generate() -> Self {
21 let mut key = [0u8; 32];
22 OsRng.fill_bytes(&mut key);
23 Self { key }
24 }
25
26 #[must_use]
28 pub fn from_bytes(bytes: [u8; 32]) -> Self {
29 Self { key: bytes }
30 }
31
32 #[must_use]
34 pub fn as_bytes(&self) -> &[u8; 32] {
35 &self.key
36 }
37}
38
39#[derive(Debug, Clone)]
41pub struct KeyDerivationConfig {
42 pub memory_cost: u32,
44 pub time_cost: u32,
46 pub parallelism: u32,
48}
49
50impl Default for KeyDerivationConfig {
51 fn default() -> Self {
52 Self {
53 memory_cost: 131_072, time_cost: 4, parallelism: 2, }
57 }
58}
59
60pub struct KeyDerivation {
62 config: KeyDerivationConfig,
63}
64
65impl KeyDerivation {
66 #[must_use]
68 pub fn new(config: KeyDerivationConfig) -> Self {
69 Self { config }
70 }
71
72 pub fn derive_key(&self, password: &str, salt: &[u8]) -> Result<MasterKey> {
83 let argon2 = Argon2::new(
84 argon2::Algorithm::Argon2id,
85 argon2::Version::V0x13,
86 argon2::Params::new(
87 self.config.memory_cost,
88 self.config.time_cost,
89 self.config.parallelism,
90 Some(32),
91 )
92 .map_err(|e| BackupError::EncryptionError(format!("Argon2パラメータエラー: {e}")))?,
93 );
94
95 let salt_string = SaltString::encode_b64(salt)
96 .map_err(|e| BackupError::EncryptionError(format!("Salt エンコードエラー: {e}")))?;
97
98 let password_hash = argon2
99 .hash_password(password.as_bytes(), &salt_string)
100 .map_err(|e| BackupError::EncryptionError(format!("パスワードハッシュエラー: {e}")))?;
101
102 let hash = password_hash
103 .hash
104 .ok_or_else(|| BackupError::EncryptionError("ハッシュ生成に失敗".to_string()))?;
105 let hash_bytes = hash.as_bytes();
106
107 if hash_bytes.len() != 32 {
108 return Err(BackupError::EncryptionError("無効なキー長".to_string()));
109 }
110
111 let mut key = [0u8; 32];
112 key.copy_from_slice(hash_bytes);
113 Ok(MasterKey::from_bytes(key))
114 }
115
116 #[must_use]
118 pub fn generate_salt() -> [u8; 16] {
119 let mut salt = [0u8; 16];
120 OsRng.fill_bytes(&mut salt);
121 salt
122 }
123
124 pub fn verify_password(&self, password: &str, hash: &str) -> Result<bool> {
133 let parsed_hash = PasswordHash::new(hash)
134 .map_err(|e| BackupError::EncryptionError(format!("ハッシュ解析エラー: {e}")))?;
135
136 let argon2 = Argon2::default();
137 Ok(argon2
138 .verify_password(password.as_bytes(), &parsed_hash)
139 .is_ok())
140 }
141}
142
143impl Default for KeyDerivation {
144 fn default() -> Self {
145 Self::new(KeyDerivationConfig::default())
146 }
147}
148
149#[derive(Default)]
151pub struct KeyManager {
152 derivation: KeyDerivation,
153}
154
155impl KeyManager {
156 #[must_use]
158 pub fn new(config: KeyDerivationConfig) -> Self {
159 Self {
160 derivation: KeyDerivation::new(config),
161 }
162 }
163
164 pub fn create_master_key(&self, password: &str) -> Result<(MasterKey, [u8; 16])> {
174 let salt = KeyDerivation::generate_salt();
175 let key = self.derivation.derive_key(password, &salt)?;
176 Ok((key, salt))
177 }
178
179 pub fn restore_master_key(&self, password: &str, salt: &[u8]) -> Result<MasterKey> {
189 self.derivation.derive_key(password, salt)
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 #[test]
198 fn test_master_key_generation() {
199 let key1 = MasterKey::generate();
200 let key2 = MasterKey::generate();
201
202 assert_ne!(key1.as_bytes(), key2.as_bytes());
204
205 assert_eq!(key1.as_bytes().len(), 32);
207 }
208
209 #[test]
210 fn test_key_derivation() {
211 let kd = KeyDerivation::default();
212 let password = "test_password_123";
213 let salt = KeyDerivation::generate_salt();
214
215 let key1 = kd.derive_key(password, &salt).unwrap();
216 let key2 = kd.derive_key(password, &salt).unwrap();
217
218 assert_eq!(key1.as_bytes(), key2.as_bytes());
220
221 let salt2 = KeyDerivation::generate_salt();
223 let key3 = kd.derive_key(password, &salt2).unwrap();
224 assert_ne!(key1.as_bytes(), key3.as_bytes());
225 }
226
227 #[test]
228 fn test_key_manager() {
229 let km = KeyManager::default();
230 let password = "secure_password_456";
231
232 let (key1, salt) = km.create_master_key(password).unwrap();
233 let key2 = km.restore_master_key(password, &salt).unwrap();
234
235 assert_eq!(key1.as_bytes(), key2.as_bytes());
237 }
238
239 #[test]
242 fn test_verify_password_with_correct_password() {
243 let kd = KeyDerivation::default();
244 let password = "correct_password_123";
245
246 let salt = KeyDerivation::generate_salt();
248 let argon2 = Argon2::default();
249 let salt_string = SaltString::encode_b64(&salt).unwrap();
250 let password_hash = argon2
251 .hash_password(password.as_bytes(), &salt_string)
252 .unwrap();
253 let hash_str = password_hash.to_string();
254
255 let result = kd.verify_password(password, &hash_str).unwrap();
257 assert!(result, "正しいパスワードは true を返すべき");
258 }
259
260 #[test]
261 fn test_verify_password_with_wrong_password() {
262 let kd = KeyDerivation::default();
263 let correct_password = "correct_password_123";
264 let wrong_password = "wrong_password_456";
265
266 let salt = KeyDerivation::generate_salt();
268 let argon2 = Argon2::default();
269 let salt_string = SaltString::encode_b64(&salt).unwrap();
270 let password_hash = argon2
271 .hash_password(correct_password.as_bytes(), &salt_string)
272 .unwrap();
273 let hash_str = password_hash.to_string();
274
275 let result = kd.verify_password(wrong_password, &hash_str).unwrap();
277 assert!(!result, "間違ったパスワードは false を返すべき");
278 }
279
280 #[test]
281 fn test_verify_password_edge_cases() {
282 let kd = KeyDerivation::default();
283 let password = "test_password";
284
285 let salt = KeyDerivation::generate_salt();
287 let argon2 = Argon2::default();
288 let salt_string = SaltString::encode_b64(&salt).unwrap();
289 let password_hash = argon2
290 .hash_password(password.as_bytes(), &salt_string)
291 .unwrap();
292 let hash_str = password_hash.to_string();
293
294 let result = kd.verify_password("", &hash_str).unwrap();
296 assert!(!result, "空パスワードは拒否されるべき");
297
298 let result = kd.verify_password("TEST_PASSWORD", &hash_str).unwrap();
300 assert!(!result, "大文字小文字の違いは拒否されるべき");
301
302 let result = kd.verify_password("test_pass", &hash_str).unwrap();
304 assert!(!result, "部分一致パスワードは拒否されるべき");
305 }
306
307 #[test]
308 fn test_verify_password_must_return_boolean() {
309 let kd = KeyDerivation::default();
310 let password = "any_password";
311
312 let salt = KeyDerivation::generate_salt();
314 let argon2 = Argon2::default();
315 let salt_string = SaltString::encode_b64(&salt).unwrap();
316 let password_hash = argon2
317 .hash_password(password.as_bytes(), &salt_string)
318 .unwrap();
319 let hash_str = password_hash.to_string();
320
321 let result_correct = kd.verify_password(password, &hash_str).unwrap();
323 assert!(result_correct, "verify_password(correct) must return true");
324
325 let result_wrong = kd.verify_password("different_password", &hash_str).unwrap();
327 assert!(!result_wrong, "verify_password(wrong) must return false");
328
329 assert_ne!(
331 result_correct, result_wrong,
332 "正しいパスワードと間違ったパスワードで結果が異なるべき"
333 );
334 }
335
336 #[test]
337 fn test_verify_password_invalid_hash_format() {
338 let kd = KeyDerivation::default();
339 let password = "any_password";
340
341 let result = kd.verify_password(password, "invalid_hash_format");
343 assert!(result.is_err(), "無効なハッシュ形式はエラーを返すべき");
344
345 let result = kd.verify_password(password, "");
347 assert!(result.is_err(), "空のハッシュ文字列はエラーを返すべき");
348 }
349}