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)] |
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`]. |
205 | pub struct MdRef(Opaque); |
206 | |
207 | impl ForeignTypeRef for MdRef { |
208 | type CType = ffi::EVP_MD; |
209 | } |
210 | |
211 | unsafe impl Sync for MdRef {} |
212 | unsafe impl Send for MdRef {} |
213 | |
214 | impl 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)] |
238 | mod 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 | } |
248 | |