Skip to content

Commit b6fe149

Browse files
committedMar 11, 2025
hmac legacy loading
1 parent 54e7e34 commit b6fe149

File tree

6 files changed

+201
-4
lines changed

6 files changed

+201
-4
lines changed
 

‎src/authvalue.rs

+8
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ impl AuthValue {
7676
}
7777
}
7878

79+
impl From<[u8; 32]> for AuthValue {
80+
fn from(bytes: [u8; 32]) -> Self {
81+
Self::Key256Bit {
82+
auth_key: aes256::key_from_bytes(bytes),
83+
}
84+
}
85+
}
86+
7987
impl TryFrom<&[u8]> for AuthValue {
8088
type Error = TpmError;
8189

‎src/error.rs

+2
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ pub enum TpmError {
66

77
Aes256GcmEncrypt,
88
Aes256GcmDecrypt,
9+
Aes256KeyInvalid,
910
// Aes256GcmConfig,
1011
AsnBitStringInvalid,
1112
// HmacKey,
1213
// HmacSign,
14+
HmacKeyInvalid,
1315
// EcGroup,
1416
// EcKeyGenerate,
1517
// EcKeyPrivateToDer,

‎src/legacy.rs

+185-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
1+
use crate::authvalue::AuthValue;
2+
use crate::error::TpmError;
3+
use crate::provider::SoftTpm;
4+
use crate::provider::Tpm;
5+
use crate::structures::{HmacS256Key, LoadableHmacS256Key, StorageKey};
6+
use serde::{Deserialize, Serialize};
7+
8+
use crypto_glue::aes256;
9+
use crypto_glue::aes256gcm::{AeadInPlace, Aes256GcmN16, Aes256GcmNonce16, Aes256GcmTag, KeyInit};
10+
use crypto_glue::hmac_s256;
111

212
#[derive(Debug, Clone, Serialize, Deserialize)]
313
pub enum LoadableMachineKey {
414
SoftAes256GcmV1 {
515
key: Vec<u8>,
616
tag: [u8; 16],
717
iv: [u8; 16],
8-
}
18+
},
919
}
1020

1121
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -74,3 +84,177 @@ pub enum SealedData {
7484
iv: [u8; 16],
7585
},
7686
}
87+
88+
trait LegacyTpm: Tpm {
89+
fn machine_key_load(
90+
&mut self,
91+
auth_value: &AuthValue,
92+
exported_key: &LoadableMachineKey,
93+
) -> Result<StorageKey, TpmError>;
94+
95+
fn hmac_key_load(
96+
&mut self,
97+
mk: &StorageKey,
98+
loadable_key: &LoadableHmacKey,
99+
) -> Result<HmacS256Key, TpmError>;
100+
}
101+
102+
macro_rules! unwrap_aes256gcm_nonce16 {
103+
(
104+
$wrapping_key: expr,
105+
$key_to_unwrap: expr,
106+
$tag: expr,
107+
$nonce: expr
108+
) => {{
109+
let cipher = Aes256GcmN16::new($wrapping_key);
110+
111+
let mut key = $key_to_unwrap.clone();
112+
113+
let iv = Aes256GcmNonce16::from_slice($nonce);
114+
let tag = Aes256GcmTag::from_slice($tag);
115+
116+
let associated_data = b"";
117+
118+
cipher
119+
.decrypt_in_place_detached(iv, associated_data, key.as_mut_slice(), tag)
120+
.map_err(|_| TpmError::Aes256GcmDecrypt)?;
121+
122+
if key.as_slice() == $key_to_unwrap.as_slice() {
123+
// Encryption didn't replace the buffer in place, fail.
124+
return Err(TpmError::Aes256GcmDecrypt);
125+
}
126+
127+
Ok(key)
128+
}};
129+
}
130+
131+
impl LegacyTpm for SoftTpm {
132+
fn machine_key_load(
133+
&mut self,
134+
auth_value: &AuthValue,
135+
exported_key: &LoadableMachineKey,
136+
) -> Result<StorageKey, TpmError> {
137+
match (auth_value, exported_key) {
138+
(
139+
AuthValue::Key256Bit { auth_key },
140+
LoadableMachineKey::SoftAes256GcmV1 {
141+
key: key_to_unwrap,
142+
tag,
143+
iv,
144+
},
145+
) => {
146+
let key = aes256::key_from_vec(key_to_unwrap.clone())
147+
.ok_or(TpmError::Aes256KeyInvalid)?;
148+
149+
unwrap_aes256gcm_nonce16!(auth_key, key, tag, iv)
150+
.map(|key| StorageKey::SoftAes256GcmV2 { key })
151+
}
152+
}
153+
}
154+
155+
fn hmac_key_load(
156+
&mut self,
157+
parent_key: &StorageKey,
158+
hmac_key: &LoadableHmacKey,
159+
) -> Result<HmacS256Key, TpmError> {
160+
match (parent_key, hmac_key) {
161+
(
162+
StorageKey::SoftAes256GcmV2 { key: parent_key },
163+
LoadableHmacKey::SoftSha256V1 {
164+
key: key_to_unwrap,
165+
tag,
166+
iv,
167+
},
168+
) => {
169+
tracing::trace!(key_size = %hmac_s256::key_size());
170+
tracing::trace!(new_key_size = %key_to_unwrap.len());
171+
172+
let key = unwrap_aes256gcm_nonce16!(parent_key, key_to_unwrap, tag, iv)?;
173+
174+
let mut empty_key: [u8; 64] = [0; 64];
175+
176+
empty_key
177+
.get_mut(..32)
178+
.map(|view| view.copy_from_slice(&key));
179+
180+
let empty_key = hmac_s256::key_from_bytes(empty_key);
181+
182+
Ok(HmacS256Key::SoftAes256GcmV2 { key: empty_key })
183+
}
184+
}
185+
}
186+
}
187+
188+
#[cfg(test)]
189+
mod test {
190+
use crate::authvalue::AuthValue;
191+
use crate::legacy::LegacyTpm;
192+
use crate::legacy::{LoadableHmacKey, LoadableMachineKey};
193+
use crate::provider::{SoftTpm, TpmHmacS256};
194+
195+
use crypto_glue::aes256::{self, Aes256Key};
196+
use crypto_glue::aes256gcm::Aes256Gcm;
197+
198+
#[test]
199+
fn test_legacy_hmac_load() {
200+
let _ = tracing_subscriber::fmt::try_init();
201+
202+
let auth_value = AuthValue::from([
203+
252, 167, 3, 221, 57, 147, 94, 141, 210, 66, 87, 126, 91, 77, 169, 43, 42, 92, 171, 74,
204+
158, 85, 161, 55, 79, 85, 180, 29, 12, 209, 19, 173,
205+
]);
206+
207+
let loadable_root = LoadableMachineKey::SoftAes256GcmV1 {
208+
key: [
209+
17, 66, 23, 95, 209, 206, 86, 81, 44, 2, 50, 137, 40, 130, 156, 39, 118, 200, 52,
210+
54, 91, 34, 136, 24, 22, 70, 83, 150, 211, 188, 60, 180,
211+
]
212+
.into(),
213+
tag: [
214+
111, 73, 224, 22, 91, 180, 12, 192, 201, 109, 85, 109, 51, 52, 18, 182,
215+
]
216+
.into(),
217+
iv: [
218+
87, 117, 127, 13, 107, 56, 93, 64, 136, 30, 67, 81, 37, 136, 60, 93,
219+
]
220+
.into(),
221+
};
222+
223+
let loadable_hmac = LoadableHmacKey::SoftSha256V1 {
224+
key: [
225+
219, 171, 238, 89, 195, 110, 32, 176, 235, 113, 171, 15, 0, 226, 141, 3, 223, 237,
226+
240, 47, 51, 227, 53, 7, 84, 70, 254, 151, 62, 97, 187, 25,
227+
]
228+
.into(),
229+
tag: [
230+
183, 248, 10, 77, 69, 161, 167, 131, 240, 17, 79, 47, 18, 117, 119, 163,
231+
]
232+
.into(),
233+
iv: [
234+
195, 77, 79, 140, 167, 246, 59, 58, 76, 15, 75, 70, 121, 254, 54, 114,
235+
]
236+
.into(),
237+
};
238+
239+
let expected_hmac = [
240+
78, 92, 177, 219, 206, 45, 235, 80, 202, 98, 171, 79, 120, 129, 65, 57, 126, 152, 59,
241+
176, 181, 39, 219, 160, 35, 245, 76, 128, 193, 82, 25, 195,
242+
];
243+
244+
let data = [0, 1, 2, 3];
245+
246+
let mut soft_tpm = SoftTpm::default();
247+
248+
let root_storage = soft_tpm
249+
.machine_key_load(&auth_value, &loadable_root)
250+
.unwrap();
251+
252+
let hmac_key = soft_tpm
253+
.hmac_key_load(&root_storage, &loadable_hmac)
254+
.unwrap();
255+
256+
let calced_hmac = soft_tpm.hmac_s256(&hmac_key, &data).unwrap();
257+
258+
assert_eq!(calced_hmac.into_bytes().as_slice(), expected_hmac);
259+
}
260+
}

‎src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
mod authvalue;
2222
mod error;
23+
mod legacy;
2324
mod pin;
2425
mod provider;
2526
mod structures;

‎src/provider/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ use crypto_glue::spki;
1616
use crypto_glue::traits::*;
1717
use crypto_glue::x509::BitString;
1818

19-
pub mod soft;
19+
mod soft;
20+
21+
pub use self::soft::SoftTpm;
2022

2123
pub trait Tpm {
2224
fn root_storage_key_create(

‎src/provider/soft.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crypto_glue::{
2121
use tracing::error;
2222

2323
#[derive(Default)]
24-
struct SoftTpm {}
24+
pub struct SoftTpm {}
2525

2626
macro_rules! wrap_aes256gcm {
2727
(
@@ -66,7 +66,7 @@ macro_rules! unwrap_aes256gcm {
6666

6767
if key.as_slice() == $key_to_unwrap.as_slice() {
6868
// Encryption didn't replace the buffer in place, fail.
69-
return Err(TpmError::Aes256GcmEncrypt);
69+
return Err(TpmError::Aes256GcmDecrypt);
7070
}
7171

7272
Ok(key)

0 commit comments

Comments
 (0)