• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 crate::RcRng;
16 use core::marker::PhantomData;
17 use crypto_provider::elliptic_curve::{EcdhProvider, EphemeralSecret, PublicKey};
18 use crypto_provider::x25519::X25519;
19 use rand::RngCore;
20 use rand_core::{CryptoRng, SeedableRng};
21 
22 /// The RustCrypto implementation of X25519 ECDH.
23 pub struct X25519Ecdh<R> {
24     _marker: PhantomData<R>,
25 }
26 
27 impl<R: CryptoRng + RngCore + SeedableRng + Send> EcdhProvider<X25519> for X25519Ecdh<R> {
28     type PublicKey = X25519PublicKey;
29     type EphemeralSecret = X25519EphemeralSecret<R>;
30     type SharedSecret = [u8; 32];
31 }
32 
33 /// A X25519 ephemeral secret used for Diffie-Hellman.
34 pub struct X25519EphemeralSecret<R: CryptoRng + RngCore + SeedableRng> {
35     secret: x25519_dalek::EphemeralSecret,
36     marker: PhantomData<R>,
37 }
38 
39 impl<R: CryptoRng + RngCore + SeedableRng + Send> EphemeralSecret<X25519>
40     for X25519EphemeralSecret<R>
41 {
42     type Impl = X25519Ecdh<R>;
43     type Error = Error;
44     type Rng = RcRng<R>;
45     type EncodedPublicKey = [u8; 32];
46 
generate_random(rng: &mut Self::Rng) -> Self47     fn generate_random(rng: &mut Self::Rng) -> Self {
48         Self {
49             secret: x25519_dalek::EphemeralSecret::random_from_rng(&mut rng.0),
50             marker: Default::default(),
51         }
52     }
53 
public_key_bytes(&self) -> Self::EncodedPublicKey54     fn public_key_bytes(&self) -> Self::EncodedPublicKey {
55         let pubkey: x25519_dalek::PublicKey = (&self.secret).into();
56         pubkey.to_bytes()
57     }
58 
diffie_hellman( self, other_pub: &<X25519Ecdh<R> as EcdhProvider<X25519>>::PublicKey, ) -> Result<<X25519Ecdh<R> as EcdhProvider<X25519>>::SharedSecret, Self::Error>59     fn diffie_hellman(
60         self,
61         other_pub: &<X25519Ecdh<R> as EcdhProvider<X25519>>::PublicKey,
62     ) -> Result<<X25519Ecdh<R> as EcdhProvider<X25519>>::SharedSecret, Self::Error> {
63         Ok(x25519_dalek::EphemeralSecret::diffie_hellman(self.secret, &other_pub.0).to_bytes())
64     }
65 }
66 
67 #[cfg(test)]
68 impl<R: CryptoRng + RngCore + SeedableRng + Send>
69     crypto_provider_test::elliptic_curve::EphemeralSecretForTesting<X25519>
70     for X25519EphemeralSecret<R>
71 {
from_private_components( private_bytes: &[u8; 32], _public_key: &X25519PublicKey, ) -> Result<Self, Self::Error>72     fn from_private_components(
73         private_bytes: &[u8; 32],
74         _public_key: &X25519PublicKey,
75     ) -> Result<Self, Self::Error> {
76         Ok(Self {
77             secret: x25519_dalek::EphemeralSecret::random_from_rng(crate::testing::MockCryptoRng {
78                 values: private_bytes.iter(),
79             }),
80             marker: Default::default(),
81         })
82     }
83 }
84 
85 /// A X25519 public key.
86 #[derive(Debug, PartialEq, Eq)]
87 pub struct X25519PublicKey(x25519_dalek::PublicKey);
88 
89 impl PublicKey<X25519> for X25519PublicKey {
90     type Error = Error;
91     type EncodedPublicKey = [u8; 32];
92 
from_bytes(bytes: &[u8]) -> Result<Self, Self::Error>93     fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
94         let byte_sized: [u8; 32] = bytes.try_into().map_err(|_| Error::WrongSize)?;
95         Ok(Self(byte_sized.into()))
96     }
97 
to_bytes(&self) -> Self::EncodedPublicKey98     fn to_bytes(&self) -> Self::EncodedPublicKey {
99         self.0.to_bytes()
100     }
101 }
102 
103 /// Error type for the RustCrypto implementation of x25519.
104 #[derive(Debug)]
105 pub enum Error {
106     /// Unexpected size for the given input.
107     WrongSize,
108 }
109 
110 #[cfg(test)]
111 mod tests {
112     use super::X25519Ecdh;
113     use core::marker::PhantomData;
114     use crypto_provider_test::x25519::*;
115     use rand::rngs::StdRng;
116 
117     #[apply(x25519_test_cases)]
x25519_tests(testcase: CryptoProviderTestCase<X25519Ecdh<StdRng>>)118     fn x25519_tests(testcase: CryptoProviderTestCase<X25519Ecdh<StdRng>>) {
119         testcase(PhantomData::<X25519Ecdh<StdRng>>)
120     }
121 }
122