From 8159d743efb6b7ce6111da894917f767999d61a4 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Thu, 18 Aug 2016 18:08:02 +0200 Subject: [PATCH] ECIES without MAC (#1948) * Use random IV for ECIES AES * ECIES encrypt/decrypt for a single message * Derive IV from shared secret --- util/src/crypto.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/util/src/crypto.rs b/util/src/crypto.rs index f4bc4c62e..298bc205e 100644 --- a/util/src/crypto.rs +++ b/util/src/crypto.rs @@ -311,6 +311,7 @@ pub mod ecies { use hash::*; use bytes::*; use crypto::*; + use sha3::Hashable; /// Encrypt a message with a public key pub fn encrypt(public: &Public, shared_mac: &[u8], plain: &[u8]) -> Result { @@ -334,9 +335,11 @@ pub mod ecies { { let msgd = &mut msg[1..]; r.public().copy_to(&mut msgd[0..64]); + let iv = H128::random(); + iv.copy_to(&mut msgd[64..(64+16)]); { let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())]; - aes::encrypt(ekey, &H128::new(), plain, cipher); + aes::encrypt(ekey, &iv, plain, cipher); } let mut hmac = Hmac::new(Sha256::new(), &mkey); { @@ -349,6 +352,33 @@ pub mod ecies { Ok(msg) } + /// Encrypt a message with a public key + pub fn encrypt_single_message(public: &Public, plain: &[u8]) -> Result { + use ::rcrypto::digest::Digest; + use ::rcrypto::sha2::Sha256; + let r = try!(KeyPair::create()); + 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.sha3()[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 pub fn decrypt(secret: &Secret, shared_mac: &[u8], encrypted: &[u8]) -> Result { use ::rcrypto::digest::Digest; @@ -394,6 +424,36 @@ pub mod ecies { Ok(msg) } + /// Decrypt single message with a secret key + pub fn decrypt_single_message(secret: &Secret, encrypted: &[u8]) -> Result { + use ::rcrypto::digest::Digest; + use ::rcrypto::sha2::Sha256; + + let meta_len = 64; + if encrypted.len() < meta_len { + return Err(CryptoError::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.sha3()[0..16]); + aes::decrypt(ekey, &iv, cipher, &mut msg[..]); + Ok(msg) + } + fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) { use ::rcrypto::digest::Digest; use ::rcrypto::sha2::Sha256; @@ -487,4 +547,14 @@ mod tests { let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap(); assert_eq!(decrypted[..message.len()], message[..]); } + + #[test] + fn ecies_shared_single() { + let kp = KeyPair::create().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[..]); + } }