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 | TpmHash::Sha3_512 => MessageDigest::sm3(),
78 TpmHash::Sha3_256 => MessageDigest::sha3_256(),
79 TpmHash::Sha3_384 => MessageDigest::sha3_384(),
80 TpmHash::Shake128 => MessageDigest::shake_128(),
81 TpmHash::Shake256 => MessageDigest::shake_256(),
82 TpmHash::Null => MessageDigest::null(),
83 }
84 }
85}
86
87impl TpmHash {
88 #[must_use]
90 pub fn size(&self) -> usize {
91 Into::<MessageDigest>::into(*self).size()
92 }
93
94 pub fn digest(&self, data_chunks: &[&[u8]]) -> Result<Vec<u8>, TpmCryptoError> {
104 let md = (*self).into();
105 let mut hasher = Hasher::new(md).map_err(|_| TpmCryptoError::OutOfMemory)?;
106 for chunk in data_chunks {
107 hasher
108 .update(chunk)
109 .map_err(|_| TpmCryptoError::OperationFailed)?;
110 }
111 Ok(hasher
112 .finish()
113 .map_err(|_| TpmCryptoError::OperationFailed)?
114 .to_vec())
115 }
116
117 pub fn hmac(&self, key: &[u8], data_chunks: &[&[u8]]) -> Result<Vec<u8>, TpmCryptoError> {
128 if key.is_empty() {
129 return Err(TpmCryptoError::KeyIsEmpty);
130 }
131 let md = (*self).into();
132 let public_key = PKey::hmac(key).map_err(|_| TpmCryptoError::OutOfMemory)?;
133 let mut signer = Signer::new(md, &public_key).map_err(|_| TpmCryptoError::OutOfMemory)?;
134 for chunk in data_chunks {
135 signer
136 .update(chunk)
137 .map_err(|_| TpmCryptoError::OperationFailed)?;
138 }
139 signer
140 .sign_to_vec()
141 .map_err(|_| TpmCryptoError::OperationFailed)
142 }
143
144 pub fn hmac_verify(
156 &self,
157 key: &[u8],
158 data_chunks: &[&[u8]],
159 signature: &[u8],
160 ) -> Result<(), TpmCryptoError> {
161 let expected = self.hmac(key, data_chunks)?;
162 if memcmp::eq(&expected, signature) {
163 Ok(())
164 } else {
165 Err(TpmCryptoError::PermissionDenied)
166 }
167 }
168
169 pub fn kdfa(
180 &self,
181 hmac_key: &[u8],
182 label: &str,
183 context_a: &[u8],
184 context_b: &[u8],
185 key_bits: u16,
186 ) -> Result<Vec<u8>, TpmCryptoError> {
187 if hmac_key.is_empty() {
188 return Err(TpmCryptoError::KeyIsEmpty);
189 }
190
191 let key_bytes = (key_bits as usize).div_ceil(8);
192 let mut key_stream = Vec::with_capacity(key_bytes);
193
194 let mut counter: u32 = 1;
195 let key_bits_bytes = u32::from(key_bits).to_be_bytes();
196
197 let md = (*self).into();
198 let pkey = PKey::hmac(hmac_key).map_err(|_| TpmCryptoError::OutOfMemory)?;
199
200 while key_stream.len() < key_bytes {
201 let counter_bytes = counter.to_be_bytes();
202 let hmac_payload = [
203 counter_bytes.as_slice(),
204 label.as_bytes(),
205 &[0u8],
206 context_a,
207 context_b,
208 key_bits_bytes.as_slice(),
209 ];
210
211 let mut signer = Signer::new(md, &pkey).map_err(|_| TpmCryptoError::OutOfMemory)?;
212 for chunk in &hmac_payload {
213 signer
214 .update(chunk)
215 .map_err(|_| TpmCryptoError::OperationFailed)?;
216 }
217 let result = signer
218 .sign_to_vec()
219 .map_err(|_| TpmCryptoError::OperationFailed)?;
220
221 let remaining = key_bytes - key_stream.len();
222 let to_take = remaining.min(result.len());
223 key_stream.extend_from_slice(&result[..to_take]);
224
225 counter += 1;
226 }
227
228 Ok(key_stream)
229 }
230
231 pub fn kdfe(
241 &self,
242 z: &[u8],
243 label: &str,
244 context_u: &[u8],
245 context_v: &[u8],
246 key_bits: u16,
247 ) -> Result<Vec<u8>, TpmCryptoError> {
248 let key_bytes = (key_bits as usize).div_ceil(8);
249 let mut key_stream = Vec::with_capacity(key_bytes);
250
251 let (label_data, terminator) = if label.as_bytes().last() == Some(&0) {
252 (label.as_bytes(), &[][..])
253 } else {
254 (label.as_bytes(), &[0u8][..])
255 };
256
257 let mut counter: u32 = 1;
258 let md = (*self).into();
259
260 while key_stream.len() < key_bytes {
261 let counter_bytes = counter.to_be_bytes();
262 let digest_payload = [
263 &counter_bytes,
264 z,
265 label_data,
266 terminator,
267 context_u,
268 context_v,
269 ];
270
271 let mut hasher = Hasher::new(md).map_err(|_| TpmCryptoError::OutOfMemory)?;
272 for chunk in &digest_payload {
273 hasher
274 .update(chunk)
275 .map_err(|_| TpmCryptoError::OperationFailed)?;
276 }
277 let result = hasher
278 .finish()
279 .map_err(|_| TpmCryptoError::OperationFailed)?;
280
281 let remaining = key_bytes - key_stream.len();
282 let to_take = remaining.min(result.len());
283 key_stream.extend_from_slice(&result[..to_take]);
284
285 counter += 1;
286 }
287
288 Ok(key_stream)
289 }
290}