Skip to content

Commit

Permalink
Merge pull request #1741 from wiktor-k/improve-docs
Browse files Browse the repository at this point in the history
Improve documentation and doctests
  • Loading branch information
sfackler authored Dec 4, 2022
2 parents 6643d07 + d390c41 commit 54d4496
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 45 deletions.
50 changes: 50 additions & 0 deletions openssl/src/derive.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,54 @@
//! 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;
Expand Down
2 changes: 2 additions & 0 deletions openssl/src/dh.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Diffie-Hellman key agreement.

use cfg_if::cfg_if;
use foreign_types::{ForeignType, ForeignTypeRef};
use std::mem;
Expand Down
64 changes: 55 additions & 9 deletions openssl/src/ec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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 {
Expand Down
103 changes: 69 additions & 34 deletions openssl/src/hash.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,35 @@
//! 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;
Expand All @@ -18,6 +50,7 @@ cfg_if! {
}
}

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

Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -411,13 +420,39 @@ 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)?;
h.finish()
}

/// 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)?;
Expand Down
2 changes: 2 additions & 0 deletions openssl/src/md.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Message digest algorithms.

#[cfg(ossl300)]
use crate::cvt_p;
#[cfg(ossl300)]
Expand Down
6 changes: 4 additions & 2 deletions openssl/src/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@ impl<'a> Write for Signer<'a> {
}
}

/// A type which can be used to verify the integrity and authenticity
/// of data given the signature.
pub struct Verifier<'a> {
md_ctx: *mut ffi::EVP_MD_CTX,
pctx: *mut ffi::EVP_PKEY_CTX,
Expand All @@ -426,7 +428,7 @@ impl<'a> Verifier<'a> {
/// Creates a new `Verifier`.
///
/// This cannot be used with Ed25519 or Ed448 keys. Please refer to
/// `new_without_digest`.
/// [`Verifier::new_without_digest`].
///
/// OpenSSL documentation at [`EVP_DigestVerifyInit`].
///
Expand Down Expand Up @@ -553,7 +555,7 @@ impl<'a> Verifier<'a> {
/// Feeds more data into the `Verifier`.
///
/// Please note that PureEdDSA (Ed25519 and Ed448 keys) do not support streaming.
/// Use `verify_oneshot` instead.
/// Use [`Verifier::verify_oneshot`] instead.
///
/// OpenSSL documentation at [`EVP_DigestUpdate`].
///
Expand Down
2 changes: 2 additions & 0 deletions openssl/src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
// limitations under the License.
//

//! Build and version information.

use cfg_if::cfg_if;
use openssl_macros::corresponds;
use std::ffi::CStr;
Expand Down

0 comments on commit 54d4496

Please sign in to comment.