Skip to content

Commit 8444c3d

Browse files
committed
Add RSA OAEP example
This adds a basic worked example of RSA OAEP encryption and decryption Signed-off-by: William Brown <william.brown@suse.com>
1 parent 63298c2 commit 8444c3d

File tree

1 file changed

+159
-0
lines changed

1 file changed

+159
-0
lines changed

tss-esapi/examples/rsa_oaep.rs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// Copyright 2020 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
/*
5+
* This example demonstrates how to use RSA OAEP for encryption and decryption
6+
*/
7+
8+
use tss_esapi::{
9+
attributes::ObjectAttributesBuilder,
10+
interface_types::{
11+
algorithm::{HashingAlgorithm, PublicAlgorithm},
12+
key_bits::RsaKeyBits,
13+
resource_handles::Hierarchy,
14+
},
15+
structures::{
16+
CreatePrimaryKeyResult, Data, Digest, HashScheme, PublicBuilder, PublicKeyRsa,
17+
PublicRsaParametersBuilder, RsaDecryptionScheme, RsaExponent, RsaScheme,
18+
SymmetricCipherParameters, SymmetricDefinitionObject,
19+
},
20+
Context, TctiNameConf,
21+
};
22+
23+
use std::convert::TryFrom;
24+
25+
fn main() {
26+
// Create a new TPM context. This reads from the environment variable `TPM2TOOLS_TCTI` or `TCTI`
27+
//
28+
// It's recommended you use `TCTI=device:/dev/tpmrm0` for the linux kernel
29+
// tpm resource manager.
30+
let mut context = Context::new(
31+
TctiNameConf::from_environment_variable()
32+
.expect("Failed to get TCTI / TPM2TOOLS_TCTI from environment. Try `export TCTI=device:/dev/tpmrm0`"),
33+
)
34+
.expect("Failed to create Context");
35+
36+
// This example won't go over the process to create a new parent. For more detail see `examples/hmac.rs`.
37+
38+
let primary = create_primary(&mut context);
39+
40+
// Begin to create our new RSA key.
41+
let object_attributes = ObjectAttributesBuilder::new()
42+
.with_fixed_tpm(true)
43+
.with_fixed_parent(true)
44+
.with_st_clear(false)
45+
.with_sensitive_data_origin(true)
46+
.with_user_with_auth(true)
47+
// We need a key that can decrypt values - we don't need to worry
48+
// about signatures.
49+
.with_decrypt(true)
50+
// Note that we don't set the key as restricted.
51+
.build()
52+
.expect("Failed to build object attributes");
53+
54+
let rsa_params = PublicRsaParametersBuilder::new()
55+
// The value for scheme may have requirements set by a combination of the
56+
// sign, decrypt, and restricted flags. For an unrestricted signing and
57+
// decryption key then scheme must be NULL. For an unrestricted decryption key,
58+
// NULL, OAEP or RSAES are valid for use.
59+
.with_scheme(RsaScheme::Null)
60+
.with_key_bits(RsaKeyBits::Rsa2048)
61+
.with_exponent(RsaExponent::default())
62+
.with_is_decryption_key(true)
63+
// We don't require signatures, but some users may.
64+
// .with_is_signing_key(true)
65+
.with_restricted(false)
66+
.build()
67+
.expect("Failed to build rsa parameters");
68+
69+
let key_pub = PublicBuilder::new()
70+
.with_public_algorithm(PublicAlgorithm::Rsa)
71+
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
72+
.with_object_attributes(object_attributes)
73+
.with_rsa_parameters(rsa_params)
74+
.with_rsa_unique_identifier(PublicKeyRsa::default())
75+
.build()
76+
.unwrap();
77+
78+
let (enc_private, public) = context
79+
.execute_with_nullauth_session(|ctx| {
80+
ctx.create(primary.key_handle, key_pub, None, None, None, None)
81+
.map(|key| (key.out_private, key.out_public))
82+
})
83+
.unwrap();
84+
85+
let data_to_encrypt = PublicKeyRsa::try_from("TPMs are cool.".as_bytes().to_vec())
86+
.expect("Failed to create buffer for data to encrypt.");
87+
88+
// To encrypt data to a key, we only need it's public component. We demonstrate how
89+
// to load that public component into a TPM and then encrypt to it.
90+
let encrypted_data = context
91+
.execute_with_nullauth_session(|ctx| {
92+
let rsa_pub_key = ctx
93+
.load_external_public(public.clone(), Hierarchy::Null)
94+
.unwrap();
95+
96+
ctx.rsa_encrypt(
97+
rsa_pub_key,
98+
data_to_encrypt.clone(),
99+
RsaDecryptionScheme::Oaep(HashScheme::new(HashingAlgorithm::Sha1)),
100+
Data::default(),
101+
)
102+
})
103+
.unwrap();
104+
105+
// The data is now encrypted.
106+
println!("encrypted_data = {:?}", encrypted_data);
107+
assert_ne!(encrypted_data, data_to_encrypt);
108+
109+
// To decrypt the data, we need to load the private key into the TPM.
110+
let decrypted_data = context
111+
.execute_with_nullauth_session(|ctx| {
112+
let rsa_priv_key = ctx
113+
.load(primary.key_handle, enc_private.clone(), public.clone())
114+
.unwrap();
115+
116+
ctx.rsa_decrypt(
117+
rsa_priv_key,
118+
encrypted_data,
119+
RsaDecryptionScheme::Oaep(HashScheme::new(HashingAlgorithm::Sha1)),
120+
Data::default(),
121+
)
122+
})
123+
.unwrap();
124+
125+
println!("data_to_encrypt = {:?}", data_to_encrypt);
126+
println!("decrypted_data = {:?}", decrypted_data);
127+
// They are the same!
128+
assert_eq!(data_to_encrypt, decrypted_data);
129+
}
130+
131+
fn create_primary(context: &mut Context) -> CreatePrimaryKeyResult {
132+
let object_attributes = ObjectAttributesBuilder::new()
133+
.with_fixed_tpm(true)
134+
.with_fixed_parent(true)
135+
.with_st_clear(false)
136+
.with_sensitive_data_origin(true)
137+
.with_user_with_auth(true)
138+
.with_decrypt(true)
139+
.with_restricted(true)
140+
.build()
141+
.expect("Failed to build object attributes");
142+
143+
let primary_pub = PublicBuilder::new()
144+
.with_public_algorithm(PublicAlgorithm::SymCipher)
145+
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
146+
.with_object_attributes(object_attributes)
147+
.with_symmetric_cipher_parameters(SymmetricCipherParameters::new(
148+
SymmetricDefinitionObject::AES_128_CFB,
149+
))
150+
.with_symmetric_cipher_unique_identifier(Digest::default())
151+
.build()
152+
.unwrap();
153+
154+
context
155+
.execute_with_nullauth_session(|ctx| {
156+
ctx.create_primary(Hierarchy::Owner, primary_pub, None, None, None, None)
157+
})
158+
.unwrap()
159+
}

0 commit comments

Comments
 (0)