Merge pull request #5952 from paritytech/constant-time-mac-compare
constant time HMAC comparison and clarify docs in ethkey
This commit is contained in:
commit
a3e693d5c3
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -672,6 +672,7 @@ dependencies = [
|
|||||||
"ethcore-bigint 0.1.3",
|
"ethcore-bigint 0.1.3",
|
||||||
"ethkey 0.2.0",
|
"ethkey 0.2.0",
|
||||||
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"subtle 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2461,6 +2462,14 @@ name = "strsim"
|
|||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "0.11.11"
|
version = "0.11.11"
|
||||||
@ -3100,6 +3109,7 @@ dependencies = [
|
|||||||
"checksum spmc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93bdab61c1a413e591c4d17388ffa859eaff2df27f1e13a5ec8b716700605adf"
|
"checksum spmc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93bdab61c1a413e591c4d17388ffa859eaff2df27f1e13a5ec8b716700605adf"
|
||||||
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
|
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
|
||||||
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
|
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
|
||||||
|
"checksum subtle 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b811576c12506ff3f6da145585dc833edc32ee34c9fc021127d90e8134cc05c"
|
||||||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||||
"checksum syntex 0.58.0 (registry+https://github.com/rust-lang/crates.io-index)" = "35f3cc9d446323ef8fefad933b65cd6de271d29fa14a2e9d036a084770c6d6d5"
|
"checksum syntex 0.58.0 (registry+https://github.com/rust-lang/crates.io-index)" = "35f3cc9d446323ef8fefad933b65cd6de271d29fa14a2e9d036a084770c6d6d5"
|
||||||
|
@ -9,4 +9,4 @@ tiny-keccak = "1.2"
|
|||||||
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
|
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
|
||||||
ethkey = { path = "../ethkey" }
|
ethkey = { path = "../ethkey" }
|
||||||
ethcore-bigint = { path = "../util/bigint" }
|
ethcore-bigint = { path = "../util/bigint" }
|
||||||
|
subtle = "0.1"
|
||||||
|
@ -16,11 +16,12 @@
|
|||||||
|
|
||||||
//! Crypto utils used ethstore and network.
|
//! Crypto utils used ethstore and network.
|
||||||
|
|
||||||
extern crate ethcore_bigint as bigint;
|
|
||||||
extern crate tiny_keccak;
|
|
||||||
extern crate crypto as rcrypto;
|
extern crate crypto as rcrypto;
|
||||||
extern crate secp256k1;
|
extern crate ethcore_bigint as bigint;
|
||||||
extern crate ethkey;
|
extern crate ethkey;
|
||||||
|
extern crate secp256k1;
|
||||||
|
extern crate subtle;
|
||||||
|
extern crate tiny_keccak;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use tiny_keccak::Keccak;
|
use tiny_keccak::Keccak;
|
||||||
@ -34,7 +35,7 @@ pub const KEY_LENGTH: usize = 32;
|
|||||||
pub const KEY_ITERATIONS: usize = 10240;
|
pub const KEY_ITERATIONS: usize = 10240;
|
||||||
pub const KEY_LENGTH_AES: usize = KEY_LENGTH / 2;
|
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];
|
pub const DEFAULT_MAC: [u8; 2] = [0, 0];
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
@ -149,13 +150,13 @@ pub mod aes {
|
|||||||
use rcrypto::symmetriccipher::{Encryptor, Decryptor, SymmetricCipherError};
|
use rcrypto::symmetriccipher::{Encryptor, Decryptor, SymmetricCipherError};
|
||||||
use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer, WriteBuffer};
|
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]) {
|
pub fn encrypt(k: &[u8], iv: &[u8], plain: &[u8], dest: &mut [u8]) {
|
||||||
let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec());
|
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");
|
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]) {
|
pub fn decrypt(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) {
|
||||||
let mut encryptor = CtrMode::new(AesSafe128Encryptor::new(k), iv.to_vec());
|
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");
|
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 ethkey::{Random, Generator, Public, Secret};
|
||||||
use {Error, ecdh, aes, Keccak256};
|
use {Error, ecdh, aes, Keccak256};
|
||||||
|
|
||||||
/// Encrypt a message with a public key
|
/// Encrypt a message with a public key, writing an HMAC covering both
|
||||||
pub fn encrypt(public: &Public, shared_mac: &[u8], plain: &[u8]) -> Result<Vec<u8>, Error> {
|
/// 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()
|
let r = Random.generate()
|
||||||
.expect("context known to have key-generation capabilities; qed");
|
.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())];
|
let cipher_iv = &msgd[64..(64 + 16 + plain.len())];
|
||||||
hmac.input(cipher_iv);
|
hmac.input(cipher_iv);
|
||||||
}
|
}
|
||||||
hmac.input(shared_mac);
|
hmac.input(auth_data);
|
||||||
hmac.raw_result(&mut msgd[(64 + 16 + plain.len())..]);
|
hmac.raw_result(&mut msgd[(64 + 16 + plain.len())..]);
|
||||||
}
|
}
|
||||||
Ok(msg)
|
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> {
|
pub fn encrypt_single_message(public: &Public, plain: &[u8]) -> Result<Vec<u8>, Error> {
|
||||||
let r = Random.generate()
|
let r = Random.generate()
|
||||||
.expect("context known to have key-generation capabilities");
|
.expect("context known to have key-generation capabilities");
|
||||||
@ -272,8 +276,9 @@ pub mod ecies {
|
|||||||
Ok(msgd)
|
Ok(msgd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decrypt a message with a secret key
|
/// Decrypt a message with a secret key, checking HMAC for ciphertext
|
||||||
pub fn decrypt(secret: &Secret, shared_mac: &[u8], encrypted: &[u8]) -> Result<Vec<u8>, Error> {
|
/// 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;
|
let meta_len = 1 + 64 + 16 + 32;
|
||||||
if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 {
|
if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 {
|
||||||
return Err(Error::InvalidMessage); //invalid message: publickey
|
return Err(Error::InvalidMessage); //invalid message: publickey
|
||||||
@ -300,10 +305,12 @@ pub mod ecies {
|
|||||||
// Verify tag
|
// Verify tag
|
||||||
let mut hmac = Hmac::new(Sha256::new(), &mkey);
|
let mut hmac = Hmac::new(Sha256::new(), &mkey);
|
||||||
hmac.input(cipher_with_iv);
|
hmac.input(cipher_with_iv);
|
||||||
hmac.input(shared_mac);
|
hmac.input(auth_data);
|
||||||
let mut mac = [0u8; 32];
|
let mut mac = [0u8; 32];
|
||||||
hmac.raw_result(&mut mac);
|
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);
|
return Err(Error::InvalidMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,7 +319,7 @@ pub mod ecies {
|
|||||||
Ok(msg)
|
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> {
|
pub fn decrypt_single_message(secret: &Secret, encrypted: &[u8]) -> Result<Vec<u8>, Error> {
|
||||||
let meta_len = 64;
|
let meta_len = 64;
|
||||||
if encrypted.len() < meta_len {
|
if encrypted.len() < meta_len {
|
||||||
|
Loading…
Reference in New Issue
Block a user