Skip to content

Commit

Permalink
Merge branch 'master' into dp/chore/update-rlp-to-ethereum-types-0.5
Browse files Browse the repository at this point in the history
* master:
  Remove unused test support files (#162)
  [parity-crypto] bump version to 0.4.0 (#149)
  [parity-crypto] zero memory for hmac signing keys (#157)
  Added absolute path for 'Result' usage in macros to avoid type collisions. (#160)
  • Loading branch information
dvdplm committed May 23, 2019
2 parents dbb0b9b + 5fe3bf4 commit 1cc5e43
Show file tree
Hide file tree
Showing 11 changed files with 347 additions and 284 deletions.
9 changes: 5 additions & 4 deletions parity-crypto/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "parity-crypto"
version = "0.3.1"
version = "0.4.0"
authors = ["Parity Technologies <admin@parity.io>"]
repository = "https://github.com/paritytech/parity-common"
description = "Crypto utils used by ethstore and network."
Expand All @@ -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"
Expand All @@ -24,7 +23,9 @@ 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]
criterion = "0.2"
hex-literal = "0.2"
5 changes: 4 additions & 1 deletion parity-crypto/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
156 changes: 100 additions & 56 deletions parity-crypto/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<dyn StdError + Send>) {
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<std::io::Error> 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<std::io::Error> for Error {
fn into(self) -> std::io::Error {
std::io::Error::new(std::io::ErrorKind::Other, format!("Crypto error: {}",self))
}
}

impl From<block_modes::BlockModeError> for SymmError {
fn from(e: block_modes::BlockModeError) -> SymmError {
SymmError(PrivSymmErr::BlockMode(e))
Expand All @@ -109,3 +128,28 @@ impl From<aes_ctr::stream_cipher::LoopError> for SymmError {
SymmError(PrivSymmErr::KeyStream(e))
}
}

impl From<rscrypt::errors::InvalidParams> for ScryptError {
fn from(e: rscrypt::errors::InvalidParams) -> ScryptError {
ScryptError::ScryptParam(e)
}
}

impl From<rscrypt::errors::InvalidOutputLen> for ScryptError {
fn from(e: rscrypt::errors::InvalidOutputLen) -> ScryptError {
ScryptError::ScryptLength(e)
}
}

impl From<ScryptError> for Error {
fn from(e: ScryptError) -> Error {
Error::Scrypt(e)
}
}

impl From<SymmError> for Error {
fn from(e: SymmError) -> Error {
Error::Symm(e)
}
}

50 changes: 40 additions & 10 deletions parity-crypto/src/hmac/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use rhmac::{Hmac, Mac as _};
use rsha2;
use std::marker::PhantomData;
use std::ops::Deref;
use memzero::Memzero;

/// HMAC signature.
#[derive(Debug)]
Expand All @@ -45,20 +46,43 @@ impl<T> Deref for Signature<T> {
/// HMAC signing key.
pub struct SigKey<T>(KeyInner, PhantomData<T>);

#[derive(PartialEq)]
// Using `Box[u8]` guarantees no reallocation can happen
struct DisposableBox(Memzero<Box<[u8]>>);

impl std::fmt::Debug for DisposableBox {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", &self.0.as_ref())
}
}

impl DisposableBox {
fn from_slice(data: &[u8]) -> Self {
Self(Memzero::from(data.to_vec().into_boxed_slice()))
}
}

#[derive(Debug, PartialEq)]
enum KeyInner {
Sha256(Vec<u8>),
Sha512(Vec<u8>),
Sha256(DisposableBox),
Sha512(DisposableBox),
}

impl SigKey<Sha256> {
pub fn sha256(key: &[u8]) -> SigKey<Sha256> {
SigKey(KeyInner::Sha256(key.to_vec()), PhantomData)
SigKey(
KeyInner::Sha256(DisposableBox::from_slice(key)),
PhantomData
)
}
}

impl SigKey<Sha512> {
pub fn sha512(key: &[u8]) -> SigKey<Sha512> {
SigKey(KeyInner::Sha512(key.to_vec()), PhantomData)
SigKey(
KeyInner::Sha512(DisposableBox::from_slice(key)),
PhantomData
)
}
}

Expand All @@ -83,7 +107,7 @@ impl<T> Signer<T> {
KeyInner::Sha256(key_bytes) => {
Signer(
SignerInner::Sha256(
Hmac::<rsha2::Sha256>::new_varkey(key_bytes)
Hmac::<rsha2::Sha256>::new_varkey(&key_bytes.0)
.expect("always returns Ok; qed")
),
PhantomData
Expand All @@ -92,7 +116,7 @@ impl<T> Signer<T> {
KeyInner::Sha512(key_bytes) => {
Signer(
SignerInner::Sha512(
Hmac::<rsha2::Sha512>::new_varkey(key_bytes)
Hmac::<rsha2::Sha512>::new_varkey(&key_bytes.0)
.expect("always returns Ok; qed")
), PhantomData
)
Expand Down Expand Up @@ -120,27 +144,33 @@ pub struct VerifyKey<T>(KeyInner, PhantomData<T>);

impl VerifyKey<Sha256> {
pub fn sha256(key: &[u8]) -> VerifyKey<Sha256> {
VerifyKey(KeyInner::Sha256(key.to_vec()), PhantomData)
VerifyKey(
KeyInner::Sha256(DisposableBox::from_slice(key)),
PhantomData
)
}
}

impl VerifyKey<Sha512> {
pub fn sha512(key: &[u8]) -> VerifyKey<Sha512> {
VerifyKey(KeyInner::Sha512(key.to_vec()), PhantomData)
VerifyKey(
KeyInner::Sha512(DisposableBox::from_slice(key)),
PhantomData
)
}
}

/// Verify HMAC signature of `data`.
pub fn verify<T>(key: &VerifyKey<T>, data: &[u8], sig: &[u8]) -> bool {
match &key.0 {
KeyInner::Sha256(key_bytes) => {
let mut ctx = Hmac::<rsha2::Sha256>::new_varkey(key_bytes)
let mut ctx = Hmac::<rsha2::Sha256>::new_varkey(&key_bytes.0)
.expect("always returns Ok; qed");
ctx.input(data);
ctx.verify(sig).is_ok()
},
KeyInner::Sha512(key_bytes) => {
let mut ctx = Hmac::<rsha2::Sha512>::new_varkey(key_bytes)
let mut ctx = Hmac::<rsha2::Sha512>::new_varkey(&key_bytes.0)
.expect("always returns Ok; qed");
ctx.input(data);
ctx.verify(sig).is_ok()
Expand Down
Loading

0 comments on commit 1cc5e43

Please sign in to comment.