aboutsummaryrefslogtreecommitdiff
path: root/src/security
diff options
context:
space:
mode:
authorKatharina Fey <kookie@spacekookie.de>2017-12-26 17:24:03 +0100
committerKatharina Fey <kookie@spacekookie.de>2017-12-26 17:24:03 +0100
commitc8010e87a9fba35973088830d1532f0371b65643 (patch)
treebe8d9bbaad75c111e281a356d8b66f24f519d87a /src/security
parenta65b387dfcc9778cd60371a954841d6c4c3b3583 (diff)
parentb029e84f7298fe949fa3281f6bf9cf34720c859d (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.rs102
-rw-r--r--src/security/encoding.rs10
-rw-r--r--src/security/encryption.rs78
-rw-r--r--src/security/engine.rs32
-rw-r--r--src/security/keys.rs53
-rw-r--r--src/security/mod.rs16
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::*;