apple_security_framework/os/macos/
digest_transform.rs1use std::ptr;
4
5use core_foundation::{
6 base::{CFIndex, TCFType},
7 data::CFData,
8 error::CFError,
9 string::CFString,
10};
11use core_foundation_sys::{base::CFTypeRef, data::CFDataRef, string::CFStringRef};
12use security_framework_sys::{digest_transform::*, transform::*};
13
14use crate::os::macos::transform::SecTransform;
15
16#[derive(Debug, Copy, Clone)]
17pub struct DigestType(CFStringRef);
19
20#[allow(missing_docs)]
21impl DigestType {
22 #[inline(always)]
23 #[must_use]
24 pub fn hmac_md5() -> Self {
25 unsafe { Self(kSecDigestHMACMD5) }
26 }
27
28 #[inline(always)]
29 #[must_use]
30 pub fn hmac_sha1() -> Self {
31 unsafe { Self(kSecDigestHMACSHA1) }
32 }
33
34 #[inline(always)]
35 #[must_use]
36 pub fn hmac_sha2() -> Self {
37 unsafe { Self(kSecDigestHMACSHA2) }
38 }
39
40 #[inline(always)]
41 #[must_use]
42 pub fn md2() -> Self {
43 unsafe { Self(kSecDigestMD2) }
44 }
45
46 #[inline(always)]
47 #[must_use]
48 pub fn md4() -> Self {
49 unsafe { Self(kSecDigestMD4) }
50 }
51
52 #[inline(always)]
53 #[must_use]
54 pub fn md5() -> Self {
55 unsafe { Self(kSecDigestMD5) }
56 }
57
58 #[inline(always)]
59 #[must_use]
60 pub fn sha1() -> Self {
61 unsafe { Self(kSecDigestSHA1) }
62 }
63
64 #[inline(always)]
65 #[must_use]
66 pub fn sha2() -> Self {
67 unsafe { Self(kSecDigestSHA2) }
68 }
69
70 #[inline(always)]
71 fn to_type(self) -> CFTypeRef {
72 self.0 as CFTypeRef
73 }
74}
75
76pub struct Builder {
78 digest_type: Option<DigestType>,
79 digest_length: Option<CFIndex>,
80 hmac_key: Option<CFData>,
81}
82
83impl Default for Builder {
84 #[inline(always)]
85 fn default() -> Self {
86 Self::new()
87 }
88}
89
90impl Builder {
91 #[inline(always)]
93 #[must_use]
94 pub fn new() -> Self {
95 Self {
96 digest_type: None,
97 digest_length: None,
98 hmac_key: None,
99 }
100 }
101
102 #[inline]
106 pub fn type_(&mut self, digest_type: DigestType) -> &mut Self {
107 self.digest_type = Some(digest_type);
108 self
109 }
110
111 #[inline]
116 pub fn length(&mut self, digest_length: CFIndex) -> &mut Self {
117 self.digest_length = Some(digest_length);
118 self
119 }
120
121 #[inline]
125 pub fn hmac_key(&mut self, hmac_key: CFData) -> &mut Self {
126 self.hmac_key = Some(hmac_key);
127 self
128 }
129
130 pub fn execute(&self, data: &CFData) -> Result<CFData, CFError> {
132 unsafe {
133 let digest_type = match self.digest_type {
134 Some(ref digest_type) => digest_type.to_type(),
135 None => ptr::null(),
136 };
137
138 let digest_length = self.digest_length.unwrap_or(0);
139
140 let mut error = ptr::null_mut();
141 let transform = SecDigestTransformCreate(digest_type, digest_length, &mut error);
142 if transform.is_null() {
143 return Err(CFError::wrap_under_create_rule(error));
144 }
145 let mut transform = SecTransform::wrap_under_create_rule(transform);
146
147 if let Some(ref hmac_key) = self.hmac_key {
148 let key = CFString::wrap_under_get_rule(kSecDigestHMACKeyAttribute);
149 transform.set_attribute(&key, hmac_key)?;
150 }
151
152 let key = CFString::wrap_under_get_rule(kSecTransformInputAttributeName);
153 transform.set_attribute(&key, data)?;
154
155 let result = transform.execute()?;
156 Ok(CFData::wrap_under_get_rule(
157 result.as_CFTypeRef() as CFDataRef
158 ))
159 }
160 }
161}
162
163#[cfg(test)]
164mod test {
165 use core_foundation::data::CFData;
166 use hex;
167
168 use super::*;
169
170 #[test]
171 fn md5() {
172 let data = CFData::from_buffer("The quick brown fox jumps over the lazy dog".as_bytes());
173 let hash = Builder::new()
174 .type_(DigestType::md5())
175 .execute(&data)
176 .unwrap();
177 assert_eq!(
178 hex::encode(hash.bytes()),
179 "9e107d9d372bb6826bd81d3542a419d6"
180 );
181 }
182
183 #[test]
184 fn hmac_sha1() {
185 let data = CFData::from_buffer("The quick brown fox jumps over the lazy dog".as_bytes());
186 let key = CFData::from_buffer(b"key");
187 let hash = Builder::new()
188 .type_(DigestType::hmac_sha1())
189 .hmac_key(key)
190 .execute(&data)
191 .unwrap();
192 assert_eq!(
193 hex::encode(hash.bytes()),
194 "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"
195 );
196 }
197}