1use crate::constants::{PBKDF2_ITERATIONS, SALT_SIZE};
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
26pub struct KeyDerivationParams {
27 pub salt: [u8; SALT_SIZE],
28 pub iterations: u32,
29}
30
31impl Default for KeyDerivationParams {
32 fn default() -> Self {
46 let mut salt = [0u8; SALT_SIZE];
47 rand::RngCore::fill_bytes(&mut rand::thread_rng(), &mut salt);
48 Self {
49 salt,
50 iterations: PBKDF2_ITERATIONS,
51 }
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58
59 #[test]
60 fn test_key_derivation_params_default() {
61 let params = KeyDerivationParams::default();
62
63 assert_eq!(params.iterations, PBKDF2_ITERATIONS);
65
66 assert_eq!(params.salt.len(), SALT_SIZE);
68 }
69
70 #[test]
71 fn test_default_salt_is_random() {
72 let params1 = KeyDerivationParams::default();
74 let params2 = KeyDerivationParams::default();
75
76 assert_ne!(params1.salt, params2.salt);
78
79 assert_ne!(params1.salt, [0u8; SALT_SIZE]);
81 assert_ne!(params2.salt, [0u8; SALT_SIZE]);
82 }
83
84 #[test]
85 fn test_key_derivation_params_clone() {
86 let params = KeyDerivationParams::default();
87 let cloned = params.clone();
88
89 assert_eq!(params, cloned);
91 assert_eq!(params.salt, cloned.salt);
92 assert_eq!(params.iterations, cloned.iterations);
93 }
94
95 #[test]
96 fn test_key_derivation_params_equality() {
97 let params1 = KeyDerivationParams {
98 salt: [42u8; SALT_SIZE],
99 iterations: 100000,
100 };
101 let params2 = KeyDerivationParams {
102 salt: [42u8; SALT_SIZE],
103 iterations: 100000,
104 };
105 let params3 = KeyDerivationParams {
106 salt: [43u8; SALT_SIZE],
107 iterations: 100000,
108 };
109
110 assert_eq!(params1, params2);
112
113 assert_ne!(params1, params3);
115 }
116
117 #[test]
118 fn test_key_derivation_params_serialization() {
119 let params = KeyDerivationParams {
120 salt: [123u8; SALT_SIZE],
121 iterations: 200000,
122 };
123
124 let json = serde_json::to_string(¶ms).expect("Serialization failed");
126
127 let deserialized: KeyDerivationParams =
129 serde_json::from_str(&json).expect("Deserialization failed");
130
131 assert_eq!(params, deserialized);
133 assert_eq!(params.salt, deserialized.salt);
134 assert_eq!(params.iterations, deserialized.iterations);
135 }
136
137 #[test]
138 fn test_key_derivation_params_debug() {
139 let params = KeyDerivationParams {
140 salt: [1u8; SALT_SIZE],
141 iterations: 150000,
142 };
143
144 let debug_str = format!("{:?}", params);
146 assert!(debug_str.contains("KeyDerivationParams"));
147 assert!(debug_str.contains("salt"));
148 assert!(debug_str.contains("iterations"));
149 }
150
151 #[test]
152 fn test_iterations_constant_is_reasonable() {
153 #[allow(clippy::assertions_on_constants)]
157 {
158 assert!(
159 PBKDF2_ITERATIONS >= 100_000,
160 "Iterations too low for security"
161 );
162 }
163 #[allow(clippy::assertions_on_constants)]
164 {
165 assert!(
166 PBKDF2_ITERATIONS <= 10_000_000,
167 "Iterations too high for usability"
168 );
169 }
170 }
171
172 #[test]
173 fn test_salt_size_is_reasonable() {
174 #[allow(clippy::assertions_on_constants)]
177 {
178 assert!(SALT_SIZE >= 16, "Salt size too small for security");
179 }
180 #[allow(clippy::assertions_on_constants)]
181 {
182 assert!(SALT_SIZE <= 64, "Salt size unnecessarily large");
183 }
184 }
185
186 #[test]
187 fn test_manual_construction() {
188 let custom_salt = [99u8; SALT_SIZE];
189 let custom_iterations = 500000;
190
191 let params = KeyDerivationParams {
192 salt: custom_salt,
193 iterations: custom_iterations,
194 };
195
196 assert_eq!(params.salt, custom_salt);
197 assert_eq!(params.iterations, custom_iterations);
198 }
199
200 #[test]
201 fn test_different_defaults_have_different_salts() {
202 let instances: Vec<KeyDerivationParams> =
204 (0..5).map(|_| KeyDerivationParams::default()).collect();
205
206 for i in 0..instances.len() {
208 for j in (i + 1)..instances.len() {
209 assert_ne!(
210 instances[i].salt, instances[j].salt,
211 "Salts at indices {} and {} should be different",
212 i, j
213 );
214 }
215 }
216 }
217}