Software APIs
aes.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/aes_commands.h"
16 
17 enum {
18  kAesBlockBytes = 128 / 8,
19  kAesBlockWords = kAesBlockBytes / sizeof(uint32_t),
20  kAesMaxKeyBytes = 256 / 8,
21  kAesMaxKeyWords = kAesMaxKeyBytes / 4,
22 };
23 
24 // Arbitrary mask for testing (borrowed from aes_functest.c).
25 static const uint32_t kKeyMask[8] = {
26  0x1b81540c, 0x220733c9, 0x8bf85383, 0x05ab50b4,
27  0x8acdcb7e, 0x15e76440, 0x8459b2ce, 0xdc2110cc,
28 };
29 
30 status_t handle_aes_block(ujson_t *uj) {
31  cryptotest_aes_mode_t uj_mode;
32  cryptotest_aes_operation_t uj_op;
33  cryptotest_aes_padding_t uj_padding;
34  cryptotest_aes_data_t uj_data;
35  TRY(ujson_deserialize_cryptotest_aes_mode_t(uj, &uj_mode));
36  TRY(ujson_deserialize_cryptotest_aes_operation_t(uj, &uj_op));
37  TRY(ujson_deserialize_cryptotest_aes_padding_t(uj, &uj_padding));
38  TRY(ujson_deserialize_cryptotest_aes_data_t(uj, &uj_data));
39 
41  otcrypto_key_mode_t key_mode;
42  switch (uj_mode) {
43  case kCryptotestAesModeEcb:
44  mode = kOtcryptoAesModeEcb;
45  key_mode = kOtcryptoKeyModeAesEcb;
46  break;
47  case kCryptotestAesModeCbc:
48  mode = kOtcryptoAesModeCbc;
49  key_mode = kOtcryptoKeyModeAesCbc;
50  break;
51  case kCryptotestAesModeCfb:
52  mode = kOtcryptoAesModeCfb;
53  key_mode = kOtcryptoKeyModeAesCfb;
54  break;
55  case kCryptotestAesModeOfb:
56  mode = kOtcryptoAesModeOfb;
57  key_mode = kOtcryptoKeyModeAesOfb;
58  break;
59  case kCryptotestAesModeCtr:
60  mode = kOtcryptoAesModeCtr;
61  key_mode = kOtcryptoKeyModeAesCtr;
62  break;
63  default:
64  LOG_ERROR("Unrecognized AES block cipher mode: %d", uj_mode);
65  return INVALID_ARGUMENT();
66  }
67 
69  switch (uj_op) {
70  case kCryptotestAesOperationEncrypt:
71  op = kOtcryptoAesOperationEncrypt;
72  break;
73  case kCryptotestAesOperationDecrypt:
74  op = kOtcryptoAesOperationDecrypt;
75  break;
76  default:
77  LOG_ERROR("Unrecognized AES operation: %d", uj_op);
78  return INVALID_ARGUMENT();
79  }
80 
81  otcrypto_aes_padding_t padding;
82  switch (uj_padding) {
83  case kCryptotestAesPaddingPkcs7:
84  padding = kOtcryptoAesPaddingPkcs7;
85  break;
86  case kCryptotestAesPaddingIso9797M2:
87  padding = kOtcryptoAesPaddingIso9797M2;
88  break;
89  case kCryptotestAesPaddingNull:
90  padding = kOtcryptoAesPaddingNull;
91  break;
92  default:
93  LOG_ERROR("Unrecognized AES padding scheme: %d", uj_op);
94  return INVALID_ARGUMENT();
95  }
96 
97  // Convert the data struct into cryptolib types
98  const size_t AES_IV_SIZE = 4;
99  uint32_t iv_buf[AES_IV_SIZE];
100  memcpy(iv_buf, uj_data.iv, AES_IV_SIZE * 4);
101  otcrypto_word32_buf_t iv = {
102  .data = iv_buf,
103  .len = kAesBlockWords,
104  };
105 
106  otcrypto_const_byte_buf_t input = {
107  .data = uj_data.input,
108  .len = (size_t)uj_data.input_len,
109  };
110 
111  // Build the key configuration
112  otcrypto_key_config_t config = {
113  .version = kOtcryptoLibVersion1,
114  .key_mode = key_mode,
115  .key_length = uj_data.key_length,
116  .hw_backed = kHardenedBoolFalse,
117  .security_level = kOtcryptoKeySecurityLevelLow,
118  };
119  // Create buffer to store key
120  uint32_t key_buf[kAesMaxKeyWords];
121  memcpy(key_buf, uj_data.key, kAesMaxKeyBytes);
122  // Create keyblob
123  uint32_t keyblob[keyblob_num_words(config)];
124  // Create blinded key
125  TRY(keyblob_from_key_and_mask(key_buf, kKeyMask, config, keyblob));
126  otcrypto_blinded_key_t key = {
127  .config = config,
128  .keyblob_length = sizeof(keyblob),
129  .keyblob = keyblob,
130  };
131  key.checksum = integrity_blinded_checksum(&key);
132 
133  size_t padded_len_bytes;
134  otcrypto_aes_padded_plaintext_length((size_t)uj_data.input_len, padding,
135  &padded_len_bytes);
136  if (padded_len_bytes > AES_CMD_MAX_MSG_BYTES) {
137  return OUT_OF_RANGE();
138  }
139  uint32_t output_buf[padded_len_bytes / sizeof(uint32_t)];
140  otcrypto_byte_buf_t output = {
141  .data = (unsigned char *)output_buf,
142  .len = sizeof(output_buf),
143  };
144 
145  otcrypto_aes(&key, iv, mode, op, input, padding, output);
146 
147  cryptotest_aes_output_t uj_output;
148  uj_output.output_len = padded_len_bytes;
149  memset(uj_output.output, 0, AES_CMD_MAX_MSG_BYTES);
150  memcpy(uj_output.output, output_buf, uj_output.output_len);
151  RESP_OK(ujson_serialize_cryptotest_aes_output_t, uj, &uj_output);
152  return OK_STATUS(0);
153 }
154 
155 status_t handle_aes(ujson_t *uj) {
156  aes_subcommand_t cmd;
157  TRY(ujson_deserialize_aes_subcommand_t(uj, &cmd));
158  switch (cmd) {
159  case kAesSubcommandAesBlock:
160  return handle_aes_block(uj);
161  break;
162  default:
163  LOG_ERROR("Unrecognized AES subcommand: %d", cmd);
164  return INVALID_ARGUMENT();
165  }
166  return OK_STATUS(0);
167 }