Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

SecretStore: generating signatures #5764

Merged
merged 52 commits into from
Jul 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
bdea714
refactoring traits
svyatonik May 10, 2017
de3d882
separate generation session
svyatonik May 11, 2017
68cfc48
generalized ClusterSessions
svyatonik May 11, 2017
679fcbe
signing session prototype
svyatonik May 11, 2017
56a7458
full_signature_math_session
svyatonik May 17, 2017
296aa7a
consensus session prototype
svyatonik May 19, 2017
eed126f
continue signing session
svyatonik May 22, 2017
4de05de
continue signing session
svyatonik May 22, 2017
b29ac81
continue signing session
svyatonik May 22, 2017
495e45f
continue signing session
svyatonik May 22, 2017
20cba71
isolated consensus logic
svyatonik May 22, 2017
c43e6bf
started work on signing test
svyatonik May 22, 2017
dcfb98a
complete_gen_sign_session works
svyatonik May 23, 2017
537a575
consensus tests
svyatonik May 23, 2017
10210ae
get rid of duplicated data in SigningSession
svyatonik May 23, 2017
40e7a68
TODOs in signing session
svyatonik May 23, 2017
9e1d817
fixing tests
svyatonik May 23, 2017
7efdad0
fixed last test
svyatonik May 23, 2017
e503113
signing session in http listener
svyatonik May 24, 2017
3a843d4
new key server tests
svyatonik May 24, 2017
eb480aa
Merge branch 'master' into secretstore_signing
svyatonik May 24, 2017
b0f344a
fix after merge
svyatonik May 24, 2017
a792b30
enabled warnings
svyatonik May 24, 2017
6999957
fixed possible race
svyatonik May 24, 2017
7497654
ignore previous jobs responses
svyatonik May 24, 2017
340c357
include sef node in consensus when confirmed
svyatonik May 24, 2017
e2e89b6
fixed warning
svyatonik May 24, 2017
1b26bd9
removed extra clones
svyatonik May 24, 2017
acdabc5
consensus_restarts_after_node_timeout
svyatonik May 24, 2017
f8646ab
encrypt signature before return
svyatonik May 25, 2017
e0d891f
Merge branch 'master' into secretstore_signing
svyatonik May 25, 2017
4f181c7
return error text along with HTTP status
svyatonik May 25, 2017
92c1c20
fix for odd-of-N (share check fails + not equal to local sign)
svyatonik May 29, 2017
4d1b750
fixed t-of-N for odd t
svyatonik May 29, 2017
a0e6735
fixed test cases in complete_gen_sign_session
svyatonik May 30, 2017
810e725
fixed mistimed response reaction
svyatonik May 30, 2017
ba50ca0
Merge branch 'secretstore_signing' into secretstore_signing2
svyatonik May 30, 2017
6d4b473
Merge branch 'secretstore_errortext' into secretstore_signing2
svyatonik May 30, 2017
8912a19
Merge branch 'secretstore_oddsigning' into secretstore_signing2
svyatonik May 30, 2017
48693ca
jobs draft
svyatonik Jun 1, 2017
7b4f591
DecryptionJob
svyatonik Jun 1, 2017
a596c82
consensus session tets
svyatonik Jun 2, 2017
9e2448f
fixed decryption tests
svyatonik Jun 5, 2017
2db6f48
signing job implementation
svyatonik Jun 5, 2017
3f61001
siginng_session using new consensus_session
svyatonik Jun 5, 2017
009d93e
added license preambles
svyatonik Jun 5, 2017
2912f8e
same_consensus_group_returned_after_second_selection
svyatonik Jun 5, 2017
8dc6b0f
database upgrade v0 -> v1
svyatonik Jun 5, 2017
bbe4c24
Merge branch 'master' into secretstore_signing2
svyatonik Jun 5, 2017
2ba595e
typo
svyatonik Jun 21, 2017
b3392af
fixed grumbles
svyatonik Jun 27, 2017
9c56d8e
Merge branch 'master' into secretstore_signing2
arkpar Jun 30, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions ethkey/src/secret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ impl Secret {
Ok(())
}

