Skip to content

Commit 2b643f1

Browse files
authored
Merge pull request #417 from Firstyear/20230704-21-examples
Add example for hmac
2 parents 6ad4b5f + dd3f59e commit 2b643f1

File tree

2 files changed

+174
-0
lines changed

2 files changed

+174
-0
lines changed

tss-esapi/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ license = "Apache-2.0"
1111
repository = "https://github.com/parallaxsecond/rust-tss-esapi"
1212
documentation = "https://docs.rs/crate/tss-esapi"
1313

14+
[[example]]
15+
name = "hmac"
16+
1417
[dependencies]
1518
bitfield = "0.13.2"
1619
serde = { version = "1.0.115", features = ["derive"] }

tss-esapi/examples/hmac.rs

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
// Copyright 2020 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
/*
5+
* This example demonstrates how to create an HMAC key that can be reloaded.
6+
*/
7+
8+
use tss_esapi::{
9+
attributes::ObjectAttributesBuilder,
10+
interface_types::{
11+
algorithm::{HashingAlgorithm, PublicAlgorithm},
12+
resource_handles::Hierarchy,
13+
},
14+
structures::{
15+
Digest, KeyedHashScheme, MaxBuffer, PublicBuilder, PublicKeyedHashParameters,
16+
SymmetricCipherParameters, SymmetricDefinitionObject,
17+
},
18+
Context, TctiNameConf,
19+
};
20+
21+
use std::convert::TryFrom;
22+
23+
fn main() {
24+
// Create a new TPM context. This reads from the environment variable `TPM2TOOLS_TCTI` or `TCTI`
25+
//
26+
// It's recommended you use `TCTI=device:/dev/tpmrm0` for the linux kernel
27+
// tpm resource manager.
28+
let mut context = Context::new(
29+
TctiNameConf::from_environment_variable()
30+
.expect("Failed to get TCTI / TPM2TOOLS_TCTI from environment. Try `export TCTI=device:/dev/tpmrm0`"),
31+
)
32+
.expect("Failed to create Context");
33+
34+
// Create the primary key. A primary key is the "root" of a collection of objects.
35+
// These other objects are encrypted by the primary key allowing them to persist
36+
// over a reboot and reloads.
37+
//
38+
// A primary key is derived from a seed, and provided that the same inputs are given
39+
// the same primary key will be derived in the tpm. This means that you do not need
40+
// to store or save the details of this key - only the parameters of how it was created.
41+
42+
let object_attributes = ObjectAttributesBuilder::new()
43+
// Indicate the key can only exist within this tpm and can not be exported.
44+
.with_fixed_tpm(true)
45+
// The primary key and it's descendent keys can't be moved to other primary
46+
// keys.
47+
.with_fixed_parent(true)
48+
// The primary key will persist over suspend and resume of the system.
49+
.with_st_clear(false)
50+
// The primary key was generated entirely inside the TPM - only this TPM
51+
// knows it's content.
52+
.with_sensitive_data_origin(true)
53+
// This key requires "authentication" to the TPM to access - this can be
54+
// an HMAC or password session. HMAC sessions are used by default with
55+
// the "execute_with_nullauth_session" function.
56+
.with_user_with_auth(true)
57+
// This key has the ability to decrypt
58+
.with_decrypt(true)
59+
// This key may only be used to encrypt or sign objects that are within
60+
// the TPM - it can not encrypt or sign external data.
61+
.with_restricted(true)
62+
.build()
63+
.expect("Failed to build object attributes");
64+
65+
let primary_pub = PublicBuilder::new()
66+
// This key is a symmetric key.
67+
.with_public_algorithm(PublicAlgorithm::SymCipher)
68+
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
69+
.with_object_attributes(object_attributes)
70+
.with_symmetric_cipher_parameters(SymmetricCipherParameters::new(
71+
SymmetricDefinitionObject::AES_128_CFB,
72+
))
73+
.with_symmetric_cipher_unique_identifier(Digest::default())
74+
.build()
75+
.unwrap();
76+
77+
let primary = context
78+
.execute_with_nullauth_session(|ctx| {
79+
// Create the key under the "owner" hierarchy. Other hierarchies are platform
80+
// which is for boot services, null which is ephemeral and resets after a reboot,
81+
// and endorsement which allows key certification by the TPM manufacturer.
82+
ctx.create_primary(Hierarchy::Owner, primary_pub, None, None, None, None)
83+
})
84+
.unwrap();
85+
86+
// Create the HMAC key. This key exists under the primary key in it's hierarchy
87+
// and can only be used if the same primary key is recreated from the parameters
88+
// defined above.
89+
90+
let object_attributes = ObjectAttributesBuilder::new()
91+
.with_fixed_tpm(true)
92+
.with_fixed_parent(true)
93+
.with_st_clear(false)
94+
.with_sensitive_data_origin(true)
95+
.with_user_with_auth(true)
96+
// The key is used only for signing.
97+
.with_sign_encrypt(true)
98+
.build()
99+
.expect("Failed to build object attributes");
100+
101+
let key_pub = PublicBuilder::new()
102+
// This key is a HMAC key
103+
.with_public_algorithm(PublicAlgorithm::KeyedHash)
104+
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
105+
.with_object_attributes(object_attributes)
106+
.with_keyed_hash_parameters(PublicKeyedHashParameters::new(
107+
KeyedHashScheme::HMAC_SHA_256,
108+
))
109+
.with_keyed_hash_unique_identifier(Digest::default())
110+
.build()
111+
.unwrap();
112+
113+
let (enc_private, public) = context
114+
.execute_with_nullauth_session(|ctx| {
115+
// Create the HMAC key given our primary key as it's parent. This returns the private
116+
// and public portions of the key. It's *important* to note that the private component
117+
// is *encrypted* by a key associated with the primary key. It is not plaintext or
118+
// leaked in this step.
119+
ctx.create(primary.key_handle, key_pub, None, None, None, None)
120+
.map(|key| (key.out_private, key.out_public))
121+
})
122+
.unwrap();
123+
124+
// Once the key is created, we have it's parameters in the private and public values.
125+
// We now need to load it into the tpm so that it can be used.
126+
//
127+
// The enc_private and public values can be serialised and persisted - that way they can
128+
// be reloaded for future use.
129+
130+
let input_data = MaxBuffer::try_from("TPMs are cool.".as_bytes().to_vec())
131+
.expect("Failed to create buffer for input data.");
132+
133+
let hmac1 = context
134+
.execute_with_nullauth_session(|ctx| {
135+
// Load the HMAC key into the tpm context.
136+
let hmac_key = ctx
137+
.load(primary.key_handle, enc_private.clone(), public.clone())
138+
.unwrap();
139+
// Perform the HMAC.
140+
let r = ctx.hmac(
141+
hmac_key.into(),
142+
input_data.clone(),
143+
HashingAlgorithm::Sha256,
144+
);
145+
// Unload the key from the context.
146+
ctx.flush_context(hmac_key.into()).unwrap();
147+
r
148+
})
149+
.unwrap();
150+
151+
// Reload the key and perform the same hmac.
152+
let hmac2 = context
153+
.execute_with_nullauth_session(|ctx| {
154+
let hmac_key = ctx
155+
.load(primary.key_handle, enc_private.clone(), public.clone())
156+
.unwrap();
157+
let r = ctx.hmac(
158+
hmac_key.into(),
159+
input_data.clone(),
160+
HashingAlgorithm::Sha256,
161+
);
162+
ctx.flush_context(hmac_key.into()).unwrap();
163+
r
164+
})
165+
.unwrap();
166+
167+
println!("hmac1 = {:?}", hmac1);
168+
println!("hmac2 = {:?}", hmac2);
169+
// They are the same!
170+
assert_eq!(hmac1, hmac2);
171+
}

0 commit comments

Comments
 (0)