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 resource_handles::Hierarchy,
8 },
9 structures::{Digest, HashcheckTicket, InitialValue, MaxBuffer},
10 tss2_esys::{Esys_EncryptDecrypt2, Esys_HMAC, Esys_Hash},
11 Context, Error, Result,
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::resource_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::try_from(
62 /// # random_digest
63 /// # )
64 /// # .expect("Failed to create primary key auth");
65 /// # // Create primary key
66 /// # let primary_key_handle = context.execute_with_session(Some(AuthSession::Password), |ctx| {
67 /// # ctx.create_primary(
68 /// # tss_esapi::interface_types::resource_handles::Hierarchy::Owner,
69 /// # tss_esapi::utils::create_restricted_decryption_rsa_public(
70 /// # SymmetricDefinitionObject::AES_256_CFB,
71 /// # RsaKeyBits::Rsa2048,
72 /// # RsaExponent::default(),
73 /// # )
74 /// # .expect("Failed to create public for primary key"),
75 /// # Some(primary_key_auth.clone()),
76 /// # None,
77 /// # None,
78 /// # None,
79 /// # )
80 /// # .expect("Failed to create primary handle")
81 /// # .key_handle
82 /// # });
83 /// # // Set auth for the primary key handle
84 /// # context
85 /// # .tr_set_auth(primary_key_handle.into(), primary_key_auth)
86 /// # .expect("Failed to set auth from primary key handle.");
87 /// # // Create symmetric key object attributes
88 /// # let symmetric_key_object_attributes = ObjectAttributesBuilder::new()
89 /// # .with_user_with_auth(true)
90 /// # .with_sign_encrypt(true)
91 /// # .with_decrypt(true)
92 /// # .build()
93 /// # .expect("Failed to create object attributes for symmetric key");
94 /// # // Create public part for the symmetric key
95 /// # let symmetric_key_public = PublicBuilder::new()
96 /// # .with_public_algorithm(PublicAlgorithm::SymCipher)
97 /// # .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
98 /// # .with_object_attributes(symmetric_key_object_attributes)
99 /// # .with_symmetric_cipher_parameters(SymmetricCipherParameters::new(SymmetricDefinitionObject::AES_256_CFB))
100 /// # .with_symmetric_cipher_unique_identifier(Default::default())
101 /// # .build()
102 /// # .expect("Failed to create public for symmetric key public");
103 /// # // Create auth for the symmetric key
104 /// # let mut random_digest = vec![0u8; 16];
105 /// # getrandom::getrandom(&mut random_digest).expect("get_rand call failed");
106 /// # let symmetric_key_auth = Auth::try_from(
107 /// # random_digest
108 /// # )
109 /// # .expect("Failed to create symmetric key auth");
110 /// # // Create symmetric key data
111 /// # let symmetric_key_value =
112 /// # SensitiveData::try_from(vec![
113 /// # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
114 /// # 17, 18, 19, 20, 21, 22 ,23, 24, 25, 26, 27, 28, 29, 30, 31, 32])
115 /// # .expect("Failed to create sensitive data from data");
116 /// # // Create the symmetric key
117 /// # // if this fails with "tpm:parameter(2):inconsistent attributes" then the symmetric
118 /// # // cipher is probably not supported.
119 /// # let symmetric_key_creation_data =
120 /// # context.execute_with_session(Some(AuthSession::Password), |ctx| {
121 /// # ctx.create(
122 /// # primary_key_handle,
123 /// # symmetric_key_public,
124 /// # Some(symmetric_key_auth.clone()),
125 /// # Some(symmetric_key_value),
126 /// # None,
127 /// # None,
128 /// # )
129 /// # .expect("Failed to create symmetric key")
130 /// # });
131 /// # // Load the symmetric key in order to get handle to it.
132 /// # let symmetric_key_handle =
133 /// # context.execute_with_session(Some(AuthSession::Password), |ctx| {
134 /// # ctx.load(
135 /// # primary_key_handle,
136 /// # symmetric_key_creation_data.out_private,
137 /// # symmetric_key_creation_data.out_public,
138 /// # )
139 /// # .expect("Failed to load symmetric key")
140 /// # });
141 /// # // Set auth for the handle to be able to use it.
142 /// # context
143 /// # .tr_set_auth(symmetric_key_handle.into(), symmetric_key_auth)
144 /// # .expect("Failed to set auth on symmetric key handle");
145 /// #
146 /// # // Create initial value to be used by the algorithm.
147 /// # let initial_value =
148 /// # InitialValue::try_from(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
149 /// # .expect("Failed to create InitialValue from data");
150 /// # // Create data to be encrypted.
151 /// # let data = MaxBuffer::try_from(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 16])
152 /// # .expect("Failed to create MaxBuffer from data");
153 /// // Encrypt the data
154 /// let (encrypted_data, _initial_value_out) =
155 /// context.execute_with_session(Some(AuthSession::Password), |ctx| {
156 /// ctx.encrypt_decrypt_2(
157 /// symmetric_key_handle, // Handle to a symmetric key
158 /// false, // false, indicates that the data should be encrypted.
159 /// SymmetricMode::Cfb, // The symmetric mode of the encryption.
160 /// data.clone(), // The data that is to be encrypted.
161 /// initial_value.clone(), // Initial value needed by the algorithm.
162 /// )
163 /// .expect("Call to encrypt_decrypt_2 failed when encrypting data")
164 /// });
165 ///
166 /// assert_ne!(data.clone(), encrypted_data);
167 /// #
168 /// # let (decrypted_data, _) =
169 /// # context.execute_with_session(Some(AuthSession::Password), |ctx| {
170 /// # ctx.encrypt_decrypt_2(
171 /// # symmetric_key_handle,
172 /// # true,
173 /// # SymmetricMode::Cfb,
174 /// # encrypted_data,
175 /// # initial_value,
176 /// # )
177 /// # .expect("Call to encrypt_decrypt_2 failed when decrypting data")
178 /// # });
179 /// #
180 /// # debug_assert_eq!(data, decrypted_data);
181 /// ```
182 pub fn encrypt_decrypt_2(
183 &mut self,
184 key_handle: KeyHandle,
185 decrypt: bool,
186 mode: SymmetricMode,
187 in_data: MaxBuffer,
188 initial_value_in: InitialValue,
189 ) -> Result<(MaxBuffer, InitialValue)> {
190 let mut out_data_ptr = null_mut();
191 let mut iv_out_ptr = null_mut();
192 let ret = unsafe {
193 Esys_EncryptDecrypt2(
194 self.mut_context(),
195 key_handle.into(),
196 self.required_session_1()?,
197 self.optional_session_2(),
198 self.optional_session_3(),
199 &in_data.into(),
200 decrypt.into(),
201 mode.into(),
202 &initial_value_in.into(),
203 &mut out_data_ptr,
204 &mut iv_out_ptr,
205 )
206 };
207
208 let ret = Error::from_tss_rc(ret);
209 if ret.is_success() {
210 Ok((
211 MaxBuffer::try_from(Context::ffi_data_to_owned(out_data_ptr))?,
212 InitialValue::try_from(Context::ffi_data_to_owned(iv_out_ptr))?,
213 ))
214 } else {
215 error!(
216 "Error failed to perform encrypt or decrypt operations {}",
217 ret
218 );
219 Err(ret)
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, resource_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 let ret = unsafe {
271 #[allow(unexpected_cfgs)]
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!(tpm2_tss_version = "2") {
280 TpmHandle::from(hierarchy).into()
281 } else {
282 ObjectHandle::from(hierarchy).into()
283 },
284 &mut out_hash_ptr,
285 &mut validation_ptr,
286 )
287 };
288 let ret = Error::from_tss_rc(ret);
289 if ret.is_success() {
290 Ok((
291 Digest::try_from(Context::ffi_data_to_owned(out_hash_ptr))?,
292 HashcheckTicket::try_from(Context::ffi_data_to_owned(validation_ptr))?,
293 ))
294 } else {
295 error!("Error failed to perform hash operation: {}", ret);
296 Err(ret)
297 }
298 }
299
300 /// Asks the TPM to compute an HMAC over buffer with the specified key
301 ///
302 /// # Example
303 ///
304 /// ```rust
305 /// # use tss_esapi::{
306 /// # attributes::ObjectAttributesBuilder,
307 /// # structures::{MaxBuffer, Ticket, PublicKeyedHashParameters, KeyedHashScheme, HmacScheme, PublicBuilder, Digest},
308 /// # interface_types::{
309 /// # resource_handles::Hierarchy,
310 /// # algorithm::{HashingAlgorithm, PublicAlgorithm},
311 /// # },
312 /// # Context, tcti_ldr::TctiNameConf,
313 /// # };
314 /// # use std::convert::TryFrom;
315 /// # // Create context
316 /// # let mut context =
317 /// # Context::new(
318 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
319 /// # ).expect("Failed to create Context");
320 /// // Create a key
321 /// let object_attributes = ObjectAttributesBuilder::new()
322 /// .with_sign_encrypt(true)
323 /// .with_sensitive_data_origin(true)
324 /// .with_user_with_auth(true)
325 /// .build()
326 /// .expect("Failed to build object attributes");
327 /// let key_pub = PublicBuilder::new()
328 /// .with_public_algorithm(PublicAlgorithm::KeyedHash)
329 /// .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
330 /// .with_object_attributes(object_attributes)
331 /// .with_keyed_hash_parameters(PublicKeyedHashParameters::new(KeyedHashScheme::HMAC_SHA_256))
332 /// .with_keyed_hash_unique_identifier(Digest::default())
333 /// .build()
334 /// .unwrap();
335 ///
336 /// let input_data = MaxBuffer::try_from("There is no spoon".as_bytes().to_vec())
337 /// .expect("Failed to create buffer for input data.");
338 ///
339 /// let hmac = context.execute_with_nullauth_session(|ctx| {
340 /// let key = ctx.create_primary(Hierarchy::Owner, key_pub, None, None, None, None).unwrap();
341 ///
342 /// ctx.hmac(key.key_handle.into(), input_data, HashingAlgorithm::Sha256)
343 /// }).unwrap();
344 ///
345 /// ```
346 ///
347 /// # Errors
348 /// * if any of the public parameters is not compatible with the TPM,
349 /// an `Err` containing the specific unmarshalling error will be returned.
350 pub fn hmac(
351 &mut self,
352 handle: ObjectHandle,
353 buffer: MaxBuffer,
354 alg_hash: HashingAlgorithm,
355 ) -> Result<Digest> {
356 let mut out_hmac_ptr = null_mut();
357 let ret = unsafe {
358 Esys_HMAC(
359 self.mut_context(),
360 handle.into(),
361 self.required_session_1()?,
362 self.optional_session_2(),
363 self.optional_session_3(),
364 &buffer.into(),
365 alg_hash.into(),
366 &mut out_hmac_ptr,
367 )
368 };
369 let ret = Error::from_tss_rc(ret);
370
371 if ret.is_success() {
372 Digest::try_from(Context::ffi_data_to_owned(out_hmac_ptr))
373 } else {
374 error!("Error in hmac: {}", ret);
375 Err(ret)
376 }
377 }
378
379 // Missing function: MAC
380}