Directory Restructure (#1163)

* Move tests -> testing

* Directory restructure

* Update Cargo.toml during restructure

* Update Makefile during restructure

* Fix arbitrary path
This commit is contained in:
Paul Hauner
2020-05-18 21:24:23 +10:00
committed by GitHub
parent c571afb8d8
commit 4331834003
358 changed files with 217 additions and 229 deletions

View File

@@ -0,0 +1,75 @@
//! Defines the JSON representation of the "checksum" module.
//!
//! This file **MUST NOT** contain any logic beyond what is required to serialize/deserialize the
//! data structures. Specifically, there should not be any actual crypto logic in this file.
use super::hex_bytes::HexBytes;
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use std::convert::TryFrom;
/// Used for ensuring that serde only decodes valid checksum functions.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(try_from = "String", into = "String")]
pub enum ChecksumFunction {
Sha256,
}
impl Into<String> for ChecksumFunction {
fn into(self) -> String {
match self {
ChecksumFunction::Sha256 => "sha256".into(),
}
}
}
impl TryFrom<String> for ChecksumFunction {
type Error = String;
fn try_from(s: String) -> Result<Self, Self::Error> {
match s.as_ref() {
"sha256" => Ok(ChecksumFunction::Sha256),
other => Err(format!("Unsupported checksum function: {}", other)),
}
}
}
/// Used for ensuring serde only decodes an empty map.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(try_from = "Value", into = "Value")]
pub struct EmptyMap;
impl Into<Value> for EmptyMap {
fn into(self) -> Value {
Value::Object(Map::default())
}
}
impl TryFrom<Value> for EmptyMap {
type Error = &'static str;
fn try_from(v: Value) -> Result<Self, Self::Error> {
match v {
Value::Object(map) if map.is_empty() => Ok(Self),
_ => Err("Checksum params must be an empty map"),
}
}
}
/// Checksum module for `Keystore`.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ChecksumModule {
pub function: ChecksumFunction,
pub params: EmptyMap,
pub message: HexBytes,
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct Sha256Checksum(String);
impl Sha256Checksum {
pub fn function() -> ChecksumFunction {
ChecksumFunction::Sha256
}
}

View File

@@ -0,0 +1,64 @@
//! Defines the JSON representation of the "cipher" module.
//!
//! This file **MUST NOT** contain any logic beyond what is required to serialize/deserialize the
//! data structures. Specifically, there should not be any actual crypto logic in this file.
use super::hex_bytes::HexBytes;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
/// Used for ensuring that serde only decodes valid cipher functions.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(try_from = "String", into = "String")]
pub enum CipherFunction {
Aes128Ctr,
}
impl Into<String> for CipherFunction {
fn into(self) -> String {
match self {
CipherFunction::Aes128Ctr => "aes-128-ctr".into(),
}
}
}
impl TryFrom<String> for CipherFunction {
type Error = String;
fn try_from(s: String) -> Result<Self, Self::Error> {
match s.as_ref() {
"aes-128-ctr" => Ok(CipherFunction::Aes128Ctr),
other => Err(format!("Unsupported cipher function: {}", other)),
}
}
}
/// Cipher module representation.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CipherModule {
pub function: CipherFunction,
pub params: Cipher,
pub message: HexBytes,
}
/// Parameters for AES128 with ctr mode.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Aes128Ctr {
pub iv: HexBytes,
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(untagged, deny_unknown_fields)]
pub enum Cipher {
Aes128Ctr(Aes128Ctr),
}
impl Cipher {
pub fn function(&self) -> CipherFunction {
match &self {
Cipher::Aes128Ctr(_) => CipherFunction::Aes128Ctr,
}
}
}

View File

