keepass_db/kdf/
mod.rs

1use std::convert::TryInto;
2use std::io;
3use std::io::Cursor;
4use std::collections::HashMap;
5
6use log::info;
7use uuid::Uuid;
8use openssl::symm::{Cipher, Crypter, Mode};
9use ring::digest::{Context, SHA256};
10use byteorder::{LittleEndian, ReadBytesExt};
11
12use crate::{KDF_AES_KDBX3, MapValue};
13
14pub use self::argon2::*;
15
16mod argon2;
17
18#[cfg(test)]
19mod tests;
20
21pub const KDF_PARAM_UUID: &str = "$UUID"; // UUID, KDF used to derive master key
22pub const KDF_PARAM_SALT: &str = "S"; // Byte[], Generates 32 bytes, required
23pub const KDF_PARAM_ROUNDS: &str = "R"; // Byte[], Generates 32 bytes, required
24pub const KDF_PARAM_PARALLELISM: &str = "P"; // UInt32, Default, required
25pub const KDF_PARAM_MEMORY: &str = "M"; // UInt64, Default, required
26pub const KDF_PARAM_ITERATIONS: &str = "I"; // UInt64, Default, required
27pub const KDF_PARAM_VERSION: &str = "V"; // UInt32, Min/Max, Default Max, required
28const _KDF_PARAM_SECRET_KEY: &str = "K"; // Byte[]
29const _KDF_PARAM_ASSOC_DATA: &str = "A"; // Byte[]
30
31pub trait Kdf {
32    fn uuid(&self) -> Uuid;
33    fn randomize(&mut self);
34    fn transform_key(&self, composite_key: &[u8]) -> io::Result<Vec<u8>>;
35    fn save(&self, custom_data: &mut HashMap<String, MapValue>);
36}
37
38pub struct AesKdf {
39    salt: [u8; 32],
40    rounds: u64,
41}
42
43impl AesKdf {
44    pub fn load(custom_data: &HashMap<String, MapValue>) -> io::Result<Self> {
45        // let salt = &custom_data[KDF_PARAM_SALT];
46        // let mut c = custom_data[KDF_PARAM_ROUNDS];
47        match (&custom_data[KDF_PARAM_SALT], &custom_data[KDF_PARAM_ROUNDS]) {
48            (MapValue::ByteArray(ref salt), MapValue::UInt64(rounds)) => Ok(AesKdf {
49                salt: salt.clone().try_into().unwrap(), /*From::<Vec<u8>>::try_into(salt.clone()).unwrap()*/
50                rounds: *rounds,
51            }),
52            _ => Err(io::Error::new(io::ErrorKind::Unsupported, "Bad rounds")),
53        }
54    }
55}
56
57impl Kdf for AesKdf {
58    fn uuid(&self) -> Uuid {
59        KDF_AES_KDBX3
60    }
61
62    fn randomize(&mut self) {
63        unimplemented!("Can't randomize yet")
64    }
65
66    fn save(&self, custom_data: &mut HashMap<String, MapValue>) {
67        custom_data.insert(KDF_PARAM_ROUNDS.to_string(), MapValue::UInt64(self.rounds));
68        custom_data.insert(
69            KDF_PARAM_SALT.to_string(),
70            MapValue::ByteArray(self.salt.into()),
71        );
72    }
73
74    fn transform_key(&self, composite_key: &[u8]) -> io::Result<Vec<u8>> {
75        info!("Found AES KDF");
76        println!("Calculating transformed key ({})", self.rounds);
77
78        let mut transform_key = composite_key.to_owned();
79        let cipher = Cipher::aes_256_ecb();
80        let mut c = Crypter::new(cipher, Mode::Encrypt, &self.salt, None)?;
81        for _ in 0..cipher.block_size() {
82            transform_key.push(0);
83        }
84        let mut out = vec![0; 16 + 16 + cipher.block_size()];
85        c.pad(false);
86        for _ in 0..self.rounds {
87            c.update(&transform_key[0..32], &mut out)?;
88            let temp = transform_key;
89            transform_key = out;
90            out = temp;
91        }
92        transform_key.truncate(32);
93        let mut context = Context::new(&SHA256);
94        context.update(&transform_key);
95        Ok(context.finish().as_ref().to_owned())
96    }
97}
98
99impl Default for AesKdf {
100    fn default() -> Self {
101        Self {
102            salt: [0; 32],
103            rounds: 60000,
104        }
105    }
106}
107
108pub fn transform_aes_kdf(
109    composite_key: &[u8],
110    custom_data: &HashMap<String, Vec<u8>>,
111) -> io::Result<Vec<u8>> {
112    let transform_seed = &custom_data[KDF_PARAM_SALT];
113    let mut c = Cursor::new(&custom_data[KDF_PARAM_ROUNDS]);
114    let transform_round = c.read_u64::<LittleEndian>()?;
115
116    info!("Found AES KDF");
117    println!("Calculating transformed key ({})", transform_round);
118
119    let mut transform_key = composite_key.to_owned();
120    let cipher = Cipher::aes_256_ecb();
121    let mut c = Crypter::new(cipher, Mode::Encrypt, transform_seed, None)?;
122    for _ in 0..cipher.block_size() {
123        transform_key.push(0);
124    }
125    let mut out = vec![0; 16 + 16 + cipher.block_size()];
126    c.pad(false);
127    for _ in 0..transform_round {
128        c.update(&transform_key[0..32], &mut out)?;
129        let temp = transform_key;
130        transform_key = out;
131        out = temp;
132    }
133    transform_key.truncate(32);
134    let mut context = Context::new(&SHA256);
135    context.update(&transform_key);
136    Ok(context.finish().as_ref().to_owned())
137}