crypt_config/config/
hasher.rs1extern crate base64;
2extern crate serde;
3extern crate serde_json;
4
5use std::collections::HashMap;
6
7use serde::{Deserialize, Serialize};
8
9use crate::error::{CryptError, CryptResult};
10use crate::hasher::{BcryptHasher, IHasher, Pbkdf2Hasher};
11
12#[derive(Serialize, Deserialize)]
13pub struct HasherConfig {
14 algorithm: String,
15 rounds: u32,
16 salt: Vec<u8>
17}
18
19#[allow(dead_code)]
20pub struct HasherData {
21 configurations: HashMap<String, Box<HasherConfig>>,
22 latest_version: String
23}
24
25impl HasherConfig {
26 #[allow(dead_code)]
27 pub fn new(algorithm: String, rounds: u32, salt: Vec<u8>) -> HasherConfig {
28 HasherConfig { algorithm: algorithm, rounds: rounds, salt: salt }
29 }
30}
31
32impl HasherData {
33 #[allow(dead_code)]
34 pub fn new() -> HasherData {
35 HasherData { configurations: HashMap::new(), latest_version: "0".to_string() }
36 }
37
38 pub fn contains_configuration(&self, version: &str) -> bool {
39 self.configurations.contains_key(version)
40 }
41
42 pub fn insert_configuration(&mut self, version: &str, cfg: Box<HasherConfig>) {
43 self.configurations.insert(version.to_string(), cfg);
44 self.update_version(version);
45 }
46
47 pub fn get_all_versions(&self) -> Vec<&String> {
48 self.configurations.keys().collect::<Vec<_>>()
49 }
50
51 pub fn get_latest_version(&self) -> &str {
52 self.latest_version.as_str()
53 }
54
55 pub fn get_config<'a>(&'a self, version: &str) -> Option<&'a Box<HasherConfig>> {
56 self.configurations.get(version)
57 }
58
59 fn update_version(&mut self, version: &str) {
60 if self.latest_version.as_str() < version {
61 self.latest_version = version.to_string()
62 }
63 }
64}
65
66#[allow(dead_code)]
67pub fn generate_hasher_from_config(cfg: &HasherConfig) -> CryptResult<Box<dyn IHasher>> {
68 match cfg.algorithm.as_ref() {
69 "bcrypt" => Ok(Box::new(BcryptHasher::new(cfg.rounds, &cfg.salt))),
70 "pbkdf2" => Ok(Box::new(Pbkdf2Hasher::new(cfg.rounds, &cfg.salt))),
71 _ => Err(CryptError::HasherNotFound(cfg.algorithm.clone()))
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::generate_hasher_from_config;
78 use super::HasherConfig;
79 #[test]
80 fn bcrypt_algorithm() {
81 let rounds = 10;
82 let salt = [10u8, 16].to_vec();
83 let cfg = HasherConfig { rounds: rounds, salt: salt, algorithm: "bcrypt".to_string() };
84
85 let hasher = generate_hasher_from_config(&cfg).unwrap();
86 let password = "password";
87 let data = hasher.encrypt(password);
88
89 assert!(hasher.verify(&data, password));
90
91 let password = "password2";
92 assert!(!hasher.verify(&data, password));
93 }
94
95 #[test]
96 fn pbkdf2_algorithm() {
97 let rounds = 10;
98 let salt = [10u8, 16].to_vec();
99 let cfg = HasherConfig { rounds: rounds, salt: salt, algorithm: "pbkdf2".to_string() };
100
101 let hasher = generate_hasher_from_config(&cfg).unwrap();
102 let password = "password";
103 let data = hasher.encrypt(password);
104
105 assert!(hasher.verify(&data, password));
106
107 let password = "password2";
108 assert!(!hasher.verify(&data, password));
109 }
110
111 #[test]
112 fn unknown_algorithm() {
113 let rounds = 10;
114 let salt = [10u8, 16].to_vec();
115 let cfg = HasherConfig { rounds: rounds, salt: salt, algorithm: "unknown".to_string() };
116
117 let out = generate_hasher_from_config(&cfg);
118 assert!(out.is_err());
119 }
120
121 #[test]
122 fn mixed_algorithm() {
123 let rounds = 10;
124 let salt = [10u8, 16].to_vec();
125 let cfg1 = HasherConfig { rounds: rounds, salt: salt, algorithm: "bcrypt".to_string() };
126 let salt = [10u8, 16].to_vec();
127 let cfg2 = HasherConfig { rounds: rounds, salt: salt, algorithm: "pbkdf2".to_string() };
128
129 let hasher1 = generate_hasher_from_config(&cfg1).unwrap();
130 let hasher2 = generate_hasher_from_config(&cfg2).unwrap();
131 let password = "password";
132 let data1 = hasher1.encrypt(password);
133 let data2 = hasher2.encrypt(password);
134
135 assert!(hasher1.verify(&data1, password));
136 assert!(hasher2.verify(&data2, password));
137 assert!(!hasher1.verify(&data2, password));
138 assert!(!hasher2.verify(&data1, password));
139
140 let password = "password2";
141 assert!(!hasher1.verify(&data1, password));
142 assert!(!hasher2.verify(&data2, password));
143 assert!(!hasher1.verify(&data2, password));
144 assert!(!hasher2.verify(&data1, password));
145 }
146}