From cb5d318daaa94a6c03f9f6ec1009c48c81f23b3c Mon Sep 17 00:00:00 2001 From: jrconlin Date: Tue, 30 Apr 2019 13:09:52 -0700 Subject: [PATCH] feat: Add convenience functions for encrypt/decrypt Closes #25 --- Cargo.toml | 3 +- src/aesgcm.rs | 4 +-- src/crypto_backends/openssl.rs | 4 +-- src/lib.rs | 54 ++++++++++++++++++++++++++++++---- 4 files changed, 55 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0342df1..9de5ea3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ece" -version = "0.1.3" +version = "0.2.0" authors = ["Edouard Oger ", "JR Conlin "] license = "MPL-2.0" edition = "2018" @@ -16,6 +16,7 @@ base64 = "0.10" hkdf = { version = "0.7", optional = true } lazy_static = { version = "1.2", optional = true } openssl = { version = "0.10", optional = true } +rand = "0.6" sha2 = { version = "0.8", optional = true } [dev-dependencies] diff --git a/src/aesgcm.rs b/src/aesgcm.rs index c38bb42..3dcf1c0 100644 --- a/src/aesgcm.rs +++ b/src/aesgcm.rs @@ -42,8 +42,8 @@ impl AesGcmEncryptedBlock { /// Create a new block from the various header strings and body content. pub fn new( - dh: &Vec, - salt: &Vec, + dh: &[u8], + salt: &[u8], rs: u32, ciphertext: Vec, ) -> Result { diff --git a/src/crypto_backends/openssl.rs b/src/crypto_backends/openssl.rs index 1f7e722..31be89c 100644 --- a/src/crypto_backends/openssl.rs +++ b/src/crypto_backends/openssl.rs @@ -34,7 +34,7 @@ impl OpenSSLRemotePublicKey { let mut bn_ctx = BigNumContext::new()?; let point = EcPoint::from_bytes(&GROUP_P256, &self.raw_pub_key, &mut bn_ctx)?; let ec = EcKey::from_public_key(&GROUP_P256, &point)?; - PKey::from_ec_key(ec).map_err(|e| e.into()) + PKey::from_ec_key(ec).map_err(std::convert::Into::into) } pub fn from_raw(raw: &[u8]) -> Self { @@ -80,7 +80,7 @@ impl OpenSSLLocalKeyPair { } fn to_pkey(&self) -> Result> { - PKey::from_ec_key(self.ec_key.clone()).map_err(|e| e.into()) + PKey::from_ec_key(self.ec_key.clone()).map_err(std::convert::Into::into) } } diff --git a/src/lib.rs b/src/lib.rs index 09e0686..24524fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,9 @@ mod crypto_backend; mod crypto_backends; mod error; +use rand; +use rand::Rng; + pub use crate::{ aes128gcm::Aes128GcmEceWebPush, aesgcm::{AesGcmEceWebPush, AesGcmEncryptedBlock}, @@ -21,6 +24,7 @@ pub type Aes128GcmEceWebPushImpl = aes128gcm::Aes128GcmEceWebPush; pub use crate::crypto_backends::{CryptoImpl, LocalKeyPairImpl, RemoteKeyPairImpl}; +/// Generate a local ECE key pair and auth nonce. pub fn generate_keypair_and_auth_secret( ) -> Result<(LocalKeyPairImpl, [u8; ECE_WEBPUSH_AUTH_SECRET_LENGTH])> { let local_key_pair = LocalKeyPairImpl::generate_random()?; @@ -29,6 +33,34 @@ pub fn generate_keypair_and_auth_secret( Ok((local_key_pair, auth_secret)) } +/// Encrypt a block using default AES128GCM encoding. +/// +/// param remote_pub &[u8] - The remote public key +/// param remote_auth &u8 - The remote authorization token +/// param salt &[u8] - The locally generated random salt +/// param data &[u8] - The data to encrypt +/// +pub fn encrypt(remote_pub: &[u8], remote_auth: &[u8], salt: &[u8], data: &[u8]) -> Result> { + let remote_key = crypto_backends::CryptoImpl::public_key_from_raw(remote_pub)?; + let local_key = LocalKeyPairImpl::generate_random()?; + // TODO: randomize pad. + let mut rng = rand::thread_rng(); + let pad = rng.gen_range(1, 4096 - data.len()); + let params = WebPushParams::new(4096, pad, Vec::from(salt)); + Aes128GcmEceWebPushImpl::encrypt_with_keys(&local_key, &remote_key, &remote_auth, data, params) +} + +/// Decrypt a block using default AES128GCM encoding. +/// +/// param local_priv &str - The locally generated Private key as a raw, hex encoded string +/// param auth &str - The locally generated auth token (this value was shared with the encryptor) +/// param data &[u8] - The encrypted data block +/// +pub fn decrypt(local_priv: &[u8], auth: &[u8], data: &[u8]) -> Result> { + let priv_key = LocalKeyPairImpl::new(local_priv).unwrap(); + Aes128GcmEceWebPushImpl::decrypt(&priv_key, &auth, data) +} + #[cfg(test)] mod aes128gcm_tests { extern crate hex; @@ -70,11 +102,11 @@ mod aes128gcm_tests { } fn try_decrypt(priv_key: &str, auth_secret: &str, payload: &str) -> Result { - let priv_key = hex::decode(priv_key).unwrap(); - let priv_key = LocalKeyPairImpl::new(&priv_key)?; - let auth_secret = hex::decode(auth_secret).unwrap(); - let payload = hex::decode(payload).unwrap(); - let plaintext = Aes128GcmEceWebPushImpl::decrypt(&priv_key, &auth_secret, &payload)?; + let plaintext = decrypt( + &hex::decode(priv_key).unwrap(), + &hex::decode(auth_secret).unwrap(), + &hex::decode(payload).unwrap(), + )?; Ok(String::from_utf8(plaintext).unwrap()) } @@ -100,6 +132,18 @@ mod aes128gcm_tests { assert_eq!(decrypted, plaintext); } + #[test] + fn test_conv_fn() -> Result<()> { + let (local_key, auth) = generate_keypair_and_auth_secret()?; + let plaintext = b"Mary had a little lamb, with some nice mint jelly"; + let mut salt = vec![0u8; 16]; + CryptoImpl::random(&mut salt)?; + let encoded = encrypt(&local_key.pub_as_raw()?, &auth, &salt, plaintext).unwrap(); + let decoded = decrypt(&local_key.to_raw(), &auth, &encoded)?; + assert_eq!(decoded, plaintext.to_vec()); + Ok(()) + } + #[test] fn try_encrypt_ietf_rfc() { let ciphertext = try_encrypt(