192f3ab15Sopenharmony_ci//! Shared secret derivation. 292f3ab15Sopenharmony_ci//! 392f3ab15Sopenharmony_ci//! # Example 492f3ab15Sopenharmony_ci//! 592f3ab15Sopenharmony_ci//! The following example implements [ECDH] using `NIST P-384` keys: 692f3ab15Sopenharmony_ci//! 792f3ab15Sopenharmony_ci//! ``` 892f3ab15Sopenharmony_ci//! # fn main() -> Result<(), Box<dyn std::error::Error>> { 992f3ab15Sopenharmony_ci//! # use std::convert::TryInto; 1092f3ab15Sopenharmony_ci//! use openssl::bn::BigNumContext; 1192f3ab15Sopenharmony_ci//! use openssl::pkey::PKey; 1292f3ab15Sopenharmony_ci//! use openssl::derive::Deriver; 1392f3ab15Sopenharmony_ci//! use openssl::ec::{EcGroup, EcKey, EcPoint, PointConversionForm}; 1492f3ab15Sopenharmony_ci//! use openssl::nid::Nid; 1592f3ab15Sopenharmony_ci//! 1692f3ab15Sopenharmony_ci//! let group = EcGroup::from_curve_name(Nid::SECP384R1)?; 1792f3ab15Sopenharmony_ci//! 1892f3ab15Sopenharmony_ci//! let first: PKey<_> = EcKey::generate(&group)?.try_into()?; 1992f3ab15Sopenharmony_ci//! 2092f3ab15Sopenharmony_ci//! // second party generates an ephemeral key and derives 2192f3ab15Sopenharmony_ci//! // a shared secret using first party's public key 2292f3ab15Sopenharmony_ci//! let shared_key = EcKey::generate(&group)?; 2392f3ab15Sopenharmony_ci//! // shared_public is sent to first party 2492f3ab15Sopenharmony_ci//! let mut ctx = BigNumContext::new()?; 2592f3ab15Sopenharmony_ci//! let shared_public = shared_key.public_key().to_bytes( 2692f3ab15Sopenharmony_ci//! &group, 2792f3ab15Sopenharmony_ci//! PointConversionForm::COMPRESSED, 2892f3ab15Sopenharmony_ci//! &mut ctx, 2992f3ab15Sopenharmony_ci//! )?; 3092f3ab15Sopenharmony_ci//! 3192f3ab15Sopenharmony_ci//! let shared_key: PKey<_> = shared_key.try_into()?; 3292f3ab15Sopenharmony_ci//! let mut deriver = Deriver::new(&shared_key)?; 3392f3ab15Sopenharmony_ci//! deriver.set_peer(&first)?; 3492f3ab15Sopenharmony_ci//! // secret can be used e.g. as a symmetric encryption key 3592f3ab15Sopenharmony_ci//! let secret = deriver.derive_to_vec()?; 3692f3ab15Sopenharmony_ci//! # drop(deriver); 3792f3ab15Sopenharmony_ci//! 3892f3ab15Sopenharmony_ci//! // first party derives the same shared secret using 3992f3ab15Sopenharmony_ci//! // shared_public 4092f3ab15Sopenharmony_ci//! let point = EcPoint::from_bytes(&group, &shared_public, &mut ctx)?; 4192f3ab15Sopenharmony_ci//! let recipient_key: PKey<_> = EcKey::from_public_key(&group, &point)?.try_into()?; 4292f3ab15Sopenharmony_ci//! let mut deriver = Deriver::new(&first)?; 4392f3ab15Sopenharmony_ci//! deriver.set_peer(&recipient_key)?; 4492f3ab15Sopenharmony_ci//! let first_secret = deriver.derive_to_vec()?; 4592f3ab15Sopenharmony_ci//! 4692f3ab15Sopenharmony_ci//! assert_eq!(secret, first_secret); 4792f3ab15Sopenharmony_ci//! # Ok(()) } 4892f3ab15Sopenharmony_ci//! ``` 4992f3ab15Sopenharmony_ci//! 5092f3ab15Sopenharmony_ci//! [ECDH]: https://wiki.openssl.org/index.php/Elliptic_Curve_Diffie_Hellman 5192f3ab15Sopenharmony_ci 5292f3ab15Sopenharmony_ciuse foreign_types::ForeignTypeRef; 5392f3ab15Sopenharmony_ciuse std::marker::PhantomData; 5492f3ab15Sopenharmony_ciuse std::ptr; 5592f3ab15Sopenharmony_ci 5692f3ab15Sopenharmony_ciuse crate::error::ErrorStack; 5792f3ab15Sopenharmony_ciuse crate::pkey::{HasPrivate, HasPublic, PKeyRef}; 5892f3ab15Sopenharmony_ciuse crate::{cvt, cvt_p}; 5992f3ab15Sopenharmony_ciuse openssl_macros::corresponds; 6092f3ab15Sopenharmony_ci 6192f3ab15Sopenharmony_ci/// A type used to derive a shared secret between two keys. 6292f3ab15Sopenharmony_cipub struct Deriver<'a>(*mut ffi::EVP_PKEY_CTX, PhantomData<&'a ()>); 6392f3ab15Sopenharmony_ci 6492f3ab15Sopenharmony_ciunsafe impl<'a> Sync for Deriver<'a> {} 6592f3ab15Sopenharmony_ciunsafe impl<'a> Send for Deriver<'a> {} 6692f3ab15Sopenharmony_ci 6792f3ab15Sopenharmony_ci#[allow(clippy::len_without_is_empty)] 6892f3ab15Sopenharmony_ciimpl<'a> Deriver<'a> { 6992f3ab15Sopenharmony_ci /// Creates a new `Deriver` using the provided private key. 7092f3ab15Sopenharmony_ci /// 7192f3ab15Sopenharmony_ci /// This corresponds to [`EVP_PKEY_derive_init`]. 7292f3ab15Sopenharmony_ci /// 7392f3ab15Sopenharmony_ci /// [`EVP_PKEY_derive_init`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html 7492f3ab15Sopenharmony_ci pub fn new<T>(key: &'a PKeyRef<T>) -> Result<Deriver<'a>, ErrorStack> 7592f3ab15Sopenharmony_ci where 7692f3ab15Sopenharmony_ci T: HasPrivate, 7792f3ab15Sopenharmony_ci { 7892f3ab15Sopenharmony_ci unsafe { 7992f3ab15Sopenharmony_ci cvt_p(ffi::EVP_PKEY_CTX_new(key.as_ptr(), ptr::null_mut())) 8092f3ab15Sopenharmony_ci .map(|p| Deriver(p, PhantomData)) 8192f3ab15Sopenharmony_ci .and_then(|ctx| cvt(ffi::EVP_PKEY_derive_init(ctx.0)).map(|_| ctx)) 8292f3ab15Sopenharmony_ci } 8392f3ab15Sopenharmony_ci } 8492f3ab15Sopenharmony_ci 8592f3ab15Sopenharmony_ci /// Sets the peer key used for secret derivation. 8692f3ab15Sopenharmony_ci #[corresponds(EVP_PKEY_derive_set_peer)] 8792f3ab15Sopenharmony_ci pub fn set_peer<T>(&mut self, key: &'a PKeyRef<T>) -> Result<(), ErrorStack> 8892f3ab15Sopenharmony_ci where 8992f3ab15Sopenharmony_ci T: HasPublic, 9092f3ab15Sopenharmony_ci { 9192f3ab15Sopenharmony_ci unsafe { cvt(ffi::EVP_PKEY_derive_set_peer(self.0, key.as_ptr())).map(|_| ()) } 9292f3ab15Sopenharmony_ci } 9392f3ab15Sopenharmony_ci 9492f3ab15Sopenharmony_ci /// Sets the peer key used for secret derivation along with optionally validating the peer public key. 9592f3ab15Sopenharmony_ci /// 9692f3ab15Sopenharmony_ci /// Requires OpenSSL 3.0.0 or newer. 9792f3ab15Sopenharmony_ci #[corresponds(EVP_PKEY_derive_set_peer_ex)] 9892f3ab15Sopenharmony_ci #[cfg(ossl300)] 9992f3ab15Sopenharmony_ci pub fn set_peer_ex<T>( 10092f3ab15Sopenharmony_ci &mut self, 10192f3ab15Sopenharmony_ci key: &'a PKeyRef<T>, 10292f3ab15Sopenharmony_ci validate_peer: bool, 10392f3ab15Sopenharmony_ci ) -> Result<(), ErrorStack> 10492f3ab15Sopenharmony_ci where 10592f3ab15Sopenharmony_ci T: HasPublic, 10692f3ab15Sopenharmony_ci { 10792f3ab15Sopenharmony_ci unsafe { 10892f3ab15Sopenharmony_ci cvt(ffi::EVP_PKEY_derive_set_peer_ex( 10992f3ab15Sopenharmony_ci self.0, 11092f3ab15Sopenharmony_ci key.as_ptr(), 11192f3ab15Sopenharmony_ci validate_peer as i32, 11292f3ab15Sopenharmony_ci )) 11392f3ab15Sopenharmony_ci .map(|_| ()) 11492f3ab15Sopenharmony_ci } 11592f3ab15Sopenharmony_ci } 11692f3ab15Sopenharmony_ci 11792f3ab15Sopenharmony_ci /// Returns the size of the shared secret. 11892f3ab15Sopenharmony_ci /// 11992f3ab15Sopenharmony_ci /// It can be used to size the buffer passed to [`Deriver::derive`]. 12092f3ab15Sopenharmony_ci /// 12192f3ab15Sopenharmony_ci /// This corresponds to [`EVP_PKEY_derive`]. 12292f3ab15Sopenharmony_ci /// 12392f3ab15Sopenharmony_ci /// [`Deriver::derive`]: #method.derive 12492f3ab15Sopenharmony_ci /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html 12592f3ab15Sopenharmony_ci pub fn len(&mut self) -> Result<usize, ErrorStack> { 12692f3ab15Sopenharmony_ci unsafe { 12792f3ab15Sopenharmony_ci let mut len = 0; 12892f3ab15Sopenharmony_ci cvt(ffi::EVP_PKEY_derive(self.0, ptr::null_mut(), &mut len)).map(|_| len) 12992f3ab15Sopenharmony_ci } 13092f3ab15Sopenharmony_ci } 13192f3ab15Sopenharmony_ci 13292f3ab15Sopenharmony_ci /// Derives a shared secret between the two keys, writing it into the buffer. 13392f3ab15Sopenharmony_ci /// 13492f3ab15Sopenharmony_ci /// Returns the number of bytes written. 13592f3ab15Sopenharmony_ci /// 13692f3ab15Sopenharmony_ci /// This corresponds to [`EVP_PKEY_derive`]. 13792f3ab15Sopenharmony_ci /// 13892f3ab15Sopenharmony_ci /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html 13992f3ab15Sopenharmony_ci pub fn derive(&mut self, buf: &mut [u8]) -> Result<usize, ErrorStack> { 14092f3ab15Sopenharmony_ci let mut len = buf.len(); 14192f3ab15Sopenharmony_ci unsafe { 14292f3ab15Sopenharmony_ci cvt(ffi::EVP_PKEY_derive( 14392f3ab15Sopenharmony_ci self.0, 14492f3ab15Sopenharmony_ci buf.as_mut_ptr() as *mut _, 14592f3ab15Sopenharmony_ci &mut len, 14692f3ab15Sopenharmony_ci )) 14792f3ab15Sopenharmony_ci .map(|_| len) 14892f3ab15Sopenharmony_ci } 14992f3ab15Sopenharmony_ci } 15092f3ab15Sopenharmony_ci 15192f3ab15Sopenharmony_ci /// A convenience function which derives a shared secret and returns it in a new buffer. 15292f3ab15Sopenharmony_ci /// 15392f3ab15Sopenharmony_ci /// This simply wraps [`Deriver::len`] and [`Deriver::derive`]. 15492f3ab15Sopenharmony_ci /// 15592f3ab15Sopenharmony_ci /// [`Deriver::len`]: #method.len 15692f3ab15Sopenharmony_ci /// [`Deriver::derive`]: #method.derive 15792f3ab15Sopenharmony_ci pub fn derive_to_vec(&mut self) -> Result<Vec<u8>, ErrorStack> { 15892f3ab15Sopenharmony_ci let len = self.len()?; 15992f3ab15Sopenharmony_ci let mut buf = vec![0; len]; 16092f3ab15Sopenharmony_ci let len = self.derive(&mut buf)?; 16192f3ab15Sopenharmony_ci buf.truncate(len); 16292f3ab15Sopenharmony_ci Ok(buf) 16392f3ab15Sopenharmony_ci } 16492f3ab15Sopenharmony_ci} 16592f3ab15Sopenharmony_ci 16692f3ab15Sopenharmony_ciimpl<'a> Drop for Deriver<'a> { 16792f3ab15Sopenharmony_ci fn drop(&mut self) { 16892f3ab15Sopenharmony_ci unsafe { 16992f3ab15Sopenharmony_ci ffi::EVP_PKEY_CTX_free(self.0); 17092f3ab15Sopenharmony_ci } 17192f3ab15Sopenharmony_ci } 17292f3ab15Sopenharmony_ci} 17392f3ab15Sopenharmony_ci 17492f3ab15Sopenharmony_ci#[cfg(test)] 17592f3ab15Sopenharmony_cimod test { 17692f3ab15Sopenharmony_ci use super::*; 17792f3ab15Sopenharmony_ci 17892f3ab15Sopenharmony_ci use crate::ec::{EcGroup, EcKey}; 17992f3ab15Sopenharmony_ci use crate::nid::Nid; 18092f3ab15Sopenharmony_ci use crate::pkey::PKey; 18192f3ab15Sopenharmony_ci 18292f3ab15Sopenharmony_ci #[test] 18392f3ab15Sopenharmony_ci fn derive_without_peer() { 18492f3ab15Sopenharmony_ci let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 18592f3ab15Sopenharmony_ci let ec_key = EcKey::generate(&group).unwrap(); 18692f3ab15Sopenharmony_ci let pkey = PKey::from_ec_key(ec_key).unwrap(); 18792f3ab15Sopenharmony_ci let mut deriver = Deriver::new(&pkey).unwrap(); 18892f3ab15Sopenharmony_ci deriver.derive_to_vec().unwrap_err(); 18992f3ab15Sopenharmony_ci } 19092f3ab15Sopenharmony_ci 19192f3ab15Sopenharmony_ci #[test] 19292f3ab15Sopenharmony_ci fn test_ec_key_derive() { 19392f3ab15Sopenharmony_ci let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 19492f3ab15Sopenharmony_ci let ec_key = EcKey::generate(&group).unwrap(); 19592f3ab15Sopenharmony_ci let ec_key2 = EcKey::generate(&group).unwrap(); 19692f3ab15Sopenharmony_ci let pkey = PKey::from_ec_key(ec_key).unwrap(); 19792f3ab15Sopenharmony_ci let pkey2 = PKey::from_ec_key(ec_key2).unwrap(); 19892f3ab15Sopenharmony_ci let mut deriver = Deriver::new(&pkey).unwrap(); 19992f3ab15Sopenharmony_ci deriver.set_peer(&pkey2).unwrap(); 20092f3ab15Sopenharmony_ci let shared = deriver.derive_to_vec().unwrap(); 20192f3ab15Sopenharmony_ci assert!(!shared.is_empty()); 20292f3ab15Sopenharmony_ci } 20392f3ab15Sopenharmony_ci 20492f3ab15Sopenharmony_ci #[test] 20592f3ab15Sopenharmony_ci #[cfg(ossl300)] 20692f3ab15Sopenharmony_ci fn test_ec_key_derive_ex() { 20792f3ab15Sopenharmony_ci let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 20892f3ab15Sopenharmony_ci let ec_key = EcKey::generate(&group).unwrap(); 20992f3ab15Sopenharmony_ci let ec_key2 = EcKey::generate(&group).unwrap(); 21092f3ab15Sopenharmony_ci let pkey = PKey::from_ec_key(ec_key).unwrap(); 21192f3ab15Sopenharmony_ci let pkey2 = PKey::from_ec_key(ec_key2).unwrap(); 21292f3ab15Sopenharmony_ci let mut deriver = Deriver::new(&pkey).unwrap(); 21392f3ab15Sopenharmony_ci deriver.set_peer_ex(&pkey2, true).unwrap(); 21492f3ab15Sopenharmony_ci let shared = deriver.derive_to_vec().unwrap(); 21592f3ab15Sopenharmony_ci assert!(!shared.is_empty()); 21692f3ab15Sopenharmony_ci } 21792f3ab15Sopenharmony_ci} 218