You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

80 lines
2.4 KiB
Rust

use super::db;
use crypto::aes::{self, KeySize};
use crypto::hmac::Hmac;
use crypto::mac::{Mac, MacResult};
use crypto::scrypt::{self, ScryptParams};
use crypto::sha2::Sha256;
use rand::rngs::OsRng;
use rand::Rng;
use rustc_serialize::base64;
use rustc_serialize::base64::{FromBase64, ToBase64};
use std::io;
pub struct EncryptedValue {
pub ciphertext: Vec<u8>,
pub iv: [u8; 32],
pub mac: MacResult,
}
pub fn get_master_key(db_conn: &db::DbHandle, master_password: &str) -> io::Result<[u8; 32]> {
let scrypt_params: ScryptParams = ScryptParams::new(12, 16, 2);
let salt: Vec<u8> = get_salt(db_conn)?;
// 256 bit derived key
let mut derived_key = [0u8; 32];
scrypt::scrypt(
master_password.as_bytes(),
&*salt,
&scrypt_params,
&mut derived_key,
);
Ok(derived_key)
}
fn get_salt(db_conn: &db::DbHandle) -> io::Result<Vec<u8>> {
let existing_salt: Option<String> = db_conn
.get_db_property("salt")
.expect("There was a problem reading from the db");
match existing_salt {
Some(salt) => Ok(salt.from_base64().unwrap()),
None => {
let mut rng = OsRng::new()?;
// 128 bit salt
let salt: Vec<u8> = rng.gen::<[u8; 16]>().to_vec();
db_conn.set_db_property("salt", &salt.to_base64(base64::STANDARD));
Ok(salt)
}
}
}
pub fn decrypt_value(value: Vec<u8>, master_key: [u8; 32], iv: [u8; 32], mac: [u8; 32]) -> Vec<u8> {
let mut hmac = Hmac::new(Sha256::new(), &master_key);
hmac.input(&value[..]);
if hmac.result() != MacResult::new(&mac) {
panic!("Mac did not match, corrupted data");
}
let mut cipher = aes::ctr(KeySize::KeySize256, &master_key, &iv);
let mut output: Vec<u8> = vec![0; value.len() as usize];
cipher.process(&value, output.as_mut_slice());
output
}
pub fn encrypt_value(value: &str, master_key: [u8; 32]) -> EncryptedValue {
let mut random = OsRng::new().unwrap();
let iv: [u8; 32] = random.gen::<[u8; 32]>();
let mut cipher = aes::ctr(KeySize::KeySize256, &master_key, &iv);
let mut output: Vec<u8> = vec![0; value.len() as usize];
cipher.process(value.as_bytes(), output.as_mut_slice());
let mut hmac = Hmac::new(Sha256::new(), &master_key);
hmac.input(&output[..]);
EncryptedValue {
ciphertext: output,
iv: iv,
mac: hmac.result(),
}
}