diff options
author | Katharina Fey <kookie@spacekookie.de> | 2017-12-26 17:24:03 +0100 |
---|---|---|
committer | Katharina Fey <kookie@spacekookie.de> | 2017-12-26 17:24:03 +0100 |
commit | c8010e87a9fba35973088830d1532f0371b65643 (patch) | |
tree | be8d9bbaad75c111e281a356d8b66f24f519d87a /src/security | |
parent | a65b387dfcc9778cd60371a954841d6c4c3b3583 (diff) | |
parent | b029e84f7298fe949fa3281f6bf9cf34720c859d (diff) |
Merge branch 'fixing'
# Conflicts:
# src/main.rs
# src/record/mod.rs
# src/record/version.rs
# src/security/aes.rs
# src/security/engine.rs
# src/security/mod.rs
# src/vault/mod.rs
Diffstat (limited to 'src/security')
-rw-r--r-- | src/security/aes.rs | 102 | ||||
-rw-r--r-- | src/security/encoding.rs | 10 | ||||
-rw-r--r-- | src/security/encryption.rs | 78 | ||||
-rw-r--r-- | src/security/engine.rs | 32 | ||||
-rw-r--r-- | src/security/keys.rs | 53 | ||||
-rw-r--r-- | src/security/mod.rs | 16 |
6 files changed, 267 insertions, 24 deletions
diff --git a/src/security/aes.rs b/src/security/aes.rs index 4b82175..a229dc2 100644 --- a/src/security/aes.rs +++ b/src/security/aes.rs @@ -1,5 +1,11 @@ -//! Wrapper AES encryption, decryption functions +//! Primitive AES encryption module //! +//! This module has no concept of higher-level types. It only deals with vectors of raw data +//! and strings. It pads data wherever neccessary with symbols that are stripped out when +//! converting it to higher level types. +//! +//! This module is by no means perfect and shouldn't be considered incredibly secure. +//! The API can remain the same as features underneath are exchanged and hardnened. //! @@ -7,8 +13,96 @@ use aesni::{Aes128, BlockCipher}; use generic_array::GenericArray; use std::str::from_utf8_unchecked; -use record::{Record, Header, Payload, Version}; +use super::keys::{KEY_LENGTH, Key}; +/// Low-level wrapper around the AES block encrypt functions pub struct AES { - aes: Aes128, -}
\ No newline at end of file + ctx: Aes128, + pub key: Key, +} + +impl AES { + /// Create a new AES context from a key context + pub fn new(key: &Key) -> AES { + return AES { + ctx: Aes128::new_varkey(&key.data).unwrap(), + key: key.clone(), + }; + } + + /// Encrypt a generic vector of data into another vector + pub fn encrypt(&self, d: &Vec<u8>) -> Vec<u8> { + let mut encrypted: Vec<u8> = Vec::new(); + let mut start: usize = 0; + let mut stop: usize = KEY_LENGTH; + + /* Pad the data */ + let padded = AES::pad(&d); + let padded_slice = padded.as_slice(); + + loop { + let slice = &padded_slice[start..stop]; + + /* Encrypt the slice in place */ + let mut block = GenericArray::clone_from_slice(slice); + self.ctx.encrypt_block(&mut block); + + for byte in block { + encrypted.push(byte); + } + + start = stop; + stop += KEY_LENGTH; + if padded.len() < stop { + break; + } + } + + return encrypted; + } + + pub fn decrypt(&self, vec: &Vec<u8>) -> String { + let mut decrypted = String::new(); + let mut start: usize = 0; + let mut stop: usize = KEY_LENGTH; + + loop { + let slice = &vec[start..stop]; + let mut block = GenericArray::clone_from_slice(slice); + + /* Encrypt block and push to collection */ + self.ctx.decrypt_block(&mut block); + decrypted.push_str(&AES::vec_to_str(&block)); + + start = stop; + stop += KEY_LENGTH; + if vec.len() < stop { + break; + } + } + + return decrypted; + } + + /* Some utility functions below */ + + fn pad(data: &Vec<u8>) -> Vec<u8> { + let mut padded = data.clone(); + + if padded.len() % KEY_LENGTH == 0 { + return padded; + } + + let to_pad = data.len() + (data.len() % KEY_LENGTH); + for _ in 1..to_pad { + padded.push(' ' as u8); + } + + return padded; + } + + /// Convert a vector of u8 into a utf-8 string + fn vec_to_str(vec: &[u8]) -> String { + return unsafe { String::from(from_utf8_unchecked(vec)) }; + } +} diff --git a/src/security/encoding.rs b/src/security/encoding.rs index f0cd054..5c32251 100644 --- a/src/security/encoding.rs +++ b/src/security/encoding.rs @@ -7,11 +7,21 @@ use base64; /// Takes a utf-8 string of raw binary data and converts itto base64 encoded form +#[deprecated] pub fn encode_base64(data: &str) -> String { return base64::encode(data.as_bytes()); } +pub fn base64_encode(data: &Vec<u8>) -> String { + return base64::encode(data); +} + +pub fn base64_decode(data: &String) -> Vec<u8> { + return base64::decode(data).unwrap(); +} + /// Takes a base64 string and converts it to raw binary data +#[deprecated] pub fn decode_base64(base64: &str) -> String { let vec = base64::decode(base64).unwrap(); let decoded = unsafe { from_utf8_unchecked(&vec) }; diff --git a/src/security/encryption.rs b/src/security/encryption.rs new file mode 100644 index 0000000..d08b6a0 --- /dev/null +++ b/src/security/encryption.rs @@ -0,0 +1,78 @@ +//! High level utility wrapper module around crypto calls +//! + +use super::aes::AES; +use super::encoding; +use super::keys::{Key, generate_key}; + +use serde_json; +use serde::Serialize; +use serde::de::DeserializeOwned; + + +pub trait Encryptor<'a, T: Serialize + DeserializeOwned> { + fn encrypt(&self, data: &T) -> String; + fn decrypt(&self, data: String) -> T; +} + + +/// Wraps high-level utilities +pub struct CryptoHandler { + core: AES, +} + +impl<'a, T: Serialize + DeserializeOwned> Encryptor<'a, T> for CryptoHandler { + + /// Generic encryption function for any higher level type that can be Serialised + /// + /// Returns a bse64 encoded string of ciphertext + fn encrypt(&self, data: &T) -> String { + let encoded = serde_json::to_string(&data).unwrap(); + let vec = str_to_vec(&encoded); + + /* ✨ M A G I C ✨ */ + let encrypted = self.core.encrypt(&vec); + let base64 = encoding::base64_encode(&encrypted); + return base64.to_owned(); + } + + /// Generic decryption function for any higher level type that can be Deserialised + /// + /// Takes a base64 encoded string as data + fn decrypt(&self, data: String) -> T { + let decoded: Vec<u8> = encoding::base64_decode(&data); + let decrypted: String = self.core.decrypt(&decoded); + + let data: T = serde_json::from_str(&decrypted).unwrap(); + return data; + } +} + +impl CryptoHandler { + + /// Create a new key and crypto context from scratch + pub fn new() -> CryptoHandler { + let k = generate_key(); + return CryptoHandler { core: AES::new(&k) }; + } + + /// Create a new context with an existing key + pub fn existing(key: &Key) -> CryptoHandler { + return CryptoHandler { core: AES::new(key) }; + } + + /// Get the currently in-use key + pub fn get_active_key(&self) -> &Key { + return &self.core.key; + } +} + + +/// Convert a utf-8 string to a vector of u8 +fn str_to_vec(string: &str) -> Vec<u8> { + let mut vec: Vec<u8> = Vec::new(); + for b in string.as_bytes() { + vec.push(*b); + } + return vec; +} diff --git a/src/security/engine.rs b/src/security/engine.rs index 5cb1401..639443b 100644 --- a/src/security/engine.rs +++ b/src/security/engine.rs @@ -2,20 +2,23 @@ //! //! -use super::DEFAULT_KEYLENGTH; +// use super::DEFAULT_KEYLENGTH; use super::encoding; use super::random; use super::hash; -use aesni::{Aes256, BlockCipher}; +use super::keys::KEY_LENGTH; + +use aesni::{Aes128, BlockCipher}; use generic_array::GenericArray; use std::str::from_utf8_unchecked; /// The crypto engine which holds the key and AES context /// +#[deprecated] pub struct CryptoEngine { encrypted_key: Option<String>, - aes: Aes256, + aes: Aes128, } @@ -25,13 +28,14 @@ impl CryptoEngine { pub fn new(password: &str, _: &str) -> CryptoEngine { /* Generate a random key */ - let secret_key = random::bytes(DEFAULT_KEYLENGTH); + let secret_key = random::bytes(KEY_LENGTH); + println!("RAW KEY key: {}", encoding::encode_base64(&CryptoEngine::vec_to_str(&secret_key))); /* Encrypt secret_key with password */ let k = hash::blake2_16(password, ""); let tmp = CryptoEngine { encrypted_key: None, - aes: Aes256::new_varkey(&k).unwrap(), + aes: Aes128::new_varkey(&k).unwrap(), }; /* Encrypt and encode the secret key */ @@ -42,7 +46,7 @@ impl CryptoEngine { /* Then actually create an engine and return it */ let me = CryptoEngine { encrypted_key: Some(encoded), - aes: Aes256::new_varkey(&secret_key).unwrap(), + aes: Aes128::new_varkey(&secret_key).unwrap(), }; return me; @@ -55,7 +59,7 @@ impl CryptoEngine { let k = hash::blake2_16(password, ""); let tmp = CryptoEngine { encrypted_key: Some(String::from(encrypted_key)), - aes: Aes256::new_varkey(&k).unwrap(), + aes: Aes128::new_varkey(&k).unwrap(), }; /* Decode and decrypt key */ @@ -65,7 +69,7 @@ impl CryptoEngine { /* Then initialise a new crypto engine with the newly decrypted key */ let me = CryptoEngine { encrypted_key: Some(String::from(encrypted_key)), - aes: Aes256::new_varkey(&decrypted.as_bytes()).unwrap(), + aes: Aes128::new_varkey(&decrypted.as_bytes()).unwrap(), }; return me; @@ -84,7 +88,7 @@ impl CryptoEngine { let mut encrypted: Vec<u8> = Vec::new(); let mut start: usize = 0; - let mut stop: usize = 16; + let mut stop: usize = KEY_LENGTH; loop { let slice = to_encrypt[start..stop].as_bytes(); @@ -98,7 +102,7 @@ impl CryptoEngine { } start = stop; - stop += 16; + stop += KEY_LENGTH; if to_encrypt.len() < stop { break; } @@ -117,7 +121,7 @@ impl CryptoEngine { let sliced = CryptoEngine::str_to_vec(&data); let mut start: usize = 0; - let mut stop: usize = 16; + let mut stop: usize = KEY_LENGTH; loop { let slice = &sliced[start..stop]; @@ -128,7 +132,7 @@ impl CryptoEngine { decryted.push_str(&CryptoEngine::vec_to_str(&block)); start = stop; - stop += 16; + stop += KEY_LENGTH; if sliced.len() < stop { break; } @@ -157,14 +161,14 @@ impl CryptoEngine { /// data padding soon. But it works for now, I guess fn pad_data(&self, data: &str) -> String { - if data.len() % DEFAULT_KEYLENGTH == 0 { + if data.len() % KEY_LENGTH == 0 { return String::from(data); } return format!( "{: <width$}", data, - width = data.len() + (data.len() % DEFAULT_KEYLENGTH) + width = data.len() + (data.len() % KEY_LENGTH) ); } } diff --git a/src/security/keys.rs b/src/security/keys.rs new file mode 100644 index 0000000..6b33889 --- /dev/null +++ b/src/security/keys.rs @@ -0,0 +1,53 @@ +//! A module that handles key generation and key loading +//! + + + +use std::fs::File; +use std::ffi::OsStr; +use std::io::prelude::*; + +use super::random; +use super::encoding; +use super::hash; + +pub const KEY_LENGTH: usize = 16; + + +/// A wrapper to represent a key for encryption +#[derive(Clone, Serialize, Deserialize)] +pub struct Key { + pub data: [u8; KEY_LENGTH], +} + + +/// A helper function to easily load a key into memory +pub fn load_key(path: &OsStr) -> Key { + + let mut key = String::new(); + let mut key_file = File::open(path).unwrap(); + key_file.read_to_string(&mut key).expect( + "Failed to load primary key file!", + ); + + let vec = encoding::base64_decode(&key); + let mut k: [u8; 16] = [0; 16]; + k.clone_from_slice(&vec); + + return Key { data: k }; +} + + +pub fn password_to_key(password: &str) -> Key { + let hashed = hash::blake2_16(password, ""); + return Key { data: hashed }; +} + +pub fn generate_key() -> Key { + let key = random::bytes(KEY_LENGTH); + + let mut k: [u8; KEY_LENGTH] = [0; KEY_LENGTH]; + k.clone_from_slice(&key); + + return Key { data: k }; +} diff --git a/src/security/mod.rs b/src/security/mod.rs index 21736a3..ad757c9 100644 --- a/src/security/mod.rs +++ b/src/security/mod.rs @@ -3,12 +3,16 @@ //! A crypto engine is attached to a vault and provides easy to use //! and high-level encryption and decryption functions. -// mod aes; - -pub mod hash; -pub mod random; +// FIXME: Remove this with time pub mod engine; -pub mod encoding; +// Utility modules +pub mod encoding; +pub mod random; +pub mod hash; +pub mod keys; -const DEFAULT_KEYLENGTH: usize = 32; +// Core cryptography +pub mod aes; +pub mod encryption; +pub use self::encryption::*; |