Software APIs
hmac_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 <stdbool.h>
6 #include <stdint.h>
7 
11 #include "sw/device/lib/base/status.h"
15 #include "sw/device/lib/testing/hexstr.h"
17 #include "sw/device/silicon_creator/lib/drivers/hmac.h"
18 #include "sw/device/silicon_creator/lib/error.h"
19 
21 
22 enum {
23  kSha256BlockBits = 512,
24  kSha256BlockBytes = kSha256BlockBits / 8,
25 };
26 
27 // From: http://www.abrahamlincolnonline.org/lincoln/speeches/gettysburg.htm
28 static const char kGettysburgPrelude[] =
29  "Four score and seven years ago our fathers brought forth on this "
30  "continent, a new nation, conceived in Liberty, and dedicated to the "
31  "proposition that all men are created equal.";
32 
33 // The following shell command will produce the sha256sum and convert the
34 // digest into valid C hexadecimal constants:
35 //
36 // $ echo -n "Four score and seven years ago our fathers brought forth on this
37 // continent, a new nation, conceived in Liberty, and dedicated to the
38 // proposition that all men are created equal." |
39 // sha256sum - | cut -f1 -d' ' | sed -e "s/......../0x&,\n/g" | tac
40 //
41 static const uint32_t kGettysburgDigest[] = {
42  0x8b8cc7ba, 0xe29f6ac0, 0xeb3dd433, 0x420ec587,
43  0x96c324ed, 0x775708a3, 0x0f9034cd, 0x1e6fd403,
44 };
45 
46 /*
47  * For the big-endian version of the test, we use the unmodified output of
48  * sha256sum:
49  *
50  $ echo -n "Four score and seven years ago our fathers brought forth on this\
51  continent, a new nation, conceived in Liberty, and dedicated to the\
52  proposition that all men are created equal." | sha256sum -
53 
54  1e6fd4030f9034cd775708a396c324ed420ec587eb3dd433e29f6ac08b8cc7ba -
55  */
56 static const char kGettysburgDigestBigEndian[] =
57  "1e6fd4030f9034cd775708a396c324ed420ec587eb3dd433e29f6ac08b8cc7ba";
58 
59 rom_error_t hmac_test(void) {
60  hmac_digest_t digest;
61  hmac_sha256(kGettysburgPrelude, sizeof(kGettysburgPrelude) - 1, &digest);
62 
63  const size_t len = ARRAYSIZE(digest.digest);
64  for (int i = 0; i < len; ++i) {
65  LOG_INFO("word %d = 0x%08x", i, digest.digest[i]);
66  if (digest.digest[i] != kGettysburgDigest[i]) {
67  return kErrorUnknown;
68  }
69  }
70  return kErrorOk;
71 }
72 
73 rom_error_t hmac_process_nowait_test(void) {
74  hmac_digest_t digest;
75  hmac_sha256_init();
76  hmac_sha256_update(kGettysburgPrelude, sizeof(kGettysburgPrelude) - 1);
77  hmac_sha256_process();
78  hmac_sha256_final(&digest);
79 
80  const size_t len = ARRAYSIZE(digest.digest);
81  for (int i = 0; i < len; ++i) {
82  LOG_INFO("word %d = 0x%08x", i, digest.digest[i]);
83  if (digest.digest[i] != kGettysburgDigest[i]) {
84  return kErrorUnknown;
85  }
86  }
87  return kErrorOk;
88 }
89 
90 rom_error_t hmac_process_wait_test(void) {
91  hmac_digest_t digest;
92  hmac_sha256_init();
93  hmac_sha256_update(kGettysburgPrelude, sizeof(kGettysburgPrelude) - 1);
94  hmac_sha256_process();
95  // Wait for 1ms (1000 us).
96  busy_spin_micros(1000);
97  hmac_sha256_final(&digest);
98 
99  const size_t len = ARRAYSIZE(digest.digest);
100  for (int i = 0; i < len; ++i) {
101  LOG_INFO("word %d = 0x%08x", i, digest.digest[i]);
102  if (digest.digest[i] != kGettysburgDigest[i]) {
103  return kErrorUnknown;
104  }
105  }
106  return kErrorOk;
107 }
108 
109 rom_error_t hmac_truncated_test(void) {
110  uint32_t digest[3];
111  hmac_sha256_init();
112  hmac_sha256_update(kGettysburgPrelude, sizeof(kGettysburgPrelude) - 1);
113  hmac_sha256_process();
114  hmac_sha256_final_truncated(digest, ARRAYSIZE(digest));
115 
116  const size_t len = ARRAYSIZE(digest);
117  for (int i = 0; i < len; ++i) {
118  LOG_INFO("word %d = 0x%08x", i, digest[i]);
119  if (digest[i] != kGettysburgDigest[i]) {
120  return kErrorUnknown;
121  }
122  }
123  return kErrorOk;
124 }
125 
126 rom_error_t hmac_bigendian_test(void) {
127  uint32_t result[8];
128  hexstr_decode(&result, sizeof(result), kGettysburgDigestBigEndian);
129 
130  hmac_digest_t digest;
131  hmac_sha256_configure(true);
132  hmac_sha256_start();
133  hmac_sha256_update(kGettysburgPrelude, sizeof(kGettysburgPrelude) - 1);
134  hmac_sha256_process();
135  hmac_sha256_final(&digest);
136 
137  const size_t len = ARRAYSIZE(digest.digest);
138  for (int i = 0; i < len; ++i) {
139  LOG_INFO("word %d = 0x%08x", i, digest.digest[i]);
140  if (digest.digest[i] != result[i]) {
141  return kErrorUnknown;
142  }
143  }
144  return kErrorOk;
145 }
146 
147 rom_error_t hmac_bigendian_truncated_test(void) {
148  uint32_t result[8];
149  hexstr_decode(&result, sizeof(result), kGettysburgDigestBigEndian);
150 
151  hmac_sha256_configure(true);
152  hmac_sha256_start();
153  hmac_sha256_update(kGettysburgPrelude, sizeof(kGettysburgPrelude) - 1);
154  hmac_sha256_process();
155  uint32_t digest[3];
156  hmac_sha256_final_truncated(digest, ARRAYSIZE(digest));
157 
158  const size_t len = ARRAYSIZE(digest);
159  for (int i = 0; i < len; ++i) {
160  LOG_INFO("word %d = 0x%08x", i, digest[i]);
161  if (digest[i] != result[i]) {
162  return kErrorUnknown;
163  }
164  }
165  return kErrorOk;
166 }
167 
168 static_assert(sizeof(kGettysburgPrelude) - 1 > kSha256BlockBytes,
169  "Test assumes that the test message is longer than a SHA-256 "
170  "message block.");
171 rom_error_t hmac_save_restore_test(void) {
172  // Start a little-endian computation with the first block of input.
173  unsigned char *input = (unsigned char *)kGettysburgPrelude;
174  size_t remaining_input_len = sizeof(kGettysburgPrelude) - 1;
175  hmac_sha256_init();
176  hmac_sha256_update(input, kSha256BlockBytes);
177  input += kSha256BlockBytes;
178  remaining_input_len -= kSha256BlockBytes;
179 
180  // Save the little-endian computation.
181  hmac_context_t ctx;
182  hmac_sha256_save(&ctx);
183 
184  // Do a big-endian computation.
185  hmac_sha256_configure(true);
186  hmac_sha256_start();
187  hmac_sha256_update(kGettysburgPrelude, sizeof(kGettysburgPrelude) - 1);
188  hmac_sha256_process();
189  hmac_digest_t digest_be;
190  hmac_sha256_final(&digest_be);
191 
192  // Restore and complete the little-endian computation.
193  hmac_sha256_configure(false);
194  hmac_sha256_restore(&ctx);
195  hmac_sha256_update(input, remaining_input_len);
196  hmac_sha256_process();
197  hmac_digest_t digest_le;
198  hmac_sha256_final(&digest_le);
199 
200  // Check that the big-endian result was correct.
201  uint32_t expected_digest_be[8];
202  hexstr_decode(&expected_digest_be, sizeof(expected_digest_be),
203  kGettysburgDigestBigEndian);
204  for (int i = 0; i < ARRAYSIZE(digest_be.digest); ++i) {
205  LOG_INFO("word %d = 0x%08x", i, digest_be.digest[i]);
206  if (digest_be.digest[i] != expected_digest_be[i]) {
207  return kErrorUnknown;
208  }
209  }
210 
211  // Check that the little-endian result was correct.
212  for (int i = 0; i < ARRAYSIZE(digest_le.digest); ++i) {
213  LOG_INFO("word %d = 0x%08x", i, digest_le.digest[i]);
214  if (digest_le.digest[i] != kGettysburgDigest[i]) {
215  return kErrorUnknown;
216  }
217  }
218  return kErrorOk;
219 }
220 
221 static_assert(sizeof(kGettysburgPrelude) - 1 > 2 * kSha256BlockBytes,
222  "Test assumes that the test message is more than 2x longer than "
223  "a SHA-256 message block.");
224 rom_error_t hmac_save_restore_repeated_test(void) {
225  // Start a little-endian computation with the first block of input.
226  unsigned char *input = (unsigned char *)kGettysburgPrelude;
227  size_t remaining_input_len = sizeof(kGettysburgPrelude) - 1;
228  hmac_sha256_init();
229  hmac_sha256_update(input, kSha256BlockBytes);
230  input += kSha256BlockBytes;
231  remaining_input_len -= kSha256BlockBytes;
232 
233  // Save the little-endian computation and repeatedly restore it.
234  hmac_context_t ctx;
235  hmac_sha256_save(&ctx);
236  hmac_sha256_restore(&ctx);
237  hmac_sha256_update(input, kSha256BlockBytes);
238  input += kSha256BlockBytes;
239  remaining_input_len -= kSha256BlockBytes;
240  hmac_sha256_save(&ctx);
241  hmac_sha256_restore(&ctx);
242  hmac_sha256_update(input, remaining_input_len);
243  hmac_sha256_process();
244  hmac_digest_t digest_le;
245  hmac_sha256_final(&digest_le);
246 
247  // Check that the little-endian result was correct.
248  for (int i = 0; i < ARRAYSIZE(digest_le.digest); ++i) {
249  LOG_INFO("word %d = 0x%08x", i, digest_le.digest[i]);
250  if (digest_le.digest[i] != kGettysburgDigest[i]) {
251  return kErrorUnknown;
252  }
253  }
254  return kErrorOk;
255 }
256 
257 OTTF_DEFINE_TEST_CONFIG();
258 
259 bool test_main(void) {
260  status_t result = OK_STATUS();
261  EXECUTE_TEST(result, hmac_test);
262  EXECUTE_TEST(result, hmac_process_nowait_test);
263  EXECUTE_TEST(result, hmac_process_wait_test);
264  EXECUTE_TEST(result, hmac_truncated_test);
265  EXECUTE_TEST(result, hmac_bigendian_test);
266  EXECUTE_TEST(result, hmac_bigendian_truncated_test);
267  EXECUTE_TEST(result, hmac_save_restore_test);
268  EXECUTE_TEST(result, hmac_save_restore_repeated_test);
269  return status_ok(result);
270 }