@@ -279,6 +279,28 @@ otcrypto_status_t otcrypto_aes_padded_plaintext_length(
279279 return OTCRYPTO_OK ;
280280}
281281
282+ /**
283+ * Consolidated state for AES operations.
284+ * Grouping these reduces the compiler RAII tracking overhead to a single
285+ * variable.
286+ */
287+ typedef struct {
288+ aes_key_t key ;
289+ aes_block_t iv ;
290+ aes_block_t block_in ;
291+ aes_block_t block_out ;
292+ } aes_impl_state_t ;
293+
294+ /**
295+ * Cleanup function.
296+ */
297+ static void cleanup_aes_state (aes_impl_state_t * state ) {
298+ (void )aes_clear ();
299+ (void )keymgr_sideload_clear_aes ();
300+ hardened_memshred ((uint32_t * )state ,
301+ sizeof (aes_impl_state_t ) / sizeof (uint32_t ));
302+ }
303+
282304/**
283305 * Performs the AES operation.
284306 *
@@ -297,6 +319,10 @@ static otcrypto_status_t otcrypto_aes_impl(
297319 otcrypto_aes_mode_t aes_mode , otcrypto_aes_operation_t aes_operation ,
298320 const otcrypto_const_byte_buf_t * cipher_input ,
299321 otcrypto_aes_padding_t aes_padding , otcrypto_byte_buf_t * cipher_output ) {
322+ // Set the attribute with the state to clean up all sensitive variables and
323+ // clear the HW upon exit.
324+ aes_impl_state_t state __attribute__((cleanup (cleanup_aes_state ))) = {0 };
325+
300326 // Calculate the number of blocks for the input, including the padding for
301327 // encryption.
302328 size_t input_nblocks ;
@@ -324,7 +350,6 @@ static otcrypto_status_t otcrypto_aes_impl(
324350
325351 // Construct the IV and check its length. ECB mode will ignore the IV, so in
326352 // this case it is left uninitialized.
327- aes_block_t aes_iv ;
328353 if (aes_mode == kAesCipherModeEcb ) {
329354 HARDENED_CHECK_EQ (launder32 (aes_mode ), kAesCipherModeEcb );
330355 } else {
@@ -335,23 +360,22 @@ static otcrypto_status_t otcrypto_aes_impl(
335360 return OTCRYPTO_BAD_ARGS ;
336361 }
337362 HARDENED_CHECK_EQ (launder32 (iv -> len ), kAesBlockNumWords );
338- HARDENED_TRY (hardened_memcpy (aes_iv .data , iv -> data , kAesBlockNumWords ));
363+ HARDENED_TRY (hardened_memcpy (state . iv .data , iv -> data , kAesBlockNumWords ));
339364 }
340365
341366 // Parse the AES key.
342- aes_key_t aes_key ;
343- HARDENED_TRY (aes_key_construct (key , aes_mode , & aes_key ));
367+ HARDENED_TRY (aes_key_construct (key , aes_mode , & state .key ));
344368
345369 // Start the operation (encryption or decryption).
346370 otcrypto_aes_operation_t aes_operation_started = launder32 (0 );
347371 switch (aes_operation ) {
348372 case kOtcryptoAesOperationEncrypt :
349- HARDENED_TRY (aes_encrypt_begin (aes_key , & aes_iv ));
373+ HARDENED_TRY (aes_encrypt_begin (state . key , & state . iv ));
350374 aes_operation_started =
351375 launder32 (aes_operation_started ) | kOtcryptoAesOperationEncrypt ;
352376 break ;
353377 case kOtcryptoAesOperationDecrypt :
354- HARDENED_TRY (aes_decrypt_begin (aes_key , & aes_iv ));
378+ HARDENED_TRY (aes_decrypt_begin (state . key , & state . iv ));
355379 aes_operation_started =
356380 launder32 (aes_operation_started ) | kOtcryptoAesOperationDecrypt ;
357381 break ;
@@ -389,45 +413,44 @@ static otcrypto_status_t otcrypto_aes_impl(
389413 //
390414 // See the AES driver for details.
391415 const size_t block_offset = input_nblocks >= 3 ? 2 : 1 ;
392- aes_block_t block_in ;
393- aes_block_t block_out ;
394416 size_t i ;
395417
396418 // Provide the first `block_offset` number of input blocks and call the AES
397419 // cipher.
398420 for (i = 0 ; launder32 (i ) < block_offset ; ++ i ) {
399- HARDENED_TRY (get_block (cipher_input , aes_padding , i , & block_in ));
400- HARDENED_TRY (aes_update (/*dest=*/ NULL , & block_in ));
421+ HARDENED_TRY (get_block (cipher_input , aes_padding , i , & state . block_in ));
422+ HARDENED_TRY (aes_update (/*dest=*/ NULL , & state . block_in ));
401423 }
402424 // Check that the loop ran for the correct number of iterations.
403425 HARDENED_CHECK_EQ (i , block_offset );
404426
405427 // Call the AES cipher while providing new input and copying data to the
406428 // output buffer.
407429 for (i = block_offset ; launder32 (i ) < input_nblocks ; ++ i ) {
408- HARDENED_TRY (get_block (cipher_input , aes_padding , i , & block_in ));
409- HARDENED_TRY (hardened_memshred (block_out .data , ARRAYSIZE (block_out .data )));
410- HARDENED_TRY (aes_update (& block_out , & block_in ));
430+ HARDENED_TRY (get_block (cipher_input , aes_padding , i , & state .block_in ));
431+ HARDENED_TRY (hardened_memshred (state .block_out .data ,
432+ ARRAYSIZE (state .block_out .data )));
433+ HARDENED_TRY (aes_update (& state .block_out , & state .block_in ));
411434 // Byte buffers passed as input may not be word-aligned, so we cannot
412435 // use `hardened_memcpy`.
413436 // Hence, use `randomized_bytecopy` instead.
414437 HARDENED_TRY (randomized_bytecopy (
415438 & cipher_output -> data [(i - block_offset ) * kAesBlockNumBytes ],
416- block_out .data , kAesBlockNumBytes ));
439+ state . block_out .data , kAesBlockNumBytes ));
417440 }
418441 // Check that the loop ran for the correct number of iterations.
419442 HARDENED_CHECK_EQ (i , input_nblocks );
420443
421444 // Retrieve the output from the final `block_offset` blocks (providing no
422445 // input).
423446 for (i = block_offset ; i > 0 ; -- i ) {
424- HARDENED_TRY (aes_update (& block_out , /*src=*/ NULL ));
447+ HARDENED_TRY (aes_update (& state . block_out , /*src=*/ NULL ));
425448 // Byte buffers passed as input may not be word-aligned, so we cannot
426449 // use `hardened_memcpy`.
427450 // Hence, use `randomized_bytecopy` instead.
428451 HARDENED_TRY (randomized_bytecopy (
429452 & cipher_output -> data [(input_nblocks - i ) * kAesBlockNumBytes ],
430- block_out .data , kAesBlockNumBytes ));
453+ state . block_out .data , kAesBlockNumBytes ));
431454 }
432455 // Check that the loop ran for the correct number of iterations.
433456 HARDENED_CHECK_EQ (launder32 (i ), 0 );
@@ -439,19 +462,18 @@ static otcrypto_status_t otcrypto_aes_impl(
439462 hardened_bool_t encrypt = kHardenedBoolTrue ;
440463 if (aes_operation == kOtcryptoAesOperationDecrypt )
441464 encrypt = kHardenedBoolFalse ;
442- HARDENED_TRY (aes_verify_ctrl_reg (aes_key , encrypt ));
465+ HARDENED_TRY (aes_verify_ctrl_reg (state . key , encrypt ));
443466 HARDENED_TRY (aes_verify_ctrl_aux_reg ());
444467
445468 // Deinitialize the AES block and update the IV (in ECB mode, skip the IV).
446469 if (aes_mode == kAesCipherModeEcb ) {
447470 HARDENED_TRY (aes_end (NULL ));
448471 } else {
449- HARDENED_TRY (aes_end (& aes_iv ));
450- HARDENED_TRY (hardened_memcpy (iv -> data , aes_iv .data , kAesBlockNumWords ));
472+ HARDENED_TRY (aes_end (& state . iv ));
473+ HARDENED_TRY (hardened_memcpy (iv -> data , state . iv .data , kAesBlockNumWords ));
451474 }
452475
453- // In case the key was sideloaded, clear it.
454- return otcrypto_eval_exit (keymgr_sideload_clear_aes ());
476+ return otcrypto_eval_exit (OTCRYPTO_OK );
455477}
456478
457479otcrypto_status_t otcrypto_aes_padding_strip (
0 commit comments