aboutsummaryrefslogtreecommitdiff
path: root/lockchain-crypto/src
diff options
context:
space:
mode:
authorKatharina Sabel <katharina.sabel@asquera.de>2018-05-08 01:06:58 +0200
committerKatharina Sabel <katharina.sabel@asquera.de>2018-05-08 01:06:58 +0200
commit4a86ec4771d6049fc4a8d0e82bf4a13a20bcfa1d (patch)
treefb4fc3550cb848df5c1cbcadc3b713a08b477a29 /lockchain-crypto/src
parent2aa9772596b12496c05c46caed9c7c8c5ae9b32a (diff)
Basic encryption functions work
Diffstat (limited to 'lockchain-crypto/src')
-rw-r--r--lockchain-crypto/src/data.rs13
-rw-r--r--lockchain-crypto/src/databody.rs8
-rw-r--r--lockchain-crypto/src/engine.rs62
-rw-r--r--lockchain-crypto/src/keys.rs37
-rw-r--r--lockchain-crypto/src/lib.rs18
-rw-r--r--lockchain-crypto/src/utils.rs88
6 files changed, 215 insertions, 11 deletions
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<u8>,
+ pub iv: Vec<u8>,
+ pub data: Vec<u8>,
+}
+
+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<String, Payload>,
}
+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<u8>,
+}
+
+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<DataBody> 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<DataBody> {
+ 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<u8>,
+}
+
+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<u8> = 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<u8>) -> String {
+ return base64::encode(data);
+ }
+
+ /// Decode a base64 string into arbitrary data
+ pub fn base64_decode(data: &String) -> Vec<u8> {
+ 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<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;
+ }
+}