Software APIs
aes_kwp_kat_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 
6 #include "sw/device/lib/crypto/drivers/entropy.h"
7 #include "sw/device/lib/crypto/impl/aes_kwp/aes_kwp.h"
8 #include "sw/device/lib/crypto/impl/status.h"
10 #include "sw/device/lib/testing/test_framework/check.h"
12 
13 // Module ID for status codes.
14 #define MODULE_ID MAKE_MODULE_ID('t', 's', 't')
15 
16 // Buffer with 256 bits of zeroes to use for the second shares of AES keys.
17 static const uint32_t kZero[256 / 32] = {0, 0, 0, 0, 0, 0, 0, 0};
18 
19 /**
20  * Construct an AES key struct for AES-KWP from a raw word buffer.
21  *
22  * @param key Wrapping key data.
23  * @param key_words Wrapping key length in 32-bit words.
24  * @return Constructed AES key.
25  */
26 static aes_key_t make_aes_key(const uint32_t *key, size_t key_words) {
27  return (aes_key_t){
28  .mode = kAesCipherModeEcb,
29  .sideload = kHardenedBoolFalse,
30  .key_len = key_words,
31  .key_shares = {key, kZero},
32  };
33 }
34 
35 /**
36  * Run an AES-KWP encryption known-answer test.
37  *
38  * This test uses the internal AES-KWP implementation rather than the cryptolib
39  * API, since the cryptolib API pre-formats the key input and stores
40  * configuration information along with the key, which makes it insuitable for
41  * known-answer tests.
42  *
43  * @param kek Key to wrap with (key encryption key).
44  * @param kek_words Length of the key encryption key in 32-bit words.
45  * @param ptext Key material to wrap.
46  * @param ptext_bytes Length of plaintext in bytes.
47  * @param ctext Expected ciphertext.
48  * @param ctext_words Length of expected ciphertext in 32-bit words.
49  */
50 static status_t aes_kwp_wrap_kat(const uint32_t *kek, size_t kek_words,
51  const uint32_t *ptext, size_t ptext_bytes,
52  const uint32_t *ctext, size_t ctext_words) {
53  // Construct an AES key.
54  aes_key_t aes_kek = make_aes_key(kek, kek_words);
55 
56  // Run key wrapping and check the result.
57  uint32_t act_ctext[ctext_words + 1];
58  act_ctext[ctext_words] = 0xffffffff;
59  TRY(aes_kwp_wrap(aes_kek, ptext, ptext_bytes, act_ctext));
60  TRY_CHECK_ARRAYS_EQ(act_ctext, ctext, ctext_words);
61 
62  // Check that the last word of the "actual ciphertext" buffer is still the
63  // same (i.e. the kwp routine did not write past the expected point).
64  TRY_CHECK(act_ctext[ctext_words] == 0xffffffff);
65  return OK_STATUS();
66 }
67 
68 /**
69  * Run an AES-KWP decryption known-answer test.
70  *
71  * This test uses the internal AES-KWP implementation rather than the cryptolib
72  * API, since the cryptolib API pre-formats the key input and stores
73  * configuration information along with the key, which makes it insuitable for
74  * known-answer tests.
75  *
76  * @param kek Key to wrap with (key encryption key).
77  * @param kek_words Length of the key encryption key in 32-bit words.
78  * @param ctext Ciphertext.
79  * @param ctext_words Length of expected ciphertext in 32-bit words.
80  * @param valid Whether the ciphertext is valid or not.
81  * @param ptext Expected plaintext (ignored if valid=false).
82  * @param ptext_bytes Length of plaintext in bytes.
83  */
84 static status_t aes_kwp_unwrap_kat(const uint32_t *kek, size_t kek_words,
85  const uint32_t *ctext, size_t ctext_words,
86  bool valid, const uint32_t *ptext,
87  size_t ptext_bytes) {
88  // Construct an AES key.
89  aes_key_t aes_kek = make_aes_key(kek, kek_words);
90 
91  // Run key unwrapping.
92  size_t ptext_words = (ptext_bytes + sizeof(uint32_t) - 1) / sizeof(uint32_t);
93  uint32_t act_ptext[ptext_words];
94  hardened_bool_t success;
95  TRY(aes_kwp_unwrap(aes_kek, ctext, ctext_words * sizeof(uint32_t), &success,
96  act_ptext));
97 
98  // Check results.
99  if (valid) {
100  TRY_CHECK(success == kHardenedBoolTrue);
101  TRY_CHECK_ARRAYS_EQ((unsigned char *)act_ptext, (unsigned char *)ptext,
102  ptext_bytes);
103  } else {
104  TRY_CHECK(success == kHardenedBoolFalse);
105  }
106 
107  return OK_STATUS();
108 }
109 
110 /**
111  * Basic test with valid data and no padding.
112  *
113  * This test data was taken from the Wycheproof test set (kwp_test.json, test
114  * ID 1).
115  */
116 static status_t no_padding_test(void) {
117  uint32_t kek[] = {0x6d48676f, 0x1944911e, 0x85c243cb, 0xeac1c709};
118  uint32_t ptext[] = {0x2d63c08d, 0xe40bee92, 0x840240f7, 0x7082b010};
119  uint32_t ctext[] = {0xa63fd68c, 0xeda58a78, 0xc83f75fa,
120  0x675a647d, 0x7c10142b, 0xe719453b};
121 
122  TRY(aes_kwp_wrap_kat(kek, ARRAYSIZE(kek), ptext, sizeof(ptext), ctext,
123  ARRAYSIZE(ctext)));
124  return aes_kwp_unwrap_kat(kek, ARRAYSIZE(kek), ctext, ARRAYSIZE(ctext),
125  /*valid=*/true, ptext, sizeof(ptext));
126 }
127 
128 /**
129  * Basic test with valid data and padding.
130  *
131  * This test data was taken from the NIST CAVP test set (first test in the set
132  * with plaintext_len=72 from KWP_AE_128.txt).
133  */
134 static status_t needs_padding_test(void) {
135  uint32_t kek[] = {0x0fe26578, 0x9a65213c, 0x620b69b4, 0xc43cdf9c};
136  // Last word padded with 1 bits; these should be replaced with 0s during
137  // padding.
138  uint32_t ptext[] = {0xd44368bd, 0xc88d3720, 0xffffff96};
139  size_t ptext_len = 9;
140  uint32_t ctext[] = {0x56a9ec41, 0x7e04aad4, 0xfe4ecfb5,
141  0xe7619665, 0xc5f8b64d, 0x0035e264};
142 
143  TRY(aes_kwp_wrap_kat(kek, ARRAYSIZE(kek), ptext, ptext_len, ctext,
144  ARRAYSIZE(ctext)));
145  return aes_kwp_unwrap_kat(kek, ARRAYSIZE(kek), ctext, ARRAYSIZE(ctext),
146  /*valid=*/true, ptext, ptext_len);
147 }
148 
149 OTTF_DEFINE_TEST_CONFIG();
150 
151 bool test_main(void) {
152  status_t result = OK_STATUS();
153 
154  CHECK_STATUS_OK(entropy_complex_init());
155  EXECUTE_TEST(result, no_padding_test);
156  EXECUTE_TEST(result, needs_padding_test);
157 
158  return status_ok(result);
159 }