Software APIs
hmac.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/base/status.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/test_framework/ujson_ottf.h"
13 #include "sw/device/lib/ujson/ujson.h"
14 #include "sw/device/tests/crypto/cryptotest/json/hmac_commands.h"
15 
16 const unsigned int kOtcryptoHmacTagBytesSha256 = 32;
17 const unsigned int kOtcryptoHmacTagBytesSha384 = 48;
18 const unsigned int kOtcryptoHmacTagBytesSha512 = 64;
19 
20 const int MaxTagBytes = kOtcryptoHmacTagBytesSha512;
21 const int MaxTagWords = MaxTagBytes / sizeof(uint32_t);
22 
23 // Random value for masking, as large as the longest test key. This value
24 // should not affect the result.
25 static const uint32_t kTestMask[48] = {
26  0xBA81767F, 0xA913C751, 0x34209992, 0x5F66021B, 0x775F4577, 0x7C02E1CE,
27  0xB4A8B698, 0x1986B902, 0x7251045B, 0x3C827C6F, 0x00909D12, 0x81ABC8F9,
28  0x62F2FCB6, 0x15B63124, 0x66F60052, 0xAD637669, 0x522779CF, 0x07E9FBA8,
29  0x1258E541, 0x860719EF, 0x1D4F5386, 0xA9B04F7C, 0x6E98A861, 0xEFADEBA6,
30  0x900E1EC8, 0xB290DBCE, 0x05946814, 0xB83A01CE, 0x4EEC86BD, 0xAE836C6C,
31  0x20182AAE, 0x4476F6F4, 0x7C4A0A31, 0x7D2809BA, 0x367B29B9, 0x42444BEA,
32  0xDFD6025C, 0x1E665207, 0x18E0895B, 0x20D435DB, 0xC509A6D6, 0x8CC19AB1,
33  0xA5D39BD2, 0xAB479AD5, 0x5786D029, 0x2E4B7CD7, 0xB77A3D76, 0xE2A09962,
34 };
35 
36 status_t handle_hmac(ujson_t *uj) {
37  // Declare test arguments
38  cryptotest_hmac_hash_alg_t uj_hash_alg;
39  cryptotest_hmac_key_t uj_key;
40  cryptotest_hmac_message_t uj_message;
41  // Deserialize test arguments from UART
42  TRY(ujson_deserialize_cryptotest_hmac_hash_alg_t(uj, &uj_hash_alg));
43  TRY(ujson_deserialize_cryptotest_hmac_key_t(uj, &uj_key));
44  TRY(ujson_deserialize_cryptotest_hmac_message_t(uj, &uj_message));
45 
46  otcrypto_key_mode_t key_mode;
47  unsigned int tag_bytes;
48  switch (uj_hash_alg) {
49  case kCryptotestHmacHashAlgSha256:
50  key_mode = kOtcryptoKeyModeHmacSha256;
51  tag_bytes = kOtcryptoHmacTagBytesSha256;
52  break;
53  case kCryptotestHmacHashAlgSha384:
54  key_mode = kOtcryptoKeyModeHmacSha384;
55  tag_bytes = kOtcryptoHmacTagBytesSha384;
56  break;
57  case kCryptotestHmacHashAlgSha512:
58  key_mode = kOtcryptoKeyModeHmacSha512;
59  tag_bytes = kOtcryptoHmacTagBytesSha512;
60  break;
61  default:
62  LOG_ERROR("Unsupported HMAC key mode: %d", uj_hash_alg);
63  return INVALID_ARGUMENT();
64  }
65  // Build the key configuration
66  otcrypto_key_config_t config = {
67  .version = kOtcryptoLibVersion1,
68  .key_mode = key_mode,
69  .key_length = uj_key.key_len,
70  .hw_backed = kHardenedBoolFalse,
71  .security_level = kOtcryptoKeySecurityLevelLow,
72  };
73  // Create buffer to store key
74  uint32_t key_buf[uj_key.key_len];
75  memcpy(key_buf, uj_key.key, uj_key.key_len);
76  // Create keyblob
77  uint32_t keyblob[keyblob_num_words(config)];
78  // Create blinded key
79  TRY(keyblob_from_key_and_mask(key_buf, kTestMask, config, keyblob));
81  .config = config,
82  .keyblob_length = sizeof(keyblob),
83  .keyblob = keyblob,
84  };
85 
86  // Create input message
87  uint8_t msg_buf[uj_message.message_len];
88  memcpy(msg_buf, uj_message.message, uj_message.message_len);
89  otcrypto_const_byte_buf_t input_message = {
90  .len = uj_message.message_len,
91  .data = msg_buf,
92  };
93 
94  // Create tag
95  uint32_t tag_buf[MaxTagWords];
96  otcrypto_word32_buf_t tag = {
97  .len = tag_bytes / sizeof(uint32_t),
98  .data = tag_buf,
99  };
100  otcrypto_status_t status = otcrypto_hmac(&key, input_message, tag);
101  if (status.value != kOtcryptoStatusValueOk) {
102  return INTERNAL(status.value);
103  }
104  // Copy tag to uJSON type
105  cryptotest_hmac_tag_t uj_tag;
106  memcpy(uj_tag.tag, tag_buf, tag_bytes);
107  uj_tag.tag_len = tag_bytes;
108 
109  // Send tag to host via UART
110  RESP_OK(ujson_serialize_cryptotest_hmac_tag_t, uj, &uj_tag);
111  return OK_STATUS(0);
112 }