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