Revert removing ecies (#2009)

* revert removing ECIES without MAC

* removed reverted change in encrypt
This commit is contained in:
Marek Kotewicz 2016-08-25 12:11:06 +02:00 committed by Arkadiy Paronyan
parent 3e07135df3
commit 09e0842f56
2 changed files with 90 additions and 4 deletions

1
Cargo.lock generated
View File

@ -290,7 +290,6 @@ version = "1.4.0"
dependencies = [ dependencies = [
"clippy 0.0.85 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.85 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-devtools 1.4.0",
"ethcore-rpc 1.4.0", "ethcore-rpc 1.4.0",
"ethcore-util 1.4.0", "ethcore-util 1.4.0",
"hyper 0.9.4 (git+https://github.com/ethcore/hyper)", "hyper 0.9.4 (git+https://github.com/ethcore/hyper)",

View File

@ -33,6 +33,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;
#[derive(PartialEq, Debug)]
pub enum Error { pub enum Error {
Secp(SecpError), Secp(SecpError),
InvalidMessage, InvalidMessage,
@ -147,9 +148,9 @@ pub mod ecies {
use rcrypto::sha2::Sha256; use rcrypto::sha2::Sha256;
use rcrypto::hmac::Hmac; use rcrypto::hmac::Hmac;
use rcrypto::mac::Mac; use rcrypto::mac::Mac;
use bigint::hash::FixedHash; use bigint::hash::{FixedHash, H128};
use ethkey::{Random, Generator, Public, Secret}; use ethkey::{Random, Generator, Public, Secret};
use {Error, ecdh, aes}; use {Error, ecdh, aes, Keccak256};
/// Encrypt a message with a public key /// Encrypt a message with a public key
pub fn encrypt(public: &Public, shared_mac: &[u8], plain: &[u8]) -> Result<Vec<u8>, Error> { pub fn encrypt(public: &Public, shared_mac: &[u8], plain: &[u8]) -> Result<Vec<u8>, Error> {
@ -169,9 +170,11 @@ pub mod ecies {
{ {
let msgd = &mut msg[1..]; let msgd = &mut msg[1..];
msgd[0..64].copy_from_slice(r.public()); msgd[0..64].copy_from_slice(r.public());
let iv = H128::random();
msgd[64..80].copy_from_slice(&iv);
{ {
let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())]; let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())];
aes::encrypt(ekey, &[0u8; 16], plain, cipher); aes::encrypt(ekey, &iv, plain, cipher);
} }
let mut hmac = Hmac::new(Sha256::new(), &mkey); let mut hmac = Hmac::new(Sha256::new(), &mkey);
{ {
@ -184,6 +187,31 @@ pub mod ecies {
Ok(msg) Ok(msg)
} }
/// Encrypt a message with a public key
pub fn encrypt_single_message(public: &Public, plain: &[u8]) -> Result<Vec<u8>, Error> {
let r = Random.generate().unwrap();
let z = try!(ecdh::agree(r.secret(), public));
let mut key = [0u8; 32];
let mut mkey = [0u8; 32];
kdf(&z, &[0u8; 0], &mut key);
let mut hasher = Sha256::new();
let mkey_material = &key[16..32];
hasher.input(mkey_material);
hasher.result(&mut mkey);
let ekey = &key[0..16];
let mut msgd = vec![0u8; (64 + plain.len())];
{
r.public().copy_to(&mut msgd[0..64]);
let iv = H128::from_slice(&z.keccak256()[0..16]);
{
let cipher = &mut msgd[64..(64 + plain.len())];
aes::encrypt(ekey, &iv, plain, cipher);
}
}
Ok(msgd)
}
/// Decrypt a message with a secret key /// Decrypt a message with a secret key
pub fn decrypt(secret: &Secret, shared_mac: &[u8], encrypted: &[u8]) -> Result<Vec<u8>, Error> { pub fn decrypt(secret: &Secret, shared_mac: &[u8], encrypted: &[u8]) -> Result<Vec<u8>, Error> {
let meta_len = 1 + 64 + 16 + 32; let meta_len = 1 + 64 + 16 + 32;
@ -224,6 +252,33 @@ pub mod ecies {
Ok(msg) Ok(msg)
} }
/// Decrypt single message with a secret key
pub fn decrypt_single_message(secret: &Secret, encrypted: &[u8]) -> Result<Vec<u8>, Error> {
let meta_len = 64;
if encrypted.len() < meta_len {
return Err(Error::InvalidMessage); //invalid message: publickey
}
let e = encrypted;
let p = Public::from_slice(&e[0..64]);
let z = try!(ecdh::agree(secret, &p));
let mut key = [0u8; 32];
kdf(&z, &[0u8; 0], &mut key);
let ekey = &key[0..16];
let mkey_material = &key[16..32];
let mut hasher = Sha256::new();
let mut mkey = [0u8; 32];
hasher.input(mkey_material);
hasher.result(&mut mkey);
let clen = encrypted.len() - meta_len;
let cipher = &e[64..(64+clen)];
let mut msg = vec![0u8; clen];
let iv = H128::from_slice(&z.keccak256()[0..16]);
aes::decrypt(ekey, &iv, cipher, &mut msg[..]);
Ok(msg)
}
fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) { fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) {
let mut hasher = Sha256::new(); let mut hasher = Sha256::new();
// SEC/ISO/Shoup specify counter size SHOULD be equivalent // SEC/ISO/Shoup specify counter size SHOULD be equivalent
@ -244,3 +299,35 @@ pub mod ecies {
} }
} }
#[cfg(test)]
mod tests {
use ethkey::{Random, Generator};
use ecies;
#[test]
fn ecies_shared() {
let kp = Random.generate().unwrap();
let message = b"So many books, so little time";
let shared = b"shared";
let wrong_shared = b"incorrect";
let encrypted = ecies::encrypt(kp.public(), shared, message).unwrap();
assert!(encrypted[..] != message[..]);
assert_eq!(encrypted[0], 0x04);
assert!(ecies::decrypt(kp.secret(), wrong_shared, &encrypted).is_err());
let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap();
assert_eq!(decrypted[..message.len()], message[..]);
}
#[test]
fn ecies_shared_single() {
let kp = Random.generate().unwrap();
let message = b"So many books, so little time";
let encrypted = ecies::encrypt_single_message(kp.public(), message).unwrap();
assert!(encrypted[..] != message[..]);
let decrypted = ecies::decrypt_single_message(kp.secret(), &encrypted).unwrap();
assert_eq!(decrypted[..message.len()], message[..]);
}
}