secret store separated from util (#1304)

* bump rust-crypto

* initial version of account provider utilizing secret store

* update lazy_static to latest version

* AccountProvider accounts method

* new AccountProvider tests in progress

* basic tests for new AccountProvider

* ethcore compiles with new account provider and secret store

* ethcore-rpc build now compiling with new AccountProvider

* most rpc tests passing with new accounts_provider

* fixed basic_authority tests

* fixed eth_transaction_count rpc test

* fixed mocked/eth.rs tests

* fixed personal tests

* fixed personal signer rpc tests

* removed warnings

* parity compiling fine with new sstore

* fixed import direction

* do not unlock temporarily when we have the password

* removed TODO in account import

* display warning on auto account import failure

* fixed compiling of ethstore on windows

* ethstore as a part of parity repo

* added ethkey
This commit is contained in:
Marek Kotewicz
2016-06-20 00:10:34 +02:00
committed by Gav Wood
parent 08522eec37
commit 6b074e8fb2
84 changed files with 4027 additions and 2682 deletions

View File

@@ -0,0 +1,75 @@
use serde::{Serialize, Serializer, Deserialize, Deserializer, Error as SerdeError};
use serde::de::Visitor;
use super::{Error, H128};
#[derive(Debug, PartialEq)]
pub enum CipherSer {
Aes128Ctr,
}
impl Serialize for CipherSer {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer {
match *self {
CipherSer::Aes128Ctr => serializer.serialize_str("aes-128-ctr"),
}
}
}
impl Deserialize for CipherSer {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer {
deserializer.deserialize(CipherSerVisitor)
}
}
struct CipherSerVisitor;
impl Visitor for CipherSerVisitor {
type Value = CipherSer;
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
match value {
"aes-128-ctr" => Ok(CipherSer::Aes128Ctr),
_ => Err(SerdeError::custom(Error::UnsupportedCipher))
}
}
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: SerdeError {
self.visit_str(value.as_ref())
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Aes128Ctr {
pub iv: H128,
}
#[derive(Debug, PartialEq)]
pub enum CipherSerParams {
Aes128Ctr(Aes128Ctr),
}
impl Serialize for CipherSerParams {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer {
match *self {
CipherSerParams::Aes128Ctr(ref params) => params.serialize(serializer),
}
}
}
impl Deserialize for CipherSerParams {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer {
Aes128Ctr::deserialize(deserializer)
.map(CipherSerParams::Aes128Ctr)
.map_err(|_| Error::InvalidCipherParams)
.map_err(SerdeError::custom)
}
}
#[derive(Debug, PartialEq)]
pub enum Cipher {
Aes128Ctr(Aes128Ctr),
}

184
ethstore/src/json/crypto.rs Normal file
View File

@@ -0,0 +1,184 @@
use serde::{Deserialize, Deserializer, Serialize, Serializer, Error};
use serde::de::{Visitor, MapVisitor};
use serde::ser;
use super::{Cipher, CipherSer, CipherSerParams, Kdf, KdfSer, KdfSerParams, H256};
#[derive(Debug, PartialEq)]
pub struct Crypto {
pub cipher: Cipher,
pub ciphertext: H256,
pub kdf: Kdf,
pub mac: H256,
}
enum CryptoField {
Cipher,
CipherParams,
CipherText,
Kdf,
KdfParams,
Mac,
}
impl Deserialize for CryptoField {
fn deserialize<D>(deserializer: &mut D) -> Result<CryptoField, D::Error>
where D: Deserializer
{
deserializer.deserialize(CryptoFieldVisitor)
}
}
struct CryptoFieldVisitor;
impl Visitor for CryptoFieldVisitor {
type Value = CryptoField;
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E>
where E: Error
{
match value {
"cipher" => Ok(CryptoField::Cipher),
"cipherparams" => Ok(CryptoField::CipherParams),
"ciphertext" => Ok(CryptoField::CipherText),
"kdf" => Ok(CryptoField::Kdf),
"kdfparams" => Ok(CryptoField::KdfParams),
"mac" => Ok(CryptoField::Mac),
_ => Err(Error::custom(format!("Unknown field: '{}'", value))),
}
}
}
impl Deserialize for Crypto {
fn deserialize<D>(deserializer: &mut D) -> Result<Crypto, D::Error>
where D: Deserializer
{
static FIELDS: &'static [&'static str] = &["id", "version", "crypto", "Crypto", "address"];
deserializer.deserialize_struct("Crypto", FIELDS, CryptoVisitor)
}
}
struct CryptoVisitor;
impl Visitor for CryptoVisitor {
type Value = Crypto;
fn visit_map<V>(&mut self, mut visitor: V) -> Result<Self::Value, V::Error>
where V: MapVisitor
{
let mut cipher = None;
let mut cipherparams = None;
let mut ciphertext = None;
let mut kdf = None;
let mut kdfparams = None;
let mut mac = None;
loop {
match try!(visitor.visit_key()) {
Some(CryptoField::Cipher) => { cipher = Some(try!(visitor.visit_value())); }
Some(CryptoField::CipherParams) => { cipherparams = Some(try!(visitor.visit_value())); }
Some(CryptoField::CipherText) => { ciphertext = Some(try!(visitor.visit_value())); }
Some(CryptoField::Kdf) => { kdf = Some(try!(visitor.visit_value())); }
Some(CryptoField::KdfParams) => { kdfparams = Some(try!(visitor.visit_value())); }
Some(CryptoField::Mac) => { mac = Some(try!(visitor.visit_value())); }
None => { break; }
}
}
let cipher = match (cipher, cipherparams) {
(Some(CipherSer::Aes128Ctr), Some(CipherSerParams::Aes128Ctr(params))) => Cipher::Aes128Ctr(params),
(None, _) => return Err(Error::missing_field("cipher")),
(Some(_), None) => return Err(Error::missing_field("cipherparams")),
};
let ciphertext = match ciphertext {
Some(ciphertext) => ciphertext,
None => try!(visitor.missing_field("ciphertext")),
};
let kdf = match (kdf, kdfparams) {
(Some(KdfSer::Pbkdf2), Some(KdfSerParams::Pbkdf2(params))) => Kdf::Pbkdf2(params),
(Some(KdfSer::Scrypt), Some(KdfSerParams::Scrypt(params))) => Kdf::Scrypt(params),
(Some(_), Some(_)) => return Err(Error::custom("Invalid cipherparams")),
(None, _) => return Err(Error::missing_field("kdf")),
(Some(_), None) => return Err(Error::missing_field("kdfparams")),
};
let mac = match mac {
Some(mac) => mac,
None => try!(visitor.missing_field("mac")),
};
try!(visitor.end());
let result = Crypto {
cipher: cipher,
ciphertext: ciphertext,
kdf: kdf,
mac: mac,
};
Ok(result)
}
}
impl Serialize for Crypto {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer
{
serializer.serialize_struct("Crypto", CryptoMapVisitor {
value: self,
state: 0,
})
}
}
struct CryptoMapVisitor<'a> {
value: &'a Crypto,
state: u8,
}
impl<'a> ser::MapVisitor for CryptoMapVisitor<'a> {
fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
where S: Serializer
{
match self.state {
0 => {
self.state += 1;
match self.value.cipher {
Cipher::Aes128Ctr(_) => Ok(Some(try!(serializer.serialize_struct_elt("cipher", &CipherSer::Aes128Ctr)))),
}
},
1 => {
self.state += 1;
match self.value.cipher {
Cipher::Aes128Ctr(ref params) => Ok(Some(try!(serializer.serialize_struct_elt("cipherparams", params)))),
}
},
2 => {
self.state += 1;
Ok(Some(try!(serializer.serialize_struct_elt("ciphertext", &self.value.ciphertext))))
},
3 => {
self.state += 1;
match self.value.kdf {
Kdf::Pbkdf2(_) => Ok(Some(try!(serializer.serialize_struct_elt("kdf", &KdfSer::Pbkdf2)))),
Kdf::Scrypt(_) => Ok(Some(try!(serializer.serialize_struct_elt("kdf", &KdfSer::Scrypt)))),
}
},
4 => {
self.state += 1;
match self.value.kdf {
Kdf::Pbkdf2(ref params) => Ok(Some(try!(serializer.serialize_struct_elt("kdfparams", params)))),
Kdf::Scrypt(ref params) => Ok(Some(try!(serializer.serialize_struct_elt("kdfparams", params)))),
}
},
5 => {
self.state += 1;
Ok(Some(try!(serializer.serialize_struct_elt("mac", &self.value.mac))))
},
_ => {
Ok(None)
}
}
}
}

