diff --git a/parity-crypto/Cargo.toml b/parity-crypto/Cargo.toml index a03fe7f01..5f4b8ef54 100644 --- a/parity-crypto/Cargo.toml +++ b/parity-crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "parity-crypto" -version = "0.3.1" +version = "0.4.0" authors = ["Parity Technologies "] repository = "https://github.com/paritytech/parity-common" description = "Crypto utils used by ethstore and network." @@ -13,9 +13,8 @@ harness = false [dependencies] -quick-error = "1.2.2" tiny-keccak = "1.4" -scrypt = { version = "0.1.1", default-features = false } +scrypt = { version = "0.2", default-features = false } ripemd160 = "0.8.0" sha2 = "0.8.0" digest = "0.8" @@ -24,7 +23,7 @@ aes = "0.3.2" aes-ctr = "0.3.0" block-modes = "0.3.3" pbkdf2 = "0.3.0" -constant_time_eq = "0.1.3" +subtle = "2.1" memzero = "0.1" [dev-dependencies] diff --git a/parity-crypto/README.md b/parity-crypto/README.md index 9e3c41767..51390fe4f 100644 --- a/parity-crypto/README.md +++ b/parity-crypto/README.md @@ -2,4 +2,7 @@ General cryptographic utilities for Ethereum. -By default, this library is compiled with the `secp256k1` feature, which provides ECDH and ECIES capability on that curve. It can be compiled without to avoid a dependency on the `libsecp256k1` library. + +## Changelog + +The 0.4 release removes the dependency on `ring` and replaces it with prue-rust alternatives. As a consequence of this, AES GCM support has been removed. `subtle` is used for constant time equality testing and error handling is pared down to the bare minimum required. diff --git a/parity-crypto/src/error.rs b/parity-crypto/src/error.rs index 8759c3e2d..1cbee709f 100644 --- a/parity-crypto/src/error.rs +++ b/parity-crypto/src/error.rs @@ -18,80 +18,99 @@ use rscrypt; use block_modes; use aes_ctr; use std::error::Error as StdError; +use std::{fmt, result}; -quick_error! { - #[derive(Debug)] - pub enum Error { - Scrypt(e: ScryptError) { - cause(e) - from() - } - Symm(e: SymmError) { - cause(e) - from() - } - AsymShort(det: &'static str) { - description(det) - } - AsymFull(e: Box) { - cause(&**e) - description(e.description()) +#[derive(Debug)] +pub enum Error { + Scrypt(ScryptError), + Symm(SymmError), +} + +#[derive(Debug)] +pub enum ScryptError { + // log(N) < r / 16 + InvalidN, + // p <= (2^31-1 * 32)/(128 * r) + InvalidP, + ScryptParam(rscrypt::errors::InvalidParams), + ScryptLength(rscrypt::errors::InvalidOutputLen), +} + +#[derive(Debug)] +pub struct SymmError(PrivSymmErr); + +#[derive(Debug)] +enum PrivSymmErr { + BlockMode(block_modes::BlockModeError), + KeyStream(aes_ctr::stream_cipher::LoopError), + InvalidKeyLength(block_modes::InvalidKeyIvLength), +} + +impl StdError for Error { + fn source(&self) -> Option<&(StdError + 'static)> { + match self { + Error::Scrypt(scrypt_err) => Some(scrypt_err), + Error::Symm(symm_err) => Some(symm_err), } } } -impl Into for Error { - fn into(self) -> std::io::Error { - std::io::Error::new(std::io::ErrorKind::Other, format!("Crypto error: {}",self)) +impl StdError for ScryptError { + fn source(&self) -> Option<&(StdError + 'static)> { + match self { + ScryptError::ScryptParam(err) => Some(err), + ScryptError::ScryptLength(err) => Some(err), + _ => None, + } } } -quick_error! { - #[derive(Debug)] - pub enum ScryptError { - // log(N) < r / 16 - InvalidN { - display("Invalid N argument of the scrypt encryption") - } - // p <= (2^31-1 * 32)/(128 * r) - InvalidP { - display("Invalid p argument of the scrypt encryption") - } - ScryptParam(e: rscrypt::errors::InvalidParams) { - display("invalid params for scrypt: {}", e) - cause(e) - from() - } - ScryptLength(e: rscrypt::errors::InvalidOutputLen) { - display("invalid scrypt output length: {}", e) - cause(e) - from() +impl StdError for SymmError { + fn source(&self) -> Option<&(StdError + 'static)> { + match &self.0 { + PrivSymmErr::BlockMode(err) => Some(err), + PrivSymmErr::InvalidKeyLength(err) => Some(err), + _ => None, } } } - -quick_error! { - #[derive(Debug)] - pub enum SymmError wraps PrivSymmErr { - Offset(x: usize) { - display("offset {} greater than slice length", x) - } - BlockMode(e: block_modes::BlockModeError) { - display("symmetric crypto error") - from() +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + match self { + Error::Scrypt(err)=> write!(f, "scrypt error: {}", err), + Error::Symm(err) => write!(f, "symm error: {}", err), } - KeyStream(e: aes_ctr::stream_cipher::LoopError) { - display("ctr key stream ended") - from() + } +} + +impl fmt::Display for ScryptError { + fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + match self { + ScryptError::InvalidN => write!(f, "invalid n argument"), + ScryptError::InvalidP => write!(f, "invalid p argument"), + ScryptError::ScryptParam(err) => write!(f, "invalid params: {}", err), + ScryptError::ScryptLength(err) => write!(f, "invalid output length: {}", err), } - InvalidKeyLength(e: block_modes::InvalidKeyIvLength) { - display("Error with RustCrypto key length : {}", e) - from() + } +} + +impl fmt::Display for SymmError { + fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { + match self { + SymmError(PrivSymmErr::BlockMode(err)) => write!(f, "block cipher error: {}", err), + SymmError(PrivSymmErr::KeyStream(err)) => write!(f, "ctr key stream ended: {}", err), + SymmError(PrivSymmErr::InvalidKeyLength(err)) => write!(f, "block cipher key length: {}", err), } } } +impl Into for Error { + fn into(self) -> std::io::Error { + std::io::Error::new(std::io::ErrorKind::Other, format!("Crypto error: {}",self)) + } +} + impl From for SymmError { fn from(e: block_modes::BlockModeError) -> SymmError { SymmError(PrivSymmErr::BlockMode(e)) @@ -109,3 +128,28 @@ impl From for SymmError { SymmError(PrivSymmErr::KeyStream(e)) } } + +impl From for ScryptError { + fn from(e: rscrypt::errors::InvalidParams) -> ScryptError { + ScryptError::ScryptParam(e) + } +} + +impl From for ScryptError { + fn from(e: rscrypt::errors::InvalidOutputLen) -> ScryptError { + ScryptError::ScryptLength(e) + } +} + +impl From for Error { + fn from(e: ScryptError) -> Error { + Error::Scrypt(e) + } +} + +impl From for Error { + fn from(e: SymmError) -> Error { + Error::Symm(e) + } +} + diff --git a/parity-crypto/src/lib.rs b/parity-crypto/src/lib.rs index 20c0eacf9..7d3fda363 100644 --- a/parity-crypto/src/lib.rs +++ b/parity-crypto/src/lib.rs @@ -16,8 +16,6 @@ //! Crypto utils used by ethstore and network. -#[macro_use] -extern crate quick_error; extern crate tiny_keccak; extern crate scrypt as rscrypt; extern crate ripemd160 as rripemd160; @@ -28,7 +26,7 @@ extern crate aes as raes; extern crate aes_ctr; extern crate block_modes; extern crate pbkdf2 as rpbkdf2; -extern crate constant_time_eq; +extern crate subtle; extern crate memzero; #[cfg(test)] @@ -45,6 +43,7 @@ pub mod pbkdf2; pub use error::Error; use tiny_keccak::Keccak; +use subtle::ConstantTimeEq; pub const KEY_LENGTH: usize = 32; pub const KEY_ITERATIONS: usize = 10240; @@ -83,5 +82,19 @@ pub fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Vec { } pub fn is_equal(a: &[u8], b: &[u8]) -> bool { - constant_time_eq::constant_time_eq(a, b) + a.ct_eq(b).into() +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn can_test_for_equality() { + let a = b"abc"; + let b = b"abc"; + let c = b"efg"; + assert!(is_equal(a, b)); + assert!(!is_equal(a, c)); + } } diff --git a/parity-crypto/src/pbkdf2/test.rs b/parity-crypto/src/pbkdf2/test.rs index 399a05a17..0aca66967 100644 --- a/parity-crypto/src/pbkdf2/test.rs +++ b/parity-crypto/src/pbkdf2/test.rs @@ -15,7 +15,6 @@ // along with Parity. If not, see . use super::*; -use std::num::NonZeroU32; #[test] fn basic_test() {