openssl/
md.rs

1//! Message digest algorithms.
2
3#[cfg(ossl300)]
4use crate::cvt_p;
5#[cfg(ossl300)]
6use crate::error::ErrorStack;
7#[cfg(ossl300)]
8use crate::lib_ctx::LibCtxRef;
9use crate::nid::Nid;
10use cfg_if::cfg_if;
11use foreign_types::{ForeignTypeRef, Opaque};
12use openssl_macros::corresponds;
13#[cfg(ossl300)]
14use std::ffi::CString;
15#[cfg(ossl300)]
16use std::ptr;
17
18cfg_if! {
19    if #[cfg(ossl300)] {
20        use foreign_types::ForeignType;
21        use std::ops::{Deref, DerefMut};
22
23        type Inner = *mut ffi::EVP_MD;
24
25        impl Drop for Md {
26            #[inline]
27            fn drop(&mut self) {
28                unsafe {
29                    ffi::EVP_MD_free(self.as_ptr());
30                }
31            }
32        }
33
34        impl ForeignType for Md {
35            type CType = ffi::EVP_MD;
36            type Ref = MdRef;
37
38            #[inline]
39            unsafe fn from_ptr(ptr: *mut Self::CType) -> Self {
40                Md(ptr)
41            }
42
43            #[inline]
44            fn as_ptr(&self) -> *mut Self::CType {
45                self.0
46            }
47        }
48
49        impl Deref for Md {
50            type Target = MdRef;
51
52            #[inline]
53            fn deref(&self) -> &Self::Target {
54                unsafe {
55                    MdRef::from_ptr(self.as_ptr())
56                }
57            }
58        }
59
60        impl DerefMut for Md {
61            #[inline]
62            fn deref_mut(&mut self) -> &mut Self::Target {
63                unsafe {
64                    MdRef::from_ptr_mut(self.as_ptr())
65                }
66            }
67        }
68    } else {
69        enum Inner {}
70    }
71}
72
73/// A message digest algorithm.
74pub struct Md(Inner);
75
76unsafe impl Sync for Md {}
77unsafe impl Send for Md {}
78
79impl Md {
80    /// Returns the `Md` corresponding to an [`Nid`].
81    #[corresponds(EVP_get_digestbynid)]
82    pub fn from_nid(type_: Nid) -> Option<&'static MdRef> {
83        ffi::init();
84        unsafe {
85            let ptr = ffi::EVP_get_digestbynid(type_.as_raw());
86            if ptr.is_null() {
87                None
88            } else {
89                Some(MdRef::from_ptr(ptr as *mut _))
90            }
91        }
92    }
93
94    /// Fetches an `Md` object corresponding to the specified algorithm name and properties.
95    ///
96    /// Requires OpenSSL 3.0.0 or newer.
97    #[corresponds(EVP_MD_fetch)]
98    #[cfg(ossl300)]
99    pub fn fetch(
100        ctx: Option<&LibCtxRef>,
101        algorithm: &str,
102        properties: Option<&str>,
103    ) -> Result<Self, ErrorStack> {
104        ffi::init();
105        let algorithm = CString::new(algorithm).unwrap();
106        let properties = properties.map(|s| CString::new(s).unwrap());
107
108        unsafe {
109            let ptr = cvt_p(ffi::EVP_MD_fetch(
110                ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
111                algorithm.as_ptr(),
112                properties.as_ref().map_or(ptr::null_mut(), |s| s.as_ptr()),
113            ))?;
114
115            Ok(Md::from_ptr(ptr))
116        }
117    }
118
119    #[inline]
120    #[cfg(not(boringssl))]
121    pub fn null() -> &'static MdRef {
122        unsafe { MdRef::from_ptr(ffi::EVP_md_null() as *mut _) }
123    }
124
125    #[inline]
126    pub fn md5() -> &'static MdRef {
127        unsafe { MdRef::from_ptr(ffi::EVP_md5() as *mut _) }
128    }
129
130    #[inline]
131    pub fn sha1() -> &'static MdRef {
132        unsafe { MdRef::from_ptr(ffi::EVP_sha1() as *mut _) }
133    }
134
135    #[inline]
136    pub fn sha224() -> &'static MdRef {
137        unsafe { MdRef::from_ptr(ffi::EVP_sha224() as *mut _) }
138    }
139
140    #[inline]
141    pub fn sha256() -> &'static MdRef {
142        unsafe { MdRef::from_ptr(ffi::EVP_sha256() as *mut _) }
143    }
144
145    #[inline]
146    pub fn sha384() -> &'static MdRef {
147        unsafe { MdRef::from_ptr(ffi::EVP_sha384() as *mut _) }
148    }
149
150    #[inline]
151    pub fn sha512() -> &'static MdRef {
152        unsafe { MdRef::from_ptr(ffi::EVP_sha512() as *mut _) }
153    }
154
155    #[cfg(any(ossl111, libressl380))]
156    #[inline]
157    pub fn sha3_224() -> &'static MdRef {
158        unsafe { MdRef::from_ptr(ffi::EVP_sha3_224() as *mut _) }
159    }
160
161    #[cfg(any(ossl111, libressl380))]
162    #[inline]
163    pub fn sha3_256() -> &'static MdRef {
164        unsafe { MdRef::from_ptr(ffi::EVP_sha3_256() as *mut _) }
165    }
166
167    #[cfg(any(ossl111, libressl380))]
168    #[inline]
169    pub fn sha3_384() -> &'static MdRef {
170        unsafe { MdRef::from_ptr(ffi::EVP_sha3_384() as *mut _) }
171    }
172
173    #[cfg(any(ossl111, libressl380))]
174    #[inline]
175    pub fn sha3_512() -> &'static MdRef {
176        unsafe { MdRef::from_ptr(ffi::EVP_sha3_512() as *mut _) }
177    }
178
179    #[cfg(ossl111)]
180    #[inline]
181    pub fn shake128() -> &'static MdRef {
182        unsafe { MdRef::from_ptr(ffi::EVP_shake128() as *mut _) }
183    }
184
185    #[cfg(ossl111)]
186    #[inline]
187    pub fn shake256() -> &'static MdRef {
188        unsafe { MdRef::from_ptr(ffi::EVP_shake256() as *mut _) }
189    }
190
191    #[cfg(not(osslconf = "OPENSSL_NO_RMD160"))]
192    #[inline]
193    pub fn ripemd160() -> &'static MdRef {
194        unsafe { MdRef::from_ptr(ffi::EVP_ripemd160() as *mut _) }
195    }
196
197    #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))]
198    #[inline]
199    pub fn sm3() -> &'static MdRef {
200        unsafe { MdRef::from_ptr(ffi::EVP_sm3() as *mut _) }
201    }
202}
203
204/// A reference to an [`Md`].
205pub struct MdRef(Opaque);
206
207impl ForeignTypeRef for MdRef {
208    type CType = ffi::EVP_MD;
209}
210
211unsafe impl Sync for MdRef {}
212unsafe impl Send for MdRef {}
213
214impl MdRef {
215    /// Returns the block size of the digest in bytes.
216    #[corresponds(EVP_MD_block_size)]
217    #[inline]
218    pub fn block_size(&self) -> usize {
219        unsafe { ffi::EVP_MD_block_size(self.as_ptr()) as usize }
220    }
221
222    /// Returns the size of the digest in bytes.
223    #[corresponds(EVP_MD_size)]
224    #[inline]
225    pub fn size(&self) -> usize {
226        unsafe { ffi::EVP_MD_size(self.as_ptr()) as usize }
227    }
228
229    /// Returns the [`Nid`] of the digest.
230    #[corresponds(EVP_MD_type)]
231    #[inline]
232    pub fn type_(&self) -> Nid {
233        unsafe { Nid::from_raw(ffi::EVP_MD_type(self.as_ptr())) }
234    }
235}
236
237#[cfg(test)]
238mod test {
239    #[cfg(ossl300)]
240    use super::Md;
241
242    #[test]
243    #[cfg(ossl300)]
244    fn test_md_fetch_properties() {
245        assert!(Md::fetch(None, "SHA-256", Some("provider=gibberish")).is_err());
246    }
247}