Software APIs
hash.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 
9 #include "sw/device/lib/base/status.h"
10 #include "sw/device/lib/crypto/drivers/kmac.h"
11 #include "sw/device/lib/crypto/impl/integrity.h"
12 #include "sw/device/lib/crypto/impl/keyblob.h"
15 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
16 #include "sw/device/lib/ujson/ujson.h"
17 #include "sw/device/tests/crypto/cryptotest/json/hash_commands.h"
18 
19 status_t handle_hash(ujson_t *uj) {
20  // Declare test arguments
21  cryptotest_hash_algorithm_t uj_algorithm;
22  cryptotest_hash_shake_digest_length_t uj_shake_digest_length;
23  cryptotest_hash_message_t uj_message;
24  // Deserialize test arguments from UART
25  TRY(ujson_deserialize_cryptotest_hash_algorithm_t(uj, &uj_algorithm));
26  TRY(ujson_deserialize_cryptotest_hash_shake_digest_length_t(
27  uj, &uj_shake_digest_length));
28  TRY(ujson_deserialize_cryptotest_hash_message_t(uj, &uj_message));
29 
30  // Create input message
31  uint8_t msg_buf[uj_message.message_len];
32  memcpy(msg_buf, uj_message.message, uj_message.message_len);
33  otcrypto_const_byte_buf_t input_message = {
34  .len = uj_message.message_len,
35  .data = msg_buf,
36  };
37  uint8_t customization_string_buf[uj_message.customization_string_len];
38  memcpy(customization_string_buf, uj_message.customization_string,
39  uj_message.customization_string_len);
40  otcrypto_const_byte_buf_t customization_string = {
41  .len = uj_message.customization_string_len,
42  .data = customization_string_buf,
43  };
44  // If we are using cSHAKE, the empty function name tells cryptolib not to
45  // apply any function on top of cSHAKE.
46  otcrypto_const_byte_buf_t cshake_function_name = {
47  .len = 0,
48  };
49 
50  // Handle to correct oneshot hash API for the provided algorithm
53 
54  // Digest length in 32-bit words
55  size_t digest_len;
56  uint8_t test_stepwise = false;
58  switch (uj_algorithm) {
59  case kCryptotestHashAlgorithmSha256:
60  mode = kOtcryptoHashModeSha256;
61  digest_len = kSha256DigestWords;
62  hash_oneshot = otcrypto_hash;
63  test_stepwise = true;
64  break;
65  case kCryptotestHashAlgorithmSha384:
66  mode = kOtcryptoHashModeSha384;
67  digest_len = kSha384DigestWords;
68  hash_oneshot = otcrypto_hash;
69  test_stepwise = true;
70  break;
71  case kCryptotestHashAlgorithmSha512:
72  mode = kOtcryptoHashModeSha512;
73  digest_len = kSha512DigestWords;
74  hash_oneshot = otcrypto_hash;
75  test_stepwise = true;
76  break;
77  case kCryptotestHashAlgorithmSha3_224:
78  mode = kOtcryptoHashModeSha3_224;
79  digest_len = kSha3_224DigestWords;
80  hash_oneshot = otcrypto_hash;
81  break;
82  case kCryptotestHashAlgorithmSha3_256:
83  mode = kOtcryptoHashModeSha3_256;
84  digest_len = kSha3_256DigestWords;
85  hash_oneshot = otcrypto_hash;
86  break;
87  case kCryptotestHashAlgorithmSha3_384:
88  mode = kOtcryptoHashModeSha3_384;
89  digest_len = kSha3_384DigestWords;
90  hash_oneshot = otcrypto_hash;
91  break;
92  case kCryptotestHashAlgorithmSha3_512:
93  mode = kOtcryptoHashModeSha3_512;
94  digest_len = kSha3_512DigestWords;
95  hash_oneshot = otcrypto_hash;
96  break;
97  case kCryptotestHashAlgorithmShake128:
98  mode = kOtcryptoHashXofModeShake128;
99  digest_len = ceil_div(uj_shake_digest_length.length, sizeof(uint32_t));
100  hash_oneshot = otcrypto_xof_shake;
101  break;
102  case kCryptotestHashAlgorithmShake256:
103  mode = kOtcryptoHashXofModeShake256;
104  digest_len = ceil_div(uj_shake_digest_length.length, sizeof(uint32_t));
105  hash_oneshot = otcrypto_xof_shake;
106  break;
107  case kCryptotestHashAlgorithmCshake128:
108  mode = kOtcryptoHashXofModeCshake128;
109  digest_len = ceil_div(uj_shake_digest_length.length, sizeof(uint32_t));
110  break;
111  case kCryptotestHashAlgorithmCshake256:
112  mode = kOtcryptoHashXofModeCshake256;
113  digest_len = ceil_div(uj_shake_digest_length.length, sizeof(uint32_t));
114  break;
115  default:
116  LOG_ERROR("Unsupported hash algorithm: %d", uj_algorithm);
117  return INVALID_ARGUMENT();
118  }
119 
120  // Create digest skeleton
121  uint32_t digest_buf[digest_len];
122  memset(digest_buf, 0, digest_len * sizeof(uint32_t));
123  otcrypto_hash_digest_t digest = {
124  .data = digest_buf,
125  .mode = mode,
126  .len = digest_len,
127  };
129  // Test oneshot API
130  switch (uj_algorithm) {
131  case kCryptotestHashAlgorithmCshake128:
133  case kCryptotestHashAlgorithmCshake256:
134  status = otcrypto_xof_cshake(input_message, cshake_function_name,
135  customization_string, digest);
136  break;
137  default:
138  status = hash_oneshot(input_message, digest);
139  }
140  if (status.value != kOtcryptoStatusValueOk) {
141  LOG_ERROR("Bad status value: 0x%x", status.value);
142  return INTERNAL(status.value);
143  }
144  cryptotest_hash_output_t uj_output;
145  uj_output.digest_len = digest_len * sizeof(uint32_t);
146  // Copy oneshot digest to uJSON type
147  memcpy(uj_output.oneshot_digest, digest_buf, digest_len * sizeof(uint32_t));
148  // Zero out digest_buf to mitigate chance of a false positive in the
149  // stepwise test
150  memset(digest_buf, 0, digest_len * sizeof(uint32_t));
151  // Test the stepwise API for algorithms that support it
152  if (test_stepwise) {
154  status = otcrypto_hash_init(&ctx, mode);
155  if (status.value != kOtcryptoStatusValueOk) {
156  return INTERNAL(status.value);
157  }
158  // Split up input mesasge into 2 shares for better coverage of stepwise
159  // hashing
160  otcrypto_const_byte_buf_t input_message_share1 = {
161  .len = uj_message.message_len / 2,
162  .data = msg_buf,
163  };
164  otcrypto_const_byte_buf_t input_message_share2 = {
165  .len = ceil_div(uj_message.message_len, 2),
166  .data = &msg_buf[uj_message.message_len / 2],
167  };
168  status = otcrypto_hash_update(&ctx, input_message_share1);
169  if (status.value != kOtcryptoStatusValueOk) {
170  return INTERNAL(status.value);
171  }
172  status = otcrypto_hash_update(&ctx, input_message_share2);
173  if (status.value != kOtcryptoStatusValueOk) {
174  return INTERNAL(status.value);
175  }
176  status = otcrypto_hash_final(&ctx, digest);
177  if (status.value != kOtcryptoStatusValueOk) {
178  return INTERNAL(status.value);
179  }
180  // Copy stepwise result to uJSON type
181  memcpy(uj_output.stepwise_digest, digest_buf,
182  digest_len * sizeof(uint32_t));
183  }
184  // Send digest to host via UART
185  RESP_OK(ujson_serialize_cryptotest_hash_output_t, uj, &uj_output);
186  return OK_STATUS(0);
187 }