constant time HMAC comparison and clarify docs in ethkey

This commit is contained in:
Robert Habermeier
2017-06-29 13:44:24 +02:00
parent 201f34620a
commit 8a3e82d99a
3 changed files with 33 additions and 16 deletions

View File

@@ -9,4 +9,4 @@ tiny-keccak = "1.2"
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
ethkey = { path = "../ethkey" }
ethcore-bigint = { path = "../util/bigint" }
subtle = "0.1"

View File

@@ -16,11 +16,12 @@
//! Crypto utils used ethstore and network.
extern crate ethcore_bigint as bigint;
extern crate tiny_keccak;
extern crate crypto as rcrypto;
extern crate secp256k1;
extern crate ethcore_bigint as bigint;
extern crate ethkey;
extern crate secp256k1;
extern crate subtle;
extern crate tiny_keccak;
use std::fmt;
use tiny_keccak::Keccak;
@@ -34,7 +35,7 @@ pub const KEY_LENGTH: usize = 32;
pub const KEY_ITERATIONS: usize = 10240;
pub const KEY_LENGTH_AES: usize = KEY_LENGTH / 2;
/// Default MAC to use (in RPC).
/// Default authenticated data to use (in RPC).
pub const DEFAULT_MAC: [u8; 2] = [0, 0];
#[derive(PartialEq, Debug)]
@@ -149,13 +150,13 @@ pub mod aes {
use rcrypto::symmetriccipher::{Encryptor, Decryptor, SymmetricCipherError};
use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer, WriteBuffer};
/// Encrypt a message
/// Encrypt a message (CTR mode)
pub fn encrypt(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) {
let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec());
encryptor.encrypt(&mut RefReadBuffer::new(plain), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding");
}
/// Decrypt a message
/// Decrypt a message (CTR mode)
pub fn decrypt(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) {
let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec());
encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding");
@@ -208,8 +209,11 @@ pub mod ecies {
use ethkey::{Random, Generator, Public, Secret};
use {Error, ecdh, aes, Keccak256};
/// Encrypt a message with a public key
pub fn encrypt(public: &Public, shared_mac: &[u8], plain: &[u8]) -> Result<Vec<u8>, Error> {
/// Encrypt a message with a public key, writing an HMAC covering both
/// the plaintext and authenticated data.
///
/// Authenticated data may be empty.
pub fn encrypt(public: &Public, auth_data: &[u8], plain: &[u8]) -> Result<Vec<u8>, Error> {
let r = Random.generate()
.expect("context known to have key-generation capabilities; qed");
@@ -239,13 +243,13 @@ pub mod ecies {
let cipher_iv = &msgd[64..(64 + 16 + plain.len())];
hmac.input(cipher_iv);
}
hmac.input(shared_mac);
hmac.input(auth_data);
hmac.raw_result(&mut msgd[(64 + 16 + plain.len())..]);
}
Ok(msg)
}
/// Encrypt a message with a public key
/// Encrypt a message with a public key and no HMAC
pub fn encrypt_single_message(public: &Public, plain: &[u8]) -> Result<Vec<u8>, Error> {
let r = Random.generate()
.expect("context known to have key-generation capabilities");
@@ -272,8 +276,9 @@ pub mod ecies {
Ok(msgd)
}
/// Decrypt a message with a secret key
pub fn decrypt(secret: &Secret, shared_mac: &[u8], encrypted: &[u8]) -> Result<Vec<u8>, Error> {
/// Decrypt a message with a secret key, checking HMAC for ciphertext
/// and authenticated data validity.
pub fn decrypt(secret: &Secret, auth_data: &[u8], encrypted: &[u8]) -> Result<Vec<u8>, Error> {
let meta_len = 1 + 64 + 16 + 32;
if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 {
return Err(Error::InvalidMessage); //invalid message: publickey
@@ -300,10 +305,12 @@ pub mod ecies {
// Verify tag
let mut hmac = Hmac::new(Sha256::new(), &mkey);
hmac.input(cipher_with_iv);
hmac.input(shared_mac);
hmac.input(auth_data);
let mut mac = [0u8; 32];
hmac.raw_result(&mut mac);
if &mac[..] != msg_mac {
// constant time compare to avoid timing attack.
if ::subtle::arrays_equal(&mac[..], msg_mac) != 1 {
return Err(Error::InvalidMessage);
}
@@ -312,7 +319,7 @@ pub mod ecies {
Ok(msg)
}
/// Decrypt single message with a secret key
/// Decrypt single message with a secret key and no HMAC.
pub fn decrypt_single_message(secret: &Secret, encrypted: &[u8]) -> Result<Vec<u8>, Error> {
let meta_len = 64;
if encrypted.len() < meta_len {