aboutsummaryrefslogtreecommitdiff
path: root/src/security
diff options
context:
space:
mode:
authorKatharina Fey <kookie@spacekookie.de>2017-12-15 01:26:27 +0100
committerKatharina Fey <kookie@spacekookie.de>2017-12-15 01:26:27 +0100
commitbb84351e65787d5ca5e3c687950adbabd801ba77 (patch)
treea0590fc1fcad2f5240a6e845e23e01f8575f9999 /src/security
parent7a2d7474da81f0bddbb895537de4661bdec09c0f (diff)
Refactoring the crypto/security module
Diffstat (limited to 'src/security')
-rw-r--r--src/security/aes.rs14
-rw-r--r--src/security/encoding.rs30
-rw-r--r--src/security/engine.rs170
-rw-r--r--src/security/hash.rs56
-rw-r--r--src/security/mod.rs14
-rw-r--r--src/security/random.rs34
6 files changed, 318 insertions, 0 deletions
diff --git a/src/security/aes.rs b/src/security/aes.rs
new file mode 100644
index 0000000..4b82175
--- /dev/null
+++ b/src/security/aes.rs
@@ -0,0 +1,14 @@
+//! Wrapper AES encryption, decryption functions
+//!
+//!
+
+
+use aesni::{Aes128, BlockCipher};
+use generic_array::GenericArray;
+use std::str::from_utf8_unchecked;
+
+use record::{Record, Header, Payload, Version};
+
+pub struct AES {
+ aes: Aes128,
+} \ No newline at end of file
diff --git a/src/security/encoding.rs b/src/security/encoding.rs
new file mode 100644
index 0000000..f0cd054
--- /dev/null
+++ b/src/security/encoding.rs
@@ -0,0 +1,30 @@
+//! Simple encoding submodule
+//!
+
+use std::fmt::Write;
+use std::str::from_utf8_unchecked;
+use base64;
+
+
+/// Takes a utf-8 string of raw binary data and converts itto base64 encoded form
+pub fn encode_base64(data: &str) -> String {
+ return base64::encode(data.as_bytes());
+}
+
+/// Takes a base64 string and converts it to raw binary data
+pub fn decode_base64(base64: &str) -> String {
+ let vec = base64::decode(base64).unwrap();
+ let decoded = unsafe { from_utf8_unchecked(&vec) };
+ return String::from(decoded);
+}
+
+/// Simply encode a byte-string as hexadecimal symbols
+#[allow(unused)]
+pub fn encode_hex(data: &str) -> String {
+ let mut s = String::new();
+ for &byte in data.as_bytes() {
+ write!(&mut s, "{:X}", byte).expect("Unable to HEX encode!");
+ }
+
+ return s;
+}
diff --git a/src/security/engine.rs b/src/security/engine.rs
new file mode 100644
index 0000000..5a93b65
--- /dev/null
+++ b/src/security/engine.rs
@@ -0,0 +1,170 @@
+//! Crypto engine implementation
+//!
+//!
+
+use super::DEFAULT_KEYLENGTH;
+use super::encoding;
+use super::random;
+use super::hash;
+
+use aesni::{Aes256, BlockCipher};
+use generic_array::GenericArray;
+use std::str::from_utf8_unchecked;
+
+/// The crypto engine which holds the key and AES context
+///
+pub struct CryptoEngine {
+ encrypted_key: Option<String>,
+ aes: Aes256,
+}
+
+
+impl CryptoEngine {
+
+ /// Generate a new random key which is encrypted with the password
+ pub fn new(password: &str, _: &str) -> CryptoEngine {
+
+ /* Generate a random key */
+ let secret_key = random::bytes(DEFAULT_KEYLENGTH);
+
+ /* Encrypt secret_key with password */
+ let k = hash::blake2_16(password, "");
+ let tmp = CryptoEngine {
+ encrypted_key: None,
+ aes: Aes256::new_varkey(&k).unwrap(),
+ };
+
+ /* Encrypt and encode the secret key */
+ let string = CryptoEngine::vec_to_str(&secret_key);
+ let encrypted = tmp.encrypt(&string);
+ let encoded = encoding::encode_base64(&encrypted);
+
+ /* Then actually create an engine and return it */
+ let me = CryptoEngine {
+ encrypted_key: Some(encoded),
+ aes: Aes256::new_varkey(&secret_key).unwrap(),
+ };
+
+ return me;
+ }
+
+ /// Load an existing vault with it's encrypted key and password
+ pub fn load_existing(encrypted_key: &str, password: &str) -> CryptoEngine {
+
+ /* Decrypt key with password */
+ let k = hash::blake2_16(password, "");
+ let tmp = CryptoEngine {
+ encrypted_key: Some(String::from(encrypted_key)),
+ aes: Aes256::new_varkey(&k).unwrap(),
+ };
+
+ /* Decode and decrypt key */
+ let decoded = encoding::decode_base64(&encrypted_key);
+ let decrypted = tmp.decrypt(&decoded);
+
+ /* 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(),
+ };
+
+ return me;
+ }
+
+ /// Get the encrypted key that was used for a vault
+ pub fn dump_encrypted_key(&self) -> Option<String> {
+ return self.encrypted_key.clone();
+ }
+
+ /// Takes a simple utf-8 encoded string and encrypts it
+ ///
+ /// Outputs a base64 encoded string
+ pub fn encrypt(&self, utf_8: &str) -> String {
+ let to_encrypt = self.pad_data(&utf_8);
+
+ let mut encrypted: Vec<u8> = Vec::new();
+ let mut start: usize = 0;
+ let mut stop: usize = DEFAULT_KEYLENGTH;
+
+ loop {
+ let slice = to_encrypt[start..stop].as_bytes();
+
+ /* Encrypt the slice in place */
+ let mut block = GenericArray::clone_from_slice(slice);
+ self.aes.encrypt_block(&mut block);
+
+ for byte in block {
+ encrypted.push(byte);
+ }
+
+ start = stop;
+ stop += DEFAULT_KEYLENGTH;
+ if to_encrypt.len() < stop {
+ break;
+ }
+ }
+
+ return encoding::encode_base64(&CryptoEngine::vec_to_str(&encrypted));
+ }
+
+
+ /// Takes a base64 encoded, encrypted string and decrypts it
+ ///
+ /// Outputs a simple utf-8 string
+ pub fn decrypt(&self, base64: &str) -> String {
+ let mut decryted = String::new();
+ let data = encoding::decode_base64(base64);
+ let sliced = CryptoEngine::str_to_vec(&data);
+
+ let mut start: usize = 0;
+ let mut stop: usize = DEFAULT_KEYLENGTH;
+
+ loop {
+ let slice = &sliced[start..stop];
+ let mut block = GenericArray::clone_from_slice(slice);
+
+ /* Encrypt block and push to collection */
+ self.aes.decrypt_block(&mut block);
+ decryted.push_str(&CryptoEngine::vec_to_str(&block));
+
+ start = stop;
+ stop += DEFAULT_KEYLENGTH;
+ if sliced.len() < stop {
+ break;
+ }
+ }
+
+ return decryted;
+ }
+
+ /// 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)) };
+ }
+
+ /// 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;
+ }
+
+ /// Pad a string to the block-size of the cipher
+ ///
+ /// This is a rather bad function and should be replaced with random
+ /// data padding soon. But it works for now, I guess
+ fn pad_data(&self, data: &str) -> String {
+
+ if data.len() % DEFAULT_KEYLENGTH == 0 {
+ return String::from(data);
+ }
+
+ return format!(
+ "{: <width$}",
+ data,
+ width = data.len() + (data.len() % DEFAULT_KEYLENGTH)
+ );
+ }
+}
diff --git a/src/security/hash.rs b/src/security/hash.rs
new file mode 100644
index 0000000..7b0db9a
--- /dev/null
+++ b/src/security/hash.rs
@@ -0,0 +1,56 @@
+//! Hashing submodule
+//!
+
+use blake2::Blake2s;
+use blake2::digest::{Input, VariableOutput};
+
+/* To make sure I don't typo all over this */
+const BLAKE_16_LENGTH: usize = 32;
+
+pub fn blake2_16(data: &str, salt: &str) -> [u8; BLAKE_16_LENGTH] {
+
+ let mut hasher = match Blake2s::new(BLAKE_16_LENGTH) {
+ Ok(res) => res,
+ Err(some) => panic!(some),
+ };
+
+ let to_hash = format!("{}{}", data, salt);
+ hasher.process(to_hash.as_bytes());
+
+ let mut buffer = [0u8; BLAKE_16_LENGTH];
+ match hasher.variable_result(&mut buffer) {
+ Ok(res) => res,
+ Err(e) => panic!(e),
+ };
+
+ return buffer;
+}
+
+
+ // use blake2::Blake2s;
+ // use blake2::digest::{Input, VariableOutput};
+ // use std::fmt::Write;
+
+ // let mut hasher = Blake2s::new(16).unwrap();
+ // // instead of `input` method here we should use `process`
+ // hasher.process(b"hello world");
+ // let mut buf = [0u8; 16];
+ // hasher.variable_result(&mut buf).unwrap();
+
+
+
+// use blake2::{Blake2b, Digest};
+
+// let record = Record::new("facebook", "web");
+// let mut j = serde_json::to_string(&record).unwrap();
+// println!("{}", j);
+
+// // create a Blake2b object
+// let mut hasher = Blake2b::new();
+
+// // write input message
+// hasher.input(j.as_bytes());
+
+// // read hash digest and consume hasher
+// let output = hasher.result();
+// println!("{:x}", output); \ No newline at end of file
diff --git a/src/security/mod.rs b/src/security/mod.rs
new file mode 100644
index 0000000..21736a3
--- /dev/null
+++ b/src/security/mod.rs
@@ -0,0 +1,14 @@
+//! Cryptography module for lockchain
+//!
+//! 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;
+pub mod engine;
+pub mod encoding;
+
+
+const DEFAULT_KEYLENGTH: usize = 32;
diff --git a/src/security/random.rs b/src/security/random.rs
new file mode 100644
index 0000000..bc96032
--- /dev/null
+++ b/src/security/random.rs
@@ -0,0 +1,34 @@
+//! Random number utility module for lockchain
+//!
+//! Provides stateless secure random number and byte generation
+
+use rand::{thread_rng, Rng};
+
+
+/// Generate a random number with an upper bound
+#[allow(unused)]
+pub fn number(bound: u64) -> u64 {
+ return thread_rng().next_u64() % bound;
+}
+
+
+/// Generate a sequence of random bytes that are returned
+/// as a vector.
+///
+/// Can at most allocate 2048 bytes at a time
+pub fn bytes(length: usize) -> Vec<u8> {
+ let mut vec: Vec<u8> = Vec::new();
+
+ if length > 2048 {
+ return vec;
+ }
+
+ let mut random_data = [0u8; 2048];
+ thread_rng().fill_bytes(&mut random_data);
+
+ for i in 0..length {
+ vec.push(random_data[i]);
+ }
+
+ return vec;
+} \ No newline at end of file