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 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)]
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))]
119 pub fn null() -> &'static MdRef {
120 unsafe { MdRef::from_ptr(ffi::EVP_md_null() as *mut _) }
121 }
122
123 #[inline]
124 pub fn md5() -> &'static MdRef {
125 unsafe { MdRef::from_ptr(ffi::EVP_md5() as *mut _) }
126 }
127
128 #[inline]
129 pub fn sha1() -> &'static MdRef {
130 unsafe { MdRef::from_ptr(ffi::EVP_sha1() as *mut _) }
131 }
132
133 #[inline]
134 pub fn sha224() -> &'static MdRef {
135 unsafe { MdRef::from_ptr(ffi::EVP_sha224() as *mut _) }
136 }
137
138 #[inline]
139 pub fn sha256() -> &'static MdRef {
140 unsafe { MdRef::from_ptr(ffi::EVP_sha256() as *mut _) }
141 }
142
143 #[inline]
144 pub fn sha384() -> &'static MdRef {
145 unsafe { MdRef::from_ptr(ffi::EVP_sha384() as *mut _) }
146 }
147
148 #[inline]
149 pub fn sha512() -> &'static MdRef {
150 unsafe { MdRef::from_ptr(ffi::EVP_sha512() as *mut _) }
151 }
152
153 #[cfg(any(ossl111, libressl380))]
154 #[inline]
155 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]
161 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]
167 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]
173 pub fn sha3_512() -> &'static MdRef {
174 unsafe { MdRef::from_ptr(ffi::EVP_sha3_512() as *mut _) }
175 }
176
177 #[cfg(ossl111)]
178 #[inline]
179 pub fn shake128() -> &'static MdRef {
180 unsafe { MdRef::from_ptr(ffi::EVP_shake128() as *mut _) }
181 }
182
183 #[cfg(ossl111)]
184 #[inline]
185 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 #[inline]
191 pub fn ripemd160() -> &'static MdRef {
192 unsafe { MdRef::from_ptr(ffi::EVP_ripemd160() as *mut _) }
193 }
194
195 #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))]
196 #[inline]
197 pub fn sm3() -> &'static MdRef {
198 unsafe { MdRef::from_ptr(ffi::EVP_sm3() as *mut _) }
199 }
200}
201
202/// A reference to an [`Md`].
203pub struct MdRef(Opaque);
204
205impl ForeignTypeRef for MdRef {
206 type CType = ffi::EVP_MD;
207}
208
209unsafe impl Sync for MdRef {}
210unsafe impl Send for MdRef {}
211
212impl MdRef {
213 /// Returns the block size of the digest in bytes.
214 #[corresponds(EVP_MD_block_size)]
215 #[inline]
216 pub fn block_size(&self) -> usize {
217 unsafe { ffi::EVP_MD_block_size(self.as_ptr()) as usize }
218 }
219
220 /// Returns the size of the digest in bytes.
221 #[corresponds(EVP_MD_size)]
222 #[inline]
223 pub fn size(&self) -> usize {
224 unsafe { ffi::EVP_MD_size(self.as_ptr()) as usize }
225 }
226
227 /// Returns the [`Nid`] of the digest.
228 #[corresponds(EVP_MD_type)]
229 #[inline]
230 pub fn type_(&self) -> Nid {
231 unsafe { Nid::from_raw(ffi::EVP_MD_type(self.as_ptr())) }
232 }
233}
234