/*! * @brief Authenticate and decrypt a (CCM) stream. * * @param user_ctx The user's context * @param auth_ctx Info on this Auth operation * @param cipher_key_info Key to encrypt payload * @param auth_key_info (unused - same key in CCM) * @param auth_data_length Length in bytes of @a auth_data * @param auth_data Any auth-only data * @param payload_length Length in bytes of @a payload * @param ct The encrypted data * @param auth_value The authentication code to validate * @param[out] payload The location to store decrypted data * * @return A return code of type #fsl_shw_return_t. */ fsl_shw_return_t fsl_shw_auth_decrypt(fsl_shw_uco_t * user_ctx, fsl_shw_acco_t * auth_ctx, fsl_shw_sko_t * cipher_key_info, fsl_shw_sko_t * auth_key_info, uint32_t auth_data_length, const uint8_t * auth_data, uint32_t payload_length, const uint8_t * ct, const uint8_t * auth_value, uint8_t * payload) { SAH_SF_DCLS; uint8_t *calced_auth = NULL; unsigned blocking = user_ctx->flags & FSL_UCO_BLOCKING_MODE; SAH_SF_USER_CHECK(); /* Only support INIT and FINALIZE flags right now. */ if (auth_ctx->mode != FSL_ACC_MODE_CCM) { ret = FSL_RETURN_BAD_MODE_S; goto out; } if ((auth_ctx->flags & (FSL_ACCO_CTX_INIT | FSL_ACCO_CTX_LOAD | FSL_ACCO_CTX_SAVE | FSL_ACCO_CTX_FINALIZE)) != (FSL_ACCO_CTX_INIT | FSL_ACCO_CTX_FINALIZE)) { ret = FSL_RETURN_BAD_FLAG_S; goto out; } ret = load_ctr_key(&desc_chain, user_ctx, auth_ctx, cipher_key_info); if (ret != FSL_RETURN_OK_S) { goto out; } /* Decrypt the MAC which the user passed in */ header = SAH_HDR_SKHA_ENC_DEC; DESC_IN_OUT(header, auth_ctx->mac_length, auth_value, auth_ctx->mac_length, auth_ctx->unencrypted_mac); #ifndef NO_ZERO_IV_LOAD ret = load_dummy_iv(&desc_chain, user_ctx, 1, auth_ctx->auth_info.CCM_ctx_info.block_size_bytes); #endif if (auth_data_length > 0) { ret = add_assoc_preamble(&desc_chain, user_ctx, auth_ctx, auth_data, auth_data_length); if (ret != FSL_RETURN_OK_S) { goto out; } } /* if auth_data_length > 0 */ ret = process_payload(&desc_chain, user_ctx, 0, payload_length, ct, payload); if (ret != FSL_RETURN_OK_S) { goto out; } /* Now pull CBC context (unencrypted MAC) out for comparison. */ /* Need to allocate a place for it, to handle non-blocking mode * when this stack frame will disappear! */ calced_auth = DESC_TEMP_ALLOC(auth_ctx->mac_length); ret = extract_mac(&desc_chain, user_ctx, auth_ctx->mac_length, calced_auth); if (ret != FSL_RETURN_OK_S) { goto out; } if (!blocking) { /* get_results will need this for comparison */ desc_chain->out1_ptr = calced_auth; desc_chain->out2_ptr = auth_ctx->unencrypted_mac; desc_chain->out_len = auth_ctx->mac_length; } SAH_SF_EXECUTE(); if (blocking && (ret == FSL_RETURN_OK_S)) { unsigned i; /* Validate the auth code */ for (i = 0; i < auth_ctx->mac_length; i++) { if (calced_auth[i] != auth_ctx->unencrypted_mac[i]) { ret = FSL_RETURN_AUTH_FAILED_S; break; } } } out: SAH_SF_DESC_CLEAN(); DESC_TEMP_FREE(calced_auth); (void)auth_key_info; return ret; } /* fsl_shw_gen_decrypt() */
/*! * Get a random number * * * @param user_ctx * @param length * @param data * * @return A return code of type #fsl_shw_return_t. */ fsl_shw_return_t fsl_shw_get_random(fsl_shw_uco_t * user_ctx, uint32_t length, uint8_t * data) { SAH_SF_DCLS; /* perform a sanity check on the uco */ ret = sah_validate_uco(user_ctx); if (ret != FSL_RETURN_OK_S) { goto out; } /* There is a possible problem with the auto-seed that automatically * reseeds every 4094x1024 bytes (2^20 words). * The third generation does not occur for an unknown reason so far. * Different method for manual reseed could be used, such every XXhours, * or every YY calls of this function a seed is generated. * The choosen method counts the number of generated random bytes, and * transparently reseed every 16MB. * Note that if the auto-seed is not disabled in the SAHARA driver, the * manual seed should be done after less generated bytes (see below). */ g_gen_rnd_bytes += length; #ifndef DISABLE_AUTOSEED /* use that value if auto-reseed is set */ if(!(g_gen_rnd_bytes % (4094*1024))) { #else /* otherwise use a larger but still satisfying value */ if(!(g_gen_rnd_bytes % (0x1000000))) { #endif //DISABLE_AUTOSEED header = SAH_HDR_FORCE_SEED; DESC_OUT_OUT(header, 0, NULL, 0, NULL); SAH_SF_EXECUTE(); SAH_SF_DESC_CLEAN(); } header = SAH_HDR_RNG_GENERATE; /* Desc. #18 */ DESC_OUT_OUT(header, length, data, 0, NULL); SAH_SF_EXECUTE(); out: SAH_SF_DESC_CLEAN(); return ret; } #ifdef __KERNEL__ EXPORT_SYMBOL(fsl_shw_add_entropy); #endif /*! * Add entropy to a random number generator * @param user_ctx * @param length * @param data * * @return A return code of type #fsl_shw_return_t. */ fsl_shw_return_t fsl_shw_add_entropy(fsl_shw_uco_t * user_ctx, uint32_t length, uint8_t * data) { SAH_SF_DCLS; /* perform a sanity check on the uco */ ret = sah_validate_uco(user_ctx); if (ret != FSL_RETURN_OK_S) { goto out; } header = SAH_HDR_RNG_GENERATE; /* Desc. #18 */ /* create descriptor #18. Generate random data */ DESC_IN_IN(header, 0, NULL, length, data) SAH_SF_EXECUTE(); out: SAH_SF_DESC_CLEAN(); return ret; }
/*! * @brief Authenticate and decrypt a (CCM) stream. * * @param user_ctx The user's context * @param auth_ctx Info on this Auth operation * @param cipher_key_info Key to encrypt payload * @param auth_key_info (unused - same key in CCM) * @param auth_data_length Length in bytes of @a auth_data * @param auth_data Any auth-only data * @param payload_length Length in bytes of @a payload * @param ct The encrypted data * @param auth_value The authentication code to validate * @param[out] payload The location to store decrypted data * * @return A return code of type #fsl_shw_return_t. */ fsl_shw_return_t fsl_shw_auth_decrypt(fsl_shw_uco_t * user_ctx, fsl_shw_acco_t * auth_ctx, fsl_shw_sko_t * cipher_key_info, fsl_shw_sko_t * auth_key_info, uint32_t auth_data_length, const uint8_t * auth_data, uint32_t payload_length, const uint8_t * ct, const uint8_t * auth_value, uint8_t * payload) { SAH_SF_DCLS; #if defined(FSL_HAVE_SAHARA2) || defined(USE_S2_CCM_DECRYPT_CHAIN) uint8_t *calced_auth = NULL; unsigned blocking = user_ctx->flags & FSL_UCO_BLOCKING_MODE; #endif SAH_SF_USER_CHECK(); /* Only support CCM */ if (auth_ctx->mode != FSL_ACC_MODE_CCM) { ret = FSL_RETURN_BAD_MODE_S; goto out; } /* Only support INIT and FINALIZE flags right now. */ if ((auth_ctx->flags & (FSL_ACCO_CTX_INIT | FSL_ACCO_CTX_LOAD | FSL_ACCO_CTX_SAVE | FSL_ACCO_CTX_FINALIZE)) != (FSL_ACCO_CTX_INIT | FSL_ACCO_CTX_FINALIZE)) { ret = FSL_RETURN_BAD_FLAG_S; goto out; } /* Load CTR0 and Key */ header = SAH_HDR_SKHA_SET_MODE_IV_KEY ^ sah_insert_skha_mode_ctr ^ sah_insert_skha_modulus_128; #if defined (FSL_HAVE_SAHARA4) && !defined (USE_S2_CCM_DECRYPT_CHAIN) header ^= sah_insert_skha_aux0; #endif DESC_IN_KEY(header, auth_ctx->cipher_ctx_info.block_size_bytes, auth_ctx->cipher_ctx_info.context, cipher_key_info); /* Decrypt the MAC which the user passed in */ header = SAH_HDR_SKHA_ENC_DEC; DESC_IN_OUT(header, auth_ctx->mac_length, auth_value, auth_ctx->mac_length, auth_ctx->unencrypted_mac); #if defined(FSL_HAVE_SAHARA2) || defined(USE_S2_CCM_DECRYPT_CHAIN) #ifndef NO_ZERO_IV_LOAD header = (SAH_HDR_SKHA_SET_MODE_IV_KEY ^ sah_insert_skha_encrypt ^ sah_insert_skha_mode_cbc); DESC_IN_IN(header, auth_ctx->auth_info.CCM_ctx_info.block_size_bytes, block_zeros, 0, NULL); #endif #endif ret = add_assoc_preamble(&desc_chain, user_ctx, auth_ctx, 0, auth_data, auth_data_length); if (ret != FSL_RETURN_OK_S) { goto out; } /* Process the payload */ header = (SAH_HDR_SKHA_SET_MODE_ENC_DEC ^ sah_insert_skha_mode_ccm ^ sah_insert_skha_modulus_128); #if defined (FSL_HAVE_SAHARA4) && !defined (USE_S2_CCM_DECRYPT_CHAIN) header ^= sah_insert_skha_aux0; #endif if (payload_length != 0) { DESC_IN_OUT(header, payload_length, ct, payload_length, payload); } else { DESC_IN_OUT(header, 0, NULL, 0, NULL); } #if defined (FSL_HAVE_SAHARA2) || defined (USE_S2_CCM_DECRYPT_CHAIN) /* Now pull CBC context (unencrypted MAC) out for comparison. */ /* Need to allocate a place for it, to handle non-blocking mode * when this stack frame will disappear! */ calced_auth = DESC_TEMP_ALLOC(auth_ctx->mac_length); header = SAH_HDR_SKHA_READ_CONTEXT_IV; DESC_OUT_OUT(header, 0, NULL, auth_ctx->mac_length, calced_auth); if (!blocking) { /* get_results will need this for comparison */ desc_chain->out1_ptr = calced_auth; desc_chain->out2_ptr = auth_ctx->unencrypted_mac; desc_chain->out_len = auth_ctx->mac_length; } #endif SAH_SF_EXECUTE(); #if defined (FSL_HAVE_SAHARA2) || defined (USE_S2_CCM_DECRYPT_CHAIN) if (blocking && (ret == FSL_RETURN_OK_S)) { unsigned i; /* Validate the auth code */ for (i = 0; i < auth_ctx->mac_length; i++) { if (calced_auth[i] != auth_ctx->unencrypted_mac[i]) { ret = FSL_RETURN_AUTH_FAILED_S; break; } } } #endif out: SAH_SF_DESC_CLEAN(); #if defined (FSL_HAVE_SAHARA2) || defined (USE_S2_CCM_DECRYPT_CHAIN) DESC_TEMP_FREE(calced_auth); #endif (void)auth_key_info; return ret; } /* fsl_shw_gen_decrypt() */
/*! * @brief Generate a (CCM) auth code and encrypt the payload. * * This is a very complicated function. Seven (or eight) descriptors are * required to perform a CCM calculation. * * First: Load CTR0 and key. * * Second: Run an octet of data through to bump to CTR1. (This could be * done in software, but software will have to bump and later decrement - * or copy and bump. * * Third: (in Virtio) Load a descriptor with data of zeros for CBC IV. * * Fourth: Run any (optional) "additional data" through the CBC-mode * portion of the algorithm. * * Fifth: Run the payload through in CCM mode. * * Sixth: Extract the unencrypted MAC. * * Seventh: Load CTR0. * * Eighth: Encrypt the MAC. * * @param user_ctx The user's context * @param auth_ctx Info on this Auth operation * @param cipher_key_info Key to encrypt payload * @param auth_key_info (unused - same key in CCM) * @param auth_data_length Length in bytes of @a auth_data * @param auth_data Any auth-only data * @param payload_length Length in bytes of @a payload * @param payload The data to encrypt * @param[out] ct The location to store encrypted data * @param[out] auth_value The location to store authentication code * * @return A return code of type #fsl_shw_return_t. */ fsl_shw_return_t fsl_shw_gen_encrypt(fsl_shw_uco_t * user_ctx, fsl_shw_acco_t * auth_ctx, fsl_shw_sko_t * cipher_key_info, fsl_shw_sko_t * auth_key_info, uint32_t auth_data_length, const uint8_t * auth_data, uint32_t payload_length, const uint8_t * payload, uint8_t * ct, uint8_t * auth_value) { SAH_SF_DCLS; SAH_SF_USER_CHECK(); if (auth_ctx->mode != FSL_ACC_MODE_CCM) { ret = FSL_RETURN_BAD_MODE_S; goto out; } /* Only support INIT and FINALIZE flags right now. */ if ((auth_ctx->flags & (FSL_ACCO_CTX_INIT | FSL_ACCO_CTX_LOAD | FSL_ACCO_CTX_SAVE | FSL_ACCO_CTX_FINALIZE)) != (FSL_ACCO_CTX_INIT | FSL_ACCO_CTX_FINALIZE)) { ret = FSL_RETURN_BAD_FLAG_S; goto out; } ret = load_ctr_key(&desc_chain, user_ctx, auth_ctx, cipher_key_info); if (ret != FSL_RETURN_OK_S) { goto out; } header = SAH_HDR_SKHA_ENC_DEC; DESC_IN_OUT(header, auth_ctx->cipher_ctx_info.block_size_bytes, garbage_output, auth_ctx->cipher_ctx_info.block_size_bytes, garbage_output); #ifndef NO_ZERO_IV_LOAD ret = load_dummy_iv(&desc_chain, user_ctx, 1, auth_ctx->auth_info.CCM_ctx_info.block_size_bytes); if (ret != FSL_RETURN_OK_S) { goto out; } #endif if (auth_data_length > 0) { ret = add_assoc_preamble(&desc_chain, user_ctx, auth_ctx, auth_data, auth_data_length); if (ret != FSL_RETURN_OK_S) { goto out; } } /* if auth_data_length > 0 */ ret = process_payload(&desc_chain, user_ctx, 1, payload_length, payload, ct); if (ret != FSL_RETURN_OK_S) { goto out; } /* Pull out the CBC-MAC value. */ ret = extract_mac(&desc_chain, user_ctx, auth_ctx->mac_length, auth_ctx->unencrypted_mac); if (ret != FSL_RETURN_OK_S) { goto out; } /* Now load CTR0 in, and encrypt the MAC */ ret = encrypt_mac(&desc_chain, user_ctx, auth_ctx, auth_ctx->unencrypted_mac, auth_value); if (ret != FSL_RETURN_OK_S) { goto out; } SAH_SF_EXECUTE(); out: SAH_SF_DESC_CLEAN(); (void)auth_key_info; return ret; } /* fsl_shw_gen_encrypt() */
/*! * Generate an SSL value * * @param user_ctx Info for acquiring memory * @param auth_ctx Info for CTR0, size of MAC * @param cipher_key_info * @param auth_key_info * @param auth_data_length * @param auth_data * @param payload_length * @param payload * @param ct * @param auth_value * * @return A return code of type #fsl_shw_return_t. */ static fsl_shw_return_t do_ssl_gen(fsl_shw_uco_t * user_ctx, fsl_shw_acco_t * auth_ctx, fsl_shw_sko_t * cipher_key_info, fsl_shw_sko_t * auth_key_info, uint32_t auth_data_length, const uint8_t * auth_data, uint32_t payload_length, const uint8_t * payload, uint8_t * ct, uint8_t * auth_value) { SAH_SF_DCLS; uint8_t *ptr1 = NULL; /* Assume one-shot init-finalize... no precomputes */ header = SAH_HDR_MDHA_SET_MODE_MD_KEY ^ sah_insert_mdha_algorithm[auth_ctx->auth_info.hash_ctx_info. algorithm] ^ sah_insert_mdha_init ^ sah_insert_mdha_ssl ^ sah_insert_mdha_pdata ^ sah_insert_mdha_mac_full; /* set up hmac */ DESC_IN_KEY(header, 0, NULL, auth_key_info); /* This is wrong -- need to find 16 extra bytes of data from * somewhere */ DESC_IN_OUT(SAH_HDR_MDHA_HASH, payload_length, payload, 1, auth_value); /* set up encrypt */ header = SAH_HDR_SKHA_SET_MODE_IV_KEY ^ sah_insert_skha_mode[auth_ctx->cipher_ctx_info.mode] ^ sah_insert_skha_encrypt ^ sah_insert_skha_algorithm[cipher_key_info->algorithm]; /* Honor 'no key parity checking' for DES and TDES */ if ((cipher_key_info->flags & FSL_SKO_KEY_IGNORE_PARITY) && ((cipher_key_info->algorithm == FSL_KEY_ALG_DES) || (cipher_key_info->algorithm == FSL_KEY_ALG_TDES))) { header ^= sah_insert_skha_no_key_parity; } if (auth_ctx->cipher_ctx_info.mode == FSL_SYM_MODE_CTR) { header ^= sah_insert_skha_modulus[auth_ctx->cipher_ctx_info. modulus_exp]; } if ((auth_ctx->cipher_ctx_info.mode == FSL_SYM_MODE_ECB) || (auth_ctx->cipher_ctx_info.flags & FSL_SYM_CTX_INIT)) { ptr1 = block_zeros; } else { ptr1 = auth_ctx->cipher_ctx_info.context; } DESC_IN_KEY(header, auth_ctx->cipher_ctx_info.block_size_bytes, ptr1, cipher_key_info); /* This is wrong -- need to find 16 extra bytes of data from * somewhere... */ if (payload_length != 0) { DESC_IN_OUT(SAH_HDR_SKHA_ENC_DEC, payload_length, payload, payload_length, ct); } SAH_SF_EXECUTE(); out: SAH_SF_DESC_CLEAN(); /* Eliminate compiler warnings until full implementation... */ (void)auth_data; (void)auth_data_length; return ret; } /* do_ssl_gen() */
/*! * @brief Generate a (CCM) auth code and encrypt the payload. * * This is a very complicated function. Seven (or eight) descriptors are * required to perform a CCM calculation. * * First: Load CTR0 and key. * * Second: Run an octet of data through to bump to CTR1. (This could be * done in software, but software will have to bump and later decrement - * or copy and bump. * * Third: (in Virtio) Load a descriptor with data of zeros for CBC IV. * * Fourth: Run any (optional) "additional data" through the CBC-mode * portion of the algorithm. * * Fifth: Run the payload through in CCM mode. * * Sixth: Extract the unencrypted MAC. * * Seventh: Load CTR0. * * Eighth: Encrypt the MAC. * * @param user_ctx The user's context * @param auth_ctx Info on this Auth operation * @param cipher_key_info Key to encrypt payload * @param auth_key_info (unused - same key in CCM) * @param auth_data_length Length in bytes of @a auth_data * @param auth_data Any auth-only data * @param payload_length Length in bytes of @a payload * @param payload The data to encrypt * @param[out] ct The location to store encrypted data * @param[out] auth_value The location to store authentication code * * @return A return code of type #fsl_shw_return_t. */ fsl_shw_return_t fsl_shw_gen_encrypt(fsl_shw_uco_t * user_ctx, fsl_shw_acco_t * auth_ctx, fsl_shw_sko_t * cipher_key_info, fsl_shw_sko_t * auth_key_info, uint32_t auth_data_length, const uint8_t * auth_data, uint32_t payload_length, const uint8_t * payload, uint8_t * ct, uint8_t * auth_value) { SAH_SF_DCLS; SAH_SF_USER_CHECK(); if (auth_ctx->mode == FSL_ACC_MODE_SSL) { #if SUPPORT_SSL ret = do_ssl_gen(user_ctx, auth_ctx, cipher_key_info, auth_key_info, auth_data_length, auth_data, payload_length, payload, ct, auth_value); #else ret = FSL_RETURN_BAD_MODE_S; #endif goto out; } if (auth_ctx->mode != FSL_ACC_MODE_CCM) { ret = FSL_RETURN_BAD_MODE_S; goto out; } /* Only support INIT and FINALIZE flags right now. */ if ((auth_ctx->flags & (FSL_ACCO_CTX_INIT | FSL_ACCO_CTX_LOAD | FSL_ACCO_CTX_SAVE | FSL_ACCO_CTX_FINALIZE)) != (FSL_ACCO_CTX_INIT | FSL_ACCO_CTX_FINALIZE)) { ret = FSL_RETURN_BAD_FLAG_S; goto out; } /* Load CTR0 and Key */ header = (SAH_HDR_SKHA_SET_MODE_IV_KEY ^ sah_insert_skha_mode_ctr ^ sah_insert_skha_modulus_128 ^ sah_insert_skha_encrypt); DESC_IN_KEY(header, auth_ctx->cipher_ctx_info.block_size_bytes, auth_ctx->cipher_ctx_info.context, cipher_key_info); /* Encrypt dummy data to bump to CTR1 */ header = SAH_HDR_SKHA_ENC_DEC; DESC_IN_OUT(header, auth_ctx->mac_length, garbage_output, auth_ctx->mac_length, garbage_output); #if defined(FSL_HAVE_SAHARA2) || defined(USE_S2_CCM_ENCRYPT_CHAIN) #ifndef NO_ZERO_IV_LOAD header = (SAH_HDR_SKHA_SET_MODE_IV_KEY ^ sah_insert_skha_encrypt ^ sah_insert_skha_mode_cbc); DESC_IN_IN(header, auth_ctx->auth_info.CCM_ctx_info.block_size_bytes, block_zeros, 0, NULL); #endif #endif ret = add_assoc_preamble(&desc_chain, user_ctx, auth_ctx, 1, auth_data, auth_data_length); if (ret != FSL_RETURN_OK_S) { goto out; } /* Process the payload */ header = (SAH_HDR_SKHA_SET_MODE_ENC_DEC ^ sah_insert_skha_mode_ccm ^ sah_insert_skha_modulus_128 ^ sah_insert_skha_encrypt); #if defined (FSL_HAVE_SAHARA4) && !defined (USE_S2_CCM_ENCRYPT_CHAIN) header ^= sah_insert_skha_aux0; #endif if (payload_length != 0) { DESC_IN_OUT(header, payload_length, payload, payload_length, ct); } else { DESC_IN_OUT(header, 0, NULL, 0, NULL); } /* if payload_length */ #if defined (FSL_HAVE_SAHARA4) && !defined (USE_S2_CCM_ENCRYPT_CHAIN) /* Pull out the CBC-MAC value. */ DESC_OUT_OUT(SAH_HDR_SKHA_READ_CONTEXT_IV, 0, NULL, auth_ctx->mac_length, auth_value); #else /* Pull out the unencrypted CBC-MAC value. */ DESC_OUT_OUT(SAH_HDR_SKHA_READ_CONTEXT_IV, 0, NULL, auth_ctx->mac_length, auth_ctx->unencrypted_mac); /* Now load CTR0 in, and encrypt the MAC */ header = SAH_HDR_SKHA_SET_MODE_IV_KEY ^ sah_insert_skha_encrypt ^ sah_insert_skha_mode_ctr ^ sah_insert_skha_modulus_128; DESC_IN_IN(header, auth_ctx->cipher_ctx_info.block_size_bytes, auth_ctx->cipher_ctx_info.context, 0, NULL); header = SAH_HDR_SKHA_ENC_DEC; /* Desc. #4 SKHA Enc/Dec */ DESC_IN_OUT(header, auth_ctx->mac_length, auth_ctx->unencrypted_mac, auth_ctx->mac_length, auth_value); #endif SAH_SF_EXECUTE(); out: SAH_SF_DESC_CLEAN(); (void)auth_key_info; return ret; } /* fsl_shw_gen_encrypt() */
/*! * Place a key into a protected location for use only by cryptographic * algorithms. * * This only needs to be used to a) unwrap a key, or b) set up a key which * could be wrapped with a later call to #fsl_shw_extract_key(). Normal * cleartext keys can simply be placed into #fsl_shw_sko_t key objects with * #fsl_shw_sko_set_key() and used directly. * * The maximum key size supported for wrapped/unwrapped keys is 32 octets. * (This is the maximum reasonable key length on Sahara - 32 octets for an HMAC * key based on SHA-256.) The key size is determined by the @a key_info. The * expected length of @a key can be determined by * #fsl_shw_sko_calculate_wrapped_size() * * The protected key will not be available for use until this operation * successfully completes. * * This feature is not available for all platforms, nor for all algorithms and * modes. * * @param user_ctx A user context from #fsl_shw_register_user(). * @param[in,out] key_info The information about the key to be which will * be established. In the create case, the key * length must be set. * @param establish_type How @a key will be interpreted to establish a * key for use. * @param key If @a establish_type is #FSL_KEY_WRAP_UNWRAP, * this is the location of a wrapped key. If * @a establish_type is #FSL_KEY_WRAP_CREATE, this * parameter can be @a NULL. If @a establish_type * is #FSL_KEY_WRAP_ACCEPT, this is the location * of a plaintext key. * * @return A return code of type #fsl_shw_return_t. */ fsl_shw_return_t fsl_shw_establish_key(fsl_shw_uco_t * user_ctx, fsl_shw_sko_t * key_info, fsl_shw_key_wrap_t establish_type, const uint8_t * key) { SAH_SF_DCLS; unsigned original_key_length = key_info->key_length; unsigned rounded_key_length; unsigned slot_allocated = 0; uint32_t old_flags; header = SAH_HDR_RNG_GENERATE; /* Desc. #18 for rand */ /* TODO: THIS STILL NEEDS TO BE REFACTORED */ /* Write operations into SCC memory require word-multiple number of * bytes. For ACCEPT and CREATE functions, the key length may need * to be rounded up. Calculate. */ if (LENGTH_PATCH && (original_key_length & LENGTH_PATCH_MASK) != 0) { rounded_key_length = original_key_length + LENGTH_PATCH - (original_key_length & LENGTH_PATCH_MASK); } else { rounded_key_length = original_key_length; } SAH_SF_USER_CHECK(); if (key_info->flags & FSL_SKO_KEY_ESTABLISHED) { #ifdef DIAG_SECURITY_FUNC ret = FSL_RETURN_BAD_FLAG_S; LOG_DIAG("Key already established\n"); #endif } if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_alloc(user_ctx, key_info->key_length, key_info->userid, &(key_info->handle)); #ifdef DIAG_SECURITY_FUNC LOG_DIAG_ARGS ("key length: %i, handle: %i, rounded key length: %i", key_info->key_length, key_info->handle, rounded_key_length); #endif } else { /* Key goes in user keystore */ ret = keystore_slot_alloc(key_info->keystore, key_info->key_length, key_info->userid, &(key_info->handle)); } if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Slot allocation failed\n"); #endif goto out; } slot_allocated = 1; key_info->flags |= FSL_SKO_KEY_ESTABLISHED; switch (establish_type) { case FSL_KEY_WRAP_CREATE: #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Creating random key\n"); #endif /* Use safe version of key length */ key_info->key_length = rounded_key_length; /* Generate descriptor to put random value into */ DESC_KEY_OUT(header, key_info, 0, NULL); /* Restore actual, desired key length */ key_info->key_length = original_key_length; old_flags = user_ctx->flags; /* Now put random value into key */ SAH_SF_EXECUTE(); /* Restore user's old flag value */ user_ctx->flags = old_flags; #ifdef DIAG_SECURITY_FUNC if (ret == FSL_RETURN_OK_S) { LOG_DIAG("ret is ok"); } else { LOG_DIAG("ret is not ok"); } #endif break; case FSL_KEY_WRAP_ACCEPT: #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Accepting plaintext key\n"); #endif if (key == NULL) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("ACCEPT: Red Key is NULL"); #endif ret = FSL_RETURN_ERROR_S; goto out; } /* Copy in safe number of bytes of Red key */ if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_load(user_ctx, key_info->userid, key_info->handle, key, rounded_key_length); } else { /* Key goes in user keystore */ ret = keystore_slot_load(key_info->keystore, key_info->userid, key_info->handle, key, key_info->key_length); } break; case FSL_KEY_WRAP_UNWRAP: #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Unwrapping wrapped key\n"); #endif /* For now, disallow non-blocking calls. */ if (!(user_ctx->flags & FSL_UCO_BLOCKING_MODE)) { ret = FSL_RETURN_BAD_FLAG_S; } else if (key == NULL) { ret = FSL_RETURN_ERROR_S; } else { ret = unwrap(user_ctx, key_info, key); } break; default: ret = FSL_RETURN_BAD_FLAG_S; break; } /* switch */ out: if (slot_allocated && (ret != FSL_RETURN_OK_S)) { fsl_shw_return_t scc_err; if (key_info->keystore == NULL) { /* Key goes in system keystore */ scc_err = do_system_keystore_slot_dealloc(user_ctx, key_info->userid, key_info->handle); } else { /* Key goes in user keystore */ scc_err = keystore_slot_dealloc(key_info->keystore, key_info->userid, key_info->handle); } key_info->flags &= ~FSL_SKO_KEY_ESTABLISHED; } SAH_SF_DESC_CLEAN(); return ret; } /* fsl_shw_establish_key() */
/*! * Perform wrapping of a black key from a RED slot * * @param user_ctx A user context from #fsl_shw_register_user(). * @param[in,out] key_info The information about the key to be which will * be wrapped... key length, slot info, etc. * @param black_key Place to store encrypted key * * @return A return code of type #fsl_shw_return_t. */ static fsl_shw_return_t wrap(fsl_shw_uco_t * user_ctx, fsl_shw_sko_t * key_info, uint8_t * black_key) { SAH_SF_DCLS; unsigned slots_allocated = 0; /* boolean */ fsl_shw_sko_t T_key_info; /* for holding T */ fsl_shw_sko_t KEK_key_info; /* for holding KEK */ unsigned original_key_length = key_info->key_length; unsigned rounded_key_length; sah_Link *link1; sah_Link *link2; black_key[LENGTH_OFFSET] = key_info->key_length; black_key[ALGORITHM_OFFSET] = key_info->algorithm; memcpy(&T_key_info, key_info, sizeof(T_key_info)); fsl_shw_sko_set_key_length(&T_key_info, T_LENGTH); T_key_info.algorithm = FSL_KEY_ALG_HMAC; memcpy(&KEK_key_info, &T_key_info, sizeof(KEK_key_info)); KEK_key_info.algorithm = FSL_KEY_ALG_AES; if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_alloc(user_ctx, T_LENGTH, key_info->userid, &T_key_info.handle); } else { /* Key goes in user keystore */ ret = keystore_slot_alloc(key_info->keystore, T_LENGTH, key_info->userid, &T_key_info.handle); } if (ret != FSL_RETURN_OK_S) { goto out; } if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_alloc(user_ctx, KEK_LENGTH, key_info->userid, &KEK_key_info.handle); } else { /* Key goes in user keystore */ ret = keystore_slot_alloc(key_info->keystore, KEK_LENGTH, key_info->userid, &KEK_key_info.handle); } if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("do_scc_slot_alloc() failed"); #endif if (key_info->keystore == NULL) { /* Key goes in system keystore */ (void)do_system_keystore_slot_dealloc(user_ctx, key_info->userid, T_key_info.handle); } else { /* Key goes in user keystore */ (void)keystore_slot_dealloc(key_info->keystore, key_info->userid, T_key_info.handle); } } else { slots_allocated = 1; } /* Set up to compute everything except T' ... */ #ifndef DO_REPEATABLE_WRAP /* Compute T = RND() */ header = SAH_HDR_RNG_GENERATE; /* Desc. #18 */ DESC_KEY_OUT(header, &T_key_info, 0, NULL); #else if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_load(user_ctx, T_key_info.userid, T_key_info.handle, T_block, T_key_info.key_length); } else { /* Key goes in user keystore */ ret = keystore_slot_load(key_info->keystore, T_key_info.userid, T_key_info.handle, T_block, T_key_info.key_length); } if (ret != FSL_RETURN_OK_S) { goto out; } #endif /* Compute KEK = SHA256(T | Ownerid) */ header = (SAH_HDR_MDHA_SET_MODE_HASH /* #8 */ ^ sah_insert_mdha_init ^ sah_insert_mdha_algorithm[FSL_HASH_ALG_SHA256] ^ sah_insert_mdha_pdata); /* Input - Start with T */ ret = sah_Create_Key_Link(user_ctx->mem_util, &link1, &T_key_info); if (ret != FSL_RETURN_OK_S) { goto out; } /* Still input - append ownerid */ ret = sah_Append_Link(user_ctx->mem_util, link1, (void *)&key_info->userid, sizeof(key_info->userid), SAH_USES_LINK_DATA); if (ret != FSL_RETURN_OK_S) { goto out; } /* Output - KEK goes into RED slot */ ret = sah_Create_Key_Link(user_ctx->mem_util, &link2, &KEK_key_info); if (ret != FSL_RETURN_OK_S) { goto out; } /* Put the Hash calculation into the chain. */ ret = sah_Append_Desc(user_ctx->mem_util, &desc_chain, header, link1, link2); if (ret != FSL_RETURN_OK_S) { goto out; } #if defined(NEED_CTR_WORKAROUND) rounded_key_length = ROUND_LENGTH(original_key_length); key_info->key_length = rounded_key_length; #else rounded_key_length = original_key_length; #endif /* Compute KEY' = AES-encrypt(KEK, KEY) */ header = (SAH_HDR_SKHA_SET_MODE_IV_KEY /* #1 */ ^ sah_insert_skha_mode[FSL_SYM_MODE_CTR] ^ sah_insert_skha_algorithm[FSL_KEY_ALG_AES] ^ sah_insert_skha_modulus[FSL_CTR_MOD_128]); /* Set up KEK as key to use */ DESC_IN_KEY(header, 0, NULL, &KEK_key_info); header = SAH_HDR_SKHA_ENC_DEC; DESC_KEY_OUT(header, key_info, key_info->key_length, black_key + KEY_PRIME_OFFSET); /* Set up flags info */ black_key[FLAGS_OFFSET] = 0; if (key_info->flags & FSL_SKO_KEY_SW_KEY) { black_key[FLAGS_OFFSET] |= FLAGS_SW_KEY; } /* Compute and store ICV into Black Key */ ret = create_icv_calc(user_ctx, &desc_chain, &T_key_info, black_key, original_key_length, black_key + ICV_OFFSET); if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Creation of sah_Key_Link failed due to bad key" " flag!\n"); #endif /*DIAG_SECURITY_FUNC */ goto out; } /* Now get Sahara to do the work. */ #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Encrypting key with KEK"); #endif SAH_SF_EXECUTE(); if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("sah_Descriptor_Chain_Execute() failed"); #endif goto out; } /* Compute T' = SLID_encrypt(T); Result goes to Black Key */ if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_encrypt(user_ctx, T_key_info.userid, T_key_info.handle, T_LENGTH, black_key + T_PRIME_OFFSET); } else { /* Key goes in user keystore */ ret = keystore_slot_encrypt(user_ctx, key_info->keystore, T_key_info.userid, T_key_info.handle, T_LENGTH, black_key + T_PRIME_OFFSET); } if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("do_scc_slot_encrypt() failed"); #endif goto out; } out: key_info->key_length = original_key_length; SAH_SF_DESC_CLEAN(); if (slots_allocated) { if (key_info->keystore == NULL) { /* Key goes in system keystore */ (void)do_system_keystore_slot_dealloc(user_ctx, key_info->userid, T_key_info. handle); (void)do_system_keystore_slot_dealloc(user_ctx, key_info->userid, KEK_key_info. handle); } else { /* Key goes in user keystore */ (void)keystore_slot_dealloc(key_info->keystore, key_info->userid, T_key_info.handle); (void)keystore_slot_dealloc(key_info->keystore, key_info->userid, KEK_key_info.handle); } } return ret; } /* wrap */
/*! * Perform unwrapping of a black key into a RED slot * * @param user_ctx A user context from #fsl_shw_register_user(). * @param[in,out] key_info The information about the key to be which will * be unwrapped... key length, slot info, etc. * @param black_key Encrypted key * * @return A return code of type #fsl_shw_return_t. */ static fsl_shw_return_t unwrap(fsl_shw_uco_t * user_ctx, fsl_shw_sko_t * key_info, const uint8_t * black_key) { SAH_SF_DCLS; uint8_t *hmac = NULL; fsl_shw_sko_t t_key_info; sah_Link *link1 = NULL; sah_Link *link2 = NULL; unsigned i; unsigned rounded_key_length; unsigned original_key_length = key_info->key_length; hmac = DESC_TEMP_ALLOC(ICV_LENGTH); /* Set up key_info for "T" - use same slot as eventual key */ fsl_shw_sko_init(&t_key_info, FSL_KEY_ALG_AES); t_key_info.userid = key_info->userid; t_key_info.handle = key_info->handle; t_key_info.flags = key_info->flags; t_key_info.key_length = T_LENGTH; t_key_info.keystore = key_info->keystore; /* Validate SW flags to prevent misuse */ if ((key_info->flags & FSL_SKO_KEY_SW_KEY) && !(black_key[FLAGS_OFFSET] & FLAGS_SW_KEY)) { ret = FSL_RETURN_BAD_FLAG_S; goto out; } /* Compute T = SLID_decrypt(T'); leave in RED slot */ if (key_info->keystore == NULL) { /* Key goes in system keystore */ ret = do_system_keystore_slot_decrypt(user_ctx, key_info->userid, t_key_info.handle, T_LENGTH, black_key + T_PRIME_OFFSET); } else { /* Key goes in user keystore */ ret = keystore_slot_decrypt(user_ctx, key_info->keystore, key_info->userid, t_key_info.handle, T_LENGTH, black_key + T_PRIME_OFFSET); } if (ret != FSL_RETURN_OK_S) { goto out; } /* Compute ICV = HMAC(T, ownerid | len | alg | key' */ ret = create_icv_calc(user_ctx, &desc_chain, &t_key_info, black_key, original_key_length, hmac); if (ret != FSL_RETURN_OK_S) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Creation of sah_Key_Link failed due to bad key" " flag!\n"); #endif /*DIAG_SECURITY_FUNC */ goto out; } #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Validating MAC of wrapped key"); #endif SAH_SF_EXECUTE(); if (ret != FSL_RETURN_OK_S) { goto out; } SAH_SF_DESC_CLEAN(); /* Check computed ICV against value in Black Key */ for (i = 0; i < ICV_LENGTH; i++) { if (black_key[ICV_OFFSET + i] != hmac[i]) { #ifdef DIAG_SECURITY_FUNC LOG_DIAG_ARGS("computed ICV fails at offset %i\n", i); { char buff[300]; int a; for (a = 0; a < ICV_LENGTH; a++) sprintf(&(buff[a * 2]), "%02x", black_key[ICV_OFFSET + a]); buff[a * 2 + 1] = 0; LOG_DIAG_ARGS("black key: %s", buff); for (a = 0; a < ICV_LENGTH; a++) sprintf(&(buff[a * 2]), "%02x", hmac[a]); buff[a * 2 + 1] = 0; LOG_DIAG_ARGS("hmac: %s", buff); } #endif ret = FSL_RETURN_AUTH_FAILED_S; goto out; } } /* This is no longer needed. */ DESC_TEMP_FREE(hmac); /* Compute KEK = SHA256(T | ownerid). Rewrite slot with value */ header = (SAH_HDR_MDHA_SET_MODE_HASH /* #8 */ ^ sah_insert_mdha_init ^ sah_insert_mdha_algorithm_sha256 ^ sah_insert_mdha_pdata); /* Input - Start with T */ ret = sah_Create_Key_Link(user_ctx->mem_util, &link1, &t_key_info); if (ret != FSL_RETURN_OK_S) { goto out; } /* Still input - append ownerid */ ret = sah_Append_Link(user_ctx->mem_util, link1, (void *)&key_info->userid, sizeof(key_info->userid), SAH_USES_LINK_DATA); if (ret != FSL_RETURN_OK_S) { goto out; } /* Output - KEK goes into RED slot */ ret = sah_Create_Key_Link(user_ctx->mem_util, &link2, &t_key_info); if (ret != FSL_RETURN_OK_S) { goto out; } /* Put the Hash calculation into the chain. */ ret = sah_Append_Desc(user_ctx->mem_util, &desc_chain, header, link1, link2); if (ret != FSL_RETURN_OK_S) { goto out; } /* Compute KEY = AES-decrypt(KEK, KEY') */ header = (SAH_HDR_SKHA_SET_MODE_IV_KEY /* #1 */ ^ sah_insert_skha_mode_ctr ^ sah_insert_skha_algorithm_aes ^ sah_insert_skha_modulus_128); /* Load KEK in as the key to use */ DESC_IN_KEY(header, 0, NULL, &t_key_info); rounded_key_length = ROUND_LENGTH(original_key_length); key_info->key_length = rounded_key_length; /* Now set up for computation. Result in RED */ header = SAH_HDR_SKHA_ENC_DEC; /* #4 */ DESC_IN_KEY(header, rounded_key_length, black_key + KEY_PRIME_OFFSET, key_info); /* Perform the operation */ #ifdef DIAG_SECURITY_FUNC LOG_DIAG("Decrypting key with KEK"); #endif SAH_SF_EXECUTE(); out: key_info->key_length = original_key_length; SAH_SF_DESC_CLEAN(); DESC_TEMP_FREE(hmac); /* Erase tracks */ t_key_info.userid = 0xdeadbeef; t_key_info.handle = 0xdeadbeef; return ret; } /* unwrap */
/*! * Create and run the chain for a symmetric-key operation. * * @param user_ctx Who the user is * @param key_info What key is to be used * @param sym_ctx Info details about algorithm * @param encrypt 0 = decrypt, non-zero = encrypt * @param length Number of octets at @a in and @a out * @param in Pointer to input data * @param out Location to store output data * * @return The status of handing chain to driver, * or an earlier argument/flag or allocation * error. */ static fsl_shw_return_t do_symmetric(fsl_shw_uco_t * user_ctx, fsl_shw_sko_t * key_info, fsl_shw_scco_t * sym_ctx, cipher_direction_t encrypt, uint32_t length, const uint8_t * in, uint8_t * out) { SAH_SF_DCLS; uint8_t *sink = NULL; sah_Link *link1 = NULL; sah_Link *link2 = NULL; sah_Oct_Str ptr1; uint32_t size1 = sym_ctx->block_size_bytes; SAH_SF_USER_CHECK(); /* Two different sets of chains, depending on algorithm */ if (key_info->algorithm == FSL_KEY_ALG_ARC4) { if (sym_ctx->flags & FSL_SYM_CTX_INIT) { /* Desc. #35 w/ARC4 - start from key */ header = SAH_HDR_ARC4_SET_MODE_KEY ^ sah_insert_skha_algorithm_arc4; DESC_IN_KEY(header, 0, NULL, key_info); } else { /* load SBox */ /* Desc. #33 w/ARC4 and NO PERMUTE */ header = SAH_HDR_ARC4_SET_MODE_SBOX ^ sah_insert_skha_no_permute ^ sah_insert_skha_algorithm_arc4; DESC_IN_IN(header, 256, sym_ctx->context, 3, sym_ctx->context + 256); } /* load SBox */ /* Add in-out data descriptor to process the data */ if (length != 0) { DESC_IN_OUT(SAH_HDR_SKHA_ENC_DEC, length, in, length, out); } /* Operation is done ... save what came out? */ if (sym_ctx->flags & FSL_SYM_CTX_SAVE) { /* Desc. #34 - Read SBox, pointers */ header = SAH_HDR_ARC4_READ_SBOX; DESC_OUT_OUT(header, 256, sym_ctx->context, 3, sym_ctx->context + 256); } } else { /* not ARC4 */ /* Doing 1- or 2- descriptor chain. */ /* Desc. #1 and algorithm and mode */ header = SAH_HDR_SKHA_SET_MODE_IV_KEY ^ sah_insert_skha_mode[sym_ctx->mode] ^ sah_insert_skha_algorithm[key_info->algorithm]; /* Honor 'no key parity checking' for DES and TDES */ if ((key_info->flags & FSL_SKO_KEY_IGNORE_PARITY) && ((key_info->algorithm == FSL_KEY_ALG_DES) || (key_info->algorithm == FSL_KEY_ALG_TDES))) { header ^= sah_insert_skha_no_key_parity; } /* Header by default is decrypting, so... */ if (encrypt == SYM_ENCRYPT) { header ^= sah_insert_skha_encrypt; } if (sym_ctx->mode == FSL_SYM_MODE_CTR) { header ^= sah_insert_skha_modulus[sym_ctx->modulus_exp]; } if (sym_ctx->mode == FSL_SYM_MODE_ECB) { ptr1 = NULL; size1 = 0; } else if (sym_ctx->flags & FSL_SYM_CTX_INIT) { ptr1 = (uint8_t *) block_zeros; } else { ptr1 = sym_ctx->context; } DESC_IN_KEY(header, sym_ctx->block_size_bytes, ptr1, key_info); /* Add in-out data descriptor */ if (length != 0) { header = SAH_HDR_SKHA_ENC_DEC; if (LENGTH_PATCH && (sym_ctx->mode == FSL_SYM_MODE_CTR) && ((length & LENGTH_PATCH_MASK) != 0)) { sink = DESC_TEMP_ALLOC(LENGTH_PATCH); ret = sah_Create_Link(user_ctx->mem_util, &link1, (uint8_t *) in, length, SAH_USES_LINK_DATA); ret = sah_Append_Link(user_ctx->mem_util, link1, (uint8_t *) sink, LENGTH_PATCH - (length & LENGTH_PATCH_MASK), SAH_USES_LINK_DATA); if (ret != FSL_RETURN_OK_S) { goto out; } ret = sah_Create_Link(user_ctx->mem_util, &link2, out, length, SAH_USES_LINK_DATA | SAH_OUTPUT_LINK); if (ret != FSL_RETURN_OK_S) { goto out; } ret = sah_Append_Link(user_ctx->mem_util, link2, sink, LENGTH_PATCH - (length & LENGTH_PATCH_MASK), SAH_USES_LINK_DATA); if (ret != FSL_RETURN_OK_S) { goto out; } ret = sah_Append_Desc(user_ctx->mem_util, &desc_chain, header, link1, link2); if (ret != FSL_RETURN_OK_S) { goto out; } link1 = link2 = NULL; } else { DESC_IN_OUT(header, length, in, length, out); } } /* Unload any desired context */ if (sym_ctx->flags & FSL_SYM_CTX_SAVE) { DESC_OUT_OUT(SAH_HDR_SKHA_READ_CONTEXT_IV, 0, NULL, sym_ctx->block_size_bytes, sym_ctx->context); } } /* not ARC4 */ SAH_SF_EXECUTE(); out: SAH_SF_DESC_CLEAN(); DESC_TEMP_FREE(sink); if (LENGTH_PATCH) { sah_Destroy_Link(user_ctx->mem_util, link1); sah_Destroy_Link(user_ctx->mem_util, link2); } return ret; }
/*! * Hash a stream of data with a cryptographic hash algorithm. * * The flags in the @a hash_ctx control the operation of this function. * * Hashing functions work on 64 octets of message at a time. Therefore, when * any partial hashing of a long message is performed, the message @a length of * each segment must be a multiple of 64. When ready to * #FSL_HASH_FLAGS_FINALIZE the hash, the @a length may be any value. * * With the #FSL_HASH_FLAGS_INIT and #FSL_HASH_FLAGS_FINALIZE flags on, a * one-shot complete hash, including padding, will be performed. The @a length * may be any value. * * The first octets of a data stream can be hashed by setting the * #FSL_HASH_FLAGS_INIT and #FSL_HASH_FLAGS_SAVE flags. The @a length must be * a multiple of 64. * * The flag #FSL_HASH_FLAGS_LOAD is used to load a context previously saved by * #FSL_HASH_FLAGS_SAVE. The two in combination will allow a (multiple-of-64 * octets) 'middle sequence' of the data stream to be hashed with the * beginning. The @a length must again be a multiple of 64. * * Since the flag #FSL_HASH_FLAGS_LOAD is used to load a context previously * saved by #FSL_HASH_FLAGS_SAVE, the #FSL_HASH_FLAGS_LOAD and * #FSL_HASH_FLAGS_FINALIZE flags, used together, can be used to finish the * stream. The @a length may be any value. * * If the user program wants to do the padding for the hash, it can leave off * the #FSL_HASH_FLAGS_FINALIZE flag. The @a length must then be a multiple of * 64 octets. * * @param user_ctx A user context from #fsl_shw_register_user(). * @param[in,out] hash_ctx Hashing algorithm and state of the cipher. * @param msg Pointer to the data to be hashed. * @param length Length, in octets, of the @a msg. * @param[out] result If not null, pointer to where to store the hash * digest. * @param result_len Number of octets to store in @a result. * * @return A return code of type #fsl_shw_return_t. */ fsl_shw_return_t fsl_shw_hash(fsl_shw_uco_t * user_ctx, fsl_shw_hco_t * hash_ctx, const uint8_t * msg, uint32_t length, uint8_t * result, uint32_t result_len) { SAH_SF_DCLS; unsigned ctx_flags = (hash_ctx->flags & (FSL_HASH_FLAGS_INIT | FSL_HASH_FLAGS_LOAD | FSL_HASH_FLAGS_SAVE | FSL_HASH_FLAGS_FINALIZE)); SAH_SF_USER_CHECK(); /* Reset expectations if user gets overly zealous. */ if (result_len > hash_ctx->digest_length) { result_len = hash_ctx->digest_length; } /* Validate hash ctx flags. * Need INIT or LOAD but not both. * Need SAVE or digest ptr (both is ok). */ if (((ctx_flags & (FSL_HASH_FLAGS_INIT | FSL_HASH_FLAGS_LOAD)) == (FSL_HASH_FLAGS_INIT | FSL_HASH_FLAGS_LOAD)) || ((ctx_flags & (FSL_HASH_FLAGS_INIT | FSL_HASH_FLAGS_LOAD)) == 0) || (!(ctx_flags & FSL_HASH_FLAGS_SAVE) && (result == NULL))) { ret = FSL_RETURN_BAD_FLAG_S; goto out; } if (ctx_flags & FSL_HASH_FLAGS_INIT) { sah_Oct_Str out_ptr; unsigned out_len; /* Create desc to perform the initial hashing operation */ /* Desc. #8 w/INIT and algorithm */ header = SAH_HDR_MDHA_SET_MODE_HASH ^ sah_insert_mdha_init ^ sah_insert_mdha_algorithm[hash_ctx->algorithm]; /* If user wants one-shot, set padding operation. */ if (ctx_flags & FSL_HASH_FLAGS_FINALIZE) { header ^= sah_insert_mdha_pdata; } /* Determine where Digest will go - hash_ctx or result */ if (ctx_flags & FSL_HASH_FLAGS_SAVE) { out_ptr = (sah_Oct_Str) hash_ctx->context; out_len = hash_ctx->context_register_length; } else { out_ptr = result; out_len = (result_len > hash_ctx->digest_length) ? hash_ctx->digest_length : result_len; } DESC_IN_OUT(header, length, (sah_Oct_Str) msg, out_len, out_ptr); } else { /* not doing hash INIT */ void *out_ptr; unsigned out_len; /* * Build two descriptors -- one to load in context/set mode, the * other to compute & retrieve hash/context value. * * First up - Desc. #6 to load context. */ /* Desc. #8 w/algorithm */ header = SAH_HDR_MDHA_SET_MODE_MD_KEY ^ sah_insert_mdha_algorithm[hash_ctx->algorithm]; if (ctx_flags & FSL_HASH_FLAGS_FINALIZE) { header ^= sah_insert_mdha_pdata; } /* Message Digest (in) */ DESC_IN_IN(header, hash_ctx->context_register_length, (sah_Oct_Str) hash_ctx->context, 0, NULL); if (ctx_flags & FSL_HASH_FLAGS_SAVE) { out_ptr = hash_ctx->context; out_len = hash_ctx->context_register_length; } else { out_ptr = result; out_len = result_len; } /* Second -- run data through and retrieve ctx regs */ /* Desc. #10 - no mode register with this. */ header = SAH_HDR_MDHA_HASH; DESC_IN_OUT(header, length, (sah_Oct_Str) msg, out_len, out_ptr); } /* else not INIT */ /* Now that execution is rejoined, we can append another descriptor to extract the digest/context a second time, into the result. */ if ((ctx_flags & FSL_HASH_FLAGS_SAVE) && (result != NULL) && (result_len != 0)) { header = SAH_HDR_MDHA_STORE_DIGEST; /* Message Digest (out) */ DESC_IN_OUT(header, 0, NULL, (result_len > hash_ctx->digest_length) ? hash_ctx->digest_length : result_len, result); } SAH_SF_EXECUTE(); out: SAH_SF_DESC_CLEAN(); return ret; } /* fsl_shw_hash() */