| // 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 |