xref: /aosp_15_r20/external/boringssl/src/rust/bssl-crypto/src/ecdh.rs (revision 8fb009dc861624b67b6cdb62ea21f0f22d0c584b)
1 /* Copyright (c) 2023, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14  */
15 
16 //! Elliptic Curve Diffie-Hellman operations.
17 //!
18 //! This module implements ECDH over the NIST curves P-256 and P-384.
19 //!
20 //! ```
21 //! use bssl_crypto::{ecdh, ec::P256};
22 //!
23 //! let alice_private_key = ecdh::PrivateKey::<P256>::generate();
24 //! let alice_public_key_serialized = alice_private_key.to_x962_uncompressed();
25 //!
26 //! // Somehow, Alice's public key is sent to Bob.
27 //! let bob_private_key = ecdh::PrivateKey::<P256>::generate();
28 //! let alice_public_key =
29 //!     ecdh::PublicKey::<P256>::from_x962_uncompressed(
30 //!         alice_public_key_serialized.as_ref())
31 //!     .unwrap();
32 //! let shared_key1 = bob_private_key.compute_shared_key(&alice_public_key);
33 //!
34 //! // Likewise, Alice gets Bob's public key and computes the same shared key.
35 //! let bob_public_key = bob_private_key.to_public_key();
36 //! let shared_key2 = alice_private_key.compute_shared_key(&bob_public_key);
37 //! assert_eq!(shared_key1, shared_key2);
38 //! ```
39 
40 use crate::{ec, sealed, with_output_vec, Buffer};
41 use alloc::vec::Vec;
42 use core::marker::PhantomData;
43 
44 /// An ECDH public key over the given curve.
45 pub struct PublicKey<C: ec::Curve> {
46     point: ec::Point,
47     marker: PhantomData<C>,
48 }
49 
50 impl<C: ec::Curve> PublicKey<C> {
51     /// Parse a public key in uncompressed X9.62 format. (This is the common
52     /// format for elliptic curve points beginning with an 0x04 byte.)
from_x962_uncompressed(x962: &[u8]) -> Option<Self>53     pub fn from_x962_uncompressed(x962: &[u8]) -> Option<Self> {
54         let point = ec::Point::from_x962_uncompressed(C::group(sealed::Sealed), x962)?;
55         Some(Self {
56             point,
57             marker: PhantomData,
58         })
59     }
60 
61     /// Serialize this key as uncompressed X9.62 format.
to_x962_uncompressed(&self) -> Buffer62     pub fn to_x962_uncompressed(&self) -> Buffer {
63         self.point.to_x962_uncompressed()
64     }
65 }
66 
67 /// An ECDH private key over the given curve.
68 pub struct PrivateKey<C: ec::Curve> {
69     key: ec::Key,
70     marker: PhantomData<C>,
71 }
72 
73 impl<C: ec::Curve> PrivateKey<C> {
74     /// Generate a random private key.
generate() -> Self75     pub fn generate() -> Self {
76         Self {
77             key: ec::Key::generate(C::group(sealed::Sealed)),
78             marker: PhantomData,
79         }
80     }
81 
82     /// Parse a `PrivateKey` from a zero-padded, big-endian representation of the secret scalar.
from_big_endian(scalar: &[u8]) -> Option<Self>83     pub fn from_big_endian(scalar: &[u8]) -> Option<Self> {
84         let key = ec::Key::from_big_endian(C::group(sealed::Sealed), scalar)?;
85         Some(Self {
86             key,
87             marker: PhantomData,
88         })
89     }
90 
91     /// Return the private scalar as zero-padded, big-endian bytes.
to_big_endian(&self) -> Buffer92     pub fn to_big_endian(&self) -> Buffer {
93         self.key.to_big_endian()
94     }
95 
96     /// Parse an ECPrivateKey structure (from RFC 5915). The key must be on the
97     /// specified curve.
from_der_ec_private_key(der: &[u8]) -> Option<Self>98     pub fn from_der_ec_private_key(der: &[u8]) -> Option<Self> {
99         let key = ec::Key::from_der_ec_private_key(C::group(sealed::Sealed), der)?;
100         Some(Self {
101             key,
102             marker: PhantomData,
103         })
104     }
105 
106     /// Serialize this private key as an ECPrivateKey structure (from RFC 5915).
to_der_ec_private_key(&self) -> Buffer107     pub fn to_der_ec_private_key(&self) -> Buffer {
108         self.key.to_der_ec_private_key()
109     }
110 
111     /// Parse a PrivateKeyInfo structure (from RFC 5208). The key must be on the
112     /// specified curve.
from_der_private_key_info(der: &[u8]) -> Option<Self>113     pub fn from_der_private_key_info(der: &[u8]) -> Option<Self> {
114         let key = ec::Key::from_der_private_key_info(C::group(sealed::Sealed), der)?;
115         Some(Self {
116             key,
117             marker: PhantomData,
118         })
119     }
120 
121     /// Serialize this private key as a PrivateKeyInfo structure (from RFC 5208).
to_der_private_key_info(&self) -> Buffer122     pub fn to_der_private_key_info(&self) -> Buffer {
123         self.key.to_der_private_key_info()
124     }
125 
126     /// Serialize the _public_ part of this key in uncompressed X9.62 format.
to_x962_uncompressed(&self) -> Buffer127     pub fn to_x962_uncompressed(&self) -> Buffer {
128         self.key.to_x962_uncompressed()
129     }
130 
131     /// Compute the shared key between this private key and the given public key.
132     /// The result should be used with a key derivation function that includes
133     /// the two public keys.
compute_shared_key(&self, other_public_key: &PublicKey<C>) -> Vec<u8>134     pub fn compute_shared_key(&self, other_public_key: &PublicKey<C>) -> Vec<u8> {
135         // 384 bits is the largest curve supported. The buffer is sized to be
136         // larger than this so that truncation of the output can be noticed.
137         let max_output = 384 / 8 + 1;
138         unsafe {
139             with_output_vec(max_output, |out_buf| {
140                 // Safety:
141                 //   - `out_buf` points to at least `max_output` bytes, as
142                 //     required.
143                 //   - The `EC_POINT` and `EC_KEY` pointers are valid by construction.
144                 let num_out_bytes = bssl_sys::ECDH_compute_key(
145                     out_buf as *mut core::ffi::c_void,
146                     max_output,
147                     other_public_key.point.as_ffi_ptr(),
148                     self.key.as_ffi_ptr(),
149                     None,
150                 );
151                 // Out of memory is not handled by this crate.
152                 assert!(num_out_bytes > 0);
153                 let num_out_bytes = num_out_bytes as usize;
154                 // If the buffer was completely filled then it was probably
155                 // truncated, which should never happen.
156                 assert!(num_out_bytes < max_output);
157                 num_out_bytes
158             })
159         }
160     }
161 
162     /// Return the public key corresponding to this private key.
to_public_key(&self) -> PublicKey<C>163     pub fn to_public_key(&self) -> PublicKey<C> {
164         PublicKey {
165             point: self.key.to_point(),
166             marker: PhantomData,
167         }
168     }
169 }
170 
171 #[cfg(test)]
172 mod test {
173     use super::*;
174     use crate::ec::{P256, P384};
175 
check_curve<C: ec::Curve>()176     fn check_curve<C: ec::Curve>() {
177         let alice_private_key = PrivateKey::<C>::generate();
178         let alice_public_key = alice_private_key.to_public_key();
179         let alice_private_key =
180             PrivateKey::<C>::from_big_endian(alice_private_key.to_big_endian().as_ref()).unwrap();
181         let alice_private_key = PrivateKey::<C>::from_der_ec_private_key(
182             alice_private_key.to_der_ec_private_key().as_ref(),
183         )
184         .unwrap();
185 
186         let bob_private_key = PrivateKey::<C>::generate();
187         let bob_public_key = bob_private_key.to_public_key();
188 
189         let shared_key1 = alice_private_key.compute_shared_key(&bob_public_key);
190         let shared_key2 = bob_private_key.compute_shared_key(&alice_public_key);
191 
192         assert_eq!(shared_key1, shared_key2);
193     }
194 
195     #[test]
p256()196     fn p256() {
197         check_curve::<P256>();
198     }
199 
200     #[test]
p384()201     fn p384() {
202         check_curve::<P384>();
203     }
204 }
205