Coverage Report

Created: 2025-09-04 06:37

/rust/registry/src/index.crates.io-6f17d22bba15001f/openssl-0.10.62/src/derive.rs
Line
Count
Source (jump to first uncovered line)
1
//! Shared secret derivation.
2
//!
3
//! # Example
4
//!
5
//! The following example implements [ECDH] using `NIST P-384` keys:
6
//!
7
//! ```
8
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
9
//! # use std::convert::TryInto;
10
//! use openssl::bn::BigNumContext;
11
//! use openssl::pkey::PKey;
12
//! use openssl::derive::Deriver;
13
//! use openssl::ec::{EcGroup, EcKey, EcPoint, PointConversionForm};
14
//! use openssl::nid::Nid;
15
//!
16
//! let group = EcGroup::from_curve_name(Nid::SECP384R1)?;
17
//!
18
//! let first: PKey<_> = EcKey::generate(&group)?.try_into()?;
19
//!
20
//! // second party generates an ephemeral key and derives
21
//! // a shared secret using first party's public key
22
//! let shared_key = EcKey::generate(&group)?;
23
//! // shared_public is sent to first party
24
//! let mut ctx = BigNumContext::new()?;
25
//! let shared_public = shared_key.public_key().to_bytes(
26
//!        &group,
27
//!        PointConversionForm::COMPRESSED,
28
//!        &mut ctx,
29
//!    )?;
30
//!
31
//! let shared_key: PKey<_> = shared_key.try_into()?;
32
//! let mut deriver = Deriver::new(&shared_key)?;
33
//! deriver.set_peer(&first)?;
34
//! // secret can be used e.g. as a symmetric encryption key
35
//! let secret = deriver.derive_to_vec()?;
36
//! # drop(deriver);
37
//!
38
//! // first party derives the same shared secret using
39
//! // shared_public
40
//! let point = EcPoint::from_bytes(&group, &shared_public, &mut ctx)?;
41
//! let recipient_key: PKey<_> = EcKey::from_public_key(&group, &point)?.try_into()?;
42
//! let mut deriver = Deriver::new(&first)?;
43
//! deriver.set_peer(&recipient_key)?;
44
//! let first_secret = deriver.derive_to_vec()?;
45
//!
46
//! assert_eq!(secret, first_secret);
47
//! # Ok(()) }
48
//! ```
49
//!
50
//! [ECDH]: https://wiki.openssl.org/index.php/Elliptic_Curve_Diffie_Hellman
51
52
use foreign_types::ForeignTypeRef;
53
use std::marker::PhantomData;
54
use std::ptr;
55
56
use crate::error::ErrorStack;
57
use crate::pkey::{HasPrivate, HasPublic, PKeyRef};
58
use crate::{cvt, cvt_p};
59
use openssl_macros::corresponds;
60
61
/// A type used to derive a shared secret between two keys.
62
pub struct Deriver<'a>(*mut ffi::EVP_PKEY_CTX, PhantomData<&'a ()>);
63
64
unsafe impl<'a> Sync for Deriver<'a> {}
65
unsafe impl<'a> Send for Deriver<'a> {}
66
67
#[allow(clippy::len_without_is_empty)]
68
impl<'a> Deriver<'a> {
69
    /// Creates a new `Deriver` using the provided private key.
70
    ///
71
    /// This corresponds to [`EVP_PKEY_derive_init`].
72
    ///
73
    /// [`EVP_PKEY_derive_init`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html
74
0
    pub fn new<T>(key: &'a PKeyRef<T>) -> Result<Deriver<'a>, ErrorStack>
75
0
    where
76
0
        T: HasPrivate,
77
0
    {
78
0
        unsafe {
79
0
            cvt_p(ffi::EVP_PKEY_CTX_new(key.as_ptr(), ptr::null_mut()))
80
0
                .map(|p| Deriver(p, PhantomData))
81
0
                .and_then(|ctx| cvt(ffi::EVP_PKEY_derive_init(ctx.0)).map(|_| ctx))
82
0
        }
83
0
    }
84
85
    /// Sets the peer key used for secret derivation.
86
    #[corresponds(EVP_PKEY_derive_set_peer)]
87
0
    pub fn set_peer<T>(&mut self, key: &'a PKeyRef<T>) -> Result<(), ErrorStack>
88
0
    where
89
0
        T: HasPublic,
90
0
    {
91
0
        unsafe { cvt(ffi::EVP_PKEY_derive_set_peer(self.0, key.as_ptr())).map(|_| ()) }
92
0
    }
93
94
    /// Sets the peer key used for secret derivation along with optionally validating the peer public key.
95
    ///
96
    /// Requires OpenSSL 3.0.0 or newer.
97
    #[corresponds(EVP_PKEY_derive_set_peer_ex)]
98
    #[cfg(ossl300)]
99
    pub fn set_peer_ex<T>(
100
        &mut self,
101
        key: &'a PKeyRef<T>,
102
        validate_peer: bool,
103
    ) -> Result<(), ErrorStack>
104
    where
105
        T: HasPublic,
106
    {
107
        unsafe {
108
            cvt(ffi::EVP_PKEY_derive_set_peer_ex(
109
                self.0,
110
                key.as_ptr(),
111
                validate_peer as i32,
112
            ))
113
            .map(|_| ())
114
        }
115
    }
116
117
    /// Returns the size of the shared secret.
118
    ///
119
    /// It can be used to size the buffer passed to [`Deriver::derive`].
120
    ///
121
    /// This corresponds to [`EVP_PKEY_derive`].
122
    ///
123
    /// [`Deriver::derive`]: #method.derive
124
    /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html
125
0
    pub fn len(&mut self) -> Result<usize, ErrorStack> {
126
0
        unsafe {
127
0
            let mut len = 0;
128
0
            cvt(ffi::EVP_PKEY_derive(self.0, ptr::null_mut(), &mut len)).map(|_| len)
129
0
        }
130
0
    }
131
132
    /// Derives a shared secret between the two keys, writing it into the buffer.
133
    ///
134
    /// Returns the number of bytes written.
135
    ///
136
    /// This corresponds to [`EVP_PKEY_derive`].
137
    ///
138
    /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html
139
0
    pub fn derive(&mut self, buf: &mut [u8]) -> Result<usize, ErrorStack> {
140
0
        let mut len = buf.len();
141
0
        unsafe {
142
0
            cvt(ffi::EVP_PKEY_derive(
143
0
                self.0,
144
0
                buf.as_mut_ptr() as *mut _,
145
0
                &mut len,
146
0
            ))
147
0
            .map(|_| len)
148
0
        }
149
0
    }
150
151
    /// A convenience function which derives a shared secret and returns it in a new buffer.
152
    ///
153
    /// This simply wraps [`Deriver::len`] and [`Deriver::derive`].
154
    ///
155
    /// [`Deriver::len`]: #method.len
156
    /// [`Deriver::derive`]: #method.derive
157
0
    pub fn derive_to_vec(&mut self) -> Result<Vec<u8>, ErrorStack> {
158
0
        let len = self.len()?;
159
0
        let mut buf = vec![0; len];
160
0
        let len = self.derive(&mut buf)?;
161
0
        buf.truncate(len);
162
0
        Ok(buf)
163
0
    }
164
}
165
166
impl<'a> Drop for Deriver<'a> {
167
0
    fn drop(&mut self) {
168
0
        unsafe {
169
0
            ffi::EVP_PKEY_CTX_free(self.0);
170
0
        }
171
0
    }
172
}
173
174
#[cfg(test)]
175
mod test {
176
    use super::*;
177
178
    use crate::ec::{EcGroup, EcKey};
179
    use crate::nid::Nid;
180
    use crate::pkey::PKey;
181
182
    #[test]
183
    fn derive_without_peer() {
184
        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
185
        let ec_key = EcKey::generate(&group).unwrap();
186
        let pkey = PKey::from_ec_key(ec_key).unwrap();
187
        let mut deriver = Deriver::new(&pkey).unwrap();
188
        deriver.derive_to_vec().unwrap_err();
189
    }
190
191
    #[test]
192
    fn test_ec_key_derive() {
193
        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
194
        let ec_key = EcKey::generate(&group).unwrap();
195
        let ec_key2 = EcKey::generate(&group).unwrap();
196
        let pkey = PKey::from_ec_key(ec_key).unwrap();
197
        let pkey2 = PKey::from_ec_key(ec_key2).unwrap();
198
        let mut deriver = Deriver::new(&pkey).unwrap();
199
        deriver.set_peer(&pkey2).unwrap();
200
        let shared = deriver.derive_to_vec().unwrap();
201
        assert!(!shared.is_empty());
202
    }
203
204
    #[test]
205
    #[cfg(ossl300)]
206
    fn test_ec_key_derive_ex() {
207
        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
208
        let ec_key = EcKey::generate(&group).unwrap();
209
        let ec_key2 = EcKey::generate(&group).unwrap();
210
        let pkey = PKey::from_ec_key(ec_key).unwrap();
211
        let pkey2 = PKey::from_ec_key(ec_key2).unwrap();
212
        let mut deriver = Deriver::new(&pkey).unwrap();
213
        deriver.set_peer_ex(&pkey2, true).unwrap();
214
        let shared = deriver.derive_to_vec().unwrap();
215
        assert!(!shared.is_empty());
216
    }
217
}