Skip to main content

crypt_config/config/
hasher.rs

1extern 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}