keepass_db/kdf/
argon2.rs

1use log::{info, debug};
2
3#[cfg(feature = "rust-argon2")]
4use ::argon2::{Config, Variant, Version};
5#[cfg(feature = "argonautica")]
6use argonautica::{
7    config::{Variant, Version},
8    Hasher,
9};
10#[cfg(feature = "argon2-kdf")]
11use argon2_kdf::{Hasher, Algorithm};
12#[cfg(feature = "argon2")]
13use ::argon2::{Argon2, Algorithm, Version, ParamsBuilder};
14
15use crate::utils::{unmake_u32, unmake_u64};
16use super::*;
17
18/* TODO Use these defaults */
19const _DEFAULT_ITERATIONS: u64 = 2;
20const _DEFAULT_MEMORY: u64 = 1024 * 1024;
21const _DEFAULT_PARALLELISM: u32 = 2;
22
23#[cfg(feature = "rust-argon2")]
24fn transform_argon2_lib(
25    composite_key: &[u8],
26    salt: &[u8],
27    version: u32,
28    mem_cost: u32,
29    time_cost: u32,
30    lanes: u32,
31) -> io::Result<Vec<u8>> {
32    debug!("Rust Argon2");
33    let version = match version {
34        0x13 => Version::Version13,
35        0x10 => Version::Version10,
36        _ => {
37            panic!("Misconfigured!");
38        }
39    };
40    let config = Config {
41        variant: Variant::Argon2d,
42        version,
43        mem_cost,
44        time_cost,
45        lanes,
46        secret: &[],
47        ad: &[],
48        hash_length: 32,
49    };
50    let hash = ::argon2::hash_raw(composite_key, salt, &config).unwrap();
51    println!(
52        "P: {:0x?}, S: {:0x?}, H: {:0x?}, C: {:#?}",
53        composite_key, salt, hash, config
54    );
55    Ok(hash)
56}
57
58#[cfg(feature = "argonautica")]
59fn transform_argon2_lib(
60    composite_key: &[u8],
61    salt: &[u8],
62    version: u32,
63    mem_cost: u32,
64    time_cost: u32,
65    lanes: u32,
66) -> io::Result<Vec<u8>> {
67    debug!("Argonautica");
68    let version = match version {
69        0x13 => Version::_0x13,
70        0x10 => Version::_0x10,
71        _ => {
72            panic!("Misconfigured!");
73        }
74    };
75    let mut hasher = Hasher::default();
76    hasher
77        .configure_iterations(time_cost)
78        .configure_lanes(lanes)
79        .configure_memory_size(mem_cost)
80        .configure_variant(Variant::Argon2d)
81        .configure_version(version)
82        .opt_out_of_secret_key(true);
83    //println!("P: {:0x?}, S: {:0x?}, H: {:0x?}, C: {:#?}", composite_key, salt, b"", hasher);//hash, config);
84    Ok(hasher
85        .with_password(composite_key)
86        .with_salt(salt)
87        .hash_raw()
88        .unwrap()
89        .raw_hash_bytes()
90        .to_owned())
91}
92
93#[cfg(feature = "argon2-kdf")]
94fn transform_argon2_lib(
95    composite_key: &[u8],
96    salt: &[u8],
97    version: u32,
98    mem_cost: u32,
99    time_cost: u32,
100    lanes: u32,
101) -> io::Result<Vec<u8>> {
102    debug!("Argon2-KDF");
103    Ok(Hasher::new()
104            .algorithm(Algorithm::Argon2d)
105            .custom_salt(salt)
106            .hash_length(32)
107            .iterations(time_cost)
108            .memory_cost_kib(mem_cost)
109            .threads(lanes)
110            .hash(composite_key)
111            .unwrap()
112            .as_bytes()
113            .to_owned())
114}
115
116#[cfg(feature = "argon2")]
117fn transform_argon2_lib(
118    composite_key: &[u8],
119    salt: &[u8],
120    version: u32,
121    mem_cost: u32,
122    time_cost: u32,
123    lanes: u32,
124) -> io::Result<Vec<u8>> {
125    debug!("Argon2");
126    let version = match version {
127        0x13 => Version::V0x13,
128        0x10 => Version::V0x10,
129        _ => {
130            panic!("Misconfigured!");
131        }
132    };
133    let mut hash = [0; 32];
134    Argon2::new(Algorithm::Argon2d, version, ParamsBuilder::new()
135        .m_cost(mem_cost)
136        .t_cost(time_cost)
137        .p_cost(lanes)
138        .output_len(32)
139        .build()
140        .unwrap()
141    ).hash_password_into(composite_key, &salt, &mut hash).unwrap();
142    Ok(hash.to_vec())
143}
144
145#[cfg(any(feature = "rust-argon2", feature = "argonautica", feature = "argon2-kdf", feature = "argon2"))]
146pub fn transform_argon2(
147    composite_key: &[u8],
148    custom_data: &HashMap<String, Vec<u8>>,
149) -> io::Result<Vec<u8>> {
150    info!("Found Argon2 KDF");
151    let salt = match custom_data.get(KDF_PARAM_SALT) {
152        Some(x) => x,
153        None => {
154            return Err(io::Error::new(io::ErrorKind::Other, "Argon2 salt missing"));
155        }
156    };
157    let version = match custom_data.get(KDF_PARAM_VERSION) {
158        Some(x) => match unmake_u32(x) {
159            Some(x) if x > 0x13 => {
160                println!("Version: {}", x);
161                return Err(io::Error::new(
162                    io::ErrorKind::Other,
163                    "Argon2 version too new",
164                ));
165            }
166            Some(x) if x == 0x13 => 0x13,
167            Some(x) if x >= 0x10 => 0x10,
168            Some(_) => {
169                return Err(io::Error::new(
170                    io::ErrorKind::Other,
171                    "Argon2 version too old",
172                ));
173            }
174            None => {
175                return Err(io::Error::new(io::ErrorKind::Other, "Invalid version"));
176            }
177        },
178        None => {
179            return Err(io::Error::new(
180                io::ErrorKind::Other,
181                "Argon2 version missing",
182            ));
183        }
184    };
185    let mem_cost = match custom_data.get(KDF_PARAM_MEMORY) {
186        Some(x) => match unmake_u64(x) {
187            Some(x) => x / 1024,
188            None => {
189                return Err(io::Error::new(
190                    io::ErrorKind::Other,
191                    "Invalid memory parameter",
192                ));
193            }
194        },
195        None => {
196            return Err(io::Error::new(
197                io::ErrorKind::Other,
198                "Argon2 memory parameter missing",
199            ));
200        }
201    };
202    let time_cost = match custom_data.get(KDF_PARAM_ITERATIONS) {
203        Some(x) => match unmake_u64(x) {
204            Some(x) => x,
205            None => {
206                return Err(io::Error::new(
207                    io::ErrorKind::Other,
208                    "Invalid time parameter",
209                ));
210            }
211        },
212        None => {
213            return Err(io::Error::new(
214                io::ErrorKind::Other,
215                "Argon2 time parameter missing",
216            ));
217        }
218    };
219    let lanes = match custom_data.get(KDF_PARAM_PARALLELISM) {
220        Some(x) => match unmake_u32(x) {
221            Some(x) => x,
222            None => {
223                return Err(io::Error::new(
224                    io::ErrorKind::Other,
225                    "Invalid parallelism parameter",
226                ));
227            }
228        },
229        None => {
230            return Err(io::Error::new(
231                io::ErrorKind::Other,
232                "Argon2 parallelism parameter missing",
233            ));
234        }
235    };
236    let hash = transform_argon2_lib(
237        composite_key,
238        salt,
239        version,
240        mem_cost as u32,
241        time_cost as u32,
242        lanes,
243    )
244    .unwrap();
245    Ok(hash)
246}
247
248#[cfg(not(any(feature = "rust-argon2", feature = "argonautica", feature = "argon2-kdf", feature = "argon2")))]
249pub fn transform_argon2(
250    _composite_key: &[u8],
251    custom_data: &HashMap<String, Vec<u8>>,
252) -> io::Result<Vec<u8>> {
253    Err(io::Error::new(io::ErrorKind::Other, "Argon2 unimplemented"))
254}