1*e1997b9aSAndroid Build Coastguard Worker // Copyright 2024, The Android Open Source Project 2*e1997b9aSAndroid Build Coastguard Worker // 3*e1997b9aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); 4*e1997b9aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License. 5*e1997b9aSAndroid Build Coastguard Worker // You may obtain a copy of the License at 6*e1997b9aSAndroid Build Coastguard Worker // 7*e1997b9aSAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0 8*e1997b9aSAndroid Build Coastguard Worker // 9*e1997b9aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 10*e1997b9aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, 11*e1997b9aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*e1997b9aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and 13*e1997b9aSAndroid Build Coastguard Worker // limitations under the License. 14*e1997b9aSAndroid Build Coastguard Worker 15*e1997b9aSAndroid Build Coastguard Worker //! Elliptic curve Diffie–Hellman. 16*e1997b9aSAndroid Build Coastguard Worker 17*e1997b9aSAndroid Build Coastguard Worker use bssl_crypto::x25519; 18*e1997b9aSAndroid Build Coastguard Worker use mls_rs_core::crypto::{CipherSuite, HpkePublicKey, HpkeSecretKey}; 19*e1997b9aSAndroid Build Coastguard Worker use mls_rs_core::error::IntoAnyError; 20*e1997b9aSAndroid Build Coastguard Worker use mls_rs_crypto_traits::{Curve, DhType}; 21*e1997b9aSAndroid Build Coastguard Worker 22*e1997b9aSAndroid Build Coastguard Worker use core::array::TryFromSliceError; 23*e1997b9aSAndroid Build Coastguard Worker use thiserror::Error; 24*e1997b9aSAndroid Build Coastguard Worker 25*e1997b9aSAndroid Build Coastguard Worker /// Errors returned from ECDH. 26*e1997b9aSAndroid Build Coastguard Worker #[derive(Debug, Error)] 27*e1997b9aSAndroid Build Coastguard Worker pub enum EcdhError { 28*e1997b9aSAndroid Build Coastguard Worker /// Error returned when conversion from slice to array fails. 29*e1997b9aSAndroid Build Coastguard Worker #[error(transparent)] 30*e1997b9aSAndroid Build Coastguard Worker TryFromSliceError(#[from] TryFromSliceError), 31*e1997b9aSAndroid Build Coastguard Worker /// Error returned when the public key is invalid. 32*e1997b9aSAndroid Build Coastguard Worker #[error("ECDH public key was invalid")] 33*e1997b9aSAndroid Build Coastguard Worker InvalidPubKey, 34*e1997b9aSAndroid Build Coastguard Worker /// Error returned when the private key length is invalid. 35*e1997b9aSAndroid Build Coastguard Worker #[error("ECDH private key of invalid length {len}, expected length {expected_len}")] 36*e1997b9aSAndroid Build Coastguard Worker InvalidPrivKeyLen { 37*e1997b9aSAndroid Build Coastguard Worker /// Invalid key length. 38*e1997b9aSAndroid Build Coastguard Worker len: usize, 39*e1997b9aSAndroid Build Coastguard Worker /// Expected key length. 40*e1997b9aSAndroid Build Coastguard Worker expected_len: usize, 41*e1997b9aSAndroid Build Coastguard Worker }, 42*e1997b9aSAndroid Build Coastguard Worker /// Error returned when the public key length is invalid. 43*e1997b9aSAndroid Build Coastguard Worker #[error("ECDH public key of invalid length {len}, expected length {expected_len}")] 44*e1997b9aSAndroid Build Coastguard Worker InvalidPubKeyLen { 45*e1997b9aSAndroid Build Coastguard Worker /// Invalid key length. 46*e1997b9aSAndroid Build Coastguard Worker len: usize, 47*e1997b9aSAndroid Build Coastguard Worker /// Expected key length. 48*e1997b9aSAndroid Build Coastguard Worker expected_len: usize, 49*e1997b9aSAndroid Build Coastguard Worker }, 50*e1997b9aSAndroid Build Coastguard Worker /// Error returned when unsupported cipher suite is requested. 51*e1997b9aSAndroid Build Coastguard Worker #[error("unsupported cipher suite")] 52*e1997b9aSAndroid Build Coastguard Worker UnsupportedCipherSuite, 53*e1997b9aSAndroid Build Coastguard Worker } 54*e1997b9aSAndroid Build Coastguard Worker 55*e1997b9aSAndroid Build Coastguard Worker impl IntoAnyError for EcdhError { into_dyn_error(self) -> Result<Box<dyn std::error::Error + Send + Sync>, Self>56*e1997b9aSAndroid Build Coastguard Worker fn into_dyn_error(self) -> Result<Box<dyn std::error::Error + Send + Sync>, Self> { 57*e1997b9aSAndroid Build Coastguard Worker Ok(self.into()) 58*e1997b9aSAndroid Build Coastguard Worker } 59*e1997b9aSAndroid Build Coastguard Worker } 60*e1997b9aSAndroid Build Coastguard Worker 61*e1997b9aSAndroid Build Coastguard Worker /// DhType implementation backed by BoringSSL. 62*e1997b9aSAndroid Build Coastguard Worker #[derive(Clone, Debug, Eq, PartialEq)] 63*e1997b9aSAndroid Build Coastguard Worker pub struct Ecdh(Curve); 64*e1997b9aSAndroid Build Coastguard Worker 65*e1997b9aSAndroid Build Coastguard Worker impl Ecdh { 66*e1997b9aSAndroid Build Coastguard Worker /// Creates a new Ecdh. new(cipher_suite: CipherSuite) -> Option<Self>67*e1997b9aSAndroid Build Coastguard Worker pub fn new(cipher_suite: CipherSuite) -> Option<Self> { 68*e1997b9aSAndroid Build Coastguard Worker Curve::from_ciphersuite(cipher_suite, /*for_sig=*/ false).map(Self) 69*e1997b9aSAndroid Build Coastguard Worker } 70*e1997b9aSAndroid Build Coastguard Worker } 71*e1997b9aSAndroid Build Coastguard Worker 72*e1997b9aSAndroid Build Coastguard Worker #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)] 73*e1997b9aSAndroid Build Coastguard Worker #[cfg_attr(all(target_arch = "wasm32", mls_build_async), maybe_async::must_be_async(?Send))] 74*e1997b9aSAndroid Build Coastguard Worker #[cfg_attr(all(not(target_arch = "wasm32"), mls_build_async), maybe_async::must_be_async)] 75*e1997b9aSAndroid Build Coastguard Worker impl DhType for Ecdh { 76*e1997b9aSAndroid Build Coastguard Worker type Error = EcdhError; 77*e1997b9aSAndroid Build Coastguard Worker dh( &self, secret_key: &HpkeSecretKey, public_key: &HpkePublicKey, ) -> Result<Vec<u8>, Self::Error>78*e1997b9aSAndroid Build Coastguard Worker async fn dh( 79*e1997b9aSAndroid Build Coastguard Worker &self, 80*e1997b9aSAndroid Build Coastguard Worker secret_key: &HpkeSecretKey, 81*e1997b9aSAndroid Build Coastguard Worker public_key: &HpkePublicKey, 82*e1997b9aSAndroid Build Coastguard Worker ) -> Result<Vec<u8>, Self::Error> { 83*e1997b9aSAndroid Build Coastguard Worker if self.0 != Curve::X25519 { 84*e1997b9aSAndroid Build Coastguard Worker return Err(EcdhError::UnsupportedCipherSuite); 85*e1997b9aSAndroid Build Coastguard Worker } 86*e1997b9aSAndroid Build Coastguard Worker if secret_key.len() != x25519::PRIVATE_KEY_LEN { 87*e1997b9aSAndroid Build Coastguard Worker return Err(EcdhError::InvalidPrivKeyLen { 88*e1997b9aSAndroid Build Coastguard Worker len: secret_key.len(), 89*e1997b9aSAndroid Build Coastguard Worker expected_len: x25519::PRIVATE_KEY_LEN, 90*e1997b9aSAndroid Build Coastguard Worker }); 91*e1997b9aSAndroid Build Coastguard Worker } 92*e1997b9aSAndroid Build Coastguard Worker if public_key.len() != x25519::PUBLIC_KEY_LEN { 93*e1997b9aSAndroid Build Coastguard Worker return Err(EcdhError::InvalidPubKeyLen { 94*e1997b9aSAndroid Build Coastguard Worker len: public_key.len(), 95*e1997b9aSAndroid Build Coastguard Worker expected_len: x25519::PUBLIC_KEY_LEN, 96*e1997b9aSAndroid Build Coastguard Worker }); 97*e1997b9aSAndroid Build Coastguard Worker } 98*e1997b9aSAndroid Build Coastguard Worker 99*e1997b9aSAndroid Build Coastguard Worker let private_key = x25519::PrivateKey(secret_key[..x25519::PRIVATE_KEY_LEN].try_into()?); 100*e1997b9aSAndroid Build Coastguard Worker match private_key.compute_shared_key(public_key[..x25519::PUBLIC_KEY_LEN].try_into()?) { 101*e1997b9aSAndroid Build Coastguard Worker Some(x) => Ok(x.to_vec()), 102*e1997b9aSAndroid Build Coastguard Worker None => Err(EcdhError::InvalidPubKey), 103*e1997b9aSAndroid Build Coastguard Worker } 104*e1997b9aSAndroid Build Coastguard Worker } 105*e1997b9aSAndroid Build Coastguard Worker to_public(&self, secret_key: &HpkeSecretKey) -> Result<HpkePublicKey, Self::Error>106*e1997b9aSAndroid Build Coastguard Worker async fn to_public(&self, secret_key: &HpkeSecretKey) -> Result<HpkePublicKey, Self::Error> { 107*e1997b9aSAndroid Build Coastguard Worker if self.0 != Curve::X25519 { 108*e1997b9aSAndroid Build Coastguard Worker return Err(EcdhError::UnsupportedCipherSuite); 109*e1997b9aSAndroid Build Coastguard Worker } 110*e1997b9aSAndroid Build Coastguard Worker if secret_key.len() != x25519::PRIVATE_KEY_LEN { 111*e1997b9aSAndroid Build Coastguard Worker return Err(EcdhError::InvalidPrivKeyLen { 112*e1997b9aSAndroid Build Coastguard Worker len: secret_key.len(), 113*e1997b9aSAndroid Build Coastguard Worker expected_len: x25519::PRIVATE_KEY_LEN, 114*e1997b9aSAndroid Build Coastguard Worker }); 115*e1997b9aSAndroid Build Coastguard Worker } 116*e1997b9aSAndroid Build Coastguard Worker 117*e1997b9aSAndroid Build Coastguard Worker let private_key = x25519::PrivateKey(secret_key[..x25519::PRIVATE_KEY_LEN].try_into()?); 118*e1997b9aSAndroid Build Coastguard Worker Ok(private_key.to_public().to_vec().into()) 119*e1997b9aSAndroid Build Coastguard Worker } 120*e1997b9aSAndroid Build Coastguard Worker generate(&self) -> Result<(HpkeSecretKey, HpkePublicKey), Self::Error>121*e1997b9aSAndroid Build Coastguard Worker async fn generate(&self) -> Result<(HpkeSecretKey, HpkePublicKey), Self::Error> { 122*e1997b9aSAndroid Build Coastguard Worker if self.0 != Curve::X25519 { 123*e1997b9aSAndroid Build Coastguard Worker return Err(EcdhError::UnsupportedCipherSuite); 124*e1997b9aSAndroid Build Coastguard Worker } 125*e1997b9aSAndroid Build Coastguard Worker 126*e1997b9aSAndroid Build Coastguard Worker let (public_key, private_key) = x25519::PrivateKey::generate(); 127*e1997b9aSAndroid Build Coastguard Worker Ok((private_key.0.to_vec().into(), public_key.to_vec().into())) 128*e1997b9aSAndroid Build Coastguard Worker } 129*e1997b9aSAndroid Build Coastguard Worker bitmask_for_rejection_sampling(&self) -> Option<u8>130*e1997b9aSAndroid Build Coastguard Worker fn bitmask_for_rejection_sampling(&self) -> Option<u8> { 131*e1997b9aSAndroid Build Coastguard Worker self.0.curve_bitmask() 132*e1997b9aSAndroid Build Coastguard Worker } 133*e1997b9aSAndroid Build Coastguard Worker public_key_validate(&self, key: &HpkePublicKey) -> Result<(), Self::Error>134*e1997b9aSAndroid Build Coastguard Worker fn public_key_validate(&self, key: &HpkePublicKey) -> Result<(), Self::Error> { 135*e1997b9aSAndroid Build Coastguard Worker if self.0 != Curve::X25519 { 136*e1997b9aSAndroid Build Coastguard Worker return Err(EcdhError::UnsupportedCipherSuite); 137*e1997b9aSAndroid Build Coastguard Worker } 138*e1997b9aSAndroid Build Coastguard Worker 139*e1997b9aSAndroid Build Coastguard Worker // bssl_crypto does not implement validation of curve25519 public keys. 140*e1997b9aSAndroid Build Coastguard Worker // Note: Neither does x25519_dalek used by RustCrypto's implementation of this function. 141*e1997b9aSAndroid Build Coastguard Worker if key.len() != x25519::PUBLIC_KEY_LEN { 142*e1997b9aSAndroid Build Coastguard Worker return Err(EcdhError::InvalidPubKeyLen { 143*e1997b9aSAndroid Build Coastguard Worker len: key.len(), 144*e1997b9aSAndroid Build Coastguard Worker expected_len: x25519::PUBLIC_KEY_LEN, 145*e1997b9aSAndroid Build Coastguard Worker }); 146*e1997b9aSAndroid Build Coastguard Worker } 147*e1997b9aSAndroid Build Coastguard Worker Ok(()) 148*e1997b9aSAndroid Build Coastguard Worker } 149*e1997b9aSAndroid Build Coastguard Worker secret_key_size(&self) -> usize150*e1997b9aSAndroid Build Coastguard Worker fn secret_key_size(&self) -> usize { 151*e1997b9aSAndroid Build Coastguard Worker self.0.secret_key_size() 152*e1997b9aSAndroid Build Coastguard Worker } 153*e1997b9aSAndroid Build Coastguard Worker } 154*e1997b9aSAndroid Build Coastguard Worker 155*e1997b9aSAndroid Build Coastguard Worker #[cfg(all(not(mls_build_async), test))] 156*e1997b9aSAndroid Build Coastguard Worker mod test { 157*e1997b9aSAndroid Build Coastguard Worker use super::{DhType, Ecdh, EcdhError}; 158*e1997b9aSAndroid Build Coastguard Worker use crate::test_helpers::decode_hex; 159*e1997b9aSAndroid Build Coastguard Worker use assert_matches::assert_matches; 160*e1997b9aSAndroid Build Coastguard Worker use mls_rs_core::crypto::{CipherSuite, HpkePublicKey, HpkeSecretKey}; 161*e1997b9aSAndroid Build Coastguard Worker 162*e1997b9aSAndroid Build Coastguard Worker #[test] dh()163*e1997b9aSAndroid Build Coastguard Worker fn dh() { 164*e1997b9aSAndroid Build Coastguard Worker // https://github.com/C2SP/wycheproof/blob/cd27d6419bedd83cbd24611ec54b6d4bfdb0cdca/testvectors/x25519_test.json#L23 165*e1997b9aSAndroid Build Coastguard Worker let private_key = HpkeSecretKey::from( 166*e1997b9aSAndroid Build Coastguard Worker decode_hex::<32>("c8a9d5a91091ad851c668b0736c1c9a02936c0d3ad62670858088047ba057475") 167*e1997b9aSAndroid Build Coastguard Worker .to_vec(), 168*e1997b9aSAndroid Build Coastguard Worker ); 169*e1997b9aSAndroid Build Coastguard Worker let public_key = HpkePublicKey::from( 170*e1997b9aSAndroid Build Coastguard Worker decode_hex::<32>("504a36999f489cd2fdbc08baff3d88fa00569ba986cba22548ffde80f9806829") 171*e1997b9aSAndroid Build Coastguard Worker .to_vec(), 172*e1997b9aSAndroid Build Coastguard Worker ); 173*e1997b9aSAndroid Build Coastguard Worker let expected_shared_secret: [u8; 32] = 174*e1997b9aSAndroid Build Coastguard Worker decode_hex("436a2c040cf45fea9b29a0cb81b1f41458f863d0d61b453d0a982720d6d61320"); 175*e1997b9aSAndroid Build Coastguard Worker 176*e1997b9aSAndroid Build Coastguard Worker let x25519 = Ecdh::new(CipherSuite::CURVE25519_AES128).unwrap(); 177*e1997b9aSAndroid Build Coastguard Worker assert_eq!(x25519.dh(&private_key, &public_key).unwrap(), expected_shared_secret); 178*e1997b9aSAndroid Build Coastguard Worker } 179*e1997b9aSAndroid Build Coastguard Worker 180*e1997b9aSAndroid Build Coastguard Worker #[test] dh_invalid_key()181*e1997b9aSAndroid Build Coastguard Worker fn dh_invalid_key() { 182*e1997b9aSAndroid Build Coastguard Worker let x25519 = Ecdh::new(CipherSuite::CURVE25519_AES128).unwrap(); 183*e1997b9aSAndroid Build Coastguard Worker 184*e1997b9aSAndroid Build Coastguard Worker let private_key_short = 185*e1997b9aSAndroid Build Coastguard Worker HpkeSecretKey::from(decode_hex::<16>("c8a9d5a91091ad851c668b0736c1c9a0").to_vec()); 186*e1997b9aSAndroid Build Coastguard Worker let public_key = HpkePublicKey::from( 187*e1997b9aSAndroid Build Coastguard Worker decode_hex::<32>("504a36999f489cd2fdbc08baff3d88fa00569ba986cba22548ffde80f9806829") 188*e1997b9aSAndroid Build Coastguard Worker .to_vec(), 189*e1997b9aSAndroid Build Coastguard Worker ); 190*e1997b9aSAndroid Build Coastguard Worker assert_matches!( 191*e1997b9aSAndroid Build Coastguard Worker x25519.dh(&private_key_short, &public_key), 192*e1997b9aSAndroid Build Coastguard Worker Err(EcdhError::InvalidPrivKeyLen { .. }) 193*e1997b9aSAndroid Build Coastguard Worker ); 194*e1997b9aSAndroid Build Coastguard Worker 195*e1997b9aSAndroid Build Coastguard Worker let private_key = HpkeSecretKey::from( 196*e1997b9aSAndroid Build Coastguard Worker decode_hex::<32>("c8a9d5a91091ad851c668b0736c1c9a02936c0d3ad62670858088047ba057475") 197*e1997b9aSAndroid Build Coastguard Worker .to_vec(), 198*e1997b9aSAndroid Build Coastguard Worker ); 199*e1997b9aSAndroid Build Coastguard Worker let public_key_short = 200*e1997b9aSAndroid Build Coastguard Worker HpkePublicKey::from(decode_hex::<16>("504a36999f489cd2fdbc08baff3d88fa").to_vec()); 201*e1997b9aSAndroid Build Coastguard Worker assert_matches!( 202*e1997b9aSAndroid Build Coastguard Worker x25519.dh(&private_key, &public_key_short), 203*e1997b9aSAndroid Build Coastguard Worker Err(EcdhError::InvalidPubKeyLen { .. }) 204*e1997b9aSAndroid Build Coastguard Worker ); 205*e1997b9aSAndroid Build Coastguard Worker } 206*e1997b9aSAndroid Build Coastguard Worker 207*e1997b9aSAndroid Build Coastguard Worker #[test] to_public()208*e1997b9aSAndroid Build Coastguard Worker fn to_public() { 209*e1997b9aSAndroid Build Coastguard Worker // https://www.rfc-editor.org/rfc/rfc7748.html#section-6.1 210*e1997b9aSAndroid Build Coastguard Worker let private_key = HpkeSecretKey::from( 211*e1997b9aSAndroid Build Coastguard Worker decode_hex::<32>("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a") 212*e1997b9aSAndroid Build Coastguard Worker .to_vec(), 213*e1997b9aSAndroid Build Coastguard Worker ); 214*e1997b9aSAndroid Build Coastguard Worker let expected_public_key = HpkePublicKey::from( 215*e1997b9aSAndroid Build Coastguard Worker decode_hex::<32>("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a") 216*e1997b9aSAndroid Build Coastguard Worker .to_vec(), 217*e1997b9aSAndroid Build Coastguard Worker ); 218*e1997b9aSAndroid Build Coastguard Worker 219*e1997b9aSAndroid Build Coastguard Worker let x25519 = Ecdh::new(CipherSuite::CURVE25519_CHACHA).unwrap(); 220*e1997b9aSAndroid Build Coastguard Worker assert_eq!(x25519.to_public(&private_key).unwrap(), expected_public_key); 221*e1997b9aSAndroid Build Coastguard Worker } 222*e1997b9aSAndroid Build Coastguard Worker 223*e1997b9aSAndroid Build Coastguard Worker #[test] to_public_invalid_key()224*e1997b9aSAndroid Build Coastguard Worker fn to_public_invalid_key() { 225*e1997b9aSAndroid Build Coastguard Worker let private_key_short = 226*e1997b9aSAndroid Build Coastguard Worker HpkeSecretKey::from(decode_hex::<16>("c8a9d5a91091ad851c668b0736c1c9a0").to_vec()); 227*e1997b9aSAndroid Build Coastguard Worker 228*e1997b9aSAndroid Build Coastguard Worker let x25519 = Ecdh::new(CipherSuite::CURVE25519_CHACHA).unwrap(); 229*e1997b9aSAndroid Build Coastguard Worker assert_matches!( 230*e1997b9aSAndroid Build Coastguard Worker x25519.to_public(&private_key_short), 231*e1997b9aSAndroid Build Coastguard Worker Err(EcdhError::InvalidPrivKeyLen { .. }) 232*e1997b9aSAndroid Build Coastguard Worker ); 233*e1997b9aSAndroid Build Coastguard Worker } 234*e1997b9aSAndroid Build Coastguard Worker 235*e1997b9aSAndroid Build Coastguard Worker #[test] generate()236*e1997b9aSAndroid Build Coastguard Worker fn generate() { 237*e1997b9aSAndroid Build Coastguard Worker let x25519 = Ecdh::new(CipherSuite::CURVE25519_AES128).unwrap(); 238*e1997b9aSAndroid Build Coastguard Worker assert!(x25519.generate().is_ok()); 239*e1997b9aSAndroid Build Coastguard Worker } 240*e1997b9aSAndroid Build Coastguard Worker 241*e1997b9aSAndroid Build Coastguard Worker #[test] public_key_validate()242*e1997b9aSAndroid Build Coastguard Worker fn public_key_validate() { 243*e1997b9aSAndroid Build Coastguard Worker // https://www.rfc-editor.org/rfc/rfc7748.html#section-6.1 244*e1997b9aSAndroid Build Coastguard Worker let public_key = HpkePublicKey::from( 245*e1997b9aSAndroid Build Coastguard Worker decode_hex::<32>("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a") 246*e1997b9aSAndroid Build Coastguard Worker .to_vec(), 247*e1997b9aSAndroid Build Coastguard Worker ); 248*e1997b9aSAndroid Build Coastguard Worker 249*e1997b9aSAndroid Build Coastguard Worker let x25519 = Ecdh::new(CipherSuite::CURVE25519_AES128).unwrap(); 250*e1997b9aSAndroid Build Coastguard Worker assert!(x25519.public_key_validate(&public_key).is_ok()); 251*e1997b9aSAndroid Build Coastguard Worker } 252*e1997b9aSAndroid Build Coastguard Worker 253*e1997b9aSAndroid Build Coastguard Worker #[test] public_key_validate_invalid_key()254*e1997b9aSAndroid Build Coastguard Worker fn public_key_validate_invalid_key() { 255*e1997b9aSAndroid Build Coastguard Worker let public_key_short = 256*e1997b9aSAndroid Build Coastguard Worker HpkePublicKey::from(decode_hex::<16>("504a36999f489cd2fdbc08baff3d88fa").to_vec()); 257*e1997b9aSAndroid Build Coastguard Worker 258*e1997b9aSAndroid Build Coastguard Worker let x25519 = Ecdh::new(CipherSuite::CURVE25519_AES128).unwrap(); 259*e1997b9aSAndroid Build Coastguard Worker assert_matches!( 260*e1997b9aSAndroid Build Coastguard Worker x25519.public_key_validate(&public_key_short), 261*e1997b9aSAndroid Build Coastguard Worker Err(EcdhError::InvalidPubKeyLen { .. }) 262*e1997b9aSAndroid Build Coastguard Worker ); 263*e1997b9aSAndroid Build Coastguard Worker } 264*e1997b9aSAndroid Build Coastguard Worker 265*e1997b9aSAndroid Build Coastguard Worker #[test] unsupported_cipher_suites()266*e1997b9aSAndroid Build Coastguard Worker fn unsupported_cipher_suites() { 267*e1997b9aSAndroid Build Coastguard Worker for suite in vec![ 268*e1997b9aSAndroid Build Coastguard Worker CipherSuite::P256_AES128, 269*e1997b9aSAndroid Build Coastguard Worker CipherSuite::P384_AES256, 270*e1997b9aSAndroid Build Coastguard Worker CipherSuite::P521_AES256, 271*e1997b9aSAndroid Build Coastguard Worker CipherSuite::CURVE448_CHACHA, 272*e1997b9aSAndroid Build Coastguard Worker CipherSuite::CURVE448_AES256, 273*e1997b9aSAndroid Build Coastguard Worker ] { 274*e1997b9aSAndroid Build Coastguard Worker assert_matches!( 275*e1997b9aSAndroid Build Coastguard Worker Ecdh::new(suite).unwrap().generate(), 276*e1997b9aSAndroid Build Coastguard Worker Err(EcdhError::UnsupportedCipherSuite) 277*e1997b9aSAndroid Build Coastguard Worker ); 278*e1997b9aSAndroid Build Coastguard Worker } 279*e1997b9aSAndroid Build Coastguard Worker } 280*e1997b9aSAndroid Build Coastguard Worker } 281