#![cfg_attr(docsrs, doc(cfg(feature = "bearssl")))]
#![cfg(feature = "bearssl")]
#![cfg(not(fips))]
#![cfg_attr(docsrs, doc(cfg(not(fips))))]
use core::{
borrow::Borrow,
cmp,
ffi::c_void,
fmt::{self, Debug},
mem::size_of,
ops::Range,
pin::Pin,
ptr,
result::Result,
slice,
};
pub use aranya_bearssl_sys;
#[allow(clippy::wildcard_imports)]
use aranya_bearssl_sys::*;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeLess};
use typenum::{Unsigned, U, U12, U16, U32};
use crate::{
aead::{
check_open_in_place_params, check_seal_in_place_params, Aead, AeadId, AeadKey, IndCca2,
Lifetime, OpenError, SealError,
},
asn1::{max_sig_len, raw_sig_len, RawSig, Sig},
csprng::Csprng,
ec::{Curve, Curve25519, Scalar, Secp256r1, Secp384r1, Secp521r1, Uncompressed},
hash::{Block, Digest, Hash, HashId},
hex::ToHex,
hkdf::hkdf_impl,
hmac::hmac_impl,
import::{ExportError, Import, ImportError},
kem::{dhkem_impl, DecapKey, Ecdh, EcdhError, EncapKey, SharedSecret},
keys::{PublicKey, SecretKey, SecretKeyBytes},
signer::{PkError, Signer, SignerError, SignerId, SigningKey, VerifyingKey},
zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing},
};
fn ct_eq_zero(x: &[u8]) -> Choice {
let mut v = Choice::from(0u8);
for c in x {
v |= c.ct_ne(&0);
}
v
}
fn ct_be_lt(x: &[u8], y: &[u8]) -> Choice {
assert_eq!(x.len(), y.len());
let mut done = Choice::from(0u8);
let mut lt = 0u8;
for (x, y) in x.iter().zip(y) {
done |= x.ct_ne(y);
lt |= u8::conditional_select(&0, &x.ct_lt(y).unwrap_u8(), done);
}
lt.into()
}
#[cfg_attr(feature = "clone-aead", derive(Clone))]
pub struct Aes256Gcm(br_aes_ct_ctr_keys);
unsafe impl Send for Aes256Gcm {}
unsafe impl Sync for Aes256Gcm {}
impl ZeroizeOnDrop for Aes256Gcm {}
impl Drop for Aes256Gcm {
fn drop(&mut self) {
self.0.skey.zeroize();
}
}
impl IndCca2 for Aes256Gcm {}
impl Aead for Aes256Gcm {
const ID: AeadId = AeadId::Aes256Gcm;
const LIFETIME: Lifetime = Lifetime::Messages(u32::MAX as u64);
type KeySize = U32;
type NonceSize = U12;
type Overhead = U16;
const MAX_PLAINTEXT_SIZE: u64 = (1 << 36) - 32; const MAX_ADDITIONAL_DATA_SIZE: u64 = (1 << 61) - 1;
type Key = AeadKey<Self::KeySize>;
#[inline]
fn new(key: &Self::Key) -> Self {
let mut bc = br_aes_ct_ctr_keys::default();
unsafe {
br_aes_ct_ctr_init(
ptr::addr_of_mut!(bc),
key.as_slice().as_ptr() as *const c_void,
key.len(),
);
}
Self(bc)
}
fn seal_in_place(
&self,
nonce: &[u8],
data: &mut [u8],
tag: &mut [u8],
additional_data: &[u8],
) -> Result<(), SealError> {
check_seal_in_place_params::<Self>(nonce, data, tag, additional_data)?;
unsafe {
let mut gc = br_gcm_context::default();
br_gcm_init(
ptr::addr_of_mut!(gc),
ptr::addr_of!(self.0.vtable).cast_mut(),
Some(br_ghash_ctmul),
);
br_gcm_reset(
ptr::addr_of_mut!(gc),
nonce.as_ptr() as *const c_void,
nonce.len(),
);
br_gcm_aad_inject(
ptr::addr_of_mut!(gc),
additional_data.as_ptr() as *const c_void,
additional_data.len(),
);
br_gcm_flip(ptr::addr_of_mut!(gc));
br_gcm_run(
ptr::addr_of_mut!(gc),
1,
data.as_mut_ptr() as *mut c_void,
data.len(),
);
br_gcm_get_tag(ptr::addr_of_mut!(gc), tag.as_mut_ptr() as *mut c_void);
}
Ok(())
}
fn open_in_place(
&self,
nonce: &[u8],
data: &mut [u8],
tag: &[u8],
additional_data: &[u8],
) -> Result<(), OpenError> {
check_open_in_place_params::<Self>(nonce, data, tag, additional_data)?;
let ret = unsafe {
let mut gc = br_gcm_context::default();
br_gcm_init(
ptr::addr_of_mut!(gc),
ptr::addr_of!(self.0.vtable).cast_mut(),
Some(br_ghash_ctmul),
);
br_gcm_reset(
ptr::addr_of_mut!(gc),
nonce.as_ptr() as *const c_void,
nonce.len(),
);
br_gcm_aad_inject(
ptr::addr_of_mut!(gc),
additional_data.as_ptr() as *const c_void,
additional_data.len(),
);
br_gcm_flip(ptr::addr_of_mut!(gc));
br_gcm_run(
ptr::addr_of_mut!(gc),
0,
data.as_mut_ptr() as *mut c_void,
data.len(),
);
br_gcm_check_tag(ptr::addr_of_mut!(gc), tag.as_ptr() as *mut c_void)
};
if ret == 1 {
Ok(())
} else {
Err(OpenError::Authentication)
}
}
}
#[cfg(feature = "committing-aead")]
mod committing {
use super::{Aes256Gcm, Sha256};
use crate::rust::Aes256;
crate::aead::utc_aead!(Cmt1Aes256Gcm, Aes256Gcm, Aes256, "CMT-1 AES-256-GCM.");
crate::aead::hte_aead!(Cmt4Aes256Gcm, Cmt1Aes256Gcm, Sha256, "CMT-4 AES-256-GCM.");
}
#[cfg(feature = "committing-aead")]
#[cfg_attr(docsrs, doc(cfg(feature = "committing-aead")))]
pub use committing::*;
macro_rules! curve_impl {
($name:ident, $doc:expr, $id:expr, $curve:ident) => {
#[doc = concat!($doc, ".")]
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
pub struct $name;
impl Curve for $name {
type ScalarSize = <$curve as Curve>::ScalarSize;
type CompressedSize = <$curve as Curve>::CompressedSize;
type UncompressedSize = <$curve as Curve>::UncompressedSize;
}
impl $name {
const ID: i32 = $id;
#[allow(non_upper_case_globals)]
const X_RANGE: Range<usize> = match $id {
BR_EC_secp256r1 | BR_EC_secp384r1 | BR_EC_secp521r1 => {
(1..1 + <$curve as Curve>::ScalarSize::USIZE)
}
_ => (0..<$curve as Curve>::ScalarSize::USIZE),
};
fn order() -> &'static [u8; $name::SCALAR_SIZE] {
let f = Self::get_impl().order.expect("`order` should be non-null");
let mut len = 0;
let order = unsafe { f(Self::ID, ptr::addr_of_mut!(len)) };
assert!(len == $name::SCALAR_SIZE);
unsafe { &*(order as *const [u8; $name::SCALAR_SIZE]) }
}
fn get_impl() -> &'static br_ec_impl {
#[allow(non_upper_case_globals)]
let mut ptr = match Self::ID {
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
BR_EC_secp256r1 => {
unsafe { br_ec_p256_m64_get() }
}
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
BR_EC_curve25519 => {
unsafe { br_ec_c25519_m64_get() }
}
_ => ptr::null::<br_ec_impl>(),
};
if ptr.is_null() {
ptr = unsafe { br_ec_get_default() };
}
(unsafe { ptr.as_ref() }).expect("`ptr` should not be null")
}
}
};
}
curve_impl!(P256, "NIST Curve P-256", BR_EC_secp256r1, Secp256r1);
curve_impl!(P384, "NIST Curve P-384", BR_EC_secp384r1, Secp384r1);
curve_impl!(P521, "NIST Curve P-521", BR_EC_secp521r1, Secp521r1);
curve_impl!(X25519, "Curve25519", BR_EC_curve25519, Curve25519);
dhkem_impl!(
DhKemP256HkdfSha256,
"DHKEM(P256, HKDF-SHA256)",
P256,
HkdfSha256,
P256PrivateKey,
P256PublicKey,
);
dhkem_impl!(
DhKemP521HkdfSha512,
"DHKEM(P521, HKDF-SHA512)",
P521,
HkdfSha512,
P521PrivateKey,
P521PublicKey,
);
macro_rules! ecdh_impl {
(
$curve:ident,
$doc:expr,
$sk:ident,
$pk:ident $(,)?
) => {
#[doc = concat!($doc, " ECDH private key.")]
#[derive(Clone, ZeroizeOnDrop)]
pub struct $sk {
/// The secret data.
kbuf: Scalar<$curve>,
}
impl $sk {
fn public(self: Pin<&Self>) -> $pk {
let sk = self.into();
#[cfg(debug_assertions)]
{
let n = unsafe {
br_ec_compute_pub(
$curve::get_impl(), // impl
ptr::null_mut(), // pk
ptr::null_mut(), // kbuf
ptr::addr_of!(sk), // sk
)
};
assert_eq!(n, <$curve as Curve>::UncompressedSize::USIZE);
}
let mut kbuf = Uncompressed::default();
unsafe {
br_ec_compute_pub(
$curve::get_impl(), ptr::null_mut(), kbuf.as_mut_ptr() as *mut c_void, ptr::addr_of!(sk), );
}
$pk { kbuf }
}
}
impl DecapKey for $sk {
type EncapKey = $pk;
#[inline]
fn public(&self) -> Result<$pk, PkError> {
let p = Pin::new(self);
Ok(Self::public(p))
}
}
impl SecretKey for $sk {
fn new<R: Csprng>(rng: &mut R) -> Self {
let mut rng = RngWrapper::new(rng);
#[cfg(debug_assertions)]
{
let n = unsafe {
br_ec_keygen(
ptr::addr_of_mut!(rng.vtable), $curve::get_impl(), ptr::null_mut(), ptr::null_mut(), $curve::ID, )
};
assert_eq!(n, $curve::SCALAR_SIZE);
}
let mut kbuf = Scalar::default();
unsafe {
br_ec_keygen(
ptr::addr_of_mut!(rng.vtable), $curve::get_impl(), ptr::null_mut(), kbuf.as_mut_ptr() as *mut c_void, $curve::ID, );
}
Self { kbuf }
}
type Size = <$curve as Curve>::ScalarSize;
#[inline]
fn try_export_secret(&self) -> Result<SecretKeyBytes<Self::Size>, ExportError> {
Ok(SecretKeyBytes::new(self.kbuf.0.into()))
}
}
impl ConstantTimeEq for $sk {
fn ct_eq(&self, other: &Self) -> Choice {
self.kbuf.ct_eq(&other.kbuf)
}
}
#[cfg(test)]
impl Debug for $sk {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.kbuf.to_hex())
}
}
impl Import<SecretKeyBytes<<Self as SecretKey>::Size>> for $sk {
#[inline]
fn import(
data: SecretKeyBytes<<Self as SecretKey>::Size>,
) -> Result<Self, ImportError> {
Self::import(data.as_bytes())
}
}
impl<'a> Import<&'a [u8]> for $sk {
fn import(data: &'a [u8]) -> Result<Self, ImportError> {
let kbuf = Scalar::import(data)?;
if !bool::from(ct_eq_zero(kbuf.as_ref())) {
return Err(ImportError::InvalidSyntax);
}
if !bool::from(ct_be_lt(kbuf.as_ref(), $curve::order())) {
return Err(ImportError::InvalidSyntax);
}
Ok(Self { kbuf })
}
}
impl From<Pin<&$sk>> for br_ec_private_key {
fn from(sk: Pin<&$sk>) -> Self {
Self {
curve: $curve::ID,
x: sk.kbuf.as_ptr() as *mut u8,
xlen: $curve::SCALAR_SIZE,
}
}
}
#[doc = concat!($doc, " ECDH public key.")]
#[derive(Clone, Eq, PartialEq)]
pub struct $pk {
/// The public data.
kbuf: Uncompressed<$curve>,
}
impl EncapKey for $pk {}
impl PublicKey for $pk {
type Data = Uncompressed<$curve>;
fn export(&self) -> Self::Data {
self.kbuf
}
}
impl Debug for $pk {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.kbuf.to_hex())
}
}
impl Import<Uncompressed<$curve>> for $pk {
#[inline]
fn import(data: Uncompressed<$curve>) -> Result<Self, ImportError> {
Self::import(data.borrow())
}
}
impl<'a> Import<&'a [u8]> for $pk {
#[inline]
fn import(data: &'a [u8]) -> Result<Self, ImportError> {
let kbuf = Uncompressed::import(data)?;
Ok(Self { kbuf })
}
}
impl From<Pin<&$pk>> for br_ec_public_key {
fn from(pk: Pin<&$pk>) -> Self {
Self {
curve: $curve::ID,
q: pk.kbuf.as_ptr() as *mut u8,
qlen: <$curve as Curve>::UncompressedSize::USIZE,
}
}
}
impl Ecdh for $curve {
const SCALAR_SIZE: usize = <$curve as Curve>::ScalarSize::USIZE;
type PrivateKey = $sk;
type PublicKey = $pk;
type SharedSecret = SharedSecret<{ $curve::SCALAR_SIZE }>;
fn ecdh(
local: &Self::PrivateKey,
remote: &Self::PublicKey,
) -> Result<Self::SharedSecret, EcdhError> {
let mut g = Zeroizing::new(remote.kbuf);
let f = Self::get_impl().mul.expect("`mul` should be non-null");
let ret = unsafe {
f(
g.as_mut_ptr(), g.len(), local.kbuf.as_ptr(), local.kbuf.len(), Self::ID, )
};
if ret == 1 {
let dh = g.as_ref()[$curve::X_RANGE]
.try_into()
.expect("DH value should have an exact length");
Ok(dh)
} else {
Err(EcdhError::Other("point not on curve"))
}
}
}
};
}
ecdh_impl!(P256, "P-256", P256PrivateKey, P256PublicKey);
ecdh_impl!(P384, "P-384", P384PrivateKey, P384PublicKey);
ecdh_impl!(P521, "P-521", P521PrivateKey, P521PublicKey);
ecdh_impl!(X25519, "X25519", X25519PrivateKey, X25519PublicKey);
macro_rules! ecdsa_impl {
(
$curve:ident,
$doc:expr,
$hash:ident,
$sk:ident,
$pk:ident,
$sig:ident $(,)?
) => {
#[doc = concat!($doc, " ECDSA private key.")]
#[derive(Clone, ZeroizeOnDrop)]
pub struct $sk {
/// The secret data.
kbuf: Scalar<$curve>,
}
impl $sk {
fn sign(self: Pin<&Self>, msg: &[u8]) -> Result<$sig, SignerError> {
let digest = $hash::hash(msg);
let sk = self.into();
let mut raw = RawSig::<{ raw_sig_len($curve::SCALAR_SIZE * 8) }>::default();
let len = unsafe {
br_ecdsa_i31_sign_raw(
$curve::get_impl() as *const br_ec_impl,
$hash::vtable(),
digest.as_ptr() as *const c_void,
ptr::addr_of!(sk),
raw.as_mut_ptr() as *mut c_void,
)
};
assert!(len != 0);
Ok($sig::from_raw(raw)?)
}
fn public(self: Pin<&Self>) -> $pk {
let sk = self.into();
#[cfg(debug_assertions)]
{
let n = unsafe {
br_ec_compute_pub(
$curve::get_impl(), ptr::null_mut(), ptr::null_mut(), ptr::addr_of!(sk), )
};
assert_eq!(n, <$curve as Curve>::UncompressedSize::USIZE);
}
let mut kbuf = Uncompressed::default();
unsafe {
br_ec_compute_pub(
$curve::get_impl(), ptr::null_mut(), kbuf.as_mut_ptr() as *mut c_void, ptr::addr_of!(sk), );
}
$pk { kbuf }
}
}
impl SigningKey<$curve> for $sk {
#[inline]
fn sign(&self, msg: &[u8]) -> Result<$sig, SignerError> {
let p = Pin::new(self);
$sk::sign(p, msg)
}
#[inline]
fn public(&self) -> Result<$pk, PkError> {
let p = Pin::new(self);
Ok(Self::public(p))
}
}
impl SecretKey for $sk {
#[inline]
fn new<R: Csprng>(rng: &mut R) -> Self {
let mut rng = RngWrapper::new(rng);
#[cfg(debug_assertions)]
{
let n = unsafe {
br_ec_keygen(
ptr::addr_of_mut!(rng.vtable), $curve::get_impl(), ptr::null_mut(), ptr::null_mut(), $curve::ID, )
};
assert_eq!(n, $curve::SCALAR_SIZE);
}
let mut kbuf = Scalar::default();
let len = unsafe {
br_ec_keygen(
ptr::addr_of_mut!(rng.vtable), $curve::get_impl(), ptr::null_mut(), kbuf.as_mut_ptr() as *mut c_void, $curve::ID, )
};
assert!(len == kbuf.len());
Self { kbuf }
}
type Size = <$curve as Curve>::ScalarSize;
#[inline]
fn try_export_secret(&self) -> Result<SecretKeyBytes<Self::Size>, ExportError> {
Ok(SecretKeyBytes::new(self.kbuf.0.into()))
}
}
#[cfg(test)]
impl Debug for $sk {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.kbuf.to_hex())
}
}
impl ConstantTimeEq for $sk {
fn ct_eq(&self, other: &Self) -> Choice {
self.kbuf.ct_eq(&other.kbuf)
}
}
impl Import<Scalar<$curve>> for $sk {
#[inline]
fn import(data: Scalar<$curve>) -> Result<Self, ImportError> {
Self::import(data.borrow())
}
}
impl<'a> Import<&'a [u8]> for $sk {
fn import(data: &'a [u8]) -> Result<Self, ImportError> {
let kbuf = Scalar::import(data)?;
if !bool::from(ct_eq_zero(kbuf.as_ref())) {
return Err(ImportError::InvalidSyntax);
}
if !bool::from(ct_be_lt(kbuf.as_ref(), $curve::order())) {
return Err(ImportError::InvalidSyntax);
}
Ok(Self { kbuf })
}
}
impl From<Pin<&$sk>> for br_ec_private_key {
fn from(sk: Pin<&$sk>) -> Self {
Self {
curve: $curve::ID,
x: sk.kbuf.as_ptr() as *mut u8,
xlen: $curve::SCALAR_SIZE,
}
}
}
#[doc = concat!($doc, " ECDSA public key.")]
#[derive(Clone, Eq, PartialEq)]
pub struct $pk {
/// The public data.
kbuf: Uncompressed<$curve>,
}
impl $pk {
fn verify(self: Pin<&Self>, msg: &[u8], sig: &$sig) -> Result<(), SignerError> {
let digest = $hash::hash(msg);
let pk = self.into();
let raw: RawSig<{ raw_sig_len($curve::SCALAR_SIZE * 8) }> = sig.to_raw()?;
let ret = unsafe {
br_ecdsa_i31_vrfy_raw(
$curve::get_impl() as *const br_ec_impl,
digest.as_ptr() as *const c_void,
digest.len(),
ptr::addr_of!(pk),
raw.as_ptr() as *const c_void,
raw.len(),
)
};
if ret == 1 {
Ok(())
} else {
Err(SignerError::Verification)
}
}
}
impl VerifyingKey<$curve> for $pk {
#[inline]
fn verify(&self, msg: &[u8], sig: &$sig) -> Result<(), SignerError> {
let p = Pin::new(self);
$pk::verify(p, msg, sig)
}
}
impl PublicKey for $pk {
type Data = Uncompressed<$curve>;
#[inline]
fn export(&self) -> Self::Data {
self.kbuf
}
}
impl Debug for $pk {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.kbuf.to_hex())
}
}
impl Import<Uncompressed<$curve>> for $pk {
#[inline]
fn import(data: Uncompressed<$curve>) -> Result<Self, ImportError> {
Self::import(data.borrow())
}
}
impl<'a> Import<&'a [u8]> for $pk {
#[inline]
fn import(data: &'a [u8]) -> Result<Self, ImportError> {
let kbuf = Uncompressed::import(data)?;
Ok(Self { kbuf })
}
}
impl From<Pin<&$pk>> for br_ec_public_key {
fn from(pk: Pin<&$pk>) -> Self {
Self {
curve: $curve::ID,
q: pk.kbuf.as_ptr() as *mut u8,
qlen: <$curve as Curve>::UncompressedSize::USIZE,
}
}
}
#[doc = concat!($doc, " ECDSA signature.")]
pub type $sig = Sig<$curve, { max_sig_len::<{ $curve::SCALAR_SIZE * 8 }>() }>;
impl Signer for $curve {
const ID: SignerId = SignerId::$curve;
type SigningKey = $sk;
type VerifyingKey = $pk;
type Signature = $sig;
}
};
}
ecdsa_impl!(
P256,
"NIST Curve P-256",
Sha256,
P256SigningKey,
P256VerifyingKey,
P256Signature,
);
ecdsa_impl!(
P384,
"NIST Curve P-384",
Sha384,
P384SigningKey,
P384VerifyingKey,
P384Signature,
);
ecdsa_impl!(
P521,
"NIST Curve P-521",
Sha512,
P521SigningKey,
P521VerifyingKey,
P521Signature,
);
macro_rules! hash_impl {
(
$name:ident,
$doc:expr,
$ctx:ident,
$vtable:ident,
$digest_size:expr,
$block_size:expr,
$init:ident,
$update:ident,
$digest:ident $(,)?
) => {
#[doc = concat!($doc, ".")]
#[derive(Copy, Clone, Debug, Default)]
pub struct $name($ctx);
impl $name {
fn vtable() -> *const br_hash_class {
#[allow(unused_unsafe)]
unsafe {
ptr::addr_of!($vtable)
}
}
}
impl Hash for $name {
const ID: HashId = HashId::$name;
type DigestSize = U<{ $digest_size as usize }>;
const DIGEST_SIZE: usize = $digest_size as usize;
const BLOCK_SIZE: usize = $block_size;
type Block = Block<{ Self::BLOCK_SIZE }>;
#[inline]
fn new() -> Self {
let mut ctx = $ctx::default();
unsafe { $init(&mut ctx) }
Self(ctx)
}
#[inline]
fn update(&mut self, data: &[u8]) {
unsafe {
$update(
ptr::addr_of_mut!(self.0),
data.as_ptr() as *const c_void,
data.len(),
)
}
}
#[inline]
fn digest(mut self) -> Digest<Self::DigestSize> {
let mut out = Digest::default();
unsafe { $digest(ptr::addr_of_mut!(self.0), out.as_mut_ptr() as *mut c_void) }
out
}
}
};
}
hash_impl!(
Sha256,
"SHA-256",
br_sha256_context,
br_sha256_vtable,
br_sha256_SIZE,
64,
br_sha256_init,
br_sha256_update,
br_sha256_out,
);
hash_impl!(
Sha384,
"SHA-384",
br_sha384_context,
br_sha384_vtable,
br_sha384_SIZE,
128,
br_sha384_init,
br_sha384_update,
br_sha384_out,
);
hash_impl!(
Sha512,
"SHA-512",
br_sha512_context,
br_sha512_vtable,
br_sha512_SIZE,
128,
br_sha512_init,
br_sha512_update,
br_sha512_out,
);
hkdf_impl!(HkdfSha256, "HKDF-SHA256", Sha256);
hkdf_impl!(HkdfSha384, "HKDF-SHA384", Sha384);
hkdf_impl!(HkdfSha512, "HKDF-SHA512", Sha512);
hmac_impl!(HmacSha256, "HMAC-SHA256", Sha256);
hmac_impl!(HmacSha384, "HMAC-SHA384", Sha384);
hmac_impl!(HmacSha512, "HMAC-SHA512", Sha512);
pub struct HmacDrbg(br_hmac_drbg_context);
impl HmacDrbg {
pub fn new(seed: [u8; 64]) -> Self {
let mut ctx = br_hmac_drbg_context::default();
unsafe {
br_hmac_drbg_init(
ptr::addr_of_mut!(ctx),
ptr::addr_of!(br_sha256_vtable),
seed.as_ptr() as *const c_void,
seed.len(),
);
}
Self(ctx)
}
pub fn from_rng<R: Csprng>(rng: &mut R) -> Self {
let mut seed = [0u8; 64];
rng.fill_bytes(&mut seed);
HmacDrbg::new(seed)
}
}
impl Csprng for HmacDrbg {
fn fill_bytes(&mut self, mut dst: &mut [u8]) {
const MAX: usize = 1 << 16;
while !dst.is_empty() {
let n = cmp::min(dst.len(), MAX);
unsafe {
br_hmac_drbg_generate(
ptr::addr_of_mut!(self.0),
dst.as_mut_ptr() as *mut c_void,
n,
);
}
dst = &mut dst[n..];
}
}
}
static RNG_WRAPPER_VTABLE: br_prng_class = br_prng_class {
context_size: size_of::<RngWrapper<'_>>(),
init: Some(rng_wrapper_init),
generate: Some(rng_wrapper_generate),
update: Some(rng_wrapper_update),
};
unsafe extern "C" fn rng_wrapper_init(
_ctx: *mut *const br_prng_class,
_params: *const c_void,
_seed: *const c_void,
_seed_len: usize,
) {
}
unsafe extern "C" fn rng_wrapper_update(
_ctx: *mut *const br_prng_class,
_seed: *const c_void,
_seed_len: usize,
) {
}
unsafe extern "C" fn rng_wrapper_generate(
ctx: *mut *const br_prng_class,
out: *mut c_void,
len: usize,
) {
let rng = unsafe { &mut *(ctx as *mut RngWrapper<'_>) };
let dst = unsafe { slice::from_raw_parts_mut(out as *mut u8, len) };
rng.rng.fill_bytes(dst)
}
#[repr(C)]
struct RngWrapper<'a> {
vtable: *const br_prng_class,
rng: &'a mut dyn Csprng,
}
impl<'a> RngWrapper<'a> {
fn new(rng: &'a mut dyn Csprng) -> Self {
let vtable = ptr::addr_of!(RNG_WRAPPER_VTABLE);
RngWrapper { vtable, rng }
}
}
#[cfg(test)]
mod tests {
use super::*;
mod ct_test {
use super::*;
#[test]
fn test_ct_be_lt() {
struct TestCase(u8, &'static [u8], &'static [u8]);
let tests = &[
TestCase(0u8, &[], &[]),
TestCase(0u8, &[0], &[0]),
TestCase(0u8, &[1], &[1]),
TestCase(0u8, &[1, 1], &[1, 1]),
TestCase(1u8, &[1, 0], &[1, 1]),
TestCase(1u8, &[0, 1], &[1, 1]),
TestCase(0u8, &[2, 1], &[2, 0]),
TestCase(0u8, &[2, 1], &[2, 0]),
TestCase(1u8, &[2, 0], &[2, 1]),
];
for (i, tc) in tests.iter().enumerate() {
assert_eq!(tc.0, ct_be_lt(tc.1, tc.2).unwrap_u8(), "tc={i}");
}
}
}
mod ciphersuite_tests {
use super::*;
use crate::test_util::{test_ciphersuite, TestCs};
test_ciphersuite!(p256, TestCs<
Aes256Gcm,
Sha512,
HkdfSha256,
DhKemP256HkdfSha256,
HmacSha512,
P256,
>);
test_ciphersuite!(p384, TestCs<
Aes256Gcm,
Sha512,
HkdfSha384,
DhKemP256HkdfSha256, HmacSha512,
P384,
>);
test_ciphersuite!(p521, TestCs<
Aes256Gcm,
Sha512,
HkdfSha512,
DhKemP521HkdfSha512,
HmacSha512,
P521,
>);
}
mod aead_tests {
use super::*;
use crate::test_util::test_aead;
test_aead!(aes256gcm, Aes256Gcm, AeadTest::AesGcm);
#[cfg(feature = "committing-aead")]
mod committing {
use super::*;
test_aead!(cmd1_aead_aes256_gcm, Cmt1Aes256Gcm);
test_aead!(cmd4_aead_aes256_gcm, Cmt4Aes256Gcm);
}
}
mod ecdh_tests {
use super::*;
use crate::test_util::vectors::{test_ecdh, EcdhTest};
#[test]
fn test_ecdh_p256() {
test_ecdh::<P256>(EcdhTest::EcdhSecp256r1Ecpoint);
}
#[test]
fn test_ecdh_p384() {
test_ecdh::<P384>(EcdhTest::EcdhSecp384r1Ecpoint);
}
}
mod ecdsa_tests {
use super::*;
use crate::test_util::test_signer;
test_signer!(p256, P256, EcdsaTest::EcdsaSecp256r1Sha256);
test_signer!(p384, P384, EcdsaTest::EcdsaSecp384r1Sha384);
test_signer!(p521, P521, EcdsaTest::EcdsaSecp521r1Sha512);
}
mod hkdf_tests {
use super::*;
use crate::test_util::test_kdf;
test_kdf!(test_hkdf_sha256, HkdfSha256, HkdfTest::HkdfSha256);
test_kdf!(test_hkdf_sha384, HkdfSha384, HkdfTest::HkdfSha384);
test_kdf!(test_hkdf_sha512, HkdfSha512, HkdfTest::HkdfSha512);
}
mod hmac_tests {
use super::*;
use crate::test_util::test_mac;
test_mac!(test_hmac_sha256, HmacSha256, MacTest::HmacSha256);
test_mac!(test_hmac_sha384, HmacSha384, MacTest::HmacSha384);
test_mac!(test_hmac_sha512, HmacSha512, MacTest::HmacSha512);
}
mod hpke_tests {
use super::*;
use crate::test_util::test_hpke;
test_hpke!(
p256_hkdf_sha256,
DhKemP256HkdfSha256,
HkdfSha256,
Aes256Gcm,
HpkeTest::HpkeDhKemP256HkdfSha256HkdfSha256Aes256Gcm,
);
test_hpke!(
p256_hkdf_sha512,
DhKemP256HkdfSha256,
HkdfSha512,
Aes256Gcm,
HpkeTest::HpkeDhKemP256HkdfSha256HkdfSha512Aes256Gcm,
);
test_hpke!(
p521_hkdf_sha256,
DhKemP521HkdfSha512,
HkdfSha256,
Aes256Gcm,
HpkeTest::HpkeDhKemP521HkdfSha512HkdfSha256Aes256Gcm,
);
test_hpke!(
p521_hkdf_sha512,
DhKemP521HkdfSha512,
HkdfSha512,
Aes256Gcm,
HpkeTest::HpkeDhKemP521HkdfSha512HkdfSha512Aes256Gcm,
);
}
}