Unverified Commit 54d4496e authored by Steven Fackler's avatar Steven Fackler Committed by GitHub
Browse files

Merge pull request #1741 from wiktor-k/improve-docs

Improve documentation and doctests
parents 6643d072 d390c414
Loading
Loading
Loading
Loading
+50 −0
Original line number Diff line number Diff line
//! Shared secret derivation.
//!
//! # Example
//!
//! The following example implements [ECDH] using `NIST P-384` keys:
//!
//! ```
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # use std::convert::TryInto;
//! use openssl::bn::BigNumContext;
//! use openssl::pkey::PKey;
//! use openssl::derive::Deriver;
//! use openssl::ec::{EcGroup, EcKey, EcPoint, PointConversionForm};
//! use openssl::nid::Nid;
//!
//! let group = EcGroup::from_curve_name(Nid::SECP384R1)?;
//!
//! let first: PKey<_> = EcKey::generate(&group)?.try_into()?;
//!
//! // second party generates an ephemeral key and derives
//! // a shared secret using first party's public key
//! let shared_key = EcKey::generate(&group)?;
//! // shared_public is sent to first party
//! let mut ctx = BigNumContext::new()?;
//! let shared_public = shared_key.public_key().to_bytes(
//!        &group,
//!        PointConversionForm::COMPRESSED,
//!        &mut ctx,
//!    )?;
//!
//! let shared_key: PKey<_> = shared_key.try_into()?;
//! let mut deriver = Deriver::new(&shared_key)?;
//! deriver.set_peer(&first)?;
//! // secret can be used e.g. as a symmetric encryption key
//! let secret = deriver.derive_to_vec()?;
//! # drop(deriver);
//!
//! // first party derives the same shared secret using
//! // shared_public
//! let point = EcPoint::from_bytes(&group, &shared_public, &mut ctx)?;
//! let recipient_key: PKey<_> = EcKey::from_public_key(&group, &point)?.try_into()?;
//! let mut deriver = Deriver::new(&first)?;
//! deriver.set_peer(&recipient_key)?;
//! let first_secret = deriver.derive_to_vec()?;
//!
//! assert_eq!(secret, first_secret);
//! # Ok(()) }
//! ```
//!
//! [ECDH]: https://wiki.openssl.org/index.php/Elliptic_Curve_Diffie_Hellman

use foreign_types::ForeignTypeRef;
use std::marker::PhantomData;
use std::ptr;
+2 −0
Original line number Diff line number Diff line
//! Diffie-Hellman key agreement.

