1use crate::TpmCryptoError;
8use openssl::{
9 hash::{Hasher, MessageDigest},
10 memcmp,
11 pkey::PKey,
12 sign::Signer,
13};
14use strum::{Display, EnumString};
15use tpm2_protocol::data::TpmAlgId;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumString, Display)]
19#[strum(serialize_all = "kebab-case")]
20pub enum TpmHash {
21 Sha1,
22 Sha256,
23 Sha384,
24 Sha512,
25 Sm3_256,
26 Sha3_256,
27 Sha3_384,
28 Sha3_512,
29 Shake128,
30 Shake256,
31 Null,
32}
33
34impl From<TpmAlgId> for TpmHash {
35 fn from(alg: TpmAlgId) -> Self {
36 match alg {
37 TpmAlgId::Sha1 => Self::Sha1,
38 TpmAlgId::Sha256 => Self::Sha256,
39 TpmAlgId::Sha384 => Self::Sha384,
40 TpmAlgId::Sha512 => Self::Sha512,
41 TpmAlgId::Sm3_256 => Self::Sm3_256,
42 TpmAlgId::Sha3_256 => Self::Sha3_256,
43 TpmAlgId::Sha3_384 => Self::Sha3_384,
44 TpmAlgId::Sha3_512 => Self::Sha3_512,
45 TpmAlgId::Shake128 => Self::Shake128,
46 TpmAlgId::Shake256 => Self::Shake256,
47 _ => Self::Null,
48 }
49 }
50}
51
52impl From<TpmHash> for TpmAlgId {
53 fn from(alg: TpmHash) -> Self {
54 match alg {
55 TpmHash::Sha1 => Self::Sha1,
56 TpmHash::Sha256 => Self::Sha256,
57 TpmHash::Sha384 => Self::Sha384,
58 TpmHash::Sha512 => Self::Sha512,
59 TpmHash::Sm3_256 => Self::Sm3_256,
60 TpmHash::Sha3_256 => Self::Sha3_256,
61 TpmHash::Sha3_384 => Self::Sha3_384,
62 TpmHash::Sha3_512 => Self::Sha3_512,
63 TpmHash::Shake128 => Self::Shake128,
64 TpmHash::Shake256 => Self::Shake256,
65 TpmHash::Null => Self::Null,
66 }
67 }
68}
69
70impl From<TpmHash> for MessageDigest {
71 fn from(alg: TpmHash) -> Self {
72 match alg {
73 TpmHash::Sha1 => MessageDigest::sha1(),
74 TpmHash::Sha256 => MessageDigest::sha256(),
75 TpmHash::Sha384 => MessageDigest::sha384(),
76 TpmHash::Sha512 => MessageDigest::sha512(),
77 TpmHash::Sm3_256 => MessageDigest::sm3(),
78 TpmHash::Sha3_256 => MessageDigest::sha3_256(),
79 TpmHash::Sha3_384 => MessageDigest::sha3_384(),
80 TpmHash::Sha3_512 => MessageDigest::sha3_512(),
81 TpmHash::Shake128 => MessageDigest::shake_128(),
82 TpmHash::Shake256 => MessageDigest::shake_256(),
83 TpmHash::Null => MessageDigest::null(),
84 }
85 }
86}
87
88impl TpmHash {
89 #[must_use]
91 pub fn size(&self) -> usize {
92 Into::<MessageDigest>::into(*self).size()
93 }
94
95 pub fn digest(&self, data_chunks: &[&[u8]]) -> Result<Vec<u8>, TpmCryptoError> {
106 if *self == TpmHash::Null {
107 return Err(TpmCryptoError::InvalidHash);
108 }
109
110 let md = (*self).into();
111 let mut hasher = Hasher::new(md).map_err(|_| TpmCryptoError::OutOfMemory)?;
112 for chunk in data_chunks {
113 hasher
114 .update(chunk)
115 .map_err(|_| TpmCryptoError::OperationFailed)?;
116 }
117 Ok(hasher
118 .finish()
119 .map_err(|_| TpmCryptoError::OperationFailed)?
120 .to_vec())
121 }
122
123 pub fn hmac(&self, key: &[u8], data_chunks: &[&[u8]]) -> Result<Vec<u8>, TpmCryptoError> {
136 if *self == TpmHash::Null {
137 return Err(TpmCryptoError::InvalidHash);
138 }
139 if key.is_empty() {
140 return Err(TpmCryptoError::KeyIsEmpty);
141 }
142 let md = (*self).into();
143 let public_key = PKey::hmac(key).map_err(|_| TpmCryptoError::OutOfMemory)?;
144 let mut signer = Signer::new(md, &public_key).map_err(|_| TpmCryptoError::OutOfMemory)?;
145 for chunk in data_chunks {
146 signer
147 .update(chunk)
148 .map_err(|_| TpmCryptoError::OperationFailed)?;
149 }
150 signer
151 .sign_to_vec()
152 .map_err(|_| TpmCryptoError::OperationFailed)
153 }
154
155 pub fn hmac_verify(
168 &self,
169 key: &[u8],
170 data_chunks: &[&[u8]],
171 signature: &[u8],
172 ) -> Result<(), TpmCryptoError> {
173 let expected = self.hmac(key, data_chunks)?;
174 if memcmp::eq(&expected, signature) {
175 Ok(())
176 } else {
177 Err(TpmCryptoError::PermissionDenied)
178 }
179 }
180
181 pub fn kdfa(
195 &self,
196 hmac_key: &[u8],
197 label: &str,
198 context_a: &[u8],
199 context_b: &[u8],
200 key_bits: u16,
201 ) -> Result<Vec<u8>, TpmCryptoError> {
202 if *self == TpmHash::Null {
203 return Err(TpmCryptoError::InvalidHash);
204 }
205 if hmac_key.is_empty() {
206 return Err(TpmCryptoError::KeyIsEmpty);
207 }
208
209 let key_bytes = (key_bits as usize).div_ceil(8);
210 let mut key_stream = Vec::with_capacity(key_bytes);
211
212 let mut counter: u32 = 1;
213 let key_bits_bytes = u32::from(key_bits).to_be_bytes();
214
215 let md = (*self).into();
216 let pkey = PKey::hmac(hmac_key).map_err(|_| TpmCryptoError::OutOfMemory)?;
217
218 while key_stream.len() < key_bytes {
219 let counter_bytes = counter.to_be_bytes();
220 let hmac_payload = [
221 counter_bytes.as_slice(),
222 label.as_bytes(),
223 &[0u8],
224 context_a,
225 context_b,
226 key_bits_bytes.as_slice(),
227 ];
228
229 let mut signer = Signer::new(md, &pkey).map_err(|_| TpmCryptoError::OutOfMemory)?;
230 for chunk in &hmac_payload {
231 signer
232 .update(chunk)
233 .map_err(|_| TpmCryptoError::OperationFailed)?;
234 }
235 let result = signer
236 .sign_to_vec()
237 .map_err(|_| TpmCryptoError::OperationFailed)?;
238
239 let remaining = key_bytes - key_stream.len();
240 let to_take = remaining.min(result.len());
241 key_stream.extend_from_slice(&result[..to_take]);
242
243 counter += 1;
244 }
245
246 Ok(key_stream)
247 }
248
249 pub fn kdfe(
260 &self,
261 z: &[u8],
262 label: &str,
263 context_u: &[u8],
264 context_v: &[u8],
265 key_bits: u16,
266 ) -> Result<Vec<u8>, TpmCryptoError> {
267 if *self == TpmHash::Null {
268 return Err(TpmCryptoError::InvalidHash);
269 }
270
271 let key_bytes = (key_bits as usize).div_ceil(8);
272 let mut key_stream = Vec::with_capacity(key_bytes);
273
274 let (label_data, terminator) = if label.as_bytes().last() == Some(&0) {
275 (label.as_bytes(), &[][..])
276 } else {
277 (label.as_bytes(), &[0u8][..])
278 };
279
280 let mut counter: u32 = 1;
281 let md = (*self).into();
282
283 while key_stream.len() < key_bytes {
284 let counter_bytes = counter.to_be_bytes();
285 let digest_payload = [
286 &counter_bytes,
287 z,
288 label_data,
289 terminator,
290 context_u,
291 context_v,
292 ];
293
294 let mut hasher = Hasher::new(md).map_err(|_| TpmCryptoError::OutOfMemory)?;
295 for chunk in &digest_payload {
296 hasher
297 .update(chunk)
298 .map_err(|_| TpmCryptoError::OperationFailed)?;
299 }
300 let result = hasher
301 .finish()
302 .map_err(|_| TpmCryptoError::OperationFailed)?;
303
304 let remaining = key_bytes - key_stream.len();
305 let to_take = remaining.min(result.len());
306 key_stream.extend_from_slice(&result[..to_take]);
307
308 counter += 1;
309 }
310
311 Ok(key_stream)
312 }
313}