Skip to content

Commit

Permalink
Merge pull request #19 from franziskuskiefer/maintenance-update
Browse files Browse the repository at this point in the history
Maintenance update
  • Loading branch information
franziskuskiefer authored May 21, 2021
2 parents 50be585 + 76eb39f commit f740af9
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 64 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ jobs:

steps:
- uses: actions/checkout@v2
- name: Setup MacOS
if: matrix.os == 'macos-latest'
run: |
sudo rm -Rf /Library/Developer/CommandLineTools/SDKs/*
sudo xcode-select -s /Applications/Xcode_12.4.app
rustup target install aarch64-apple-darwin
rustup target install aarch64-apple-ios
- name: Run tests
# Always enabling rust crypto AES for now.
run: cargo test --verbose --features rust-crypto
Expand All @@ -36,6 +43,16 @@ jobs:
- name: Run tests all features
# Always enabling rust crypto AES for now.
run: cargo test --release --verbose --all-features
- name: Apple Silicon Build
if: matrix.os == 'macos-latest'
run: |
cargo build --target aarch64-apple-darwin --tests --verbose --features rust-crypto
cargo build --release --target aarch64-apple-darwin --tests --verbose --features rust-crypto
- name: iOS build
if: matrix.os == 'macos-latest'
run: |
cargo build --target aarch64-apple-ios --tests --verbose --features rust-crypto
cargo build --release --target aarch64-apple-ios --tests --verbose --features rust-crypto
fuzz:
strategy:
fail-fast: false
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ readme = "README.md"
repository = "https://github.com/franziskuskiefer/hpke-rs"

[dependencies]
evercrypt = { version = "0.0.8" }
evercrypt = { version = "0.0.9" }
serde_json = { version = "1.0", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }

Expand Down
4 changes: 4 additions & 0 deletions src/aead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ pub enum Error {

/// Unknown AEAD mode
UnknownMode,

/// Error from the crypto library
CryptoLibError(String),
}

pub(crate) trait AeadTrait: Debug + Send + Sync {
Expand All @@ -82,6 +85,7 @@ pub(crate) trait AeadTrait: Debug + Send + Sync {
) -> Result<Vec<u8>, Error>;
fn key_length(&self) -> usize;
fn nonce_length(&self) -> usize;
fn tag_length(&self) -> usize;
}

#[derive(Debug)]
Expand Down
41 changes: 23 additions & 18 deletions src/aead_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ use evercrypt::prelude::*;

use crate::aead::{AeadTrait, Error};

impl From<evercrypt::aead::Error> for Error {
fn from(e: evercrypt::aead::Error) -> Self {
Self::CryptoLibError(format!("Evercrypt error {:?}", e))
}
}

macro_rules! implement_aead {
($name:ident, $algorithm:expr, $key_length:literal) => {
($name:ident, $algorithm:expr) => {
#[derive(Debug)]
pub(crate) struct $name {}

Expand All @@ -27,10 +33,7 @@ macro_rules! implement_aead {
Err(_) => return Err(Error::InvalidConfig),
};

let mut nonce_array = [0u8; 12];
nonce_array.clone_from_slice(nonce);

let (mut ctxt, tag) = cipher.encrypt(&plain_txt, &nonce_array, &aad).unwrap();
let (mut ctxt, tag) = cipher.encrypt(&plain_txt, &nonce, &aad)?;
ctxt.extend(tag.to_vec());
Ok(ctxt)
}
Expand All @@ -41,10 +44,12 @@ macro_rules! implement_aead {
aad: &[u8],
cipher_txt: &[u8],
) -> Result<Vec<u8>, Error> {
if nonce.len() != 12 {
let nonce_length = self.nonce_length();
if nonce.len() != nonce_length {
return Err(Error::InvalidNonce);
}
if cipher_txt.len() <= 16 {
let tag_length = self.tag_length();
if cipher_txt.len() <= tag_length {
return Err(Error::InvalidCiphertext);
}

Expand All @@ -53,29 +58,29 @@ macro_rules! implement_aead {
Err(_) => return Err(Error::InvalidConfig),
};

let mut nonce_array = [0u8; 12];
nonce_array.clone_from_slice(nonce);

match cipher.decrypt(
&cipher_txt[..cipher_txt.len() - 16],
&cipher_txt[cipher_txt.len() - 16..],
&nonce_array,
&cipher_txt[..cipher_txt.len() - tag_length],
&cipher_txt[cipher_txt.len() - tag_length..],
&nonce,
&aad,
) {
Ok(m) => Ok(m),
Err(_) => Err(Error::OpenError),
}
}
fn key_length(&self) -> usize {
$key_length
aead_key_size($algorithm)
}
fn nonce_length(&self) -> usize {
12
aead_nonce_size($algorithm)
}
fn tag_length(&self) -> usize {
aead_tag_size($algorithm)
}
}
};
}

implement_aead!(AesGcm128, AeadMode::Aes128Gcm, 16);
implement_aead!(AesGcm256, AeadMode::Aes256Gcm, 32);
implement_aead!(ChaCha20Poly1305, AeadMode::Chacha20Poly1305, 32);
implement_aead!(AesGcm128, AeadMode::Aes128Gcm);
implement_aead!(AesGcm256, AeadMode::Aes256Gcm);
implement_aead!(ChaCha20Poly1305, AeadMode::Chacha20Poly1305);
49 changes: 27 additions & 22 deletions src/dh_kem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,18 @@ impl DhKem {

/// Prepend 0x04 for uncompressed NIST curve points.
#[inline(always)]
fn nist_format_uncompressed(pk: &[u8]) -> Vec<u8> {
let mut tmp = vec![0x04];
tmp.extend(pk);
fn nist_format_uncompressed(mut pk: Vec<u8>) -> Vec<u8> {
let mut tmp = Vec::with_capacity(pk.len() + 1);
tmp.push(0x04);
tmp.append(&mut pk);
tmp
}

fn dh_base(&self, sk: &[u8]) -> Vec<u8> {
let out = ecdh_derive_base(self.dh_id, sk).unwrap();
fn dh_base(&self, sk: &[u8]) -> Result<Vec<u8>, Error> {
let out = ecdh_derive_base(self.dh_id, sk)?;
match self.dh_id {
ecdh::Mode::X25519 => out,
ecdh::Mode::P256 => Self::nist_format_uncompressed(&out),
ecdh::Mode::X25519 => Ok(out),
ecdh::Mode::P256 => Ok(Self::nist_format_uncompressed(out)),
}
}

Expand Down Expand Up @@ -109,13 +110,17 @@ impl KemTrait for DhKem {
panic!("Don't use this please");
}

fn key_gen(&self) -> (Vec<u8>, Vec<u8>) {
let sk = ecdh::key_gen(self.dh_id);
let pk = self.dh_base(&sk);
(sk, pk)
fn key_gen(&self) -> Result<(Vec<u8>, Vec<u8>), Error> {
let sk = ecdh::key_gen(self.dh_id)?;
let pk = self.dh_base(&sk)?;
Ok((sk, pk))
}

fn derive_key_pair(&self, suite_id: &[u8], ikm: &[u8]) -> (PublicKey, PrivateKey) {
fn derive_key_pair(
&self,
suite_id: &[u8],
ikm: &[u8],
) -> Result<(PublicKey, PrivateKey), Error> {
let dkp_prk = self.kdf.labeled_extract(&[], suite_id, "dkp_prk", ikm);

let sk = match self.dh_id {
Expand Down Expand Up @@ -147,46 +152,46 @@ impl KemTrait for DhKem {
}
}
};
(self.dh_base(&sk).to_vec(), sk)
Ok((self.dh_base(&sk)?, sk))
}

fn encaps(&self, pk_r: &[u8], suite_id: &[u8]) -> Result<(Vec<u8>, Vec<u8>), Error> {
let (pk_e, sk_e) = self.derive_key_pair(suite_id, &self.random());
let (pk_e, sk_e) = self.derive_key_pair(suite_id, &self.random())?;
let dh_pk = self.dh(&sk_e, pk_r)?;
let enc = self.serialize(&pk_e);

let pk_rm = self.serialize(pk_r);
let kem_context = concat(&[&enc, &pk_rm]);

let zz = self.extract_and_expand(dh_pk.to_vec(), &kem_context, suite_id);
let zz = self.extract_and_expand(dh_pk, &kem_context, suite_id);
Ok((zz, enc))
}

fn decaps(&self, enc: &[u8], sk_r: &[u8], suite_id: &[u8]) -> Result<Vec<u8>, Error> {
let pk_e = self.deserialize(enc);
let dh_pk = self.dh(sk_r, &pk_e)?;

let pk_rm = self.serialize(&self.dh_base(sk_r));
let pk_rm = self.serialize(&self.dh_base(sk_r)?);
let kem_context = concat(&[&enc, &pk_rm]);

Ok(self.extract_and_expand(dh_pk.to_vec(), &kem_context, suite_id))
Ok(self.extract_and_expand(dh_pk, &kem_context, suite_id))
}
fn auth_encaps(
&self,
pk_r: &[u8],
sk_s: &[u8],
suite_id: &[u8],
) -> Result<(Vec<u8>, Vec<u8>), Error> {
let (pk_e, sk_e) = self.derive_key_pair(suite_id, &self.random());
let (pk_e, sk_e) = self.derive_key_pair(suite_id, &self.random())?;
let dh_pk = concat(&[&self.dh(&sk_e, pk_r)?, &self.dh(&sk_s, pk_r)?]);

let enc = self.serialize(&pk_e);
let pk_rm = self.serialize(&pk_r);
let pk_sm = self.serialize(&self.dh_base(&sk_s));
let pk_sm = self.serialize(&self.dh_base(&sk_s)?);

let kem_context = concat(&[&enc, &pk_rm, &pk_sm]);

let zz = self.extract_and_expand(dh_pk.to_vec(), &kem_context, suite_id);
let zz = self.extract_and_expand(dh_pk, &kem_context, suite_id);
Ok((zz, enc))
}
fn auth_decaps(
Expand All @@ -199,11 +204,11 @@ impl KemTrait for DhKem {
let pk_e = self.deserialize(enc);
let dh_pk = concat(&[&self.dh(sk_r, &pk_e)?, &self.dh(sk_r, &pk_s)?]);

let pk_rm = self.serialize(&self.dh_base(sk_r));
let pk_rm = self.serialize(&self.dh_base(sk_r)?);
let pk_sm = self.serialize(&pk_s);
let kem_context = concat(&[&enc, &pk_rm, &pk_sm]);

Ok(self.extract_and_expand(dh_pk.to_vec(), &kem_context, suite_id))
Ok(self.extract_and_expand(dh_pk, &kem_context, suite_id))
}

#[cfg(feature = "deterministic")]
Expand Down
2 changes: 1 addition & 1 deletion src/hkdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ macro_rules! implement_hkdfs {
Self {}
}
fn digest_length(&self) -> usize {
get_tag_size($hmac_mode)
tag_size($hmac_mode)
}
fn extract(&self, salt: &[u8], ikm: &[u8]) -> Vec<u8> {
hkdf_extract($hmac_mode, &salt, &ikm)
Expand Down
12 changes: 8 additions & 4 deletions src/kem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,12 @@ pub(crate) trait KemTrait: std::fmt::Debug + Send + Sync {
where
Self: Sized;

fn key_gen(&self) -> (Vec<u8>, Vec<u8>);
fn derive_key_pair(&self, suite_id: &[u8], ikm: &[u8]) -> (PublicKey, PrivateKey);
fn key_gen(&self) -> Result<(Vec<u8>, Vec<u8>), Error>;
fn derive_key_pair(
&self,
suite_id: &[u8],
ikm: &[u8],
) -> Result<(PublicKey, PrivateKey), Error>;

fn encaps(&self, pk_r: &[u8], suite_id: &[u8]) -> Result<(Vec<u8>, Vec<u8>), Error>;
fn decaps(&self, enc: &[u8], sk_r: &[u8], suite_id: &[u8]) -> Result<Vec<u8>, Error>;
Expand Down Expand Up @@ -176,14 +180,14 @@ impl Kem {
) -> Result<Vec<u8>, Error> {
self.kem.auth_decaps(enc, sk_r, pk_s, &self.ciphersuite())
}
pub(crate) fn key_gen(&self) -> (Vec<u8>, Vec<u8>) {
pub(crate) fn key_gen(&self) -> Result<(Vec<u8>, Vec<u8>), Error> {
self.kem.key_gen()
}

/// Derive key pair from the input key material `ikm`.
///
/// Returns (PublicKey, PrivateKey).
pub(crate) fn derive_key_pair(&self, ikm: &[u8]) -> (PublicKey, PrivateKey) {
pub(crate) fn derive_key_pair(&self, ikm: &[u8]) -> Result<(PublicKey, PrivateKey), Error> {
self.kem.derive_key_pair(&self.ciphersuite(), ikm)
}

Expand Down
17 changes: 9 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ impl<'a> Context<'a> {
fn compute_nonce(&self) -> Vec<u8> {
let seq = self.sequence_number.to_be_bytes();
let mut enc_seq = vec![0u8; self.nonce.len() - seq.len()];
enc_seq.append(&mut seq.to_vec());
enc_seq.extend_from_slice(&seq);
util::xor_bytes(&enc_seq, &self.nonce)
}

Expand Down Expand Up @@ -624,18 +624,18 @@ impl Hpke {
/// This is equivalent to `derive_key_pair(random_vector(sk.len()))`
///
/// Returns an `HpkeKeyPair`.
pub fn generate_key_pair(&self) -> HpkeKeyPair {
let (sk, pk) = self.kem.key_gen();
HpkeKeyPair::new(sk, pk)
pub fn generate_key_pair(&self) -> Result<HpkeKeyPair, HpkeError> {
let (sk, pk) = self.kem.key_gen()?;
Ok(HpkeKeyPair::new(sk, pk))
}

/// 7.1.2. DeriveKeyPair
/// Derive a key pair for the used KEM with the given input key material.
///
/// Returns `HpkeKeyPair`
pub fn derive_key_pair(&self, ikm: &[u8]) -> HpkeKeyPair {
let (pk, sk) = self.kem.derive_key_pair(ikm);
HpkeKeyPair::new(sk, pk)
/// Returns an `HpkeKeyPair` result or an `HpkeError` if key derivation fails.
pub fn derive_key_pair(&self, ikm: &[u8]) -> Result<HpkeKeyPair, HpkeError> {
let (pk, sk) = self.kem.derive_key_pair(ikm)?;
Ok(HpkeKeyPair::new(sk, pk))
}

/// Set randomness for testing HPKE (KEM) without randomness.
Expand Down Expand Up @@ -850,6 +850,7 @@ impl From<aead::Error> for HpkeError {
aead::Error::InvalidNonce | aead::Error::InvalidCiphertext => HpkeError::InvalidInput,
aead::Error::InvalidConfig => HpkeError::InvalidConfig,
aead::Error::UnknownMode => HpkeError::UnknownMode,
aead::Error::CryptoLibError(_) => HpkeError::CryptoError,
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use evercrypt::prelude::get_random_vec;
use evercrypt::prelude::random_vec;

#[inline]
pub(crate) fn random(l: usize) -> Vec<u8> {
get_random_vec(l)
random_vec(l)
}

#[inline]
Expand Down
8 changes: 4 additions & 4 deletions tests/test_hpke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ macro_rules! generate_test_case {
println!("Self test {}", hpke);

// Self test seal and open with random keys.
let (sk_r, pk_r) = hpke.generate_key_pair().into_keys();
let (sk_s, pk_s) = hpke.generate_key_pair().into_keys();
let (sk_r, pk_r) = hpke.generate_key_pair().unwrap().into_keys();
let (sk_s, pk_s) = hpke.generate_key_pair().unwrap().into_keys();
let info = b"HPKE self test info";
let aad = b"HPKE self test aad";
let plain_txt = b"HPKE self test plain text";
let exporter_context = b"HPKE self test exporter context";
let psk = get_random_vec(32);
let psk_id = get_random_vec(32);
let psk = random_vec(32);
let psk_id = random_vec(32);
let (psk, psk_id): (Option<&[u8]>, Option<&[u8]>) = match $hpke_mode {
Mode::Base | Mode::Auth => (None, None),
Mode::Psk | Mode::AuthPsk => (Some(&psk), Some(&psk_id)),
Expand Down
Loading

0 comments on commit f740af9

Please sign in to comment.