wtx 0.45.0

A collection of different transport implementations and related tools focused primarily on web technologies.
Documentation
use crate::{
  crypto::{Agreement, CryptoError, P256Openssl, P384Openssl, X25519Openssl},
  rng::CryptoRng,
};
use openssl::{
  bn::BigNumContext,
  derive::Deriver,
  ec::{EcGroup, EcKey, EcPoint, PointConversionForm},
  nid::Nid,
  pkey::{PKey, Private},
};

impl Agreement for P256Openssl {
  type EphemeralSecretKey = PKey<Private>;
  type PublicKey = [u8; 65];
  type SharedSecret = [u8; 32];

  #[inline]
  fn diffie_hellman(
    esk: Self::EphemeralSecretKey,
    other_participant_pk: &[u8],
  ) -> crate::Result<Self::SharedSecret> {
    local_diffie_hellman(Nid::X9_62_PRIME256V1, esk, other_participant_pk)
  }

  #[inline]
  fn ephemeral_secret_key<RNG>(_: &mut RNG) -> crate::Result<Self::EphemeralSecretKey>
  where
    RNG: CryptoRng,
  {
    let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)?;
    Ok(PKey::from_ec_key(EcKey::generate(&group)?)?)
  }

  #[inline]
  fn public_key(esk: &Self::EphemeralSecretKey) -> crate::Result<Self::PublicKey> {
    let ec_key = esk.ec_key()?;
    let mut ctx = BigNumContext::new()?;
    let mut bytes = [0u8; 65];
    bytes.copy_from_slice(&ec_key.public_key().to_bytes(
      ec_key.group(),
      PointConversionForm::UNCOMPRESSED,
      &mut ctx,
    )?);
    Ok(bytes)
  }
}

impl Agreement for P384Openssl {
  type EphemeralSecretKey = PKey<Private>;
  type PublicKey = [u8; 97];
  type SharedSecret = [u8; 48];

  #[inline]
  fn diffie_hellman(
    esk: Self::EphemeralSecretKey,
    other_participant_pk: &[u8],
  ) -> crate::Result<Self::SharedSecret> {
    local_diffie_hellman(Nid::SECP384R1, esk, other_participant_pk)
  }

  #[inline]
  fn ephemeral_secret_key<RNG>(_: &mut RNG) -> crate::Result<Self::EphemeralSecretKey>
  where
    RNG: CryptoRng,
  {
    let group = EcGroup::from_curve_name(Nid::SECP384R1)?;
    Ok(PKey::from_ec_key(EcKey::generate(&group)?)?)
  }

  #[inline]
  fn public_key(esk: &Self::EphemeralSecretKey) -> crate::Result<Self::PublicKey> {
    let ec_key = esk.ec_key()?;
    let mut ctx = BigNumContext::new()?;
    let mut bytes = [0u8; 97];
    bytes.copy_from_slice(&ec_key.public_key().to_bytes(
      ec_key.group(),
      PointConversionForm::UNCOMPRESSED,
      &mut ctx,
    )?);
    Ok(bytes)
  }
}

impl Agreement for X25519Openssl {
  type EphemeralSecretKey = PKey<Private>;
  type PublicKey = [u8; 32];
  type SharedSecret = [u8; 32];

  #[inline]
  fn diffie_hellman(
    esk: Self::EphemeralSecretKey,
    other_participant_pk: &[u8],
  ) -> crate::Result<Self::SharedSecret> {
    let peer = PKey::public_key_from_raw_bytes(other_participant_pk, esk.id())?;
    let mut deriver = Deriver::new(&esk)?;
    deriver.set_peer(&peer)?;
    let mut secret = [0; 32];
    let _ = deriver.derive(&mut secret)?;
    Ok(secret)
  }

  #[inline]
  fn ephemeral_secret_key<RNG>(_: &mut RNG) -> crate::Result<Self::EphemeralSecretKey>
  where
    RNG: CryptoRng,
  {
    Ok(PKey::generate_x25519()?)
  }

  #[inline]
  fn public_key(esk: &Self::EphemeralSecretKey) -> crate::Result<Self::PublicKey> {
    esk.raw_public_key()?.try_into().map_err(|_err| CryptoError::PublicKeyAgreementError.into())
  }
}

fn local_diffie_hellman<const N: usize>(
  nid: Nid,
  esk: PKey<Private>,
  other_participant_pk: &[u8],
) -> crate::Result<[u8; N]> {
  let group = EcGroup::from_curve_name(nid)?;
  let mut ctx = BigNumContext::new()?;
  let point = EcPoint::from_bytes(&group, other_participant_pk, &mut ctx)?;
  let peer = PKey::from_ec_key(EcKey::from_public_key(&group, &point)?)?;
  let mut deriver = Deriver::new(&esk)?;
  deriver.set_peer(&peer)?;
  let mut secret = [0; N];
  let _ = deriver.derive(&mut secret)?;
  Ok(secret)
}