View File

@@ -0,0 +1,34 @@
use std::fmt;
#[derive(Debug, PartialEq)]
pub enum Error {
UnsupportedCipher,
InvalidCipherParams,
UnsupportedKdf,
InvalidUUID,
UnsupportedVersion,
InvalidCiphertext,
InvalidH256,
InvalidPrf,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Error::InvalidUUID => write!(f, "Invalid UUID"),
Error::UnsupportedVersion => write!(f, "Unsupported version"),
Error::UnsupportedKdf => write!(f, "Unsupported kdf"),
Error::InvalidCiphertext => write!(f, "Invalid ciphertext"),
Error::UnsupportedCipher => write!(f, "Unsupported cipher"),
Error::InvalidCipherParams => write!(f, "Invalid cipher params"),
Error::InvalidH256 => write!(f, "Invalid hash"),
Error::InvalidPrf => write!(f, "Invalid prf"),
}
}
}
impl Into<String> for Error {
fn into(self) -> String {
format!("{}", self)
}
}

71
ethstore/src/json/hash.rs Normal file
View File

@@ -0,0 +1,71 @@
use std::str::FromStr;
use rustc_serialize::hex::{FromHex, ToHex};
use serde::{Serialize, Serializer, Deserialize, Deserializer, Error as SerdeError};
use serde::de::Visitor;
use super::Error;
macro_rules! impl_hash {
($name: ident, $size: expr) => {
#[derive(Debug, PartialEq)]
pub struct $name([u8; $size]);
impl Serialize for $name {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer {
serializer.serialize_str(&self.0.to_hex())
}
}
impl Deserialize for $name {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer {
struct HashVisitor;
impl Visitor for HashVisitor {
type Value = $name;
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
FromStr::from_str(value).map_err(SerdeError::custom)
}
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: SerdeError {
self.visit_str(value.as_ref())
}
}
deserializer.deserialize(HashVisitor)
}
}
impl FromStr for $name {
type Err = Error;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value.from_hex() {
Ok(ref hex) if hex.len() == $size => {
let mut hash = [0u8; $size];
hash.clone_from_slice(hex);
Ok($name(hash))
}
_ => Err(Error::InvalidH256),
}
}
}
impl From<[u8; $size]> for $name {
fn from(bytes: [u8; $size]) -> Self {
$name(bytes)
}
}
impl Into<[u8; $size]> for $name {
fn into(self) -> [u8; $size] {
self.0
}
}
}
}
impl_hash!(H128, 16);
impl_hash!(H160, 20);
impl_hash!(H256, 32);