@@ -0,0 +1,72 @@
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
/// To allow serde to encode/decode byte arrays from HEX ASCII strings.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(try_from = "String", into = "String")]
pub struct HexBytes(Vec<u8>);
impl HexBytes {
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
pub fn len(&self) -> usize {
self.0.len()
}
}
impl From<Vec<u8>> for HexBytes {
fn from(vec: Vec<u8>) -> Self {
Self(vec)
}
}
impl Into<String> for HexBytes {
fn into(self) -> String {
hex::encode(self.0)
}
}
impl TryFrom<String> for HexBytes {
type Error = String;
fn try_from(s: String) -> Result<Self, Self::Error> {
// Left-pad with a zero if there is not an even number of hex digits to ensure
// `hex::decode` doesn't return an error.
let s = if s.len() % 2 != 0 {
format!("0{}", s)
} else {
s
};
hex::decode(s)
.map(Self)
.map_err(|e| format!("Invalid hex: {}", e))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn decode(json: &str) -> Vec<u8> {
serde_json::from_str::<HexBytes>(&format!("\"{}\"", json))
.expect("should decode json")
.as_bytes()
.to_vec()
}
#[test]
fn odd_hex_bytes() {
let empty: Vec<u8> = vec![];
assert_eq!(decode(""), empty, "should decode nothing");
assert_eq!(decode("00"), vec![0], "should decode 00");
assert_eq!(decode("0"), vec![0], "should decode 0");
assert_eq!(decode("01"), vec![1], "should decode 01");
assert_eq!(decode("1"), vec![1], "should decode 1");
assert_eq!(decode("0101"), vec![1, 1], "should decode 0101");
assert_eq!(decode("101"), vec![1, 1], "should decode 101");
}
}

View File

@@ -0,0 +1,128 @@
//! Defines the JSON representation of the "kdf" module.
//!
//! This file **MUST NOT** contain any logic beyond what is required to serialize/deserialize the
//! data structures. Specifically, there should not be any actual crypto logic in this file.
use super::hex_bytes::HexBytes;
use crypto::sha2::Sha256;
use crypto::{hmac::Hmac, mac::Mac};
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
/// KDF module representation.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct KdfModule {
pub function: KdfFunction,
pub params: Kdf,
pub message: EmptyString,
}
/// Used for ensuring serde only decodes an empty string.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(try_from = "String", into = "String")]
pub struct EmptyString;
impl Into<String> for EmptyString {
fn into(self) -> String {
"".into()
}
}
impl TryFrom<String> for EmptyString {
type Error = &'static str;
fn try_from(s: String) -> Result<Self, Self::Error> {
match s.as_ref() {
"" => Ok(Self),
_ => Err("kdf message must be empty"),
}
}
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(untagged, deny_unknown_fields)]
pub enum Kdf {
Scrypt(Scrypt),
Pbkdf2(Pbkdf2),
}
impl Kdf {
pub fn function(&self) -> KdfFunction {
match &self {
Kdf::Pbkdf2(_) => KdfFunction::Pbkdf2,
Kdf::Scrypt(_) => KdfFunction::Scrypt,
}
}
}
/// PRF for use in `pbkdf2`.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum Prf {
#[serde(rename = "hmac-sha256")]
HmacSha256,
}
impl Prf {
pub fn mac(&self, password: &[u8]) -> impl Mac {
match &self {
_hmac_sha256 => Hmac::new(Sha256::new(), password),
}
}
}
impl Default for Prf {
fn default() -> Self {
Prf::HmacSha256
}
}
/// Parameters for `pbkdf2` key derivation.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Pbkdf2 {
pub c: u32,
pub dklen: u32,
pub prf: Prf,
pub salt: HexBytes,
}
/// Used for ensuring that serde only decodes valid KDF functions.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(try_from = "String", into = "String")]
pub enum KdfFunction {
Scrypt,
Pbkdf2,
}
impl Into<String> for KdfFunction {
fn into(self) -> String {
match self {
KdfFunction::Scrypt => "scrypt".into(),
KdfFunction::Pbkdf2 => "pbkdf2".into(),
}
}
}
impl TryFrom<String> for KdfFunction {
type Error = String;
fn try_from(s: String) -> Result<Self, Self::Error> {
match s.as_ref() {
"scrypt" => Ok(KdfFunction::Scrypt),
"pbkdf2" => Ok(KdfFunction::Pbkdf2),
other => Err(format!("Unsupported kdf function: {}", other)),
}
}
}
/// Parameters for `scrypt` key derivation.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Scrypt {
pub dklen: u32,
pub n: u32,
pub r: u32,
pub p: u32,
pub salt: HexBytes,
}

View File

@@ -0,0 +1,52 @@
//! This module intends to separate the JSON representation of the keystore from the actual crypto
//! logic.
//!
//! This module **MUST NOT** contain any logic beyond what is required to serialize/deserialize the
//! data structures. Specifically, there should not be any actual crypto logic in this file.
mod checksum_module;
mod cipher_module;
mod hex_bytes;
mod kdf_module;
pub use checksum_module::{ChecksumModule, EmptyMap, Sha256Checksum};
pub use cipher_module::{Aes128Ctr, Cipher, CipherModule};
pub use hex_bytes::HexBytes;
pub use kdf_module::{EmptyString, Kdf, KdfModule, Pbkdf2, Prf, Scrypt};
pub use uuid::Uuid;
use serde::{Deserialize, Serialize};
use serde_repr::*;
/// JSON representation of [EIP-2335](https://eips.ethereum.org/EIPS/eip-2335) keystore.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct JsonKeystore {
pub crypto: Crypto,
pub uuid: Uuid,
pub path: String,
pub pubkey: String,
pub version: Version,
}
/// Version for `JsonKeystore`.
#[derive(Debug, Clone, PartialEq, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum Version {
V4 = 4,
}
impl Version {
pub fn four() -> Self {
Version::V4
}
}
/// Crypto module for keystore.
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Crypto {
pub kdf: KdfModule,
pub checksum: ChecksumModule,
pub cipher: CipherModule,
}