1 // Copyright 2023 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 use crypto_provider::elliptic_curve::{EcdhProvider, EphemeralSecret, PublicKey}; 16 use crypto_provider::x25519::X25519; 17 18 /// The BoringSSL implementation of X25519 ECDH. 19 pub struct X25519Ecdh; 20 21 impl EcdhProvider<X25519> for X25519Ecdh { 22 type PublicKey = X25519PublicKey; 23 type EphemeralSecret = X25519EphemeralSecret; 24 type SharedSecret = [u8; 32]; 25 } 26 27 /// A X25519 ephemeral secret used for Diffie-Hellman. 28 pub struct X25519EphemeralSecret { 29 public_key: bssl_crypto::x25519::PublicKey, 30 secret: bssl_crypto::x25519::PrivateKey, 31 } 32 33 impl EphemeralSecret<X25519> for X25519EphemeralSecret { 34 type Impl = X25519Ecdh; 35 type Error = Error; 36 type Rng = (); 37 type EncodedPublicKey = [u8; 32]; 38 generate_random(_rng: &mut Self::Rng) -> Self39 fn generate_random(_rng: &mut Self::Rng) -> Self { 40 let key_pair = bssl_crypto::x25519::PrivateKey::generate(); 41 Self { public_key: key_pair.0, secret: key_pair.1 } 42 } 43 public_key_bytes(&self) -> Self::EncodedPublicKey44 fn public_key_bytes(&self) -> Self::EncodedPublicKey { 45 self.public_key 46 } 47 diffie_hellman( self, other_pub: &<X25519Ecdh as EcdhProvider<X25519>>::PublicKey, ) -> Result<<X25519Ecdh as EcdhProvider<X25519>>::SharedSecret, Self::Error>48 fn diffie_hellman( 49 self, 50 other_pub: &<X25519Ecdh as EcdhProvider<X25519>>::PublicKey, 51 ) -> Result<<X25519Ecdh as EcdhProvider<X25519>>::SharedSecret, Self::Error> { 52 self.secret.compute_shared_key(&other_pub.0).ok_or(Error::WrongSize) 53 } 54 } 55 56 #[cfg(test)] 57 impl crypto_provider_test::elliptic_curve::EphemeralSecretForTesting<X25519> 58 for X25519EphemeralSecret 59 { from_private_components( private_bytes: &[u8; 32], public_key: &X25519PublicKey, ) -> Result<Self, Self::Error>60 fn from_private_components( 61 private_bytes: &[u8; 32], 62 public_key: &X25519PublicKey, 63 ) -> Result<Self, Self::Error> { 64 Ok(Self { 65 public_key: public_key.0, 66 secret: bssl_crypto::x25519::PrivateKey(*private_bytes), 67 }) 68 } 69 } 70 71 /// A X25519 public key. 72 #[derive(Debug, PartialEq, Eq)] 73 pub struct X25519PublicKey(bssl_crypto::x25519::PublicKey); 74 75 impl PublicKey<X25519> for X25519PublicKey { 76 type EncodedPublicKey = [u8; 32]; 77 type Error = Error; 78 from_bytes(bytes: &[u8]) -> Result<Self, Self::Error>79 fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> { 80 let byte_arr: [u8; 32] = bytes.try_into().map_err(|_| Error::WrongSize)?; 81 Ok(Self(bssl_crypto::x25519::PublicKey::from(byte_arr))) 82 } 83 to_bytes(&self) -> Self::EncodedPublicKey84 fn to_bytes(&self) -> Self::EncodedPublicKey { 85 self.0 86 } 87 } 88 89 /// Error type for the BoringSSL implementation of x25519. 90 #[derive(Debug)] 91 pub enum Error { 92 /// Unexpected size for the given input. 93 WrongSize, 94 } 95 96 #[cfg(test)] 97 mod tests { 98 use super::X25519Ecdh; 99 use core::marker::PhantomData; 100 use crypto_provider_test::x25519::*; 101 102 #[apply(x25519_test_cases)] x25519_tests(testcase: CryptoProviderTestCase<X25519Ecdh>)103 fn x25519_tests(testcase: CryptoProviderTestCase<X25519Ecdh>) { 104 testcase(PhantomData::<X25519Ecdh>) 105 } 106 } 107