Software APIs
hkdf_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/crypto/drivers/entropy.h"
6 #include "sw/device/lib/crypto/impl/integrity.h"
7 #include "sw/device/lib/crypto/impl/keyblob.h"
11 #include "sw/device/lib/testing/test_framework/check.h"
13 
14 // Module ID for status codes.
15 #define MODULE_ID MAKE_MODULE_ID('t', 's', 't')
16 
17 /**
18  * Represents a test for HKDF.
19  */
20 typedef struct hkdf_test_vector {
21  /**
22  * Key mode for HKDF (e.g. HMAC-256). Determines hash function.
23  */
25  /**
26  * Input key derivation key (called IKM in RFC 5869).
27  */
28  uint32_t *ikm;
29  /**
30  * Length of key derivation key in bytes.
31  */
32  size_t ikm_bytelen;
33  /**
34  * Salt value. May be NULL if `salt_bytelen` is 0.
35  */
36  uint8_t *salt;
37  /**
38  * Length of salt in bytes.
39  */
40  size_t salt_bytelen;
41  /**
42  * Context string. May be NULL if `salt_bytelen` is 0.
43  */
44  uint8_t *info;
45  /**
46  * Length of info in bytes.
47  */
48  size_t info_bytelen;
49  /**
50  * Expected value for the intermediate pseudo-random key.
51  *
52  * This is the output of the `extract` phase and the input for the `expand`
53  * phase. Its length should be the same as the hash function digest length.
54  * Some test vectors may not include an expected value for the PRK, so if
55  * this pointer is NULL, the PRK will not be checked.
56  */
57  uint32_t *prk;
58  /**
59  * Length of pseudo-random key in 32-bit words.
60  */
61  size_t prk_wordlen;
62  /**
63  * Expected output derived key (called OKM in RFC 5869).
64  */
65  uint32_t *okm;
66  /**
67  * Length of derived key in bytes.
68  */
69  size_t okm_bytelen;
71 
72 // Random value for masking, as large as the longest test key. This value
73 // should not affect the result.
74 static const uint32_t kTestMask[] = {
75  0x8cb847c3, 0xc6d34f36, 0x72edbf7b, 0x9bc0317f, 0x8f003c7f, 0x1d7ba049,
76  0xfd463b63, 0xbb720c44, 0x784c215e, 0xeb101d65, 0x35beb911, 0xab481345,
77  0xa7ebc3e3, 0x04b2a1b9, 0x764a9630, 0x78b8f9c5, 0x3f2a1d8e, 0x8cb847c3,
78  0xc6d34f36, 0x72edbf7b, 0x9bc0317f, 0x8f003c7f, 0x1d7ba049, 0xfd463b63,
79  0xbb720c44, 0x784c215e, 0xeb101d65, 0x35beb911, 0xab481345, 0xa7ebc3e3,
80  0x04b2a1b9, 0x764a9630, 0x78b8f9c5, 0x3f2a1d8e,
81 };
82 
83 /**
84  * Call HKDF through the API and check the result.
85  *
86  * @param test Test vector to run.
87  * @return Result (OK or error).
88  */
89 static status_t run_test(hkdf_test_vector_t *test) {
90  if (test->ikm_bytelen > sizeof(kTestMask)) {
91  // If we get this error, we probably just need to make `kTestMask` longer.
92  return OUT_OF_RANGE();
93  }
94 
95  // Construct the input key (IKM in the RFC terminology).
96  otcrypto_key_config_t ikm_config = {
97  .version = kOtcryptoLibVersion1,
98  .key_mode = test->hmac_key_mode,
99  .key_length = test->ikm_bytelen,
100  .hw_backed = kHardenedBoolFalse,
101  .exportable = kHardenedBoolFalse,
102  .security_level = kOtcryptoKeySecurityLevelLow,
103  };
104  uint32_t ikm_keyblob[keyblob_num_words(ikm_config)];
105  TRY(keyblob_from_key_and_mask(test->ikm, kTestMask, ikm_config, ikm_keyblob));
106  otcrypto_blinded_key_t ikm = {
107  .config = ikm_config,
108  .keyblob = ikm_keyblob,
109  .keyblob_length = sizeof(ikm_keyblob),
110  };
111  ikm.checksum = integrity_blinded_checksum(&ikm);
112 
113  // Construct a blinded key struct for the intermediate key (PRK).
114  otcrypto_key_config_t prk_config = {
115  .version = kOtcryptoLibVersion1,
116  .key_mode = test->hmac_key_mode,
117  .key_length = test->prk_wordlen * sizeof(uint32_t),
118  .hw_backed = kHardenedBoolFalse,
119  .exportable = kHardenedBoolFalse,
120  .security_level = kOtcryptoKeySecurityLevelLow,
121  };
122  uint32_t prk_keyblob[keyblob_num_words(prk_config)];
123  otcrypto_blinded_key_t prk = {
124  .config = prk_config,
125  .keyblob = prk_keyblob,
126  .keyblob_length = sizeof(prk_keyblob),
127  };
128 
129  // Construct a blinded key struct for the output key (OKM). The key mode here
130  // doesn't really matter, it just needs to be some symmetric key.
131  otcrypto_key_config_t okm_config = {
132  .version = kOtcryptoLibVersion1,
133  .key_mode = kOtcryptoKeyModeAesCtr,
134  .key_length = test->okm_bytelen,
135  .hw_backed = kHardenedBoolFalse,
136  .exportable = kHardenedBoolFalse,
137  .security_level = kOtcryptoKeySecurityLevelLow,
138  };
139  uint32_t okm_keyblob[keyblob_num_words(okm_config)];
140  otcrypto_blinded_key_t okm = {
141  .config = okm_config,
142  .keyblob = okm_keyblob,
143  .keyblob_length = sizeof(okm_keyblob),
144  };
145 
146  // Construct a buffer for the salt.
148  .data = test->salt,
149  .len = test->salt_bytelen,
150  };
151 
152  // Construct a buffer for the context info.
154  .data = test->info,
155  .len = test->info_bytelen,
156  };
157 
158  // Run the "extract" stage of HKDF.
159  TRY(otcrypto_kdf_hkdf_extract(ikm, salt, &prk));
160 
161  // If the test includes an expected value of PRK, then check the value.
162  if (test->prk != NULL) {
163  uint32_t *prk_share0;
164  uint32_t *prk_share1;
165  TRY(keyblob_to_shares(&prk, &prk_share0, &prk_share1));
166  uint32_t unmasked_prk[test->prk_wordlen];
167  for (size_t i = 0; i < ARRAYSIZE(unmasked_prk); i++) {
168  unmasked_prk[i] = prk_share0[i] ^ prk_share1[i];
169  }
170  TRY_CHECK_ARRAYS_EQ(unmasked_prk, test->prk, test->prk_wordlen);
171  }
172 
173  // Run the "expand" stage of HKDF.
174  TRY(otcrypto_kdf_hkdf_expand(prk, info, &okm));
175 
176  // Unmask the output key value and compare to the expected value.
177  uint32_t *okm_share0;
178  uint32_t *okm_share1;
179  TRY(keyblob_to_shares(&okm, &okm_share0, &okm_share1));
180  uint32_t unmasked_okm[keyblob_share_num_words(okm_config)];
181  for (size_t i = 0; i < ARRAYSIZE(unmasked_okm); i++) {
182  unmasked_okm[i] = okm_share0[i] ^ okm_share1[i];
183  }
184  TRY_CHECK_ARRAYS_EQ((unsigned char *)unmasked_okm, (unsigned char *)test->okm,
185  test->okm_bytelen);
186  return OK_STATUS();
187 }
188 
189 /**
190  * Test case 1 from RFC 5869:
191  *
192  * Basic test case with SHA-256
193  *
194  * Hash = SHA-256
195  * IKM = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (22 octets)
196  * salt = 0x000102030405060708090a0b0c (13 octets)
197  * info = 0xf0f1f2f3f4f5f6f7f8f9 (10 octets)
198  * L = 42
199  *
200  * PRK = 0x077709362c2e32df0ddc3f0dc47bba63
201  * 90b6c73bb50f9c3122ec844ad7c2b3e5 (32 octets)
202  * OKM = 0x3cb25f25faacd57a90434f64d0362f2a
203  * 2d2d0a90cf1a5a4c5db02d56ecc4c5bf
204  * 34007208d5b887185865 (42 octets)
205  */
206 static status_t rfc_test1(void) {
207  uint32_t ikm_data[] = {
208  0x0b0b0b0b, 0x0b0b0b0b, 0x0b0b0b0b, 0x0b0b0b0b, 0x0b0b0b0b, 0x00000b0b,
209  };
210  uint8_t salt_data[] = {
211  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
212  0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
213  };
214  uint8_t info_data[] = {
215  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
216  };
217  uint32_t prk_data[] = {
218  0x36097707, 0xdf322e2c, 0x0d3fdc0d, 0x63ba7bc4,
219  0x3bc7b690, 0x319c0fb5, 0x4a84ec22, 0xe5b3c2d7,
220  };
221  uint32_t okm_data[] = {
222  0x255fb23c, 0x7ad5acfa, 0x644f4390, 0x2a2f36d0, 0x900a2d2d, 0x4c5a1acf,
223  0x562db05d, 0xbfc5c4ec, 0x08720034, 0x1887b8d5, 0x00006558,
224  };
226  .hmac_key_mode = kOtcryptoKeyModeHmacSha256,
227  .ikm = ikm_data,
228  .ikm_bytelen = 22,
229  .salt = salt_data,
230  .salt_bytelen = sizeof(salt_data),
231  .info = info_data,
232  .info_bytelen = sizeof(info_data),
233  .prk = prk_data,
234  .prk_wordlen = ARRAYSIZE(prk_data),
235  .okm = okm_data,
236  .okm_bytelen = 42,
237  };
238  return run_test(&test);
239 }
240 
241 /**
242  * Test case 2 from RFC 5869:
243  *
244  * Test with SHA-256 and longer inputs/outputs
245  *
246  * Hash = SHA-256
247  * IKM = 0x000102030405060708090a0b0c0d0e0f
248  * 101112131415161718191a1b1c1d1e1f
249  * 202122232425262728292a2b2c2d2e2f
250  * 303132333435363738393a3b3c3d3e3f
251  * 404142434445464748494a4b4c4d4e4f (80 octets)
252  * salt = 0x606162636465666768696a6b6c6d6e6f
253  * 707172737475767778797a7b7c7d7e7f
254  * 808182838485868788898a8b8c8d8e8f
255  * 909192939495969798999a9b9c9d9e9f
256  * a0a1a2a3a4a5a6a7a8a9aaabacadaeaf (80 octets)
257  * info = 0xb0b1b2b3b4b5b6b7b8b9babbbcbdbebf
258  * c0c1c2c3c4c5c6c7c8c9cacbcccdcecf
259  * d0d1d2d3d4d5d6d7d8d9dadbdcdddedf
260  * e0e1e2e3e4e5e6e7e8e9eaebecedeeef
261  * f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff (80 octets)
262  * L = 82
263  *
264  * PRK = 0x06a6b88c5853361a06104c9ceb35b45c
265  * ef760014904671014a193f40c15fc244 (32 octets)
266  * OKM = 0xb11e398dc80327a1c8e7f78c596a4934
267  * 4f012eda2d4efad8a050cc4c19afa97c
268  * 59045a99cac7827271cb41c65e590e09
269  * da3275600c2f09b8367793a9aca3db71
270  * cc30c58179ec3e87c14c01d5c1f3434f
271  * 1d87 (82 octets)
272  */
273 static status_t rfc_test2(void) {
274  uint32_t ikm_data[] = {
275  0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c, 0x13121110,
276  0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x23222120, 0x27262524,
277  0x2b2a2928, 0x2f2e2d2c, 0x33323130, 0x37363534, 0x3b3a3938,
278  0x3f3e3d3c, 0x43424140, 0x47464544, 0x4b4a4948, 0x4f4e4d4c,
279  };
280  uint8_t salt_data[] = {
281  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
282  0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
283  0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
284  0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
285  0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
286  0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
287  0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
288  };
289  uint8_t info_data[] = {
290  0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb,
291  0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
292  0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3,
293  0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
294  0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
295  0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
296  0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
297  };
298  uint32_t prk_data[] = {
299  0x8cb8a606, 0x1a365358, 0x9c4c1006, 0x5cb435eb,
300  0x140076ef, 0x01714690, 0x403f194a, 0x44c25fc1,
301  };
302  uint32_t okm_data[] = {
303  0x8d391eb1, 0xa12703c8, 0x8cf7e7c8, 0x34496a59, 0xda2e014f, 0xd8fa4e2d,
304  0x4ccc50a0, 0x7ca9af19, 0x995a0459, 0x7282c7ca, 0xc641cb71, 0x090e595e,
305  0x607532da, 0xb8092f0c, 0xa9937736, 0x71dba3ac, 0x81c530cc, 0x873eec79,
306  0xd5014cc1, 0x4f43f3c1, 0x0000871d,
307 
308  };
310  .hmac_key_mode = kOtcryptoKeyModeHmacSha256,
311  .ikm = ikm_data,
312  .ikm_bytelen = 80,
313  .salt = salt_data,
314  .salt_bytelen = sizeof(salt_data),
315  .info = info_data,
316  .info_bytelen = sizeof(info_data),
317  .prk = prk_data,
318  .prk_wordlen = ARRAYSIZE(prk_data),
319  .okm = okm_data,
320  .okm_bytelen = 82,
321  };
322  return run_test(&test);
323 }
324 
325 /**
326  * Test case 3 from RFC 5869:
327  *
328  *
329  * Test with SHA-256 and zero-length salt/info
330  *
331  * Hash = SHA-256
332  * IKM = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (22 octets)
333  * salt = (0 octets)
334  * info = (0 octets)
335  * L = 42
336  *
337  * PRK = 0x19ef24a32c717b167f33a91d6f648bdf
338  * 96596776afdb6377ac434c1c293ccb04 (32 octets)
339  * OKM = 0x8da4e775a563c18f715f802a063c5a31
340  * b8a11f5c5ee1879ec3454e5f3c738d2d
341  * 9d201395faa4b61a96c8 (42 octets)
342  */
343 static status_t rfc_test3(void) {
344  uint32_t ikm_data[] = {
345  0x0b0b0b0b, 0x0b0b0b0b, 0x0b0b0b0b, 0x0b0b0b0b, 0x0b0b0b0b, 0x00000b0b,
346  };
347  uint32_t prk_data[] = {
348  0xa324ef19, 0x167b712c, 0x1da9337f, 0xdf8b646f,
349  0x76675996, 0x7763dbaf, 0x1c4c43ac, 0x04cb3c29,
350  };
351  uint32_t okm_data[] = {
352  0x75e7a48d, 0x8fc163a5, 0x2a805f71, 0x315a3c06, 0x5c1fa1b8, 0x9e87e15e,
353  0x5f4e45c3, 0x2d8d733c, 0x9513209d, 0x1ab6a4fa, 0x0000c896,
354  };
356  .hmac_key_mode = kOtcryptoKeyModeHmacSha256,
357  .ikm = ikm_data,
358  .ikm_bytelen = 22,
359  .salt = NULL,
360  .salt_bytelen = 0,
361  .info = NULL,
362  .info_bytelen = 0,
363  .prk = prk_data,
364  .prk_wordlen = ARRAYSIZE(prk_data),
365  .okm = okm_data,
366  .okm_bytelen = 42,
367  };
368  return run_test(&test);
369 }
370 
371 OTTF_DEFINE_TEST_CONFIG();
372 
373 bool test_main(void) {
374  // Start the entropy complex.
375  CHECK_STATUS_OK(entropy_complex_init());
376 
377  status_t test_result = OK_STATUS();
378  EXECUTE_TEST(test_result, rfc_test1);
379  EXECUTE_TEST(test_result, rfc_test2);
380  EXECUTE_TEST(test_result, rfc_test3);
381  return status_ok(test_result);
382 }