1 //! Message digest algorithms.
2 
3 #[cfg(ossl300)]
4 use crate::cvt_p;
5 #[cfg(ossl300)]
6 use crate::error::ErrorStack;
7 #[cfg(ossl300)]
8 use crate::lib_ctx::LibCtxRef;
9 use crate::nid::Nid;
10 use cfg_if::cfg_if;
11 use foreign_types::{ForeignTypeRef, Opaque};
12 use openssl_macros::corresponds;
13 #[cfg(ossl300)]
14 use std::ffi::CString;
15 #[cfg(ossl300)]
16 use std::ptr;
17 
18 cfg_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.
74 pub struct Md(Inner);
75 
76 unsafe impl Sync for Md {}
77 unsafe impl Send for Md {}
78 
79 impl Md {
80     /// Returns the `Md` corresponding to an [`Nid`].
81     #[corresponds(EVP_get_digestbynid)]
from_nid(type_: Nid) -> Option<&'static MdRef>82     pub fn from_nid(type_: Nid) -> Option<&'static MdRef> {
83         unsafe {
84             let ptr = ffi::EVP_get_digestbynid(type_.as_raw());
85             if ptr.is_null() {
86                 None
87             } else {
88                 Some(MdRef::from_ptr(ptr as *mut _))
89             }
90         }
91     }
92 
93     /// Fetches an `Md` object corresponding to the specified algorithm name and properties.
94     ///
95     /// Requires OpenSSL 3.0.0 or newer.
96     #[corresponds(EVP_MD_fetch)]
97     #[cfg(ossl300)]
fetch( ctx: Option<&LibCtxRef>, algorithm: &str, properties: Option<&str>, ) -> Result<Self, ErrorStack>98     pub fn fetch(
99         ctx: Option<&LibCtxRef>,
100         algorithm: &str,
101         properties: Option<&str>,
102     ) -> Result<Self, ErrorStack> {
103         let algorithm = CString::new(algorithm).unwrap();
104         let properties = properties.map(|s| CString::new(s).unwrap());
105 
106         unsafe {
107             let ptr = cvt_p(ffi::EVP_MD_fetch(
108                 ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
109                 algorithm.as_ptr(),
110                 properties.map_or(ptr::null_mut(), |s| s.as_ptr()),
111             ))?;
112 
113             Ok(Md::from_ptr(ptr))
114         }
115     }
116 
117     #[inline]
118     #[cfg(not(boringssl))]
null() -> &'static MdRef119     pub fn null() -> &'static MdRef {
120         unsafe { MdRef::from_ptr(ffi::EVP_md_null() as *mut _) }
121     }
122 
123     #[inline]
md5() -> &'static MdRef124     pub fn md5() -> &'static MdRef {
125         unsafe { MdRef::from_ptr(ffi::EVP_md5() as *mut _) }
126     }
127 
128     #[inline]
sha1() -> &'static MdRef129     pub fn sha1() -> &'static MdRef {
130         unsafe { MdRef::from_ptr(ffi::EVP_sha1() as *mut _) }
131     }
132 
133     #[inline]
sha224() -> &'static MdRef134     pub fn sha224() -> &'static MdRef {
135         unsafe { MdRef::from_ptr(ffi::EVP_sha224() as *mut _) }
136     }
137 
138     #[inline]
sha256() -> &'static MdRef139     pub fn sha256() -> &'static MdRef {
140         unsafe { MdRef::from_ptr(ffi::EVP_sha256() as *mut _) }
141     }
142 
143     #[inline]
sha384() -> &'static MdRef144     pub fn sha384() -> &'static MdRef {
145         unsafe { MdRef::from_ptr(ffi::EVP_sha384() as *mut _) }
146     }
147 
148     #[inline]
sha512() -> &'static MdRef149     pub fn sha512() -> &'static MdRef {
150         unsafe { MdRef::from_ptr(ffi::EVP_sha512() as *mut _) }
151     }
152 
153     #[cfg(any(ossl111, libressl380))]
154     #[inline]
sha3_224() -> &'static MdRef155     pub fn sha3_224() -> &'static MdRef {
156         unsafe { MdRef::from_ptr(ffi::EVP_sha3_224() as *mut _) }
157     }
158 
159     #[cfg(any(ossl111, libressl380))]
160     #[inline]
sha3_256() -> &'static MdRef161     pub fn sha3_256() -> &'static MdRef {
162         unsafe { MdRef::from_ptr(ffi::EVP_sha3_256() as *mut _) }
163     }
164 
165     #[cfg(any(ossl111, libressl380))]
166     #[inline]
sha3_384() -> &'static MdRef167     pub fn sha3_384() -> &'static MdRef {
168         unsafe { MdRef::from_ptr(ffi::EVP_sha3_384() as *mut _) }
169     }
170 
171     #[cfg(any(ossl111, libressl380))]
172     #[inline]
sha3_512() -> &'static MdRef173     pub fn sha3_512() -> &'static MdRef {
174         unsafe { MdRef::from_ptr(ffi::EVP_sha3_512() as *mut _) }
175     }
176 
177     #[cfg(ossl111)]
178     #[inline]
shake128() -> &'static MdRef179     pub fn shake128() -> &'static MdRef {
180         unsafe { MdRef::from_ptr(ffi::EVP_shake128() as *mut _) }
181     }
182 
183     #[cfg(ossl111)]
184     #[inline]
shake256() -> &'static MdRef185     pub fn shake256() -> &'static MdRef {
186         unsafe { MdRef::from_ptr(ffi::EVP_shake256() as *mut _) }
187     }
188 
189     #[cfg(not(osslconf = "OPENSSL_NO_RMD160"))]
190     #[cfg(not(boringssl))]
191     #[inline]
ripemd160() -> &'static MdRef192     pub fn ripemd160() -> &'static MdRef {
193         unsafe { MdRef::from_ptr(ffi::EVP_ripemd160() as *mut _) }
194     }
195 
196     #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))]
197     #[inline]
sm3() -> &'static MdRef198     pub fn sm3() -> &'static MdRef {
199         unsafe { MdRef::from_ptr(ffi::EVP_sm3() as *mut _) }
200     }
201 }
202 
203 /// A reference to an [`Md`].
204 pub struct MdRef(Opaque);
205 
206 impl ForeignTypeRef for MdRef {
207     type CType = ffi::EVP_MD;
208 }
209 
210 unsafe impl Sync for MdRef {}
211 unsafe impl Send for MdRef {}
212 
213 impl MdRef {
214     /// Returns the block size of the digest in bytes.
215     #[corresponds(EVP_MD_block_size)]
216     #[inline]
block_size(&self) -> usize217     pub fn block_size(&self) -> usize {
218         unsafe { ffi::EVP_MD_block_size(self.as_ptr()) as usize }
219     }
220 
221     /// Returns the size of the digest in bytes.
222     #[corresponds(EVP_MD_size)]
223     #[inline]
size(&self) -> usize224     pub fn size(&self) -> usize {
225         unsafe { ffi::EVP_MD_size(self.as_ptr()) as usize }
226     }
227 
228     /// Returns the [`Nid`] of the digest.
229     #[corresponds(EVP_MD_type)]
230     #[inline]
type_(&self) -> Nid231     pub fn type_(&self) -> Nid {
232         unsafe { Nid::from_raw(ffi::EVP_MD_type(self.as_ptr())) }
233     }
234 }
235