SecretStore: secretstore_generateDocumentKey RPC (#7864)
* SecretStore: secretstore_generateDocumentKey RPC * SecretStore: return encrypted_key from secretstore_generateDocumentKey
This commit is contained in:
parent
0da6c7eb45
commit
6d5b13c80c
@ -16,17 +16,36 @@
|
|||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use rand::{Rng, OsRng};
|
use rand::{Rng, OsRng};
|
||||||
use ethkey::{Public, Secret, math};
|
use ethkey::{Public, Secret, Random, Generator, math};
|
||||||
use crypto;
|
use crypto;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use jsonrpc_core::Error;
|
use jsonrpc_core::Error;
|
||||||
use v1::helpers::errors;
|
use v1::helpers::errors;
|
||||||
use v1::types::{H256, H512};
|
use v1::types::{H256, H512, EncryptedDocumentKey};
|
||||||
use tiny_keccak::Keccak;
|
use tiny_keccak::Keccak;
|
||||||
|
|
||||||
/// Initialization vector length.
|
/// Initialization vector length.
|
||||||
const INIT_VEC_LEN: usize = 16;
|
const INIT_VEC_LEN: usize = 16;
|
||||||
|
|
||||||
|
/// Generate document key to store in secret store.
|
||||||
|
pub fn generate_document_key(account_public: Public, server_key_public: Public) -> Result<EncryptedDocumentKey, Error> {
|
||||||
|
// generate random plain document key
|
||||||
|
let document_key = Random.generate().map_err(errors::encryption)?;
|
||||||
|
|
||||||
|
// encrypt document key using server key
|
||||||
|
let (common_point, encrypted_point) = encrypt_secret(document_key.public(), &server_key_public)?;
|
||||||
|
|
||||||
|
// ..and now encrypt document key with account public
|
||||||
|
let encrypted_key = crypto::ecies::encrypt(&account_public, &crypto::DEFAULT_MAC, document_key.public())
|
||||||
|
.map_err(errors::encryption)?;
|
||||||
|
|
||||||
|
Ok(EncryptedDocumentKey {
|
||||||
|
common_point: common_point.into(),
|
||||||
|
encrypted_point: encrypted_point.into(),
|
||||||
|
encrypted_key: encrypted_key.into(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Encrypt document with distributely generated key.
|
/// Encrypt document with distributely generated key.
|
||||||
pub fn encrypt_document(key: Bytes, document: Bytes) -> Result<Bytes, Error> {
|
pub fn encrypt_document(key: Bytes, document: Bytes) -> Result<Bytes, Error> {
|
||||||
// make document key
|
// make document key
|
||||||
@ -114,6 +133,28 @@ fn decrypt_with_shadow_coefficients(mut decrypted_shadow: Public, mut common_sha
|
|||||||
Ok(decrypted_shadow)
|
Ok(decrypted_shadow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn encrypt_secret(secret: &Public, joint_public: &Public) -> Result<(Public, Public), Error> {
|
||||||
|
// TODO: it is copypaste of `encrypt_secret` from secret_store/src/key_server_cluster/math.rs
|
||||||
|
// use shared version from SS math library, when it'll be available
|
||||||
|
|
||||||
|
let key_pair = Random.generate()
|
||||||
|
.map_err(errors::encryption)?;
|
||||||
|
|
||||||
|
// k * T
|
||||||
|
let mut common_point = math::generation_point();
|
||||||
|
math::public_mul_secret(&mut common_point, key_pair.secret())
|
||||||
|
.map_err(errors::encryption)?;
|
||||||
|
|
||||||
|
// M + k * y
|
||||||
|
let mut encrypted_point = joint_public.clone();
|
||||||
|
math::public_mul_secret(&mut encrypted_point, key_pair.secret())
|
||||||
|
.map_err(errors::encryption)?;
|
||||||
|
math::public_add(&mut encrypted_point, secret)
|
||||||
|
.map_err(errors::encryption)?;
|
||||||
|
|
||||||
|
Ok((common_point, encrypted_point))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
@ -26,9 +26,10 @@ use ethcore::account_provider::AccountProvider;
|
|||||||
use jsonrpc_core::Result;
|
use jsonrpc_core::Result;
|
||||||
use v1::helpers::errors;
|
use v1::helpers::errors;
|
||||||
use v1::helpers::accounts::unwrap_provider;
|
use v1::helpers::accounts::unwrap_provider;
|
||||||
use v1::helpers::secretstore::{encrypt_document, decrypt_document, decrypt_document_with_shadow, ordered_servers_keccak};
|
use v1::helpers::secretstore::{generate_document_key, encrypt_document,
|
||||||
|
decrypt_document, decrypt_document_with_shadow, ordered_servers_keccak};
|
||||||
use v1::traits::SecretStore;
|
use v1::traits::SecretStore;
|
||||||
use v1::types::{H160, H256, H512, Bytes};
|
use v1::types::{H160, H256, H512, Bytes, EncryptedDocumentKey};
|
||||||
|
|
||||||
/// Parity implementation.
|
/// Parity implementation.
|
||||||
pub struct SecretStoreClient {
|
pub struct SecretStoreClient {
|
||||||
@ -64,6 +65,13 @@ impl SecretStoreClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SecretStore for SecretStoreClient {
|
impl SecretStore for SecretStoreClient {
|
||||||
|
fn generate_document_key(&self, address: H160, password: String, server_key_public: H512) -> Result<EncryptedDocumentKey> {
|
||||||
|
let store = self.account_provider()?;
|
||||||
|
let account_public = store.account_public(address.into(), &password)
|
||||||
|
.map_err(|e| errors::account("Could not read account public.", e))?;
|
||||||
|
generate_document_key(account_public, server_key_public.into())
|
||||||
|
}
|
||||||
|
|
||||||
fn encrypt(&self, address: H160, password: String, key: Bytes, data: Bytes) -> Result<Bytes> {
|
fn encrypt(&self, address: H160, password: String, key: Bytes, data: Bytes) -> Result<Bytes> {
|
||||||
encrypt_document(self.decrypt_key(address, password, key)?, data.0)
|
encrypt_document(self.decrypt_key(address, password, key)?, data.0)
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crypto::DEFAULT_MAC;
|
||||||
use ethcore::account_provider::AccountProvider;
|
use ethcore::account_provider::AccountProvider;
|
||||||
use ethkey::{KeyPair, Signature, verify_public};
|
use ethkey::{KeyPair, Signature, verify_public};
|
||||||
|
|
||||||
@ -25,7 +26,7 @@ use v1::metadata::Metadata;
|
|||||||
use v1::SecretStoreClient;
|
use v1::SecretStoreClient;
|
||||||
use v1::traits::secretstore::SecretStore;
|
use v1::traits::secretstore::SecretStore;
|
||||||
use v1::helpers::secretstore::ordered_servers_keccak;
|
use v1::helpers::secretstore::ordered_servers_keccak;
|
||||||
use v1::types::H256;
|
use v1::types::{H256, EncryptedDocumentKey};
|
||||||
|
|
||||||
struct Dependencies {
|
struct Dependencies {
|
||||||
pub accounts: Arc<AccountProvider>,
|
pub accounts: Arc<AccountProvider>,
|
||||||
@ -144,3 +145,31 @@ fn rpc_secretstore_sign_raw_hash() {
|
|||||||
let hash = "0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap();
|
let hash = "0000000000000000000000000000000000000000000000000000000000000001".parse().unwrap();
|
||||||
assert!(verify_public(key_pair.public(), &signature, &hash).unwrap());
|
assert!(verify_public(key_pair.public(), &signature, &hash).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_secretstore_generate_document_key() {
|
||||||
|
let deps = Dependencies::new();
|
||||||
|
let io = deps.default_client();
|
||||||
|
|
||||||
|
// insert new account
|
||||||
|
let secret = "82758356bf46b42710d3946a8efa612b7bf5e125e4d49f28facf1139db4a46f4".parse().unwrap();
|
||||||
|
let key_pair = KeyPair::from_secret(secret).unwrap();
|
||||||
|
deps.accounts.insert_account(key_pair.secret().clone(), "password").unwrap();
|
||||||
|
|
||||||
|
// execute generation request
|
||||||
|
let generation_request = r#"{"jsonrpc": "2.0", "method": "secretstore_generateDocumentKey", "params":[
|
||||||
|
"0x00dfE63B22312ab4329aD0d28CaD8Af987A01932", "password",
|
||||||
|
"0x843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91"
|
||||||
|
], "id": 1}"#;
|
||||||
|
let generation_response = io.handle_request_sync(&generation_request).unwrap();
|
||||||
|
let generation_response = generation_response.replace(r#"{"jsonrpc":"2.0","result":"#, "");
|
||||||
|
let generation_response = generation_response.replace(r#","id":1}"#, "");
|
||||||
|
let generation_response: EncryptedDocumentKey = serde_json::from_str(&generation_response).unwrap();
|
||||||
|
|
||||||
|
// the only thing we can check is that 'encrypted_key' can be decrypted by passed account
|
||||||
|
assert!(deps.accounts.decrypt(
|
||||||
|
"00dfE63B22312ab4329aD0d28CaD8Af987A01932".parse().unwrap(),
|
||||||
|
Some("password".into()),
|
||||||
|
&DEFAULT_MAC,
|
||||||
|
&generation_response.encrypted_key.0).is_ok());
|
||||||
|
}
|
||||||
|
@ -19,11 +19,16 @@
|
|||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use jsonrpc_core::Result;
|
use jsonrpc_core::Result;
|
||||||
|
|
||||||
use v1::types::{H160, H256, H512, Bytes};
|
use v1::types::{H160, H256, H512, Bytes, EncryptedDocumentKey};
|
||||||
|
|
||||||
build_rpc_trait! {
|
build_rpc_trait! {
|
||||||
/// Parity-specific rpc interface.
|
/// Parity-specific rpc interface.
|
||||||
pub trait SecretStore {
|
pub trait SecretStore {
|
||||||
|
/// Generate document key to store in secret store.
|
||||||
|
/// Arguments: `account`, `password`, `server_key_public`.
|
||||||
|
#[rpc(name = "secretstore_generateDocumentKey")]
|
||||||
|
fn generate_document_key(&self, H160, String, H512) -> Result<EncryptedDocumentKey>;
|
||||||
|
|
||||||
/// Encrypt data with key, received from secret store.
|
/// Encrypt data with key, received from secret store.
|
||||||
/// Arguments: `account`, `password`, `key`, `data`.
|
/// Arguments: `account`, `password`, `key`, `data`.
|
||||||
#[rpc(name = "secretstore_encrypt")]
|
#[rpc(name = "secretstore_encrypt")]
|
||||||
|
@ -35,6 +35,7 @@ mod node_kind;
|
|||||||
mod provenance;
|
mod provenance;
|
||||||
mod receipt;
|
mod receipt;
|
||||||
mod rpc_settings;
|
mod rpc_settings;
|
||||||
|
mod secretstore;
|
||||||
mod sync;
|
mod sync;
|
||||||
mod trace;
|
mod trace;
|
||||||
mod trace_filter;
|
mod trace_filter;
|
||||||
@ -67,6 +68,7 @@ pub use self::node_kind::{NodeKind, Availability, Capability};
|
|||||||
pub use self::provenance::{Origin, DappId};
|
pub use self::provenance::{Origin, DappId};
|
||||||
pub use self::receipt::Receipt;
|
pub use self::receipt::Receipt;
|
||||||
pub use self::rpc_settings::RpcSettings;
|
pub use self::rpc_settings::RpcSettings;
|
||||||
|
pub use self::secretstore::EncryptedDocumentKey;
|
||||||
pub use self::sync::{
|
pub use self::sync::{
|
||||||
SyncStatus, SyncInfo, Peers, PeerInfo, PeerNetworkInfo, PeerProtocolsInfo,
|
SyncStatus, SyncInfo, Peers, PeerInfo, PeerNetworkInfo, PeerProtocolsInfo,
|
||||||
TransactionStats, ChainStatus, EthProtocolInfo, PipProtocolInfo,
|
TransactionStats, ChainStatus, EthProtocolInfo, PipProtocolInfo,
|
||||||
|
52
rpc/src/v1/types/secretstore.rs
Normal file
52
rpc/src/v1/types/secretstore.rs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use v1::types::{Bytes, H512};
|
||||||
|
|
||||||
|
/// Encrypted document key.
|
||||||
|
#[derive(Default, Debug, Serialize, PartialEq)]
|
||||||
|
#[cfg_attr(test, derive(Deserialize))]
|
||||||
|
pub struct EncryptedDocumentKey {
|
||||||
|
/// Common encryption point. Pass this to Secret Store 'Document key storing session'
|
||||||
|
pub common_point: H512,
|
||||||
|
/// Ecnrypted point. Pass this to Secret Store 'Document key storing session'.
|
||||||
|
pub encrypted_point: H512,
|
||||||
|
/// Document key itself, encrypted with passed account public. Pass this to 'secretstore_encrypt'.
|
||||||
|
pub encrypted_key: Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use serde_json;
|
||||||
|
use super::EncryptedDocumentKey;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialize_encrypted_document_key() {
|
||||||
|
let initial = EncryptedDocumentKey {
|
||||||
|
common_point: 1.into(),
|
||||||
|
encrypted_point: 2.into(),
|
||||||
|
encrypted_key: vec![3].into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let serialized = serde_json::to_string(&initial).unwrap();
|
||||||
|
assert_eq!(serialized, r#"{"common_point":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001","encrypted_point":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002","encrypted_key":"0x03"}"#);
|
||||||
|
|
||||||
|
let deserialized: EncryptedDocumentKey = serde_json::from_str(&serialized).unwrap();
|
||||||
|
assert_eq!(deserialized.common_point, 1.into());
|
||||||
|
assert_eq!(deserialized.encrypted_point, 2.into());
|
||||||
|
assert_eq!(deserialized.encrypted_key, vec![3].into());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user