aboutsummaryrefslogtreecommitdiff
path: root/openssl/src/derive.rs
diff options
context:
space:
mode:
authorSteven Fackler <[email protected]>2017-12-31 10:21:23 -0800
committerGitHub <[email protected]>2017-12-31 10:21:23 -0800
commitd3fff74ae8ab092a77050ba210b942e86c3bd9ff (patch)
treef5646108131916584291141407696ef894f2ff1e /openssl/src/derive.rs
parentMerge pull request #809 from sfackler/issuer-name (diff)
parentParameterize keys over what they contain (diff)
downloadrust-openssl-d3fff74ae8ab092a77050ba210b942e86c3bd9ff.tar.xz
rust-openssl-d3fff74ae8ab092a77050ba210b942e86c3bd9ff.zip
Merge pull request #810 from sfackler/key-tag
Parameterize keys over what they contain
Diffstat (limited to 'openssl/src/derive.rs')
-rw-r--r--openssl/src/derive.rs120
1 files changed, 120 insertions, 0 deletions
diff --git a/openssl/src/derive.rs b/openssl/src/derive.rs
new file mode 100644
index 00000000..fb7bbf14
--- /dev/null
+++ b/openssl/src/derive.rs
@@ -0,0 +1,120 @@
+//! Shared secret derivation.
+use ffi;
+use std::marker::PhantomData;
+use std::ptr;
+use foreign_types::ForeignTypeRef;
+
+use {cvt, cvt_p};
+use error::ErrorStack;
+use pkey::{HasPrivate, HasPublic, PKeyRef};
+
+/// A type used to derive a shared secret between two keys.
+pub struct Deriver<'a>(*mut ffi::EVP_PKEY_CTX, PhantomData<&'a ()>);
+
+impl<'a> Deriver<'a> {
+ /// Creates a new `Deriver` using the provided private key.
+ ///
+ /// This corresponds to [`EVP_PKEY_derive_init`].
+ ///
+ /// [`EVP_PKEY_derive_init`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html
+ pub fn new<T>(key: &'a PKeyRef<T>) -> Result<Deriver<'a>, ErrorStack>
+ where
+ T: HasPrivate,
+ {
+ unsafe {
+ cvt_p(ffi::EVP_PKEY_CTX_new(key.as_ptr(), ptr::null_mut()))
+ .map(|p| Deriver(p, PhantomData))
+ .and_then(|ctx| cvt(ffi::EVP_PKEY_derive_init(ctx.0)).map(|_| ctx))
+ }
+ }
+
+ /// Sets the peer key used for secret derivation.
+ ///
+ /// This corresponds to [`EVP_PKEY_derive_set_peer`]:
+ ///
+ /// [`EVP_PKEY_derive_set_peer`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html
+ pub fn set_peer<T>(&mut self, key: &'a PKeyRef<T>) -> Result<(), ErrorStack>
+ where
+ T: HasPublic,
+ {
+ unsafe { cvt(ffi::EVP_PKEY_derive_set_peer(self.0, key.as_ptr())).map(|_| ()) }
+ }
+
+ /// Returns the size of the shared secret.
+ ///
+ /// It can be used to size the buffer passed to [`Deriver::derive`].
+ ///
+ /// This corresponds to [`EVP_PKEY_derive`].
+ ///
+ /// [`Deriver::derive`]: #method.derive
+ /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html
+ pub fn len(&mut self) -> Result<usize, ErrorStack> {
+ unsafe {
+ let mut len = 0;
+ cvt(ffi::EVP_PKEY_derive(self.0, ptr::null_mut(), &mut len)).map(|_| len)
+ }
+ }
+
+ /// Derives a shared secret between the two keys, writing it into the buffer.
+ ///
+ /// Returns the number of bytes written.
+ ///
+ /// This corresponds to [`EVP_PKEY_derive`].
+ ///
+ /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html
+ pub fn derive(&mut self, buf: &mut [u8]) -> Result<usize, ErrorStack> {
+ let mut len = buf.len();
+ unsafe {
+ cvt(ffi::EVP_PKEY_derive(
+ self.0,
+ buf.as_mut_ptr() as *mut _,
+ &mut len,
+ )).map(|_| len)
+ }
+ }
+
+ /// A convenience function which derives a shared secret and returns it in a new buffer.
+ ///
+ /// This simply wraps [`Deriver::len`] and [`Deriver::derive`].
+ ///
+ /// [`Deriver::len`]: #method.len
+ /// [`Deriver::derive`]: #method.derive
+ pub fn derive_to_vec(&mut self) -> Result<Vec<u8>, ErrorStack> {
+ let len = self.len()?;
+ let mut buf = vec![0; len];
+ let len = self.derive(&mut buf)?;
+ buf.truncate(len);
+ Ok(buf)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ use ec::{EcGroup, EcKey};
+ use nid::Nid;
+ use pkey::PKey;
+
+ #[test]
+ fn derive_without_peer() {
+ let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
+ let ec_key = EcKey::generate(&group).unwrap();
+ let pkey = PKey::from_ec_key(ec_key).unwrap();
+ let mut deriver = Deriver::new(&pkey).unwrap();
+ deriver.derive_to_vec().unwrap_err();
+ }
+
+ #[test]
+ fn test_ec_key_derive() {
+ let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
+ let ec_key = EcKey::generate(&group).unwrap();
+ let ec_key2 = EcKey::generate(&group).unwrap();
+ let pkey = PKey::from_ec_key(ec_key).unwrap();
+ let pkey2 = PKey::from_ec_key(ec_key2).unwrap();
+ let mut deriver = Deriver::new(&pkey).unwrap();
+ deriver.set_peer(&pkey2).unwrap();
+ let shared = deriver.derive_to_vec().unwrap();
+ assert!(!shared.is_empty());
+ }
+}