From 429ca42b892e8ca5682b77a30dd920dc47b06e87 Mon Sep 17 00:00:00 2001 From: Vyacheslav Gudkov Date: Tue, 18 Apr 2017 13:48:17 +0300 Subject: [PATCH 1/2] * Refactored sodium struct, created wrapper for crypto and published in crypto service: - ed25519 - xsalsa20 - base58 --- Cargo.toml | 9 +- src/services/crypto/anoncreds/mod.rs | 8 +- src/services/crypto/mod.rs | 15 ++- .../crypto/wrappers/base58/rust_base58.rs | 44 +++++++++ src/services/crypto/wrappers/ed25519.rs | 0 .../ed25519/sodium.rs} | 91 ++++--------------- src/services/crypto/wrappers/mod.rs | 16 +++- .../crypto/wrappers/xsalsa20/sodium.rs | 73 +++++++++++++++ 8 files changed, 168 insertions(+), 88 deletions(-) create mode 100644 src/services/crypto/wrappers/base58/rust_base58.rs delete mode 100644 src/services/crypto/wrappers/ed25519.rs rename src/services/crypto/{ed25519.rs => wrappers/ed25519/sodium.rs} (52%) create mode 100644 src/services/crypto/wrappers/xsalsa20/sodium.rs diff --git a/Cargo.toml b/Cargo.toml index 580581f..f60d4e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,8 +23,11 @@ name = "sovrin" path = "src/main.rs" [features] -default = ["bn_openssl"] +default = ["bn_openssl", "ed25519_sodium", "base58_rust_base58", "xsalsa20_sodium"] bn_openssl = ["openssl"] +ed25519_sodium = ["sodiumoxide"] +base58_rust_base58 = ["rust-base58"] +xsalsa20_sodium = ["sodiumoxide"] [dependencies] int_traits = "0.1.1" @@ -35,8 +38,8 @@ openssl = { version = "0.9.9", optional = true} milagro-crypto = "0.1.0" rand = "0.3" rusqlite = "0.10.1" -rust-base58 = "0.0.4" +rust-base58 = {version = "0.0.4", optional = true} rustc-serialize = "0.3" -sodiumoxide = "0.0.14" +sodiumoxide = {version = "0.0.14", optional = true} zmq = "0.8.1" lazy_static = "0.2" diff --git a/src/services/crypto/anoncreds/mod.rs b/src/services/crypto/anoncreds/mod.rs index 0b1f98d..7206d5a 100644 --- a/src/services/crypto/anoncreds/mod.rs +++ b/src/services/crypto/anoncreds/mod.rs @@ -8,15 +8,15 @@ use services::crypto::anoncreds::issuer::Issuer; use services::crypto::anoncreds::prover::Prover; use services::crypto::anoncreds::verifier::Verifier; -pub struct AnoncredsService { +pub struct Anoncreds { issuer: Issuer, prover: Prover, verifier: Verifier } -impl AnoncredsService { - pub fn new() -> AnoncredsService { - AnoncredsService { +impl Anoncreds { + pub fn new() -> Anoncreds { + Anoncreds { issuer: Issuer::new(), prover: Prover::new(), verifier: Verifier::new() diff --git a/src/services/crypto/mod.rs b/src/services/crypto/mod.rs index 60152d0..80220b7 100644 --- a/src/services/crypto/mod.rs +++ b/src/services/crypto/mod.rs @@ -1,21 +1,26 @@ pub mod helpers; pub mod anoncreds; -pub mod ed25519; pub mod wrappers; -use self::anoncreds::AnoncredsService; -use self::ed25519::ED25519; +use self::anoncreds::Anoncreds; +use self::wrappers::base58::Base58; +use self::wrappers::ed25519::ED25519; +use self::wrappers::xsalsa20::XSalsa20; pub struct CryptoService { + anoncreds: Anoncreds, + base58: Base58, ed25519: ED25519, - anoncreds: AnoncredsService + xsalsa20: XSalsa20 } impl CryptoService { pub fn new() -> CryptoService { CryptoService { + anoncreds: Anoncreds::new(), + base58: Base58::new(), ed25519: ED25519::new(), - anoncreds: AnoncredsService::new() + xsalsa20: XSalsa20::new() } } } \ No newline at end of file diff --git a/src/services/crypto/wrappers/base58/rust_base58.rs b/src/services/crypto/wrappers/base58/rust_base58.rs new file mode 100644 index 0000000..1acb967 --- /dev/null +++ b/src/services/crypto/wrappers/base58/rust_base58.rs @@ -0,0 +1,44 @@ +extern crate rust_base58; + +use errors::crypto::CryptoError; + +use self::rust_base58::{ToBase58, FromBase58}; + +pub struct Base58 {} + +impl Base58 { + pub fn new() -> Base58 { + Base58 {} + } + + pub fn encode(&self, doc: &[u8]) -> String { + doc.to_base58() + } + + pub fn decode(&self, doc: &str) -> Result, CryptoError> { + doc.from_base58() + .map_err(|err| CryptoError::InvalidStructure(format!("{}", err))) + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn encode_works() { + let base58 = Base58::new(); + let result = base58.encode(&[1, 2, 3]); + assert_eq!("Ldp", &result, "Got unexpected data"); + } + + #[test] + fn decode_works() { + let base58 = Base58::new(); + let result = base58.decode("Ldp"); + + assert!(result.is_ok(), "Got error"); + assert_eq!(&[1, 2, 3], &result.unwrap()[..], "Get unexpected data"); + } +} \ No newline at end of file diff --git a/src/services/crypto/wrappers/ed25519.rs b/src/services/crypto/wrappers/ed25519.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/services/crypto/ed25519.rs b/src/services/crypto/wrappers/ed25519/sodium.rs similarity index 52% rename from src/services/crypto/ed25519.rs rename to src/services/crypto/wrappers/ed25519/sodium.rs index 1b6bc41..26c9d6d 100644 --- a/src/services/crypto/ed25519.rs +++ b/src/services/crypto/wrappers/ed25519/sodium.rs @@ -1,10 +1,7 @@ -extern crate rust_base58; extern crate sodiumoxide; use errors::crypto::CryptoError; -use self::rust_base58::{ToBase58, FromBase58}; use self::sodiumoxide::crypto::box_; -use self::sodiumoxide::crypto::secretbox; use self::sodiumoxide::crypto::sign; use self::sodiumoxide::randombytes; use std::convert::AsMut; @@ -16,35 +13,7 @@ impl ED25519 { ED25519 {} } - pub fn symmetric_create_key(&self) -> Vec { - secretbox::gen_key()[..].to_vec() - } - - pub fn symmetric_create_nonce(&self) -> Vec { - secretbox::gen_nonce()[..].to_vec() - } - - pub fn symmetric_encrypt(&self, key: &[u8], nonce: &[u8], doc: &[u8]) -> Vec { - let sodium = ED25519::new(); - secretbox::seal( - doc, - &secretbox::Nonce(sodium.clone_into_array(nonce)), - &secretbox::Key(sodium.clone_into_array(key)) - ) - } - - pub fn symmetric_decrypt(&self, key: &[u8], nonce: &[u8], doc: &[u8]) -> Result, CryptoError> { - let sodium = ED25519::new(); - secretbox::open( - doc, - &secretbox::Nonce(sodium.clone_into_array(nonce)), - &secretbox::Key(sodium.clone_into_array(key)) - ) - .map_err(|_| CryptoError::InvalidStructure("Unable to decrypt data".to_string())) - } - - - pub fn box_create_key_pair(&self) -> (Vec, Vec) { + pub fn create_key_pair(&self) -> (Vec, Vec) { let (public_key, private_key) = box_::gen_keypair(); (public_key[..].to_vec(), private_key[..].to_vec()) } @@ -70,7 +39,7 @@ impl ED25519 { .map_err(|_| CryptoError::InvalidStructure("Unable to decrypt data".to_string())) } - pub fn get_nonce(&self) -> Vec { + pub fn gen_nonce(&self) -> Vec { box_::gen_nonce()[..].to_vec() } @@ -107,15 +76,6 @@ impl ED25519 { .map_err(|_| CryptoError::InvalidStructure("Unable to decrypt data".to_string())) } - pub fn base58_encode(&self, doc: &[u8]) -> String { - doc.to_base58() - } - - pub fn base58_decode(&self, doc: &String) -> Result, CryptoError> { - doc.from_base58() - .map_err(|err| CryptoError::InvalidStructure(format!("{}", err))) - } - fn clone_into_array(&self, slice: &[T]) -> A where A: Sized + Default + AsMut<[T]>, T: Clone { @@ -125,58 +85,41 @@ impl ED25519 { } } - #[cfg(test)] mod tests { use super::*; #[test] - fn crypto_service_can_encode_decode_string() { - let sodium = ED25519::new(); - let data = &[1, 2, 3]; - - let encode_result = sodium.base58_encode(&data[..]); - assert_eq!("Ldp", &encode_result, "Success encrypt data"); - - let decrypted_data = sodium.base58_decode(&encode_result); - assert!(decrypted_data.is_ok(), "Success decrypt data"); - assert_eq!(data, &decrypted_data.unwrap()[..], "Get correct data"); - } - - #[test] - fn crypto_service_encode_decode_test() { - let sodium = ED25519::new(); - let (alice_pk, alice_sk) = sodium.box_create_key_pair(); - let (bob_pk, bob_sk) = sodium.box_create_key_pair(); - + fn encrypt_decrypt_works() { + let ed25519 = ED25519::new(); let text = randombytes::randombytes(16); - let nonce = sodium.get_nonce(); + let nonce = ed25519.gen_nonce(); + + let (alice_pk, alice_sk) = ed25519.create_key_pair(); + let (bob_pk, bob_sk) = ed25519.create_key_pair(); - let bob_encrypted_text = sodium.encrypt(&bob_sk, &alice_pk, &text[..], &nonce); - let bob_decrypt_result = sodium.decrypt(&alice_sk, &bob_pk, &bob_encrypted_text, &nonce); + let bob_encrypted_text = ed25519.encrypt(&bob_sk, &alice_pk, &text[..], &nonce); + let bob_decrypt_result = ed25519.decrypt(&alice_sk, &bob_pk, &bob_encrypted_text, &nonce); assert!(bob_decrypt_result.is_ok()); assert_eq!(text, bob_decrypt_result.unwrap()); - let alice_encrypted_text = sodium.encrypt(&alice_sk, &bob_pk, &text[..], &nonce); - let alice_decrypted_text = sodium.decrypt(&bob_sk, &alice_pk, &alice_encrypted_text, &nonce); + let alice_encrypted_text = ed25519.encrypt(&alice_sk, &bob_pk, &text[..], &nonce); + let alice_decrypted_text = ed25519.decrypt(&bob_sk, &alice_pk, &alice_encrypted_text, &nonce); assert!(alice_decrypted_text.is_ok()); assert_eq!(text, alice_decrypted_text.unwrap()); } #[test] - fn crypto_service_signin_verify_test() { - let sodium = ED25519::new(); + fn signin_verify_works() { + let ed25519 = ED25519::new(); let seed = randombytes::randombytes(32); - - let (public_key, secret_key) = sodium.create_key_pair_for_signature(Some(&seed[..])); - let text = randombytes::randombytes(16); - let alice_signed_text = sodium.sign(&secret_key, &text[..]); + let (public_key, secret_key) = ed25519.create_key_pair_for_signature(Some(&seed[..])); + let alice_signed_text = ed25519.sign(&secret_key, &text[..]); + let verified_data = ed25519.verify(&public_key, &alice_signed_text); - let verified_data = sodium.verify(&public_key, &alice_signed_text); assert!(verified_data.is_ok()); - assert_eq!(text, verified_data.unwrap()); } } \ No newline at end of file diff --git a/src/services/crypto/wrappers/mod.rs b/src/services/crypto/wrappers/mod.rs index 79fbf5b..054f95f 100644 --- a/src/services/crypto/wrappers/mod.rs +++ b/src/services/crypto/wrappers/mod.rs @@ -1,5 +1,17 @@ #[cfg(feature = "bn_openssl")] -#[path="bn/openssl.rs"] pub mod bn; +#[path = "bn/openssl.rs"] +pub mod bn; +#[cfg(feature = "ed25519_sodium")] +#[path = "ed25519/sodium.rs"] pub mod ed25519; -pub mod pair; \ No newline at end of file + +#[cfg(feature = "base58_rust_base58")] +#[path = "base58/rust_base58.rs"] +pub mod base58; + +pub mod pair; + +#[cfg(feature = "xsalsa20_sodium")] +#[path = "xsalsa20/sodium.rs"] +pub mod xsalsa20; \ No newline at end of file diff --git a/src/services/crypto/wrappers/xsalsa20/sodium.rs b/src/services/crypto/wrappers/xsalsa20/sodium.rs new file mode 100644 index 0000000..c688874 --- /dev/null +++ b/src/services/crypto/wrappers/xsalsa20/sodium.rs @@ -0,0 +1,73 @@ +extern crate sodiumoxide; + +use errors::crypto::CryptoError; + +use self::sodiumoxide::crypto::secretbox; +use std::convert::AsMut; + +pub struct XSalsa20 {} + +impl XSalsa20 { + pub fn new() -> XSalsa20 { + XSalsa20 {} + } + + pub fn create_key(&self) -> Vec { + secretbox::gen_key()[..].to_vec() + } + + pub fn gen_nonce(&self) -> Vec { + secretbox::gen_nonce()[..].to_vec() + } + + pub fn encrypt(&self, key: &[u8], nonce: &[u8], doc: &[u8]) -> Vec { + let sodium = XSalsa20::new(); + secretbox::seal( + doc, + &secretbox::Nonce(sodium.clone_into_array(nonce)), + &secretbox::Key(sodium.clone_into_array(key)) + ) + } + + pub fn decrypt(&self, key: &[u8], nonce: &[u8], doc: &[u8]) -> Result, CryptoError> { + let sodium = XSalsa20::new(); + secretbox::open( + doc, + &secretbox::Nonce(sodium.clone_into_array(nonce)), + &secretbox::Key(sodium.clone_into_array(key)) + ) + .map_err(|_| CryptoError::InvalidStructure("Unable to decrypt data".to_string())) + } + + fn clone_into_array(&self, slice: &[T]) -> A + where A: Sized + Default + AsMut<[T]>, T: Clone + { + let mut a = Default::default(); + >::as_mut(&mut a).clone_from_slice(slice); + a + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + use self::sodiumoxide::randombytes; + + #[test] + fn encrypt_decrypt_works() { + let xsalsa20 = XSalsa20::new(); + + let nonce = xsalsa20.gen_nonce(); + let key = xsalsa20.create_key(); + let data = randombytes::randombytes(16); + + let encrypted_data = xsalsa20.encrypt(&key, &nonce, &data); + let decrypt_result = xsalsa20.decrypt(&key, &nonce, &encrypted_data); + + assert!(decrypt_result.is_ok()); + assert_eq!(data, decrypt_result.unwrap()); + } + +} \ No newline at end of file From e18b324c5d79a52e6bb0504f5807468ee0cf2228 Mon Sep 17 00:00:00 2001 From: Vyacheslav Gudkov Date: Tue, 18 Apr 2017 13:51:15 +0300 Subject: [PATCH 2/2] * Cosmetic fixes --- .../crypto/wrappers/ed25519/sodium.rs | 30 ++++++++----------- .../crypto/wrappers/xsalsa20/sodium.rs | 12 ++++---- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/services/crypto/wrappers/ed25519/sodium.rs b/src/services/crypto/wrappers/ed25519/sodium.rs index 26c9d6d..8904670 100644 --- a/src/services/crypto/wrappers/ed25519/sodium.rs +++ b/src/services/crypto/wrappers/ed25519/sodium.rs @@ -19,22 +19,20 @@ impl ED25519 { } pub fn encrypt(&self, private_key: &[u8], public_key: &[u8], doc: &[u8], nonce: &[u8]) -> Vec { - let sodium = ED25519::new(); box_::seal( doc, - &box_::Nonce(sodium.clone_into_array(nonce)), - &box_::PublicKey(sodium.clone_into_array(public_key)), - &box_::SecretKey(sodium.clone_into_array(private_key)) + &box_::Nonce(ED25519::_clone_into_array(nonce)), + &box_::PublicKey(ED25519::_clone_into_array(public_key)), + &box_::SecretKey(ED25519::_clone_into_array(private_key)) ) } pub fn decrypt(&self, private_key: &[u8], public_key: &[u8], doc: &[u8], nonce: &[u8]) -> Result, CryptoError> { - let sodium = ED25519::new(); box_::open( doc, - &box_::Nonce(sodium.clone_into_array(nonce)), - &box_::PublicKey(sodium.clone_into_array(public_key)), - &box_::SecretKey(sodium.clone_into_array(private_key)) + &box_::Nonce(ED25519::_clone_into_array(nonce)), + &box_::PublicKey(ED25519::_clone_into_array(public_key)), + &box_::SecretKey(ED25519::_clone_into_array(private_key)) ) .map_err(|_| CryptoError::InvalidStructure("Unable to decrypt data".to_string())) } @@ -44,11 +42,10 @@ impl ED25519 { } pub fn create_key_pair_for_signature(&self, seed: Option<&[u8]>) -> (Vec, Vec) { - let sodium = ED25519::new(); let (public_key, private_key) = sign::keypair_from_seed( &sign::Seed( - sodium.clone_into_array( + ED25519::_clone_into_array( seed.unwrap_or(&randombytes::randombytes(32)[..]) ) ) @@ -68,15 +65,14 @@ impl ED25519 { } pub fn verify(&self, public_key: &[u8], doc: &[u8]) -> Result, CryptoError> { - let sodium = ED25519::new(); sign::verify( doc, - &sign::PublicKey(sodium.clone_into_array(public_key)) + &sign::PublicKey(ED25519::_clone_into_array(public_key)) ) .map_err(|_| CryptoError::InvalidStructure("Unable to decrypt data".to_string())) } - fn clone_into_array(&self, slice: &[T]) -> A + fn _clone_into_array(slice: &[T]) -> A where A: Sized + Default + AsMut<[T]>, T: Clone { let mut a = Default::default(); @@ -98,12 +94,12 @@ mod tests { let (alice_pk, alice_sk) = ed25519.create_key_pair(); let (bob_pk, bob_sk) = ed25519.create_key_pair(); - let bob_encrypted_text = ed25519.encrypt(&bob_sk, &alice_pk, &text[..], &nonce); + let bob_encrypted_text = ed25519.encrypt(&bob_sk, &alice_pk, &text, &nonce); let bob_decrypt_result = ed25519.decrypt(&alice_sk, &bob_pk, &bob_encrypted_text, &nonce); assert!(bob_decrypt_result.is_ok()); assert_eq!(text, bob_decrypt_result.unwrap()); - let alice_encrypted_text = ed25519.encrypt(&alice_sk, &bob_pk, &text[..], &nonce); + let alice_encrypted_text = ed25519.encrypt(&alice_sk, &bob_pk, &text, &nonce); let alice_decrypted_text = ed25519.decrypt(&bob_sk, &alice_pk, &alice_encrypted_text, &nonce); assert!(alice_decrypted_text.is_ok()); assert_eq!(text, alice_decrypted_text.unwrap()); @@ -115,8 +111,8 @@ mod tests { let seed = randombytes::randombytes(32); let text = randombytes::randombytes(16); - let (public_key, secret_key) = ed25519.create_key_pair_for_signature(Some(&seed[..])); - let alice_signed_text = ed25519.sign(&secret_key, &text[..]); + let (public_key, secret_key) = ed25519.create_key_pair_for_signature(Some(&seed)); + let alice_signed_text = ed25519.sign(&secret_key, &text); let verified_data = ed25519.verify(&public_key, &alice_signed_text); assert!(verified_data.is_ok()); diff --git a/src/services/crypto/wrappers/xsalsa20/sodium.rs b/src/services/crypto/wrappers/xsalsa20/sodium.rs index c688874..28a8201 100644 --- a/src/services/crypto/wrappers/xsalsa20/sodium.rs +++ b/src/services/crypto/wrappers/xsalsa20/sodium.rs @@ -21,25 +21,23 @@ impl XSalsa20 { } pub fn encrypt(&self, key: &[u8], nonce: &[u8], doc: &[u8]) -> Vec { - let sodium = XSalsa20::new(); secretbox::seal( doc, - &secretbox::Nonce(sodium.clone_into_array(nonce)), - &secretbox::Key(sodium.clone_into_array(key)) + &secretbox::Nonce(XSalsa20::_clone_into_array(nonce)), + &secretbox::Key(XSalsa20::_clone_into_array(key)) ) } pub fn decrypt(&self, key: &[u8], nonce: &[u8], doc: &[u8]) -> Result, CryptoError> { - let sodium = XSalsa20::new(); secretbox::open( doc, - &secretbox::Nonce(sodium.clone_into_array(nonce)), - &secretbox::Key(sodium.clone_into_array(key)) + &secretbox::Nonce(XSalsa20::_clone_into_array(nonce)), + &secretbox::Key(XSalsa20::_clone_into_array(key)) ) .map_err(|_| CryptoError::InvalidStructure("Unable to decrypt data".to_string())) } - fn clone_into_array(&self, slice: &[T]) -> A + fn _clone_into_array(slice: &[T]) -> A where A: Sized + Default + AsMut<[T]>, T: Clone { let mut a = Default::default();