Loading openssl/src/derive.rs +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; Loading openssl/src/dh.rs +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; Loading openssl/src/ec.rs +55 −9 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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( Loading Loading @@ -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 { Loading openssl/src/hash.rs +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; Loading @@ -18,6 +50,7 @@ cfg_if! { } } /// A message digest algorithm. #[derive(Copy, Clone, PartialEq, Eq)] pub struct MessageDigest(*const ffi::EVP_MD); Loading Loading @@ -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 Loading @@ -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, Loading Loading @@ -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)?; Loading @@ -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)?; Loading openssl/src/md.rs +2 −0 Original line number Diff line number Diff line //! Message digest algorithms. #[cfg(ossl300)] use crate::cvt_p; #[cfg(ossl300)] Loading Loading
openssl/src/derive.rs +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; Loading
openssl/src/dh.rs +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; Loading
openssl/src/ec.rs +55 −9 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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( Loading Loading @@ -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 { Loading
openssl/src/hash.rs +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; Loading @@ -18,6 +50,7 @@ cfg_if! { } } /// A message digest algorithm. #[derive(Copy, Clone, PartialEq, Eq)] pub struct MessageDigest(*const ffi::EVP_MD); Loading Loading @@ -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 Loading @@ -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, Loading Loading @@ -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)?; Loading @@ -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)?; Loading
openssl/src/md.rs +2 −0 Original line number Diff line number Diff line //! Message digest algorithms. #[cfg(ossl300)] use crate::cvt_p; #[cfg(ossl300)] Loading