tss_esapi/context/tpm_commands/symmetric_primitives.rs
1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use crate::{
4 handles::{KeyHandle, ObjectHandle, TpmHandle},
5 interface_types::{
6 algorithm::{HashingAlgorithm, SymmetricMode},
7 reserved_handles::Hierarchy,
8 },
9 structures::{Digest, HashcheckTicket, InitialValue, MaxBuffer},
10 tss2_esys::{Esys_EncryptDecrypt2, Esys_HMAC, Esys_Hash},
11 Context, Result, ReturnCode,
12};
13use log::error;
14use std::convert::TryFrom;
15use std::ptr::null_mut;
16
17impl Context {
18 // Missing function: EncryptDecrypt, deprecated use EncryptDecrypt2 instead.
19
20 /// Performs symmetric encryption or decryption of the data using
21 /// the key associated with the `key_handle`
22 ///
23 /// # Arguments
24 /// * `key_handle` - A [KeyHandle] to the key to be used.
25 /// * `decrypt` - A boolean indicating if the data should be decrypted or encrypted.
26 /// If set to true the data will be decrypted else encrypted.
27 /// * `mode` - The [SymmetricMode] to be used.
28 /// * `in_data` - The data that is going to be decrypted or encrypted.
29 /// * `initial_value_in` - An initial value as required by the algorithm.
30 ///
31 /// # Example
32 /// ```rust
33 /// # use tss_esapi::{
34 /// # constants::AlgorithmIdentifier,
35 /// # attributes::ObjectAttributesBuilder,
36 /// # Context, tcti_ldr::TctiNameConf, Result,
37 /// # structures::{
38 /// # Auth, InitialValue, MaxBuffer, SensitiveData, RsaExponent, SymmetricDefinitionObject,
39 /// # SymmetricCipherParameters, PublicBuilder,
40 /// # },
41 /// # interface_types::{
42 /// # algorithm::{PublicAlgorithm, HashingAlgorithm},
43 /// # key_bits::RsaKeyBits,
44 /// # },
45 /// # };
46 /// use tss_esapi::interface_types::session_handles::AuthSession;
47 /// use tss_esapi::interface_types::algorithm::SymmetricMode;
48 /// # use std::convert::TryFrom;
49 /// # // Create context
50 /// # let mut context =
51 /// # Context::new(
52 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
53 /// # ).expect("Failed to create Context");
54 /// # // Set auth for owner
55 /// # context
56 /// # .tr_set_auth(tss_esapi::interface_types::reserved_handles::Hierarchy::Owner.into(), Auth::default())
57 /// # .expect("Failed to set auth to empty for owner");
58 /// # // Create primary key auth
59 /// # let mut random_digest = vec![0u8; 16];
60 /// # getrandom::getrandom(&mut random_digest).expect("get_rand call failed");
61 /// # let primary_key_auth = Auth::from_bytes(
62 /// # random_digest
63 /// # .as_slice()
64 /// # )
65 /// # .expect("Failed to create primary key auth");
66 /// # // Create primary key
67 /// # let primary_key_handle = context.execute_with_session(Some(AuthSession::Password), |ctx| {
68 /// # ctx.create_primary(
69 /// # tss_esapi::interface_types::reserved_handles::Hierarchy::Owner,
70 /// # tss_esapi::utils::create_restricted_decryption_rsa_public(
71 /// # SymmetricDefinitionObject::AES_256_CFB,
72 /// # RsaKeyBits::Rsa2048,
73 /// # RsaExponent::default(),
74 /// # )
75 /// # .expect("Failed to create public for primary key"),
76 /// # Some(primary_key_auth.clone()),
77 /// # None,
78 /// # None,
79 /// # None,
80 /// # )
81 /// # .expect("Failed to create primary handle")
82 /// # .key_handle
83 /// # });
84 /// # // Set auth for the primary key handle
85 /// # context
86 /// # .tr_set_auth(primary_key_handle.into(), primary_key_auth)
87 /// # .expect("Failed to set auth from primary key handle.");
88 /// # // Create symmetric key object attributes
89 /// # let symmetric_key_object_attributes = ObjectAttributesBuilder::new()
90 /// # .with_user_with_auth(true)
91 /// # .with_sign_encrypt(true)
92 /// # .with_decrypt(true)
93 /// # .build()
94 /// # .expect("Failed to create object attributes for symmetric key");
95 /// # // Create public part for the symmetric key
96 /// # let symmetric_key_public = PublicBuilder::new()
97 /// # .with_public_algorithm(PublicAlgorithm::SymCipher)
98 /// # .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
99 /// # .with_object_attributes(symmetric_key_object_attributes)
100 /// # .with_symmetric_cipher_parameters(SymmetricCipherParameters::new(SymmetricDefinitionObject::AES_256_CFB))
101 /// # .with_symmetric_cipher_unique_identifier(Default::default())
102 /// # .build()
103 /// # .expect("Failed to create public for symmetric key public");
104 /// # // Create auth for the symmetric key
105 /// # let mut random_digest = vec![0u8; 16];
106 /// # getrandom::getrandom(&mut random_digest).expect("get_rand call failed");
107 /// # let symmetric_key_auth = Auth::from_bytes(
108 /// # random_digest
109 /// # .as_slice()
110 /// # )
111 /// # .expect("Failed to create symmetric key auth");
112 /// # // Create symmetric key data
113 /// # let symmetric_key_value =
114 /// # SensitiveData::try_from(vec![
115 /// # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
116 /// # 17, 18, 19, 20, 21, 22 ,23, 24, 25, 26, 27, 28, 29, 30, 31, 32])
117 /// # .expect("Failed to create sensitive data from data");
118 /// # // Create the symmetric key
119 /// # // if this fails with "tpm:parameter(2):inconsistent attributes" then the symmetric
120 /// # // cipher is probably not supported.
121 /// # let symmetric_key_creation_data =
122 /// # context.execute_with_session(Some(AuthSession::Password), |ctx| {
123 /// # ctx.create(
124 /// # primary_key_handle,
125 /// # symmetric_key_public,
126 /// # Some(symmetric_key_auth.clone()),
127 /// # Some(symmetric_key_value),
128 /// # None,
129 /// # None,
130 /// # )
131 /// # .expect("Failed to create symmetric key")
132 /// # });
133 /// # // Load the symmetric key in order to get handle to it.
134 /// # let symmetric_key_handle =
135 /// # context.execute_with_session(Some(AuthSession::Password), |ctx| {
136 /// # ctx.load(
137 /// # primary_key_handle,
138 /// # symmetric_key_creation_data.out_private,
139 /// # symmetric_key_creation_data.out_public,
140 /// # )
141 /// # .expect("Failed to load symmetric key")
142 /// # });
143 /// # // Set auth for the handle to be able to use it.
144 /// # context
145 /// # .tr_set_auth(symmetric_key_handle.into(), symmetric_key_auth)
146 /// # .expect("Failed to set auth on symmetric key handle");
147 /// #
148 /// # // Create initial value to be used by the algorithm.
149 /// # let initial_value =
150 /// # InitialValue::try_from(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
151 /// # .expect("Failed to create InitialValue from data");
152 /// # // Create data to be encrypted.
153 /// # let data = MaxBuffer::try_from(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 16])
154 /// # .expect("Failed to create MaxBuffer from data");
155 /// // Encrypt the data
156 /// let (encrypted_data, _initial_value_out) =
157 /// context.execute_with_session(Some(AuthSession::Password), |ctx| {
158 /// ctx.encrypt_decrypt_2(
159 /// symmetric_key_handle, // Handle to a symmetric key
160 /// false, // false, indicates that the data should be encrypted.
161 /// SymmetricMode::Cfb, // The symmetric mode of the encryption.
162 /// data.clone(), // The data that is to be encrypted.
163 /// initial_value.clone(), // Initial value needed by the algorithm.
164 /// )
165 /// .expect("Call to encrypt_decrypt_2 failed when encrypting data")
166 /// });
167 ///
168 /// assert_ne!(data.clone(), encrypted_data);
169 /// #
170 /// # let (decrypted_data, _) =
171 /// # context.execute_with_session(Some(AuthSession::Password), |ctx| {
172 /// # ctx.encrypt_decrypt_2(
173 /// # symmetric_key_handle,
174 /// # true,
175 /// # SymmetricMode::Cfb,
176 /// # encrypted_data,
177 /// # initial_value,
178 /// # )
179 /// # .expect("Call to encrypt_decrypt_2 failed when decrypting data")
180 /// # });
181 /// #
182 /// # debug_assert_eq!(data, decrypted_data);
183 /// ```
184 pub fn encrypt_decrypt_2(
185 &mut self,
186 key_handle: KeyHandle,
187 decrypt: bool,
188 mode: SymmetricMode,
189 in_data: MaxBuffer,
190 initial_value_in: InitialValue,
191 ) -> Result<(MaxBuffer, InitialValue)> {
192 let mut out_data_ptr = null_mut();
193 let mut iv_out_ptr = null_mut();
194 ReturnCode::ensure_success(
195 unsafe {
196 Esys_EncryptDecrypt2(
197 self.mut_context(),
198 key_handle.into(),
199 self.required_session_1()?,
200 self.optional_session_2(),
201 self.optional_session_3(),
202 &in_data.into(),
203 decrypt.into(),
204 mode.into(),
205 &initial_value_in.into(),
206 &mut out_data_ptr,
207 &mut iv_out_ptr,
208 )
209 },
210 |ret| {
211 error!(
212 "Error failed to perform encrypt or decrypt operations {:#010X}",
213 ret
214 );
215 },
216 )?;
217 Ok((
218 MaxBuffer::try_from(Context::ffi_data_to_owned(out_data_ptr)?)?,
219 InitialValue::try_from(Context::ffi_data_to_owned(iv_out_ptr)?)?,
220 ))
221 }
222
223 /// Hashes the provided data using the specified algorithm.
224 ///
225 /// # Details
226 /// Performs the specified hash operation on a data buffer and return
227 /// the result. The HashCheckTicket indicates if the hash can be used in
228 /// a signing operation that uses restricted signing key.
229 ///
230 /// # Example
231 ///
232 /// ```rust
233 /// # use tss_esapi::{Context, tcti_ldr::TctiNameConf,
234 /// # structures::{MaxBuffer, Ticket},
235 /// # interface_types::{algorithm::HashingAlgorithm, reserved_handles::Hierarchy},
236 /// # };
237 /// # use std::convert::TryFrom;
238 /// # // Create context
239 /// # let mut context =
240 /// # Context::new(
241 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
242 /// # ).expect("Failed to create Context");
243 /// let input_data = MaxBuffer::try_from("There is no spoon".as_bytes().to_vec())
244 /// .expect("Failed to create buffer for input data.");
245 /// let expected_hashed_data: [u8; 32] = [
246 /// 0x6b, 0x38, 0x4d, 0x2b, 0xfb, 0x0e, 0x0d, 0xfb, 0x64, 0x89, 0xdb, 0xf4, 0xf8, 0xe9,
247 /// 0xe5, 0x2f, 0x71, 0xee, 0xb1, 0x0d, 0x06, 0x4c, 0x56, 0x59, 0x70, 0xcd, 0xd9, 0x44,
248 /// 0x43, 0x18, 0x5d, 0xc1,
249 /// ];
250 /// let expected_hierarchy = Hierarchy::Owner;
251 /// let (actual_hashed_data, ticket) = context
252 /// .hash(
253 /// input_data,
254 /// HashingAlgorithm::Sha256,
255 /// expected_hierarchy,
256 /// )
257 /// .expect("Call to hash failed.");
258 /// assert_eq!(expected_hashed_data.len(), actual_hashed_data.len());
259 /// assert_eq!(&expected_hashed_data[..], &actual_hashed_data[..]);
260 /// assert_eq!(ticket.hierarchy(), expected_hierarchy);
261 /// ```
262 pub fn hash(
263 &mut self,
264 data: MaxBuffer,
265 hashing_algorithm: HashingAlgorithm,
266 hierarchy: Hierarchy,
267 ) -> Result<(Digest, HashcheckTicket)> {
268 let mut out_hash_ptr = null_mut();
269 let mut validation_ptr = null_mut();
270 ReturnCode::ensure_success(
271 unsafe {
272 Esys_Hash(
273 self.mut_context(),
274 self.optional_session_1(),
275 self.optional_session_2(),
276 self.optional_session_3(),
277 &data.into(),
278 hashing_algorithm.into(),
279 if cfg!(hierarchy_is_esys_tr) {
280 ObjectHandle::from(hierarchy).into()
281 } else {
282 TpmHandle::from(hierarchy).into()
283 },
284 &mut out_hash_ptr,
285 &mut validation_ptr,
286 )
287 },
288 |ret| {
289 error!("Error failed to perform hash operation: {:#010X}", ret);
290 },
291 )?;
292 Ok((
293 Digest::try_from(Context::ffi_data_to_owned(out_hash_ptr)?)?,
294 HashcheckTicket::try_from(Context::ffi_data_to_owned(validation_ptr)?)?,
295 ))
296 }
297
298 /// Asks the TPM to compute an HMAC over buffer with the specified key
299 ///
300 /// # Example
301 ///
302 /// ```rust
303 /// # use tss_esapi::{
304 /// # attributes::ObjectAttributesBuilder,
305 /// # structures::{MaxBuffer, Ticket, PublicKeyedHashParameters, KeyedHashScheme, HmacScheme, PublicBuilder, Digest},
306 /// # interface_types::{
307 /// # reserved_handles::Hierarchy,
308 /// # algorithm::{HashingAlgorithm, PublicAlgorithm},
309 /// # },
310 /// # Context, tcti_ldr::TctiNameConf,
311 /// # };
312 /// # use std::convert::TryFrom;
313 /// # // Create context
314 /// # let mut context =
315 /// # Context::new(
316 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
317 /// # ).expect("Failed to create Context");
318 /// // Create a key
319 /// let object_attributes = ObjectAttributesBuilder::new()
320 /// .with_sign_encrypt(true)
321 /// .with_sensitive_data_origin(true)
322 /// .with_user_with_auth(true)
323 /// .build()
324 /// .expect("Failed to build object attributes");
325 /// let key_pub = PublicBuilder::new()
326 /// .with_public_algorithm(PublicAlgorithm::KeyedHash)
327 /// .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
328 /// .with_object_attributes(object_attributes)
329 /// .with_keyed_hash_parameters(PublicKeyedHashParameters::new(KeyedHashScheme::HMAC_SHA_256))
330 /// .with_keyed_hash_unique_identifier(Digest::default())
331 /// .build()
332 /// .unwrap();
333 ///
334 /// let input_data = MaxBuffer::try_from("There is no spoon".as_bytes().to_vec())
335 /// .expect("Failed to create buffer for input data.");
336 ///
337 /// let hmac = context.execute_with_nullauth_session(|ctx| {
338 /// let key = ctx.create_primary(Hierarchy::Owner, key_pub, None, None, None, None).unwrap();
339 ///
340 /// ctx.hmac(key.key_handle.into(), input_data, HashingAlgorithm::Sha256)
341 /// }).unwrap();
342 ///
343 /// ```
344 ///
345 /// # Errors
346 /// * if any of the public parameters is not compatible with the TPM,
347 /// an `Err` containing the specific unmarshalling error will be returned.
348 pub fn hmac(
349 &mut self,
350 handle: ObjectHandle,
351 buffer: MaxBuffer,
352 alg_hash: HashingAlgorithm,
353 ) -> Result<Digest> {
354 let mut out_hmac_ptr = null_mut();
355 ReturnCode::ensure_success(
356 unsafe {
357 Esys_HMAC(
358 self.mut_context(),
359 handle.into(),
360 self.required_session_1()?,
361 self.optional_session_2(),
362 self.optional_session_3(),
363 &buffer.into(),
364 alg_hash.into(),
365 &mut out_hmac_ptr,
366 )
367 },
368 |ret| {
369 error!("Error in hmac: {:#010X}", ret);
370 },
371 )?;
372 Digest::try_from(Context::ffi_data_to_owned(out_hmac_ptr)?)
373 }
374
375 // Missing function: MAC
376}