| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #include "sw/device/lib/testing/aes_testutils.h" |
| |
| #if !OT_IS_ENGLISH_BREAKFAST |
| #include "sw/device/lib/base/mmio.h" |
| #include "sw/device/lib/dif/dif_csrng.h" |
| #include "sw/device/lib/dif/dif_csrng_shared.h" |
| #include "sw/device/lib/dif/dif_edn.h" |
| #include "sw/device/lib/testing/csrng_testutils.h" |
| #include "sw/device/lib/testing/test_framework/check.h" |
| |
| #include "csrng_regs.h" // Generated |
| #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" |
| #endif |
| |
| // `extern` declarations to give the inline functions in the |
| // corresponding header a link location. |
| |
| extern bool aes_testutils_get_status(dif_aes_t *aes, dif_aes_status_t flag); |
| |
| #if !OT_IS_ENGLISH_BREAKFAST |
| /** |
| * Constants for switching AES masking off. |
| */ |
| enum { |
| kCsrngBlockLen = 4, |
| kCsrngKeyLen = 8, |
| kEdnSeedMaterialLen = 12, |
| }; |
| |
| // CSRNG needs to constantly output these bits to EDN. The AES masking PRNG |
| // consists of five 32-bit LFSRs each followed by a linear permutation and a |
| // non-linear layer and ultimately a secret permutation spanning all five |
| // LFSRs. Only if the non-linear layers of all five LFSRs output an all-zero |
| // vector, the PRNG output is zero as well. |
| // |
| const uint32_t kAesMaskingPrngZeroOutputSeed[kCsrngBlockLen] = { |
| 0xff00ffff, 0xff00ffff, 0xff00ffff, 0xff00ffff}; |
| |
| // Seed material for instantiate command. The CTR_DRBG construction |
| // implemented by CSRNG produces |
| // |
| // key = 00 01 02 03 04 05 06 07 - 08 09 0a 0b 0c 0d 0e 0f |
| // 10 11 12 13 14 15 16 17 - 18 19 1a 1b 1c 1d 1e 1f |
| // |
| // V = 8d 97 b4 1b c2 0a cb bb - 81 06 d3 91 85 46 67 f8 |
| // |
| // from this seed material upon instantiate. The key is arbitrarity chosen. |
| // Encrypting V using this key then gives the required |
| // kAesMaskingPrngZeroOutputSeed above. |
| const uint32_t kEdnSeedMaterialInstantiate[kEdnSeedMaterialLen] = { |
| 0xf0405279, 0x50a4261f, 0xf5ace1cf, 0xfff7b7d1, 0xa6ee8307, 0x1f57dfc8, |
| 0x59757d79, 0xdeb6522e, 0xc8c67d84, 0xa16abefa, 0xc34030be, 0x530e88f8}; |
| |
| // V and key after instantiate. |
| const uint32_t kCsrngVInstantiate[kCsrngBlockLen] = {0x854667f7, 0x8106d391, |
| 0xc20acbbb, 0x8d97b41b}; |
| const uint32_t kCsrngKeyInstantiate[kCsrngKeyLen] = { |
| 0x1c1d1e1f, 0x18191a1b, 0x14151617, 0x10111213, |
| 0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203}; |
| |
| // V and key after generate. |
| const uint32_t kCsrngVGenerate[kCsrngBlockLen] = {0x1569e491, 0xe854f642, |
| 0xe931a570, 0x60939074}; |
| const uint32_t kCsrngKeyGenerate[kCsrngKeyLen] = { |
| 0xfdab6b68, 0x31920240, 0x32a48b64, 0xda4189d7, |
| 0xf49b7a55, 0x3d86fe43, 0xf4eaeab1, 0x8fae023a}; |
| |
| // Seed material for reseed command. After one generate, this seed material |
| // will bring the key and V of CSRNG back to the state after instantiate. |
| // I.e., one can again run one generate to produce the seed required for AES |
| // (see kAesMaskingPrngZeroOutputSeed). |
| const uint32_t kEdnSeedMaterialReseed[kEdnSeedMaterialLen] = { |
| 0x5f6fb665, 0x21ca8e3f, 0x5ba3dba1, 0x2c10a9ec, 0x03b8cd4b, 0x8264aaea, |
| 0x371e6305, 0x8fb186e1, 0xf622bc3e, 0x98e5d247, 0x73040c38, 0x6596739e}; |
| |
| void aes_testutils_masking_prng_zero_output_seed(void) { |
| const dif_csrng_t csrng = { |
| .base_addr = mmio_region_from_addr(TOP_EARLGREY_CSRNG_BASE_ADDR)}; |
| const dif_edn_t edn0 = { |
| .base_addr = mmio_region_from_addr(TOP_EARLGREY_EDN0_BASE_ADDR)}; |
| |
| // Shutdown EDN0 and CSRNG |
| CHECK_DIF_OK(dif_edn_stop(&edn0)); |
| CHECK_DIF_OK(dif_csrng_stop(&csrng)); |
| |
| // Re-eanble CSRNG |
| CHECK_DIF_OK(dif_csrng_configure(&csrng)); |
| |
| // Re-enable EDN0 and configure it to produce the seed that if loaded into AES |
| // causes the AES masking PRNG to output and all-zero output. |
| dif_edn_auto_params_t edn0_params = { |
| .instantiate_cmd = |
| { |
| .cmd = csrng_cmd_header_build(kCsrngAppCmdInstantiate, |
| kDifCsrngEntropySrcToggleDisable, |
| kEdnSeedMaterialLen, |
| /*generate_len=*/0), |
| .seed_material = |
| { |
| .len = kEdnSeedMaterialLen, |
| }, |
| }, |
| .reseed_cmd = |
| { |
| .cmd = csrng_cmd_header_build(kCsrngAppCmdReseed, |
| kDifCsrngEntropySrcToggleDisable, |
| kEdnSeedMaterialLen, |
| /*generate_len=*/0), |
| .seed_material = |
| { |
| .len = kEdnSeedMaterialLen, |
| }, |
| }, |
| .generate_cmd = |
| { |
| .cmd = csrng_cmd_header_build(kCsrngAppCmdGenerate, |
| kDifCsrngEntropySrcToggleDisable, |
| /*cmd_len=*/0, |
| /*generate_len=*/1), |
| .seed_material = |
| { |
| .len = 0, |
| }, |
| }, |
| .reseed_interval = 1, // Reseed after every single generate. |
| }; |
| memcpy(edn0_params.instantiate_cmd.seed_material.data, |
| kEdnSeedMaterialInstantiate, sizeof(kEdnSeedMaterialInstantiate)); |
| memcpy(edn0_params.reseed_cmd.seed_material.data, kEdnSeedMaterialReseed, |
| sizeof(kEdnSeedMaterialReseed)); |
| CHECK_DIF_OK(dif_edn_set_auto_mode(&edn0, edn0_params)); |
| } |
| |
| void aes_testutils_csrng_kat(void) { |
| const dif_csrng_t csrng = { |
| .base_addr = mmio_region_from_addr(TOP_EARLGREY_CSRNG_BASE_ADDR)}; |
| |
| // Instantiate CSRNG with seed material suitable for switching the AES masking |
| // off. |
| dif_csrng_seed_material_t seed_material_instantiate = { |
| .seed_material_len = 12, |
| }; |
| memcpy(seed_material_instantiate.seed_material, kEdnSeedMaterialInstantiate, |
| sizeof(kEdnSeedMaterialInstantiate)); |
| dif_csrng_internal_state_t expected_state_instantiate = { |
| .reseed_counter = 1, |
| .instantiated = true, |
| .fips_compliance = false, |
| }; |
| memcpy(expected_state_instantiate.v, kCsrngVInstantiate, |
| sizeof(kCsrngVInstantiate)); |
| memcpy(expected_state_instantiate.key, kCsrngKeyInstantiate, |
| sizeof(kCsrngKeyInstantiate)); |
| csrng_testutils_kat_instantiate(&csrng, false, &seed_material_instantiate, |
| &expected_state_instantiate); |
| |
| // Generate one block containting the required seed for the AES masking PRNG |
| // to output an all-zero vector. |
| dif_csrng_internal_state_t expected_state_generate = { |
| .reseed_counter = 2, |
| .instantiated = true, |
| .fips_compliance = false, |
| }; |
| memcpy(expected_state_generate.v, kCsrngVGenerate, sizeof(kCsrngVGenerate)); |
| memcpy(expected_state_generate.key, kCsrngKeyGenerate, |
| sizeof(kCsrngKeyGenerate)); |
| csrng_testutils_kat_generate(&csrng, 1, kCsrngBlockLen, |
| kAesMaskingPrngZeroOutputSeed, |
| &expected_state_generate); |
| |
| // Reseed the CSRNG instance to produce the required seed for the AES masking |
| // PRNG to output an all-zero vector upon the next generate command. |
| dif_csrng_seed_material_t seed_material_reseed = { |
| .seed_material_len = 12, |
| }; |
| memcpy(seed_material_reseed.seed_material, kEdnSeedMaterialReseed, |
| sizeof(kEdnSeedMaterialReseed)); |
| dif_csrng_internal_state_t expected_state_reseed = { |
| .reseed_counter = 1, |
| .instantiated = true, |
| .fips_compliance = false, |
| }; |
| memcpy(expected_state_reseed.v, kCsrngVInstantiate, |
| sizeof(kCsrngVInstantiate)); |
| memcpy(expected_state_reseed.key, kCsrngKeyInstantiate, |
| sizeof(kCsrngKeyInstantiate)); |
| csrng_testutils_kat_reseed(&csrng, &seed_material_reseed, |
| &expected_state_reseed); |
| |
| // Generate one block containting the required seed for the AES masking PRNG |
| // to output an all-zero vector. |
| csrng_testutils_kat_generate(&csrng, 1, kCsrngBlockLen, |
| kAesMaskingPrngZeroOutputSeed, |
| &expected_state_generate); |
| } |
| #endif |