1 //! Shared secret derivation.
2 use ffi;
3 use foreign_types::ForeignTypeRef;
4 use std::marker::PhantomData;
5 use std::ptr;
6 
7 use error::ErrorStack;
8 use pkey::{HasPrivate, HasPublic, PKeyRef};
9 use {cvt, cvt_p};
10 
11 /// A type used to derive a shared secret between two keys.
12 pub struct Deriver<'a>(*mut ffi::EVP_PKEY_CTX, PhantomData<&'a ()>);
13 
14 unsafe impl<'a> Sync for Deriver<'a> {}
15 unsafe impl<'a> Send for Deriver<'a> {}
16 
17 #[allow(clippy::len_without_is_empty)]
18 impl<'a> Deriver<'a> {
19     /// Creates a new `Deriver` using the provided private key.
20     ///
21     /// This corresponds to [`EVP_PKEY_derive_init`].
22     ///
23     /// [`EVP_PKEY_derive_init`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html
new<T>(key: &'a PKeyRef<T>) -> Result<Deriver<'a>, ErrorStack> where T: HasPrivate,24     pub fn new<T>(key: &'a PKeyRef<T>) -> Result<Deriver<'a>, ErrorStack>
25     where
26         T: HasPrivate,
27     {
28         unsafe {
29             cvt_p(ffi::EVP_PKEY_CTX_new(key.as_ptr(), ptr::null_mut()))
30                 .map(|p| Deriver(p, PhantomData))
31                 .and_then(|ctx| cvt(ffi::EVP_PKEY_derive_init(ctx.0)).map(|_| ctx))
32         }
33     }
34 
35     /// Sets the peer key used for secret derivation.
36     ///
37     /// This corresponds to [`EVP_PKEY_derive_set_peer`]:
38     ///
39     /// [`EVP_PKEY_derive_set_peer`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html
set_peer<T>(&mut self, key: &'a PKeyRef<T>) -> Result<(), ErrorStack> where T: HasPublic,40     pub fn set_peer<T>(&mut self, key: &'a PKeyRef<T>) -> Result<(), ErrorStack>
41     where
42         T: HasPublic,
43     {
44         unsafe { cvt(ffi::EVP_PKEY_derive_set_peer(self.0, key.as_ptr())).map(|_| ()) }
45     }
46 
47     /// Returns the size of the shared secret.
48     ///
49     /// It can be used to size the buffer passed to [`Deriver::derive`].
50     ///
51     /// This corresponds to [`EVP_PKEY_derive`].
52     ///
53     /// [`Deriver::derive`]: #method.derive
54     /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html
len(&mut self) -> Result<usize, ErrorStack>55     pub fn len(&mut self) -> Result<usize, ErrorStack> {
56         unsafe {
57             let mut len = 0;
58             cvt(ffi::EVP_PKEY_derive(self.0, ptr::null_mut(), &mut len)).map(|_| len)
59         }
60     }
61 
62     /// Derives a shared secret between the two keys, writing it into the buffer.
63     ///
64     /// Returns the number of bytes written.
65     ///
66     /// This corresponds to [`EVP_PKEY_derive`].
67     ///
68     /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html
derive(&mut self, buf: &mut [u8]) -> Result<usize, ErrorStack>69     pub fn derive(&mut self, buf: &mut [u8]) -> Result<usize, ErrorStack> {
70         let mut len = buf.len();
71         unsafe {
72             cvt(ffi::EVP_PKEY_derive(
73                 self.0,
74                 buf.as_mut_ptr() as *mut _,
75                 &mut len,
76             ))
77             .map(|_| len)
78         }
79     }
80 
81     /// A convenience function which derives a shared secret and returns it in a new buffer.
82     ///
83     /// This simply wraps [`Deriver::len`] and [`Deriver::derive`].
84     ///
85     /// [`Deriver::len`]: #method.len
86     /// [`Deriver::derive`]: #method.derive
derive_to_vec(&mut self) -> Result<Vec<u8>, ErrorStack>87     pub fn derive_to_vec(&mut self) -> Result<Vec<u8>, ErrorStack> {
88         let len = self.len()?;
89         let mut buf = vec![0; len];
90         let len = self.derive(&mut buf)?;
91         buf.truncate(len);
92         Ok(buf)
93     }
94 }
95 
96 #[cfg(test)]
97 mod test {
98     use super::*;
99 
100     use ec::{EcGroup, EcKey};
101     use nid::Nid;
102     use pkey::PKey;
103 
104     #[test]
derive_without_peer()105     fn derive_without_peer() {
106         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
107         let ec_key = EcKey::generate(&group).unwrap();
108         let pkey = PKey::from_ec_key(ec_key).unwrap();
109         let mut deriver = Deriver::new(&pkey).unwrap();
110         deriver.derive_to_vec().unwrap_err();
111     }
112 
113     #[test]
test_ec_key_derive()114     fn test_ec_key_derive() {
115         let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
116         let ec_key = EcKey::generate(&group).unwrap();
117         let ec_key2 = EcKey::generate(&group).unwrap();
118         let pkey = PKey::from_ec_key(ec_key).unwrap();
119         let pkey2 = PKey::from_ec_key(ec_key2).unwrap();
120         let mut deriver = Deriver::new(&pkey).unwrap();
121         deriver.set_peer(&pkey2).unwrap();
122         let shared = deriver.derive_to_vec().unwrap();
123         assert!(!shared.is_empty());
124     }
125 }
126