use cfg_if::cfg_if;
use foreign_types::{ForeignType, ForeignTypeRef};
use std::mem;
+55 −9
Original line number Diff line number Diff line
@@ -116,6 +116,19 @@ foreign_type_and_impl_send_sync! {

impl EcGroup {
    /// Returns the group of a standard named curve.
    ///
    /// # Examples
    ///
    /// ```
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// use openssl::nid::Nid;
    /// use openssl::ec::{EcGroup, EcKey};
    ///
    /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve
    /// let group = EcGroup::from_curve_name(nid)?;
    /// let key = EcKey::generate(&group)?;
    /// # Ok(()) }
    /// ```
    #[corresponds(EC_GROUP_new_by_curve_name)]
    pub fn from_curve_name(nid: Nid) -> Result<EcGroup, ErrorStack> {
        unsafe {
@@ -748,26 +761,32 @@ impl EcKey<Params> {
}

impl EcKey<Public> {
    /// Constructs an `EcKey` from the specified group with the associated `EcPoint`, public_key.
    /// Constructs an `EcKey` from the specified group with the associated [`EcPoint`]: `public_key`.
    ///
    /// This will only have the associated public_key.
    /// This will only have the associated `public_key`.
    ///
    /// # Example
    ///
    /// ```no_run
    /// ```
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// use openssl::bn::BigNumContext;
    /// use openssl::ec::*;
    /// use openssl::nid::Nid;
    /// use openssl::pkey::PKey;
    ///
    /// // get bytes from somewhere, i.e. this will not produce a valid key
    /// let public_key: Vec<u8> = vec![];
    /// let group = EcGroup::from_curve_name(Nid::SECP384R1)?;
    /// let mut ctx = BigNumContext::new()?;
    ///
    /// // get bytes from somewhere
    /// let public_key = // ...
    /// # EcKey::generate(&group)?.public_key().to_bytes(&group,
    /// # PointConversionForm::COMPRESSED, &mut ctx)?;
    ///
    /// // create an EcKey from the binary form of a EcPoint
    /// let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
    /// let mut ctx = BigNumContext::new().unwrap();
    /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx).unwrap();
    /// let key = EcKey::from_public_key(&group, &point);
    /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx)?;
    /// let key = EcKey::from_public_key(&group, &point)?;
    /// key.check_key()?;
    /// # Ok(()) }
    /// ```
    #[corresponds(EC_KEY_set_public_key)]
    pub fn from_public_key(
@@ -835,6 +854,33 @@ impl EcKey<Public> {

impl EcKey<Private> {
    /// Generates a new public/private key pair on the specified curve.
    ///
    /// # Examples
    ///
    /// ```
    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
    /// use openssl::bn::BigNumContext;
    /// use openssl::nid::Nid;
    /// use openssl::ec::{EcGroup, EcKey, PointConversionForm};
    ///
    /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve
    /// let group = EcGroup::from_curve_name(nid)?;
    /// let key = EcKey::generate(&group)?;
    ///
    /// let mut ctx = BigNumContext::new()?;
    ///
    /// let public_key = &key.public_key().to_bytes(
    ///     &group,
    ///     PointConversionForm::COMPRESSED,
    ///     &mut ctx,
    /// )?;
    /// assert_eq!(public_key.len(), 33);
    /// assert_ne!(public_key[0], 0x04);
    ///
    /// let private_key = key.private_key().to_vec();
    /// assert!(private_key.len() >= 31);
    /// # Ok(()) }
    /// ```
    #[corresponds(EC_KEY_generate_key)]
    pub fn generate(group: &EcGroupRef) -> Result<EcKey<Private>, ErrorStack> {
        unsafe {
+69 −34
Original line number Diff line number Diff line
//! Message digest (hash) computation support.
//!
//! # Examples
//!
//! Calculate a hash in one go:
//!
//! ```
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use openssl::hash::{hash, MessageDigest};
//!
//! let data = b"\x42\xF4\x97\xE0";
//! let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
//! let res = hash(MessageDigest::md5(), data)?;
//! assert_eq!(&*res, spec);
//! # Ok(()) }
//! ```
//!
//! Supply the input in chunks:
//!
//! ```
//! use openssl::hash::{Hasher, MessageDigest};
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let mut hasher = Hasher::new(MessageDigest::sha256())?;
//! hasher.update(b"test")?;
//! hasher.update(b"this")?;
//! let digest: &[u8] = &hasher.finish()?;
//!
//! let expected = hex::decode("9740e652ab5b4acd997a7cca13d6696702ccb2d441cca59fc6e285127f28cfe6")?;
//! assert_eq!(digest, expected);
//! # Ok(()) }
//! ```
use cfg_if::cfg_if;
use std::ffi::CString;
use std::fmt;
@@ -18,6 +50,7 @@ cfg_if! {
    }
}

/// A message digest algorithm.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct MessageDigest(*const ffi::EVP_MD);

@@ -174,44 +207,18 @@ use self::State::*;
///
/// # Examples
///
/// Calculate a hash in one go:
///
/// ```
/// use openssl::hash::{hash, MessageDigest};
///
/// let data = b"\x42\xF4\x97\xE0";
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
/// let res = hash(MessageDigest::md5(), data).unwrap();
/// assert_eq!(&*res, spec);
/// ```
///
/// Supply the input in chunks:
///
/// ```
/// use openssl::hash::{Hasher, MessageDigest};
///
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let data = [b"\x42\xF4", b"\x97\xE0"];
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
/// let mut h = Hasher::new(MessageDigest::md5()).unwrap();
/// h.update(data[0]).unwrap();
/// h.update(data[1]).unwrap();
/// let res = h.finish().unwrap();
/// let mut h = Hasher::new(MessageDigest::md5())?;
/// h.update(data[0])?;
/// h.update(data[1])?;
/// let res = h.finish()?;
/// assert_eq!(&*res, spec);
/// ```
///
/// Use an XOF hasher (OpenSSL 1.1.1+):
///
/// ```
/// #[cfg(ossl111)]
/// {
///     use openssl::hash::{hash_xof, MessageDigest};
///
///     let data = b"\x41\x6c\x6c\x20\x79\x6f\x75\x72\x20\x62\x61\x73\x65\x20\x61\x72\x65\x20\x62\x65\x6c\x6f\x6e\x67\x20\x74\x6f\x20\x75\x73";
///     let spec = b"\x49\xd0\x69\x7f\xf5\x08\x11\x1d\x8b\x84\xf1\x5e\x46\xda\xf1\x35";
///     let mut buf = vec![0; 16];
///     hash_xof(MessageDigest::shake_128(), data, buf.as_mut_slice()).unwrap();
///     assert_eq!(buf, spec);
/// }
/// # Ok(()) }
/// ```
///
/// # Warning
@@ -220,8 +227,10 @@ use self::State::*;
///
/// Don't ever hash passwords, use the functions in the `pkcs5` module or bcrypt/scrypt instead.
///
/// For extendable output functions (XOFs, i.e. SHAKE128/SHAKE256), you must use finish_xof instead
/// of finish and provide a buf to store the hash. The hash will be as long as the buf.
/// For extendable output functions (XOFs, i.e. SHAKE128/SHAKE256),
/// you must use [`Hasher::finish_xof`] instead of [`Hasher::finish`]
/// and provide a `buf` to store the hash. The hash will be as long as
/// the `buf`.
pub struct Hasher {
    ctx: *mut ffi::EVP_MD_CTX,
    md: *const ffi::EVP_MD,
@@ -411,6 +420,19 @@ impl fmt::Debug for DigestBytes {
}

/// Computes the hash of the `data` with the non-XOF hasher `t`.
///
/// # Examples
///
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use openssl::hash::{hash, MessageDigest};
///
/// let data = b"\x42\xF4\x97\xE0";
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
/// let res = hash(MessageDigest::md5(), data)?;
/// assert_eq!(&*res, spec);
/// # Ok(()) }
/// ```
pub fn hash(t: MessageDigest, data: &[u8]) -> Result<DigestBytes, ErrorStack> {
    let mut h = Hasher::new(t)?;
    h.update(data)?;
@@ -418,6 +440,19 @@ pub fn hash(t: MessageDigest, data: &[u8]) -> Result<DigestBytes, ErrorStack> {
}

/// Computes the hash of the `data` with the XOF hasher `t` and stores it in `buf`.
///
/// # Examples
///
/// ```
/// use openssl::hash::{hash_xof, MessageDigest};
///
/// let data = b"\x41\x6c\x6c\x20\x79\x6f\x75\x72\x20\x62\x61\x73\x65\x20\x61\x72\x65\x20\x62\x65\x6c\x6f\x6e\x67\x20\x74\x6f\x20\x75\x73";
/// let spec = b"\x49\xd0\x69\x7f\xf5\x08\x11\x1d\x8b\x84\xf1\x5e\x46\xda\xf1\x35";
/// let mut buf = vec![0; 16];
/// hash_xof(MessageDigest::shake_128(), data, buf.as_mut_slice()).unwrap();
/// assert_eq!(buf, spec);
/// ```
///
#[cfg(ossl111)]
pub fn hash_xof(t: MessageDigest, data: &[u8], buf: &mut [u8]) -> Result<(), ErrorStack> {
    let mut h = Hasher::new(t)?;
+2 −0
Original line number Diff line number Diff line
//! Message digest algorithms.

#[cfg(ossl300)]
use crate::cvt_p;
#[cfg(ossl300)]
Loading