129
ethstore/src/json/id.rs Normal file
View File

@@ -0,0 +1,129 @@
//! Universaly unique identifier.
use std::str::FromStr;
use std::fmt;
use rustc_serialize::hex::{ToHex, FromHex};
use serde::{Deserialize, Serialize, Deserializer, Serializer, Error as SerdeError};
use serde::de::Visitor;
use super::Error;
/// Universaly unique identifier.
#[derive(Debug, PartialEq)]
pub struct UUID([u8; 16]);
impl From<[u8; 16]> for UUID {
fn from(uuid: [u8; 16]) -> Self {
UUID(uuid)
}
}
impl<'a> Into<String> for &'a UUID {
fn into(self) -> String {
let d1 = &self.0[0..4];
let d2 = &self.0[4..6];
let d3 = &self.0[6..8];
let d4 = &self.0[8..10];
let d5 = &self.0[10..16];
[d1, d2, d3, d4, d5].into_iter().map(|d| d.to_hex()).collect::<Vec<String>>().join("-")
}
}
impl Into<String> for UUID {
fn into(self) -> String {
Into::into(&self)
}
}
impl Into<[u8; 16]> for UUID {
fn into(self) -> [u8; 16] {
self.0
}
}
impl fmt::Display for UUID {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let s: String = (self as &UUID).into();
write!(f, "{}", s)
}
}
fn copy_into(from: &str, into: &mut [u8]) -> Result<(), Error> {
let from = try!(from.from_hex().map_err(|_| Error::InvalidUUID));
if from.len() != into.len() {
return Err(Error::InvalidUUID);
}
into.copy_from_slice(&from);
Ok(())
}
impl FromStr for UUID {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split("-").collect();
if parts.len() != 5 {
return Err(Error::InvalidUUID);
}
let mut uuid = [0u8; 16];
try!(copy_into(parts[0], &mut uuid[0..4]));
try!(copy_into(parts[1], &mut uuid[4..6]));
try!(copy_into(parts[2], &mut uuid[6..8]));
try!(copy_into(parts[3], &mut uuid[8..10]));
try!(copy_into(parts[4], &mut uuid[10..16]));
Ok(UUID(uuid))
}
}
impl Serialize for UUID {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer {
let s: String = self.into();
serializer.serialize_str(&s)
}
}
impl Deserialize for UUID {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer {
deserializer.deserialize(UUIDVisitor)
}
}
struct UUIDVisitor;
impl Visitor for UUIDVisitor {
type Value = UUID;
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
UUID::from_str(value).map_err(SerdeError::custom)
}
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: SerdeError {
self.visit_str(value.as_ref())
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use super::UUID;
#[test]
fn uuid_from_str() {
let uuid = UUID::from_str("3198bc9c-6672-5ab3-d995-4942343ae5b6").unwrap();
assert_eq!(uuid, UUID::from([0x31, 0x98, 0xbc, 0x9c, 0x66, 0x72, 0x5a, 0xb3, 0xd9, 0x95, 0x49, 0x42, 0x34, 0x3a, 0xe5, 0xb6]));
}
#[test]
fn uuid_from_and_to_str() {
let from = "3198bc9c-6672-5ab3-d995-4942343ae5b6";
let uuid = UUID::from_str(from).unwrap();
let to: String = uuid.into();
assert_eq!(from, &to);
}
}

