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