From 4a86ec4771d6049fc4a8d0e82bf4a13a20bcfa1d Mon Sep 17 00:00:00 2001 From: Katharina Sabel Date: Tue, 8 May 2018 01:06:58 +0200 Subject: Basic encryption functions work --- lockchain-crypto/src/data.rs | 13 ++++++ lockchain-crypto/src/databody.rs | 8 ++++ lockchain-crypto/src/engine.rs | 62 +++++++++++++++++++++++++--- lockchain-crypto/src/keys.rs | 37 +++++++++++++++++ lockchain-crypto/src/lib.rs | 18 +++++--- lockchain-crypto/src/utils.rs | 88 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 215 insertions(+), 11 deletions(-) create mode 100644 lockchain-crypto/src/data.rs create mode 100644 lockchain-crypto/src/keys.rs create mode 100644 lockchain-crypto/src/utils.rs (limited to 'lockchain-crypto/src') diff --git a/lockchain-crypto/src/data.rs b/lockchain-crypto/src/data.rs new file mode 100644 index 0000000..74698e4 --- /dev/null +++ b/lockchain-crypto/src/data.rs @@ -0,0 +1,13 @@ +//! A simple data layout + +use lcc::traits::AutoEncoder; + +/// Represents some packed data – includes nonce and blob +#[derive(Serialize, Deserialize)] +pub struct PackedData { + pub nonce: Vec, + pub iv: Vec, + pub data: Vec, +} + +impl AutoEncoder for PackedData {} \ No newline at end of file diff --git a/lockchain-crypto/src/databody.rs b/lockchain-crypto/src/databody.rs index 1387f9d..aaedce7 100644 --- a/lockchain-crypto/src/databody.rs +++ b/lockchain-crypto/src/databody.rs @@ -9,6 +9,14 @@ pub struct DataBody { tree: BTreeMap, } +impl DataBody { + pub fn new() -> Self { + DataBody { + tree: BTreeMap::new(), + } + } +} + impl AutoEncoder for DataBody {} impl Body for DataBody { diff --git a/lockchain-crypto/src/engine.rs b/lockchain-crypto/src/engine.rs index 1030bf2..388f4cc 100644 --- a/lockchain-crypto/src/engine.rs +++ b/lockchain-crypto/src/engine.rs @@ -1,19 +1,69 @@ //! -use databody::DataBody; -use lcc::{traits::{Encryptable, EncryptionHandler}, +use lcc::{traits::{AutoEncoder, Encryptable, EncryptionHandler}, EncryptedBody}; +use miscreant::aead::{Aes256Siv, Algorithm}; + +use super::data::PackedData; +use super::databody::DataBody; +use super::{keys::{Key, KEY_LENGTH}, + utils::random}; + +use std::collections::BTreeMap; impl Encryptable for DataBody {} -pub struct AesEngine {} +pub struct AesEngine { + ctx: Aes256Siv, + key: Key, + iv: Vec, +} + +impl AesEngine { + /// Generate new key and encryption engine + pub fn generate() -> Self { + let key = Key::generate(); + Self { + ctx: Aes256Siv::new(&key.to_slice()), + key, + iv: random::bytes(KEY_LENGTH), + } + } + + pub fn from_pw(pw: &str, salt: &str) -> Self { + let key = Key::from_password(pw, salt); + Self { + ctx: Aes256Siv::new(&key.to_slice()), + key, + iv: random::bytes(KEY_LENGTH), + } + } +} impl EncryptionHandler for AesEngine { fn encrypt(&mut self, item: DataBody) -> EncryptedBody { - unimplemented!() + let ser = item.encode(); + let nonce = random::bytes(64); + let iv = &self.iv.as_slice(); + let data = &ser.as_bytes(); + + let encrypted = self.ctx.seal(nonce.as_slice(), iv, data); + let data = PackedData { + iv: self.iv.clone(), + data: encrypted, + nonce: nonce, + }.encode(); + + EncryptedBody { data } } - fn decrypt(&mut self, item: EncryptedBody) -> DataBody { - unimplemented!() + fn decrypt(&mut self, item: EncryptedBody) -> Option { + let packed = PackedData::decode(&item.data); + let iv = &self.iv.as_slice(); + let decrypted = self.ctx + .open(packed.nonce.as_slice(), iv, packed.data.as_slice()) + .ok()?; + + Some(DataBody::decode(&String::from_utf8(decrypted).ok()?)) } } diff --git a/lockchain-crypto/src/keys.rs b/lockchain-crypto/src/keys.rs new file mode 100644 index 0000000..bde3e69 --- /dev/null +++ b/lockchain-crypto/src/keys.rs @@ -0,0 +1,37 @@ +//! A module that handles key generation and key loading + +use super::utils::{hashing, random}; +pub const KEY_LENGTH: usize = 64; + + +/// A wrapper to represent a key for encryption +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] +pub struct Key { + pub data: Vec, +} + +impl Key { + + /// Create a new key from scratch + pub fn generate() -> Key { + let data = random::bytes(KEY_LENGTH); + return Key { data: data }; + } + + /// Use a password as a key + pub fn from_password(password: &str, salt: &str) -> Key { + let hashed = hashing::blake2(password, salt); + let mut vec: Vec = Vec::new(); + for b in &hashed { + vec.push(b.clone()); + } + return Key { data: vec }; + } + + /// Used to get the raw data from this key, as a slice copy + pub fn to_slice(&self) -> [u8; KEY_LENGTH] { + let mut slice: [u8; KEY_LENGTH] = [0; KEY_LENGTH]; + slice.clone_from_slice(&self.data); + return slice; + } +} diff --git a/lockchain-crypto/src/lib.rs b/lockchain-crypto/src/lib.rs index 0799c96..5daba02 100644 --- a/lockchain-crypto/src/lib.rs +++ b/lockchain-crypto/src/lib.rs @@ -1,17 +1,25 @@ -//! +//! A shim-layer crate for lockchain encryption +//! +//! To get going with encrypted lockchain files, just initialise an +//! AesEngine type and start working with encrypted types provided by +//! some backend. #[macro_use] extern crate serde_derive; extern crate serde; +extern crate miscreant; +extern crate base64; +extern crate blake2; +extern crate rand; extern crate lockchain_core as lcc; -use lcc::{traits::{AutoEncoder, Body}, - Payload}; -use std::collections::BTreeMap; mod databody; mod engine; +mod keys; +mod utils; +mod data; pub use databody::*; -pub use engine::*; +pub use engine::AesEngine; diff --git a/lockchain-crypto/src/utils.rs b/lockchain-crypto/src/utils.rs new file mode 100644 index 0000000..36e611c --- /dev/null +++ b/lockchain-crypto/src/utils.rs @@ -0,0 +1,88 @@ +//! A collection of utility submodules + +/// Encoding module +pub mod encoding { + use base64; + use std::fmt::Write; + + /// Encode a piece of arbitary data into a bse64 string + pub fn base64_encode(data: &Vec) -> String { + return base64::encode(data); + } + + /// Decode a base64 string into arbitrary data + pub fn base64_decode(data: &String) -> Vec { + return base64::decode(data).unwrap(); + } + + /// Simply encode a byte-string as hexadecimal symbols + 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; + } +} + +/// A hashing utility module +pub mod hashing { + use blake2::Blake2s; + use blake2::digest::{Input, VariableOutput}; + + const BLAKE_16_LENGTH: usize = 16; + + /// Hash a value with blake2 + pub fn blake2(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; + } +} + +/// Random number utility module for lockchain +/// +/// Provides stateless secure random number and byte generation +pub mod random { + use rand::{thread_rng, Rng}; + + /// Generate a random number with an upper bound + 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 + /// FIXME: That shouldn't have a limit! + pub fn bytes(length: usize) -> Vec { + let mut vec: Vec = 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; + } +} -- cgit v1.2.3