133
ethstore/src/json/kdf.rs Normal file
View File

@@ -0,0 +1,133 @@
use serde::{Serialize, Serializer, Deserialize, Deserializer, Error as SerdeError};
use serde::de::Visitor;
use serde_json::{Value, value};
use super::{Error, H256};
#[derive(Debug, PartialEq)]
pub enum KdfSer {
Pbkdf2,
Scrypt,
}
impl Serialize for KdfSer {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer {
match *self {
KdfSer::Pbkdf2 => serializer.serialize_str("pbkdf2"),
KdfSer::Scrypt => serializer.serialize_str("scrypt"),
}
}
}
impl Deserialize for KdfSer {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer {
deserializer.deserialize(KdfSerVisitor)
}
}
struct KdfSerVisitor;
impl Visitor for KdfSerVisitor {
type Value = KdfSer;
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
match value {
"pbkdf2" => Ok(KdfSer::Pbkdf2),
"scrypt" => Ok(KdfSer::Scrypt),
_ => Err(SerdeError::custom(Error::UnsupportedKdf))
}
}
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: SerdeError {
self.visit_str(value.as_ref())
}
}
#[derive(Debug, PartialEq)]
pub enum Prf {
HmacSha256,
}
impl Serialize for Prf {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer {
match *self {
Prf::HmacSha256 => serializer.serialize_str("hmac-sha256"),
}
}
}
impl Deserialize for Prf {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer {
deserializer.deserialize(PrfVisitor)
}
}
struct PrfVisitor;
impl Visitor for PrfVisitor {
type Value = Prf;
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
match value {
"hmac-sha256" => Ok(Prf::HmacSha256),
_ => Err(SerdeError::custom(Error::InvalidPrf)),
}
}
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: SerdeError {
self.visit_str(value.as_ref())
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Pbkdf2 {
pub c: u32,
pub dklen: u32,
pub prf: Prf,
pub salt: H256,
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Scrypt {
pub dklen: u32,
pub p: u32,
pub n: u32,
pub r: u32,
pub salt: H256,
}
#[derive(Debug, PartialEq)]
pub enum KdfSerParams {
Pbkdf2(Pbkdf2),
Scrypt(Scrypt),
}
impl Serialize for KdfSerParams {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer {
match *self {
KdfSerParams::Pbkdf2(ref params) => params.serialize(serializer),
KdfSerParams::Scrypt(ref params) => params.serialize(serializer),
}
}
}
impl Deserialize for KdfSerParams {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
where D: Deserializer {
let v = try!(Value::deserialize(deserializer));
Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(KdfSerParams::Pbkdf2)
.or_else(|_| Deserialize::deserialize(&mut value::Deserializer::new(v)).map(KdfSerParams::Scrypt))
.map_err(|e| D::Error::custom(format!("{}", e)))
}
}
#[derive(Debug, PartialEq)]
pub enum Kdf {
Pbkdf2(Pbkdf2),
Scrypt(Scrypt),
}

View File

@@ -0,0 +1,255 @@
use std::io::{Read, Write};
use serde::{Deserialize, Deserializer, Error};
use serde::de::{Visitor, MapVisitor};
use serde_json;
use super::{UUID, Version, Crypto, H160};
#[derive(Debug, PartialEq, Serialize)]
pub struct KeyFile {
pub id: UUID,
pub version: Version,
pub crypto: Crypto,
pub address: H160,
}
enum KeyFileField {
ID,
Version,
Crypto,
Address,
}
impl Deserialize for KeyFileField {
fn deserialize<D>(deserializer: &mut D) -> Result<KeyFileField, D::Error>
where D: Deserializer
{
deserializer.deserialize(KeyFileFieldVisitor)
}
}
struct KeyFileFieldVisitor;
impl Visitor for KeyFileFieldVisitor {
type Value = KeyFileField;
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E>
where E: Error
{
match value {
"id" => Ok(KeyFileField::ID),
"version" => Ok(KeyFileField::Version),
"crypto" => Ok(KeyFileField::Crypto),
"Crypto" => Ok(KeyFileField::Crypto),
"address" => Ok(KeyFileField::Address),
_ => Err(Error::custom(format!("Unknown field: '{}'", value))),
}
}
}
impl Deserialize for KeyFile {
fn deserialize<D>(deserializer: &mut D) -> Result<KeyFile, D::Error>
where D: Deserializer
{
static FIELDS: &'static [&'static str] = &["id", "version", "crypto", "Crypto", "address"];
deserializer.deserialize_struct("KeyFile", FIELDS, KeyFileVisitor)
}
}
struct KeyFileVisitor;
impl Visitor for KeyFileVisitor {
type Value = KeyFile;
fn visit_map<V>(&mut self, mut visitor: V) -> Result<Self::Value, V::Error>
where V: MapVisitor
{
let mut id = None;
let mut version = None;
let mut crypto = None;
let mut address = None;
loop {
match try!(visitor.visit_key()) {
Some(KeyFileField::ID) => { id = Some(try!(visitor.visit_value())); }
Some(KeyFileField::Version) => { version = Some(try!(visitor.visit_value())); }
Some(KeyFileField::Crypto) => { crypto = Some(try!(visitor.visit_value())); }
Some(KeyFileField::Address) => { address = Some(try!(visitor.visit_value())); }
None => { break; }
}
}
let id = match id {
Some(id) => id,
None => try!(visitor.missing_field("id")),
};
let version = match version {
Some(version) => version,
None => try!(visitor.missing_field("version")),
};
let crypto = match crypto {
Some(crypto) => crypto,
None => try!(visitor.missing_field("crypto")),
};
let address = match address {
Some(address) => address,
None => try!(visitor.missing_field("address")),
};
try!(visitor.end());
let result = KeyFile {
id: id,
version: version,
crypto: crypto,
address: address,
};
Ok(result)
}
}
impl KeyFile {
pub fn load<R>(reader: R) -> Result<Self, serde_json::Error> where R: Read {
serde_json::from_reader(reader)
}
pub fn write<W>(&self, writer: &mut W) -> Result<(), serde_json::Error> where W: Write {
serde_json::to_writer(writer, self)
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use serde_json;
use json::{KeyFile, UUID, Version, Crypto, Cipher, Aes128Ctr, Kdf, Scrypt, H128, H160, H256};
#[test]
fn basic_keyfile() {
let json = r#"
{
"address": "6edddfc6349aff20bc6467ccf276c5b52487f7a8",
"crypto": {
"cipher": "aes-128-ctr",
"ciphertext": "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc",
"cipherparams": {
"iv": "b5a7ec855ec9e2c405371356855fec83"
},
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 262144,
"p": 1,
"r": 8,
"salt": "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209"
},
"mac": "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f"
},
"id": "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73",
"version": 3
}"#;
let expected = KeyFile {
id: UUID::from_str("8777d9f6-7860-4b9b-88b7-0b57ee6b3a73").unwrap(),
version: Version::V3,
address: H160::from_str("6edddfc6349aff20bc6467ccf276c5b52487f7a8").unwrap(),
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: H128::from_str("b5a7ec855ec9e2c405371356855fec83").unwrap(),
}),
ciphertext: H256::from_str("7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc").unwrap(),
kdf: Kdf::Scrypt(Scrypt {
n: 262144,
dklen: 32,
p: 1,
r: 8,
salt: H256::from_str("1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209").unwrap(),
}),
mac: H256::from_str("46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f").unwrap(),
},
};
let keyfile: KeyFile = serde_json::from_str(json).unwrap();
assert_eq!(keyfile, expected);
}
#[test]
fn capital_crypto_keyfile() {
let json = r#"
{
"address": "6edddfc6349aff20bc6467ccf276c5b52487f7a8",
"Crypto": {
"cipher": "aes-128-ctr",
"ciphertext": "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc",
"cipherparams": {
"iv": "b5a7ec855ec9e2c405371356855fec83"
},
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 262144,
"p": 1,
"r": 8,
"salt": "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209"
},
"mac": "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f"
},
"id": "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73",
"version": 3
}"#;
let expected = KeyFile {
id: UUID::from_str("8777d9f6-7860-4b9b-88b7-0b57ee6b3a73").unwrap(),
version: Version::V3,
address: H160::from_str("6edddfc6349aff20bc6467ccf276c5b52487f7a8").unwrap(),
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: H128::from_str("b5a7ec855ec9e2c405371356855fec83").unwrap(),
}),
ciphertext: H256::from_str("7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc").unwrap(),
kdf: Kdf::Scrypt(Scrypt {
n: 262144,
dklen: 32,
p: 1,
r: 8,
salt: H256::from_str("1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209").unwrap(),
}),
mac: H256::from_str("46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f").unwrap(),
},
};
let keyfile: KeyFile = serde_json::from_str(json).unwrap();
assert_eq!(keyfile, expected);
}
#[test]
fn to_and_from_json() {
let file = KeyFile {
id: UUID::from_str("8777d9f6-7860-4b9b-88b7-0b57ee6b3a73").unwrap(),
version: Version::V3,
address: H160::from_str("6edddfc6349aff20bc6467ccf276c5b52487f7a8").unwrap(),
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: H128::from_str("b5a7ec855ec9e2c405371356855fec83").unwrap(),
}),
ciphertext: H256::from_str("7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc").unwrap(),
kdf: Kdf::Scrypt(Scrypt {
n: 262144,
dklen: 32,
p: 1,
r: 8,
salt: H256::from_str("1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209").unwrap(),
}),
mac: H256::from_str("46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f").unwrap(),
},
};
let serialized = serde_json::to_string(&file).unwrap();
let deserialized = serde_json::from_str(&serialized).unwrap();
assert_eq!(file, deserialized);
}
}

