Skip to content

Commit

Permalink
feat: Add convenience functions for encrypt/decrypt
Browse files Browse the repository at this point in the history
Closes #25
  • Loading branch information
jrconlin committed Apr 30, 2019
1 parent 0c57bc6 commit aafb707
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 9 deletions.
7 changes: 3 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ece"
version = "0.1.3"
version = "0.2.0"
authors = ["Edouard Oger <[email protected]>", "JR Conlin <[email protected]>"]
license = "MPL-2.0"
edition = "2018"
Expand All @@ -13,14 +13,13 @@ byteorder = "1.3"
failure = "0.1"
failure_derive = "0.1"
base64 = "0.10"
hex = "0.3"
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]
hex = "0.3"

[features]
default = ["backend-openssl"]
backend-openssl = ["openssl", "lazy_static", "hkdf", "sha2"]
68 changes: 63 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ mod crypto_backend;
mod crypto_backends;
mod error;

use hex;
use rand;
use rand::Rng;

pub use crate::{
aes128gcm::Aes128GcmEceWebPush,
aesgcm::{AesGcmEceWebPush, AesGcmEncryptedBlock},
Expand All @@ -21,6 +25,7 @@ pub type Aes128GcmEceWebPushImpl = aes128gcm::Aes128GcmEceWebPush<crypto_backend
pub type AesGcmEceWebPushImpl = aesgcm::AesGcmEceWebPush<crypto_backends::CryptoImpl>;
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()?;
Expand All @@ -29,6 +34,44 @@ pub fn generate_keypair_and_auth_secret(
Ok((local_key_pair, auth_secret))
}

/// Encrypt a block using default AES128GCM encoding.
///
/// param remote_pub &str - The remote public key in hex encoded format
/// param remote_auth &str - The remote authorization token in hex encoded format
/// param salt &[u8] - The locally generated random salt
/// param data &[u8] - The data to encrypt
///
pub fn encrypt(remote_pub: &str, remote_auth: &str, salt: &[u8], data: &[u8]) -> Result<Vec<u8>> {
let remote_decode = hex::decode(remote_pub).map_err(|_| error::ErrorKind::DecodeError)?;
let remote_key = crypto_backends::CryptoImpl::public_key_from_raw(remote_decode.as_slice())?;
let local_key = LocalKeyPairImpl::generate_random()?;
let auth_secret = hex::decode(remote_auth).map_err(|_| error::ErrorKind::DecodeError)?;
// 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,
&auth_secret.as_slice(),
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 as a hex encoded string (this value was shared with the encryptor)
/// param data &[u8] - The encrypted data block
///
pub fn decrypt(local_priv: &str, auth: &str, data: &[u8]) -> Result<Vec<u8>> {
let priv_key = hex::decode(local_priv).unwrap();
let priv_key = LocalKeyPairImpl::new(priv_key.as_slice()).unwrap();
let auth_secret = hex::decode(auth).unwrap();
Aes128GcmEceWebPushImpl::decrypt(&priv_key, &auth_secret.as_slice(), data)
}

#[cfg(test)]
mod aes128gcm_tests {
extern crate hex;
Expand Down Expand Up @@ -70,11 +113,7 @@ mod aes128gcm_tests {
}

fn try_decrypt(priv_key: &str, auth_secret: &str, payload: &str) -> Result<String> {
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(priv_key, auth_secret, &hex::decode(payload).unwrap())?;
Ok(String::from_utf8(plaintext).unwrap())
}

Expand All @@ -100,6 +139,25 @@ mod aes128gcm_tests {
assert_eq!(decrypted, plaintext);
}

#[test]
fn test_conv_fn() -> Result<()> {
let (local_key, auth) = generate_keypair_and_auth_secret()?;
let hex_auth = hex::encode(auth);
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(
&hex::encode(local_key.pub_as_raw()?),
&hex_auth,
&salt,
plaintext,
)
.unwrap();
let decoded = decrypt(&hex::encode(local_key.to_raw()), &hex_auth, &encoded)?;
assert_eq!(decoded, plaintext.to_vec());
Ok(())
}

#[test]
fn try_encrypt_ietf_rfc() {
let ciphertext = try_encrypt(
Expand Down

0 comments on commit aafb707

Please sign in to comment.