Skip to content

Commit

Permalink
feat: Add convenience functions for encrypt/decrypt (#26)
Browse files Browse the repository at this point in the history
* feat: Add convenience functions for encrypt/decrypt

Closes #25
  • Loading branch information
jrconlin authored May 1, 2019
1 parent 0c57bc6 commit d3fb5a1
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 13 deletions.
2 changes: 1 addition & 1 deletion 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 Down
4 changes: 2 additions & 2 deletions src/aesgcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ impl AesGcmEncryptedBlock {

/// Create a new block from the various header strings and body content.
pub fn new(
dh: &Vec<u8>,
salt: &Vec<u8>,
dh: &[u8],
salt: &[u8],
rs: u32,
ciphertext: Vec<u8>,
) -> Result<AesGcmEncryptedBlock> {
Expand Down
4 changes: 2 additions & 2 deletions src/crypto_backends/openssl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -80,7 +80,7 @@ impl OpenSSLLocalKeyPair {
}

fn to_pkey(&self) -> Result<PKey<Private>> {
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)
}
}

Expand Down
57 changes: 49 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,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 +30,35 @@ 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<Vec<u8>> {
let remote_key = crypto_backends::CryptoImpl::public_key_from_raw(remote_pub)?;
let local_key = LocalKeyPairImpl::generate_random()?;
let mut padr = [0u8; 2];
CryptoImpl::random(&mut padr)?;
// since it's a sampled random, endian doesn't really matter.
let pad = ((usize::from(padr[0]) + (usize::from(padr[1]) << 8)) % 4095) + 1;
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<Vec<u8>> {
let priv_key = LocalKeyPairImpl::new(local_priv).unwrap();
Aes128GcmEceWebPushImpl::decrypt(&priv_key, &auth, data)
}

#[cfg(test)]
mod aes128gcm_tests {
extern crate hex;
Expand Down Expand Up @@ -70,11 +100,11 @@ 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(
&hex::decode(priv_key).unwrap(),
&hex::decode(auth_secret).unwrap(),
&hex::decode(payload).unwrap(),
)?;
Ok(String::from_utf8(plaintext).unwrap())
}

Expand All @@ -100,6 +130,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(
Expand Down Expand Up @@ -323,9 +365,8 @@ mod aesgcm_tests {
}

#[test]
fn test_debug() {
let local_key = LocalKeyPairImpl::generate_random().unwrap();
println!("Local key = {:?}", local_key);
fn test_keygen() {
LocalKeyPairImpl::generate_random().unwrap();
}

// If decode using externally validated data works, and e2e using the same decoder work, things
Expand Down

0 comments on commit d3fb5a1

Please sign in to comment.