8
ethstore/src/json/mod.rs Normal file
View File

@@ -0,0 +1,8 @@
//! Contract interface specification.
#[cfg(feature = "serde_macros")]
include!("mod.rs.in");
#[cfg(not(feature = "serde_macros"))]
include!(concat!(env!("OUT_DIR"), "/mod.rs"));

View File

@@ -0,0 +1,18 @@
mod cipher;
mod crypto;
mod error;
mod hash;
mod id;
mod kdf;
mod key_file;
mod version;
pub use self::cipher::{Cipher, CipherSer, CipherSerParams, Aes128Ctr};
pub use self::crypto::Crypto;
pub use self::error::Error;
pub use self::hash::{H128, H160, H256};
pub use self::id::UUID;
pub use self::kdf::{Kdf, KdfSer, Prf, Pbkdf2, Scrypt, KdfSerParams};
pub use self::key_file::KeyFile;
pub use self::version::Version;

View File

@@ -0,0 +1,38 @@
use serde::{Serialize, Serializer, Deserialize, Deserializer, Error as SerdeError};
use serde::de::Visitor;
use super::Error;
#[derive(Debug, PartialEq)]
pub enum Version {
V3,
}
impl Serialize for Version {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer {
match *self {
Version::V3 => serializer.serialize_u64(3)
}
}
}
impl Deserialize for Version {
fn deserialize<D>(deserializer: &mut D) -> Result<Version, D::Error>
where D: Deserializer {
deserializer.deserialize(VersionVisitor)
}
}
struct VersionVisitor;
impl Visitor for VersionVisitor {
type Value = Version;
fn visit_u64<E>(&mut self, value: u64) -> Result<Self::Value, E> where E: SerdeError {
match value {
3 => Ok(Version::V3),
_ => Err(SerdeError::custom(Error::UnsupportedVersion))
}
}
}