Skip to content

Commit f1bebd9

Browse files
committed
Adds proper documentation for rsa_encrypt and rsa_decrypt.
Signed-off-by: Jesper Brynolf <jesper.brynolf@gmail.com>
1 parent e9ba6d8 commit f1bebd9

File tree

2 files changed

+271
-5
lines changed

2 files changed

+271
-5
lines changed

tss-esapi/src/context/tpm_commands/asymmetric_primitives.rs

Lines changed: 265 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,150 @@ use crate::{
88
Context, Result, ReturnCode,
99
};
1010
use log::error;
11-
use std::convert::TryFrom;
1211
use std::ptr::null_mut;
12+
use std::{convert::TryFrom, ptr::null};
1313

1414
impl Context {
1515
/// Perform an asymmetric RSA encryption.
16+
///
17+
/// # Arguments
18+
///
19+
/// * `key_handle` - A [KeyHandle] to to public portion of RSA key to use for encryption.
20+
/// * `message` - The message to be encrypted.
21+
/// * `in_scheme` - The padding scheme to use if scheme associated with
22+
/// the `key_handle` is [RsaDecryptionScheme::Null].
23+
/// * `label` - An optional label to be associated with the message.
24+
///
25+
/// # Details
26+
///
27+
/// *From the specification*
28+
/// > This command performs RSA encryption using the indicated padding scheme
29+
/// > according to IETF [RFC 8017](https://www.rfc-editor.org/rfc/rfc8017).
30+
///
31+
/// > The label parameter is optional. If provided (label.size != 0) then the TPM shall return TPM_RC_VALUE if
32+
/// > the last octet in label is not zero. The terminating octet of zero is included in the label used in the padding
33+
/// > scheme.
34+
/// > If the scheme does not use a label, the TPM will still verify that label is properly formatted if label is
35+
/// > present.
36+
///
37+
/// # Returns
38+
///
39+
/// The encrypted output.
40+
///
41+
/// # Example
42+
///
43+
/// ```rust
44+
/// # use tss_esapi::{
45+
/// # Context, TctiNameConf,
46+
/// # attributes::{SessionAttributesBuilder, ObjectAttributesBuilder},
47+
/// # constants::SessionType,
48+
/// # interface_types::{
49+
/// # algorithm::{
50+
/// # HashingAlgorithm, PublicAlgorithm, RsaDecryptAlgorithm,
51+
/// # },
52+
/// # key_bits::RsaKeyBits,
53+
/// # reserved_handles::Hierarchy,
54+
/// # },
55+
/// # structures::{
56+
/// # Auth, Data, RsaScheme, PublicBuilder, PublicRsaParametersBuilder, PublicKeyRsa,
57+
/// # RsaDecryptionScheme, HashScheme, SymmetricDefinition, RsaExponent,
58+
/// # },
59+
/// # };
60+
/// # use std::{env, str::FromStr, convert::TryFrom};
61+
/// # // Create context
62+
/// # let mut context =
63+
/// # Context::new(
64+
/// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
65+
/// # ).expect("Failed to create Context");
66+
/// #
67+
/// # let session = context
68+
/// # .start_auth_session(
69+
/// # None,
70+
/// # None,
71+
/// # None,
72+
/// # SessionType::Hmac,
73+
/// # SymmetricDefinition::AES_256_CFB,
74+
/// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
75+
/// # )
76+
/// # .expect("Failed to create session")
77+
/// # .expect("Received invalid handle");
78+
/// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
79+
/// # .with_decrypt(true)
80+
/// # .with_encrypt(true)
81+
/// # .build();
82+
/// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
83+
/// # .expect("Failed to set attributes on session");
84+
/// # context.set_sessions((Some(session), None, None));
85+
/// # let mut random_digest = vec![0u8; 16];
86+
/// # getrandom::getrandom(&mut random_digest).unwrap();
87+
/// # let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap();
88+
/// #
89+
/// # let object_attributes = ObjectAttributesBuilder::new()
90+
/// # .with_fixed_tpm(true)
91+
/// # .with_fixed_parent(true)
92+
/// # .with_sensitive_data_origin(true)
93+
/// # .with_user_with_auth(true)
94+
/// # .with_decrypt(true)
95+
/// # .with_sign_encrypt(true)
96+
/// # .with_restricted(false)
97+
/// # .build()
98+
/// # .expect("Should be able to build object attributes when the attributes are not conflicting.");
99+
/// #
100+
/// # let key_pub = PublicBuilder::new()
101+
/// # .with_public_algorithm(PublicAlgorithm::Rsa)
102+
/// # .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
103+
/// # .with_object_attributes(object_attributes)
104+
/// # .with_rsa_parameters(
105+
/// # PublicRsaParametersBuilder::new()
106+
/// # .with_scheme(RsaScheme::Null)
107+
/// # .with_key_bits(RsaKeyBits::Rsa2048)
108+
/// # .with_exponent(RsaExponent::default())
109+
/// # .with_is_signing_key(true)
110+
/// # .with_is_decryption_key(true)
111+
/// # .with_restricted(false)
112+
/// # .build()
113+
/// # .expect("Should be possible to build valid RSA parameters")
114+
/// # )
115+
/// # .with_rsa_unique_identifier(PublicKeyRsa::default())
116+
/// # .build()
117+
/// # .expect("Should be possible to build a valid Public object.");
118+
/// #
119+
/// # let key_handle = context
120+
/// # .create_primary(
121+
/// # Hierarchy::Owner,
122+
/// # key_pub,
123+
/// # None,
124+
/// # None,
125+
/// # None,
126+
/// # None,
127+
/// # )
128+
/// # .expect("Should be possible to create primary key from using valid Public object.")
129+
/// # .key_handle;
130+
/// // Because the key was created with RsaScheme::Null it is possible to
131+
/// // provide a scheme for the rsa_encrypt function to use.
132+
/// let scheme =
133+
/// RsaDecryptionScheme::create(RsaDecryptAlgorithm::Oaep, Some(HashingAlgorithm::Sha256))
134+
/// .expect("Failed to create rsa decryption scheme");
135+
/// let plain_text_bytes = vec![1, 2, 3, 4];
136+
/// let message_in = PublicKeyRsa::try_from(plain_text_bytes.clone())
137+
/// .expect("Should be possible to create a PublicKeyRsa object from valid bytes.");
138+
/// let cipher_text = context.rsa_encrypt(key_handle, message_in, scheme, None)
139+
/// .expect("Should be possible to call rsa_encrypt using valid arguments.");
140+
/// # let message_out = context.rsa_decrypt(key_handle, cipher_text, scheme, None)
141+
/// # .expect("Should be possible to call rsa_decrypt using valid arguments.");
142+
/// # let decrypted_bytes = message_out.as_bytes();
143+
/// # assert_eq!(plain_text_bytes, decrypted_bytes);
144+
/// ```
16145
pub fn rsa_encrypt(
17146
&mut self,
18147
key_handle: KeyHandle,
19148
message: PublicKeyRsa,
20149
in_scheme: RsaDecryptionScheme,
21-
label: Data,
150+
label: impl Into<Option<Data>>,
22151
) -> Result<PublicKeyRsa> {
23152
let mut out_data_ptr = null_mut();
153+
let potential_label = label.into().map(|v| v.into());
154+
let label_ptr = potential_label.as_ref().map_or_else(null, |v| v);
24155
ReturnCode::ensure_success(
25156
unsafe {
26157
Esys_RSA_Encrypt(
@@ -31,7 +162,7 @@ impl Context {
31162
self.optional_session_3(),
32163
&message.into(),
33164
&in_scheme.into(),
34-
&label.into(),
165+
label_ptr,
35166
&mut out_data_ptr,
36167
)
37168
},
@@ -43,14 +174,143 @@ impl Context {
43174
}
44175

45176
/// Perform an asymmetric RSA decryption.
177+
///
178+
/// # Arguments
179+
///
180+
/// * `key_handle` - A [KeyHandle] of the RSA key to use for decryption.
181+
/// * `cipher_text` - The cipher text to be decrypted.
182+
/// * `in_scheme` - The padding scheme to use if scheme associated with
183+
/// the `key_handle` is [RsaDecryptionScheme::Null].
184+
/// * `label` - An optional label whose association with the message is to be verified.
185+
///
186+
/// # Details
187+
///
188+
/// *From the specification*
189+
/// > This command performs RSA decryption using the indicated padding scheme according to IETF RFC
190+
/// > 8017 ((PKCS#1).
191+
///
192+
/// > If a label is used in the padding process of the scheme during encryption, the label parameter is required
193+
/// > to be present in the decryption process and label is required to be the same in both cases. If label is not
194+
/// > the same, the decrypt operation is very likely to fail.
195+
///
196+
/// # Returns
197+
///
198+
/// The decrypted output.
199+
///
200+
/// # Example
201+
///
202+
/// ```rust
203+
/// # use tss_esapi::{
204+
/// # Context, TctiNameConf,
205+
/// # attributes::{SessionAttributesBuilder, ObjectAttributesBuilder},
206+
/// # constants::SessionType,
207+
/// # interface_types::{
208+
/// # algorithm::{
209+
/// # HashingAlgorithm, PublicAlgorithm, RsaDecryptAlgorithm,
210+
/// # },
211+
/// # key_bits::RsaKeyBits,
212+
/// # reserved_handles::Hierarchy,
213+
/// # },
214+
/// # structures::{
215+
/// # Auth, Data, RsaScheme, PublicBuilder, PublicRsaParametersBuilder, PublicKeyRsa,
216+
/// # RsaDecryptionScheme, HashScheme, SymmetricDefinition, RsaExponent,
217+
/// # },
218+
/// # };
219+
/// # use std::{env, str::FromStr, convert::TryFrom};
220+
/// # // Create context
221+
/// # let mut context =
222+
/// # Context::new(
223+
/// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
224+
/// # ).expect("Failed to create Context");
225+
/// #
226+
/// # let session = context
227+
/// # .start_auth_session(
228+
/// # None,
229+
/// # None,
230+
/// # None,
231+
/// # SessionType::Hmac,
232+
/// # SymmetricDefinition::AES_256_CFB,
233+
/// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
234+
/// # )
235+
/// # .expect("Failed to create session")
236+
/// # .expect("Received invalid handle");
237+
/// # let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
238+
/// # .with_decrypt(true)
239+
/// # .with_encrypt(true)
240+
/// # .build();
241+
/// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
242+
/// # .expect("Failed to set attributes on session");
243+
/// # context.set_sessions((Some(session), None, None));
244+
/// # let mut random_digest = vec![0u8; 16];
245+
/// # getrandom::getrandom(&mut random_digest).unwrap();
246+
/// # let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap();
247+
/// #
248+
/// # let object_attributes = ObjectAttributesBuilder::new()
249+
/// # .with_fixed_tpm(true)
250+
/// # .with_fixed_parent(true)
251+
/// # .with_sensitive_data_origin(true)
252+
/// # .with_user_with_auth(true)
253+
/// # .with_decrypt(true)
254+
/// # .with_sign_encrypt(true)
255+
/// # .with_restricted(false)
256+
/// # .build()
257+
/// # .expect("Should be able to build object attributes when the attributes are not conflicting.");
258+
/// #
259+
/// # let key_pub = PublicBuilder::new()
260+
/// # .with_public_algorithm(PublicAlgorithm::Rsa)
261+
/// # .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
262+
/// # .with_object_attributes(object_attributes)
263+
/// # .with_rsa_parameters(
264+
/// # PublicRsaParametersBuilder::new()
265+
/// # .with_scheme(RsaScheme::Null)
266+
/// # .with_key_bits(RsaKeyBits::Rsa2048)
267+
/// # .with_exponent(RsaExponent::default())
268+
/// # .with_is_signing_key(true)
269+
/// # .with_is_decryption_key(true)
270+
/// # .with_restricted(false)
271+
/// # .build()
272+
/// # .expect("Should be possible to build valid RSA parameters")
273+
/// # )
274+
/// # .with_rsa_unique_identifier(PublicKeyRsa::default())
275+
/// # .build()
276+
/// # .expect("Should be possible to build a valid Public object.");
277+
/// #
278+
/// # let key_handle = context
279+
/// # .create_primary(
280+
/// # Hierarchy::Owner,
281+
/// # key_pub,
282+
/// # None,
283+
/// # None,
284+
/// # None,
285+
/// # None,
286+
/// # )
287+
/// # .expect("Should be possible to create primary key from using valid Public object.")
288+
/// # .key_handle;
289+
/// # let scheme =
290+
/// # RsaDecryptionScheme::create(RsaDecryptAlgorithm::RsaEs, None)
291+
/// # .expect("Failed to create rsa decryption scheme");
292+
/// # let plain_text_bytes = vec![4, 3, 2, 1, 0];
293+
/// # let message_in = PublicKeyRsa::try_from(plain_text_bytes.clone())
294+
/// # .expect("Should be possible to create a PublicKeyRsa object from valid bytes.");
295+
/// # let label = Data::default();
296+
/// # let cipher_text = context.rsa_encrypt(key_handle, message_in, scheme, label.clone())
297+
/// # .expect("Should be possible to call rsa_encrypt using valid arguments.");
298+
/// // label text needs to be the same as the on used when data was encrypted.
299+
/// let message_out = context.rsa_decrypt(key_handle, cipher_text, scheme, label)
300+
/// .expect("Should be possible to call rsa_decrypt using valid arguments.");
301+
/// let decrypted_bytes = message_out.as_bytes();
302+
/// # assert_eq!(plain_text_bytes, decrypted_bytes);
303+
/// ```
46304
pub fn rsa_decrypt(
47305
&mut self,
48306
key_handle: KeyHandle,
49307
cipher_text: PublicKeyRsa,
50308
in_scheme: RsaDecryptionScheme,
51-
label: Data,
309+
label: impl Into<Option<Data>>,
52310
) -> Result<PublicKeyRsa> {
53311
let mut message_ptr = null_mut();
312+
let potential_label = label.into().map(|v| v.into());
313+
let label_ptr = potential_label.as_ref().map_or_else(null, |v| v);
54314
ReturnCode::ensure_success(
55315
unsafe {
56316
Esys_RSA_Decrypt(
@@ -61,7 +321,7 @@ impl Context {
61321
self.optional_session_3(),
62322
&cipher_text.into(),
63323
&in_scheme.into(),
64-
&label.into(),
324+
label_ptr,
65325
&mut message_ptr,
66326
)
67327
},

tss-esapi/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@
9292
//! controlled through environment variables as explained
9393
//! [here](https://github.com/tpm2-software/tpm2-tss/blob/main/doc/logging.md#runtime-log-level).
9494
//!
95+
//! # Code examples
96+
//! The code examples in this documentation usually only showing a small part of all
97+
//! the steps that are necessary in order to make things work. For the most part it
98+
//! only shows the point of interest e.g. the code related to a context method call. It
99+
//! is therefore recommended to view the code for the whole example by looking at the
100+
//! source code or view the examples in our repository.
95101
96102
mod context;
97103

0 commit comments

Comments
 (0)