Software APIs
symmetric_keygen_functest.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include "sw/device/lib/base/status.h"
6 #include "sw/device/lib/crypto/drivers/entropy.h"
7 #include "sw/device/lib/crypto/impl/integrity.h"
8 #include "sw/device/lib/crypto/impl/keyblob.h"
12 #include "sw/device/lib/testing/randomness_quality.h"
13 #include "sw/device/lib/testing/test_framework/check.h"
15 
17 
18 #define MODULE_ID MAKE_MODULE_ID('t', 's', 't')
19 
20 OTTF_DEFINE_TEST_CONFIG();
21 
22 // Statistical significance for randomness-quality checks. This setting results
23 // in a 1% failure rate on truly random data.
24 static const randomness_quality_significance_t kSignificance =
25  kRandomnessQualitySignificanceOnePercent;
26 
27 // Personalization data for testing.
28 static const uint8_t kPersonalizationData[5] = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4};
29 static const otcrypto_const_byte_buf_t kPersonalization = {
30  .data = kPersonalizationData,
31  .len = sizeof(kPersonalizationData),
32 };
33 
34 // Represents a 192-bit AES-CBC key.
35 static const otcrypto_key_config_t kAesKeyConfig = {
36  .version = kOtcryptoLibVersion1,
37  .key_mode = kOtcryptoKeyModeAesCbc,
38  .key_length = 192 / 8,
39  .hw_backed = kHardenedBoolFalse,
40  .security_level = kOtcryptoKeySecurityLevelLow,
41 };
42 
43 // Represents a 256-bit HMAC-SHA256 key.
44 static const otcrypto_key_config_t kHmacKeyConfig = {
45  .version = kOtcryptoLibVersion1,
46  .key_mode = kOtcryptoKeyModeHmacSha256,
47  .key_length = 256 / 8,
48  .hw_backed = kHardenedBoolFalse,
49  .security_level = kOtcryptoKeySecurityLevelLow,
50 };
51 
52 // Represents a 128-bit KMAC key.
53 static const otcrypto_key_config_t kKmacKeyConfig = {
54  .version = kOtcryptoLibVersion1,
55  .key_mode = kOtcryptoKeyModeKmac128,
56  .key_length = 128 / 8,
57  .hw_backed = kHardenedBoolFalse,
58  .security_level = kOtcryptoKeySecurityLevelLow,
59 };
60 
61 static status_t entropy_complex_init_test(void) {
62  // This initialization should happen in ROM_EXT, so there is no public API
63  // for it in cryptolib.
64  TRY(entropy_complex_init());
65 
66  // Check the configuration.
67  return entropy_complex_check();
68 }
69 
70 /**
71  * Basic test for generating a symmetric key.
72  *
73  * Generates the key, runs basic statistical tests, and logs the output. This
74  * test may fail sometimes because statistical tests are inherently
75  * proababilistic.
76  *
77  * @param config Key configuration.
78  */
79 static status_t basic_keygen_test(otcrypto_key_config_t config) {
80  // Allocate and zeroize keyblob.
81  size_t key_share_words = config.key_length / sizeof(uint32_t);
82  uint32_t keyblob[key_share_words * 2];
83  memset(keyblob, 0, sizeof(keyblob));
84 
85  // Create the blinded key structure and call keygen.
87  .config = config,
88  .keyblob_length = sizeof(keyblob),
89  .keyblob = keyblob,
90  };
91  TRY(otcrypto_symmetric_keygen(kPersonalization, &key));
92 
93  // Ensure the checksum passes.
94  TRY_CHECK(integrity_blinded_key_check(&key) == kHardenedBoolTrue);
95 
96  // Do a basic statistical test.
97  TRY(randomness_quality_monobit_test((unsigned char *)keyblob, sizeof(keyblob),
98  kSignificance));
99 
100  // Log the generated key.
101  uint32_t *share0;
102  uint32_t *share1;
103  HARDENED_TRY(keyblob_to_shares(&key, &share0, &share1));
104  for (size_t i = 0; i < key_share_words; i++) {
105  LOG_INFO("key[%d] = 0x%08x", i, share0[i] ^ share1[i]);
106  }
107 
108  return OK_STATUS();
109 }
110 
111 static status_t aes_keygen_test(void) {
112  return basic_keygen_test(kAesKeyConfig);
113 }
114 
115 static status_t hmac_keygen_test(void) {
116  return basic_keygen_test(kHmacKeyConfig);
117 }
118 
119 static status_t kmac_keygen_test(void) {
120  return basic_keygen_test(kKmacKeyConfig);
121 }
122 
123 static status_t generate_multiple_keys_test(void) {
124  // Create a double-length blob for two keys.
125  size_t key_share_words = kAesKeyConfig.key_length / sizeof(uint32_t);
126  uint32_t keyblob_buffer[key_share_words * 4];
127  uint32_t *keyblob1 = keyblob_buffer;
128  uint32_t *keyblob2 = &keyblob_buffer[key_share_words * 2];
129  memset(keyblob_buffer, 0, sizeof(keyblob_buffer));
130 
131  // Generate two AES keys.
132  otcrypto_blinded_key_t key1 = {
133  .config = kAesKeyConfig,
134  .keyblob_length = sizeof(keyblob_buffer) / 2,
135  .keyblob = keyblob1,
136  };
137  otcrypto_blinded_key_t key2 = {
138  .config = kAesKeyConfig,
139  .keyblob_length = sizeof(keyblob_buffer) / 2,
140  .keyblob = keyblob2,
141  };
142  TRY(otcrypto_symmetric_keygen(kPersonalization, &key1));
143  TRY(otcrypto_symmetric_keygen(kPersonalization, &key2));
144 
145  // Do a statistical test on the entire keyblob (this will check if the keys
146  // are statistically related to each other).
147  TRY(randomness_quality_monobit_test((unsigned char *)keyblob_buffer,
148  sizeof(keyblob_buffer), kSignificance));
149 
150  return OK_STATUS();
151 }
152 
153 bool test_main(void) {
154  status_t result = OK_STATUS();
155 
156  EXECUTE_TEST(result, entropy_complex_init_test);
157  EXECUTE_TEST(result, aes_keygen_test);
158  EXECUTE_TEST(result, hmac_keygen_test);
159  EXECUTE_TEST(result, kmac_keygen_test);
160  EXECUTE_TEST(result, generate_multiple_keys_test);
161  return status_ok(result);
162 }