Skip to content

Commit

Permalink
Add HPKE secret export and implement Send for EvpHpkeCtx.
Browse files Browse the repository at this point in the history
Change-Id: I929b31f996c8b67b77286fe9f8eb1af73d2bbc72
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/68307
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
  • Loading branch information
cindylindeed authored and Boringssl LUCI CQ committed May 9, 2024
1 parent e7d76da commit d34f540
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 0 deletions.
88 changes: 88 additions & 0 deletions rust/bssl-crypto/src/hpke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@
//!
//! let received_plaintext2 = recipient_ctx.open(&msg2, aad);
//! assert!(received_plaintext2.is_none());
//!
//! // There is also an interface for exporting secrets from both sender
//! // and recipient contexts.
//! let sender_export = sender_ctx.export(b"ctx", 32);
//! let recipient_export = recipient_ctx.export(b"ctx", 32);
//! assert_eq!(sender_export, recipient_export);
//! ```
use crate::{scoped, with_output_vec, with_output_vec_fallible, FfiSlice};
Expand Down Expand Up @@ -294,6 +300,28 @@ impl SenderContext {
})
}
}

/// Exports a secret of length `out_len` from the HPKE context using `context` as the context
/// string.
pub fn export(&mut self, context: &[u8], out_len: usize) -> Vec<u8> {
unsafe {
with_output_vec(out_len, |out_buf| {
// Safety: EVP_HPKE_CTX_export
// - is called with context created from EVP_HPKE_CTX_new,
// - is called with valid buffers with corresponding pointer and length, and
// - returns 0 on error, which only occurs when OOM.
let ret = bssl_sys::EVP_HPKE_CTX_export(
self.0.as_mut_ffi_ptr(),
out_buf,
out_len,
context.as_ffi_ptr(),
context.len(),
);
assert_eq!(ret, 1);
out_len
})
}
}
}

/// HPKE recipient context. Callers may use `open()` to decrypt messages from the sender.
Expand Down Expand Up @@ -385,6 +413,28 @@ impl RecipientContext {
})
}
}

/// Exports a secret of length `out_len` from the HPKE context using `context` as the context
/// string.
pub fn export(&mut self, context: &[u8], out_len: usize) -> Vec<u8> {
unsafe {
with_output_vec(out_len, |out_buf| {
// Safety: EVP_HPKE_CTX_export
// - is called with context created from EVP_HPKE_CTX_new,
// - is called with valid buffers with corresponding pointer and length, and
// - returns 0 on error, which only occurs when OOM.
let ret = bssl_sys::EVP_HPKE_CTX_export(
self.0.as_mut_ffi_ptr(),
out_buf,
out_len,
context.as_ffi_ptr(),
context.len(),
);
assert_eq!(ret, 1);
out_len
})
}
}
}

#[cfg(test)]
Expand All @@ -404,6 +454,8 @@ mod test {
plaintext: [u8; 29], // pt
associated_data: [u8; 7], // aad
ciphertext: [u8; 45], // ct
exporter_context: [u8; 11],
exported_value: [u8; 32],
}

// https://www.rfc-editor.org/rfc/rfc9180.html#appendix-A.1
Expand All @@ -420,6 +472,8 @@ mod test {
plaintext: decode_hex("4265617574792069732074727574682c20747275746820626561757479"),
associated_data: decode_hex("436f756e742d30"),
ciphertext: decode_hex("f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a"),
exporter_context: decode_hex("54657374436f6e74657874"),
exported_value: decode_hex("e9e43065102c3836401bed8c3c3c75ae46be1639869391d62c61f1ec7af54931"),
}
}

Expand All @@ -437,6 +491,8 @@ mod test {
plaintext: decode_hex("4265617574792069732074727574682c20747275746820626561757479"),
associated_data: decode_hex("436f756e742d30"),
ciphertext: decode_hex("1c5250d8034ec2b784ba2cfd69dbdb8af406cfe3ff938e131f0def8c8b60b4db21993c62ce81883d2dd1b51a28"),
exporter_context: decode_hex("54657374436f6e74657874"),
exported_value: decode_hex("5acb09211139c43b3090489a9da433e8a30ee7188ba8b0a9a1ccf0c229283e53"),
}
}

Expand Down Expand Up @@ -562,6 +618,38 @@ mod test {
}
}

#[test]
fn export_with_vector() {
for test in vec![
x25519_hkdf_sha256_hkdf_sha256_aes_128_gcm(),
x25519_hkdf_sha256_hkdf_sha256_chacha20_poly1305(),
] {
let params = Params::new_from_rfc_ids(test.kem_id, test.kdf_id, test.aead_id).unwrap();

let (mut sender_ctx, _encapsulated_key) = new_sender_context_for_testing(
&params,
&test.recipient_pub_key,
&test.info,
&test.seed_for_testing,
);
assert_eq!(
test.exported_value.as_ref(),
sender_ctx.export(&test.exporter_context, test.exported_value.len())
);

let mut recipient_ctx = RecipientContext::new(
&params,
&test.recipient_priv_key,
&test.encapsulated_key,
&test.info,
).unwrap();
assert_eq!(
test.exported_value.as_ref(),
recipient_ctx.export(&test.exporter_context, test.exported_value.len())
);
}
}

#[test]
fn disallowed_params_fail() {
let vec: TestVector = x25519_hkdf_sha256_hkdf_sha256_aes_128_gcm();
Expand Down
3 changes: 3 additions & 0 deletions rust/bssl-crypto/src/scoped.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ impl Drop for EcKey {

/// A scoped `EVP_HPKE_CTX`.
pub struct EvpHpkeCtx(*mut bssl_sys::EVP_HPKE_CTX);
// bssl_sys::EVP_HPKE_CTX is heap-allocated and safe to transfer
// between threads.
unsafe impl Send for EvpHpkeCtx {}

impl EvpHpkeCtx {
pub fn new() -> Self {
Expand Down

0 comments on commit d34f540

Please sign in to comment.