diff options
author | Katharina Fey <kookie@spacekookie.de> | 2017-12-15 01:26:27 +0100 |
---|---|---|
committer | Katharina Fey <kookie@spacekookie.de> | 2017-12-15 01:26:27 +0100 |
commit | bb84351e65787d5ca5e3c687950adbabd801ba77 (patch) | |
tree | a0590fc1fcad2f5240a6e845e23e01f8575f9999 /src/security | |
parent | 7a2d7474da81f0bddbb895537de4661bdec09c0f (diff) |
Refactoring the crypto/security module
Diffstat (limited to 'src/security')
-rw-r--r-- | src/security/aes.rs | 14 | ||||
-rw-r--r-- | src/security/encoding.rs | 30 | ||||
-rw-r--r-- | src/security/engine.rs | 170 | ||||
-rw-r--r-- | src/security/hash.rs | 56 | ||||
-rw-r--r-- | src/security/mod.rs | 14 | ||||
-rw-r--r-- | src/security/random.rs | 34 |
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 |