/// Inplace negate secret key (-scalar)
pub fn neg(&mut self) -> Result<(), Error> {
let mut key_secret = self.to_secp256k1_secret()?;
key_secret.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;

*self = key_secret.into();
Ok(())
}

/// Inplace inverse secret key (1 / scalar)
pub fn inv(&mut self) -> Result<(), Error> {
let mut key_secret = self.to_secp256k1_secret()?;
Expand Down
14 changes: 7 additions & 7 deletions secret_store/src/acl_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ use parking_lot::Mutex;
use ethkey::public_to_address;
use ethcore::client::{Client, BlockChainClient, BlockId};
use native_contracts::SecretStoreAclStorage;
use types::all::{Error, DocumentAddress, Public};
use types::all::{Error, ServerKeyId, Public};

const ACL_CHECKER_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_acl_checker";

/// ACL storage of Secret Store
pub trait AclStorage: Send + Sync {
/// Check if requestor with `public` key can access document with hash `document`
fn check(&self, public: &Public, document: &DocumentAddress) -> Result<bool, Error>;
fn check(&self, public: &Public, document: &ServerKeyId) -> Result<bool, Error>;
}

/// On-chain ACL storage implementation.
Expand All @@ -48,7 +48,7 @@ impl OnChainAclStorage {
}

impl AclStorage for OnChainAclStorage {
fn check(&self, public: &Public, document: &DocumentAddress) -> Result<bool, Error> {
fn check(&self, public: &Public, document: &ServerKeyId) -> Result<bool, Error> {
let mut contract = self.contract.lock();
if !contract.is_some() {
*contract = self.client.registry_address(ACL_CHECKER_CONTRACT_REGISTRY_NAME.to_owned())
Expand All @@ -74,19 +74,19 @@ impl AclStorage for OnChainAclStorage {
pub mod tests {
use std::collections::{HashMap, HashSet};
use parking_lot::RwLock;
use types::all::{Error, DocumentAddress, Public};
use types::all::{Error, ServerKeyId, Public};
use super::AclStorage;

#[derive(Default, Debug)]
/// Dummy ACL storage implementation
pub struct DummyAclStorage {
prohibited: RwLock<HashMap<Public, HashSet<DocumentAddress>>>,
prohibited: RwLock<HashMap<Public, HashSet<ServerKeyId>>>,
}

impl DummyAclStorage {
#[cfg(test)]
/// Prohibit given requestor access to given document
pub fn prohibit(&self, public: Public, document: DocumentAddress) {
pub fn prohibit(&self, public: Public, document: ServerKeyId) {
self.prohibited.write()
.entry(public)
.or_insert_with(Default::default)
Expand All @@ -95,7 +95,7 @@ pub mod tests {
}

impl AclStorage for DummyAclStorage {
fn check(&self, public: &Public, document: &DocumentAddress) -> Result<bool, Error> {
fn check(&self, public: &Public, document: &ServerKeyId) -> Result<bool, Error> {
Ok(self.prohibited.read()
.get(public)
.map(|docs| !docs.contains(document))
Expand Down
237 changes: 175 additions & 62 deletions secret_store/src/http_listener.rs

Large diffs are not rendered by default.

177 changes: 151 additions & 26 deletions secret_store/src/key_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ use ethcrypto;
use ethkey;
use super::acl_storage::AclStorage;
use super::key_storage::KeyStorage;
use key_server_cluster::ClusterCore;
use traits::KeyServer;
use types::all::{Error, RequestSignature, DocumentAddress, DocumentEncryptedKey, DocumentEncryptedKeyShadow, ClusterConfiguration};
use key_server_cluster::{math, ClusterCore};
use traits::{ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer};
use types::all::{Error, Public, RequestSignature, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow,
ClusterConfiguration, MessageHash, EncryptedMessageSignature};
use key_server_cluster::{ClusterClient, ClusterConfiguration as NetClusterConfiguration};

/// Secret store key server implementation
Expand Down Expand Up @@ -56,30 +57,55 @@ impl KeyServerImpl {
}
}

impl KeyServer for KeyServerImpl {
fn generate_document_key(&self, signature: &RequestSignature, document: &DocumentAddress, threshold: usize) -> Result<DocumentEncryptedKey, Error> {
impl KeyServer for KeyServerImpl {}

impl ServerKeyGenerator for KeyServerImpl {
fn generate_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, threshold: usize) -> Result<Public, Error> {
// recover requestor' public key from signature
let public = ethkey::recover(signature, document)
let public = ethkey::recover(signature, key_id)
.map_err(|_| Error::BadSignature)?;

// generate document key
let encryption_session = self.data.lock().cluster.new_encryption_session(document.clone(), threshold)?;
let document_key = encryption_session.wait(None)?;
// generate server key
let generation_session = self.data.lock().cluster.new_generation_session(key_id.clone(), public, threshold)?;
generation_session.wait(None).map_err(Into::into)
}
}

impl DocumentKeyServer for KeyServerImpl {
fn store_document_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, common_point: Public, encrypted_document_key: Public) -> Result<(), Error> {
// store encrypted key
let encryption_session = self.data.lock().cluster.new_encryption_session(key_id.clone(), signature.clone(), common_point, encrypted_document_key)?;
encryption_session.wait(None).map_err(Into::into)
}

fn generate_document_key(&self, key_id: &ServerKeyId, signature: &RequestSignature, threshold: usize) -> Result<EncryptedDocumentKey, Error> {
// recover requestor' public key from signature
let public = ethkey::recover(signature, key_id)
.map_err(|_| Error::BadSignature)?;

// generate server key
let server_key = self.generate_key(key_id, signature, threshold)?;

// generate random document key
let document_key = math::generate_random_point()?;
let encrypted_document_key = math::encrypt_secret(&document_key, &server_key)?;

// store document key in the storage
self.store_document_key(key_id, signature, encrypted_document_key.common_point, encrypted_document_key.encrypted_point)?;

// encrypt document key with requestor public key
let document_key = ethcrypto::ecies::encrypt(&public, &ethcrypto::DEFAULT_MAC, &document_key)
.map_err(|err| Error::Internal(format!("Error encrypting document key: {}", err)))?;
Ok(document_key)
}

fn document_key(&self, signature: &RequestSignature, document: &DocumentAddress) -> Result<DocumentEncryptedKey, Error> {
fn restore_document_key(&self, key_id: &ServerKeyId, signature: &RequestSignature) -> Result<EncryptedDocumentKey, Error> {
// recover requestor' public key from signature
let public = ethkey::recover(signature, document)
let public = ethkey::recover(signature, key_id)
.map_err(|_| Error::BadSignature)?;


// decrypt document key
let decryption_session = self.data.lock().cluster.new_decryption_session(document.clone(), signature.clone(), false)?;
let decryption_session = self.data.lock().cluster.new_decryption_session(key_id.clone(), signature.clone(), false)?;
let document_key = decryption_session.wait()?.decrypted_secret;

// encrypt document key with requestor public key
Expand All @@ -88,12 +114,34 @@ impl KeyServer for KeyServerImpl {
Ok(document_key)
}

fn document_key_shadow(&self, signature: &RequestSignature, document: &DocumentAddress) -> Result<DocumentEncryptedKeyShadow, Error> {
let decryption_session = self.data.lock().cluster.new_decryption_session(document.clone(), signature.clone(), true)?;
fn restore_document_key_shadow(&self, key_id: &ServerKeyId, signature: &RequestSignature) -> Result<EncryptedDocumentKeyShadow, Error> {
let decryption_session = self.data.lock().cluster.new_decryption_session(key_id.clone(), signature.clone(), true)?;
decryption_session.wait().map_err(Into::into)
}
}

impl MessageSigner for KeyServerImpl {
fn sign_message(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
// recover requestor' public key from signature
let public = ethkey::recover(signature, key_id)
.map_err(|_| Error::BadSignature)?;

// sign message
let signing_session = self.data.lock().cluster.new_signing_session(key_id.clone(), signature.clone(), message)?;
let message_signature = signing_session.wait()?;

// compose two message signature components into single one
let mut combined_signature = [0; 64];
combined_signature[..32].clone_from_slice(&**message_signature.0);
combined_signature[32..].clone_from_slice(&**message_signature.1);

// encrypt combined signature with requestor public key
let message_signature = ethcrypto::ecies::encrypt(&public, &ethcrypto::DEFAULT_MAC, &combined_signature)
.map_err(|err| Error::Internal(format!("Error encrypting message signature: {}", err)))?;
Ok(message_signature)
}
}

impl KeyServerCore {
pub fn new(config: &ClusterConfiguration, acl_storage: Arc<AclStorage>, key_storage: Arc<KeyStorage>) -> Result<Self, Error> {
let config = NetClusterConfiguration {
Expand Down Expand Up @@ -146,24 +194,46 @@ pub mod tests {
use std::time;
use std::sync::Arc;
use ethcrypto;
use ethkey::{self, Random, Generator};
use ethkey::{self, Secret, Random, Generator};
use acl_storage::tests::DummyAclStorage;
use key_storage::tests::DummyKeyStorage;
use types::all::{Error, ClusterConfiguration, NodeAddress, RequestSignature, DocumentAddress, DocumentEncryptedKey, DocumentEncryptedKeyShadow};
use super::{KeyServer, KeyServerImpl};
use key_server_cluster::math;
use util::H256;
use types::all::{Error, Public, ClusterConfiguration, NodeAddress, RequestSignature, ServerKeyId,
EncryptedDocumentKey, EncryptedDocumentKeyShadow, MessageHash, EncryptedMessageSignature};
use traits::{ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer};
use super::KeyServerImpl;

pub struct DummyKeyServer;

impl KeyServer for DummyKeyServer {
fn generate_document_key(&self, _signature: &RequestSignature, _document: &DocumentAddress, _threshold: usize) -> Result<DocumentEncryptedKey, Error> {
impl KeyServer for DummyKeyServer {}

impl ServerKeyGenerator for DummyKeyServer {
fn generate_key(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _threshold: usize) -> Result<Public, Error> {
unimplemented!()
}
}

impl DocumentKeyServer for DummyKeyServer {
fn store_document_key(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _common_point: Public, _encrypted_document_key: Public) -> Result<(), Error> {
unimplemented!()
}

fn generate_document_key(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _threshold: usize) -> Result<EncryptedDocumentKey, Error> {
unimplemented!()
}

fn document_key(&self, _signature: &RequestSignature, _document: &DocumentAddress) -> Result<DocumentEncryptedKey, Error> {
fn restore_document_key(&self, _key_id: &ServerKeyId, _signature: &RequestSignature) -> Result<EncryptedDocumentKey, Error> {
unimplemented!()
}

fn document_key_shadow(&self, _signature: &RequestSignature, _document: &DocumentAddress) -> Result<DocumentEncryptedKeyShadow, Error> {
fn restore_document_key_shadow(&self, _key_id: &ServerKeyId, _signature: &RequestSignature) -> Result<EncryptedDocumentKeyShadow, Error> {
unimplemented!()
}
}

impl MessageSigner for DummyKeyServer {
fn sign_message(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
unimplemented!()
}
}
Expand Down Expand Up @@ -228,12 +298,12 @@ pub mod tests {
let document = Random.generate().unwrap().secret().clone();
let secret = Random.generate().unwrap().secret().clone();
let signature = ethkey::sign(&secret, &document).unwrap();
let generated_key = key_servers[0].generate_document_key(&signature, &document, threshold).unwrap();
let generated_key = key_servers[0].generate_document_key(&document, &signature, threshold).unwrap();
let generated_key = ethcrypto::ecies::decrypt(&secret, &ethcrypto::DEFAULT_MAC, &generated_key).unwrap();

// now let's try to retrieve key back
for key_server in key_servers.iter() {
let retrieved_key = key_server.document_key(&signature, &document).unwrap();
let retrieved_key = key_server.restore_document_key(&document, &signature).unwrap();
let retrieved_key = ethcrypto::ecies::decrypt(&secret, &ethcrypto::DEFAULT_MAC, &retrieved_key).unwrap();
assert_eq!(retrieved_key, generated_key);
}
Expand All @@ -250,15 +320,70 @@ pub mod tests {
let document = Random.generate().unwrap().secret().clone();
let secret = Random.generate().unwrap().secret().clone();
let signature = ethkey::sign(&secret, &document).unwrap();
let generated_key = key_servers[0].generate_document_key(&signature, &document, *threshold).unwrap();
let generated_key = key_servers[0].generate_document_key(&document, &signature, *threshold).unwrap();
let generated_key = ethcrypto::ecies::decrypt(&secret, &ethcrypto::DEFAULT_MAC, &generated_key).unwrap();

// now let's try to retrieve key back
for key_server in key_servers.iter() {
let retrieved_key = key_server.document_key(&signature, &document).unwrap();
let retrieved_key = key_server.restore_document_key(&document, &signature).unwrap();
let retrieved_key = ethcrypto::ecies::decrypt(&secret, &ethcrypto::DEFAULT_MAC, &retrieved_key).unwrap();
assert_eq!(retrieved_key, generated_key);
}
}
}

#[test]
fn server_key_generation_and_storing_document_key_works_over_network_with_3_nodes() {
//::logger::init_log();
let key_servers = make_key_servers(6090, 3);

let test_cases = [0, 1, 2];
for threshold in &test_cases {
// generate server key
let server_key_id = Random.generate().unwrap().secret().clone();
let requestor_secret = Random.generate().unwrap().secret().clone();
let signature = ethkey::sign(&requestor_secret, &server_key_id).unwrap();
let server_public = key_servers[0].generate_key(&server_key_id, &signature, *threshold).unwrap();

// generate document key (this is done by KS client so that document key is unknown to any KS)
let generated_key = Random.generate().unwrap().public().clone();
let encrypted_document_key = math::encrypt_secret(&generated_key, &server_public).unwrap();

// store document key
key_servers[0].store_document_key(&server_key_id, &signature, encrypted_document_key.common_point, encrypted_document_key.encrypted_point).unwrap();

// now let's try to retrieve key back
for key_server in key_servers.iter() {
let retrieved_key = key_server.restore_document_key(&server_key_id, &signature).unwrap();
let retrieved_key = ethcrypto::ecies::decrypt(&requestor_secret, &ethcrypto::DEFAULT_MAC, &retrieved_key).unwrap();
let retrieved_key = Public::from_slice(&retrieved_key);
assert_eq!(retrieved_key, generated_key);
}
}
}

#[test]
fn server_key_generation_and_message_signing_works_over_network_with_3_nodes() {
//::logger::init_log();
let key_servers = make_key_servers(6100, 3);

let test_cases = [0, 1, 2];
for threshold in &test_cases {
// generate server key
let server_key_id = Random.generate().unwrap().secret().clone();
let requestor_secret = Random.generate().unwrap().secret().clone();
let signature = ethkey::sign(&requestor_secret, &server_key_id).unwrap();
let server_public = key_servers[0].generate_key(&server_key_id, &signature, *threshold).unwrap();

// sign message
let message_hash = H256::from(42);
let combined_signature = key_servers[0].sign_message(&server_key_id, &signature, message_hash.clone()).unwrap();
let combined_signature = ethcrypto::ecies::decrypt(&requestor_secret, &ethcrypto::DEFAULT_MAC, &combined_signature).unwrap();
let signature_c = Secret::from_slice(&combined_signature[..32]);
let signature_s = Secret::from_slice(&combined_signature[32..]);

// check signature
assert_eq!(math::verify_signature(&server_public, &(signature_c, signature_s), &message_hash), Ok(true));
}
}
}
Loading