Embedded SDK
Embedded SDK
cx_aes_siv.c
Go to the documentation of this file.
1 /* @BANNER@ */
2 
3 #ifdef HAVE_AES_SIV
4 #if defined(HAVE_AES) && defined(HAVE_CMAC)
5 #include "cx_cmac.h"
6 #include "cx_utils.h"
7 #include "lcx_cmac.h"
8 #include "lcx_aes_siv.h"
9 
10 static void cx_clear_bits(uint8_t *input)
11 {
12  input[8] &= 0x7f;
13  input[12] &= 0x7f;
14 }
15 
16 cx_err_t cx_aes_siv_init(cx_aes_siv_context_t *ctx)
17 {
18  cx_err_t error;
19  CX_CHECK(cx_cipher_init(ctx->cipher_ctx));
20 
21 end:
22  return error;
23 }
24 
25 cx_err_t cx_aes_siv_reset(cx_aes_siv_context_t *ctx)
26 {
27  cx_err_t error = CX_INVALID_PARAMETER_VALUE;
28  if (ctx->cipher_ctx == NULL) {
29  goto end;
30  }
31  CX_CHECK(ctx->cipher_ctx->cipher_info->base->ctx_reset());
32  cx_cipher_reset(ctx->cipher_ctx);
33 
34 end:
35  return error;
36 }
37 
38 cx_err_t cx_aes_siv_set_key(cx_aes_siv_context_t *ctx, const uint8_t *key, size_t key_bitlen)
39 {
40  // AES SIV uses two keys of either 128, 192 or 256 bits each
41  if (key_bitlen > AES_SIV_MAX_KEY_LEN * AES_SIV_KEY_NUMBER * 8) {
42  return CX_INVALID_PARAMETER_SIZE;
43  }
44 
45  ctx->key_len = key_bitlen / 2;
46  memcpy(ctx->key1, key, ctx->key_len / 8);
47  memcpy(ctx->key2, key + ctx->key_len / 8, ctx->key_len / 8);
48  return CX_OK;
49 }
50 
51 cx_err_t cx_aes_siv_start(cx_aes_siv_context_t *ctx,
52  uint32_t mode,
53  const uint8_t *iv,
54  size_t iv_len)
55 {
56  uint8_t iv_used[CX_AES_BLOCK_SIZE] = {0};
57  cx_err_t error;
58 
59  // Set up cipher to be used for CMAC computation
60  CX_CHECK(cx_cipher_setup(ctx->cipher_ctx, ctx->cipher_type, CX_CHAIN_ECB));
61  CX_CHECK(cx_cmac_start(ctx->cipher_ctx, ctx->key1, ctx->key_len));
62  CX_CHECK(cx_cmac_update(ctx->cipher_ctx, iv_used, CX_AES_BLOCK_SIZE));
63  CX_CHECK(cx_cmac_finish(ctx->cipher_ctx, ctx->tag_state));
64 
65  if (CX_DECRYPT == mode) {
66  // Prepare for the AES-CTR computation
67  memcpy(iv_used, iv, iv_len);
68  cx_clear_bits(iv_used);
69  CX_CHECK(cx_cipher_setup(ctx->cipher_ctx, ctx->cipher_type, CX_CHAIN_CTR));
70  CX_CHECK(cx_cipher_setkey(ctx->cipher_ctx, ctx->key2, ctx->key_len, CX_ENCRYPT));
71  CX_CHECK(cx_cipher_setiv(ctx->cipher_ctx, iv_used, CX_AES_BLOCK_SIZE));
72  }
73  ctx->mode = mode;
74 
75 end:
76  return error;
77 }
78 
79 cx_err_t cx_aes_siv_update_aad(cx_aes_siv_context_t *ctx, const uint8_t *aad, size_t aad_len)
80 {
81  uint8_t tmp[CX_AES_BLOCK_SIZE] = {0};
82  cx_err_t error;
83 
84  CX_CHECK(cx_cipher_setup(ctx->cipher_ctx, ctx->cipher_type, CX_CHAIN_ECB));
85  CX_CHECK(cx_cmac_start(ctx->cipher_ctx, ctx->key1, ctx->key_len));
86 
87  if (NULL == aad) {
88  return CX_OK;
89  }
90 
91  CX_CHECK(cx_cmac_shift_and_xor(tmp, ctx->tag_state, CX_AES_BLOCK_SIZE));
92  CX_CHECK(cx_cmac_update(ctx->cipher_ctx, aad, aad_len));
93  CX_CHECK(cx_cmac_finish(ctx->cipher_ctx, ctx->tag_state));
94  cx_memxor(ctx->tag_state, tmp, CX_AES_BLOCK_SIZE);
95  CX_CHECK(cx_cmac_start(ctx->cipher_ctx, ctx->key1, ctx->key_len));
96 
97 end:
98  return error;
99 }
100 
101 cx_err_t cx_aes_siv_update_mac(cx_aes_siv_context_t *ctx, const uint8_t *input, size_t in_len)
102 {
103  return cx_cmac_update(ctx->cipher_ctx, input, in_len);
104 }
105 
106 cx_err_t cx_aes_siv_update(cx_aes_siv_context_t *ctx,
107  const uint8_t *input,
108  uint8_t *output,
109  size_t len)
110 {
111  size_t out_len = len;
112  cx_err_t error;
113  CX_CHECK(cx_cipher_update(ctx->cipher_ctx, input, len, output, &out_len));
114 
115 end:
116  return error;
117 }
118 
119 static cx_err_t cx_aes_siv_check_tag(cx_aes_siv_context_t *ctx, const uint8_t *tag)
120 {
121  uint8_t diff;
122  diff = cx_constant_time_eq(tag, ctx->tag_state, CX_AES_BLOCK_SIZE);
123  return diff * CX_INVALID_PARAMETER_VALUE + (1 - diff) * CX_OK;
124 }
125 
126 cx_err_t cx_aes_siv_finish(cx_aes_siv_context_t *ctx,
127  const uint8_t *input,
128  size_t in_len,
129  uint8_t *tag)
130 {
131  uint8_t tmp[CX_AES_BLOCK_SIZE] = {0};
132  cx_err_t error;
133 
134  if (in_len < CX_AES_BLOCK_SIZE) {
135  CX_CHECK(cx_cmac_shift_and_xor(tmp, ctx->tag_state, CX_AES_BLOCK_SIZE));
136  memset(ctx->tag_state, 0, CX_AES_BLOCK_SIZE);
137  memcpy(ctx->tag_state, input, in_len);
138  add_one_and_zeros_padding(ctx->tag_state, CX_AES_BLOCK_SIZE, in_len);
139  cx_memxor(tmp, ctx->tag_state, CX_AES_BLOCK_SIZE);
140  CX_CHECK(cx_cmac_update(ctx->cipher_ctx, tmp, CX_AES_BLOCK_SIZE));
141  CX_CHECK(cx_cmac_finish(ctx->cipher_ctx, ctx->tag_state));
142  }
143  else {
144  CX_CHECK(cx_cmac_update(ctx->cipher_ctx, input, in_len - CX_AES_BLOCK_SIZE));
145  cx_memxor(ctx->tag_state, input + in_len - CX_AES_BLOCK_SIZE, CX_AES_BLOCK_SIZE);
146  CX_CHECK(cx_cmac_update(ctx->cipher_ctx, ctx->tag_state, CX_AES_BLOCK_SIZE));
147  CX_CHECK(cx_cmac_finish(ctx->cipher_ctx, ctx->tag_state));
148  }
149  if (CX_DECRYPT == ctx->mode) {
150  return cx_aes_siv_check_tag(ctx, tag);
151  }
152  memcpy(tag, ctx->tag_state, CX_AES_BLOCK_SIZE);
153  // Prepare for the AES-CTR computation
154  cx_clear_bits(ctx->tag_state);
155  CX_CHECK(cx_cipher_setup(ctx->cipher_ctx, ctx->cipher_type, CX_CHAIN_CTR));
156  CX_CHECK(cx_cipher_setkey(ctx->cipher_ctx, ctx->key2, ctx->key_len, CX_ENCRYPT));
157  CX_CHECK(cx_cipher_setiv(ctx->cipher_ctx, ctx->tag_state, CX_AES_BLOCK_SIZE));
158 
159 end:
160  return error;
161 }
162 
163 cx_err_t cx_aes_siv_encrypt(cx_aes_siv_context_t *ctx,
164  const uint8_t *input,
165  size_t in_len,
166  const uint8_t *aad,
167  size_t aad_len,
168  uint8_t *output,
169  uint8_t *tag)
170 {
171  cx_err_t error;
172  cx_err_t err_reset = CX_INTERNAL_ERROR;
173  CX_CHECK(cx_aes_siv_start(ctx, CX_ENCRYPT, NULL, 0));
174  CX_CHECK(cx_aes_siv_update_aad(ctx, aad, aad_len));
175  CX_CHECK(cx_aes_siv_finish(ctx, input, in_len, tag));
176  CX_CHECK(cx_aes_siv_update(ctx, input, output, in_len));
177 end:
178  err_reset = cx_aes_siv_reset(ctx);
179  return error == CX_OK ? err_reset : error;
180 }
181 
182 cx_err_t cx_aes_siv_decrypt(cx_aes_siv_context_t *ctx,
183  const uint8_t *input,
184  size_t in_len,
185  const uint8_t *aad,
186  size_t aad_len,
187  uint8_t *output,
188  uint8_t *tag)
189 {
190  cx_err_t error;
191  cx_err_t err_reset = CX_INTERNAL_ERROR;
192  CX_CHECK(cx_aes_siv_start(ctx, CX_DECRYPT, tag, CX_AES_BLOCK_SIZE));
193  CX_CHECK(cx_aes_siv_update(ctx, input, output, in_len));
194  CX_CHECK(cx_aes_siv_reset(ctx));
195  CX_CHECK(cx_aes_siv_update_aad(ctx, aad, aad_len));
196  CX_CHECK(cx_aes_siv_finish(ctx, output, in_len, tag));
197 
198 end:
199  err_reset = cx_aes_siv_reset(ctx);
200  return error == CX_OK ? err_reset : error;
201 }
202 
203 #endif // HAVE_AES && HAVE_CMAC
204 #endif // HAVE_AES_SIV
uint8_t cx_constant_time_eq(const uint8_t *buf1, uint8_t *buf2, size_t len)
Definition: cx_utils.c:181
void cx_memxor(uint8_t *buf1, const uint8_t *buf2, size_t len)
Definition: cx_utils.c:173
Advanced Encryption Standard with Synthetic Initialization Vector (AES-SIV).
void cx_cipher_reset(cx_cipher_context_t *ctx)
Definition: cx_cipher.c:516
void add_one_and_zeros_padding(uint8_t *output, size_t out_len, size_t data_len)
Definition: cx_cipher.c:79
WARN_UNUSED_RESULT cx_err_t cx_cipher_update(cx_cipher_context_t *ctx, const uint8_t *input, size_t in_len, uint8_t *output, size_t *out_len)
Encrypt or decrypt with the given context.
Definition: cx_cipher.c:324
WARN_UNUSED_RESULT cx_err_t cx_cipher_setkey(cx_cipher_context_t *ctx, const uint8_t *key, uint32_t key_bitlen, uint32_t operation)
Set the key to use.
Definition: cx_cipher.c:253
WARN_UNUSED_RESULT cx_err_t cx_cipher_setiv(cx_cipher_context_t *ctx, const uint8_t *iv, size_t iv_len)
Set the initialization vector.
Definition: cx_cipher.c:276
WARN_UNUSED_RESULT cx_err_t cx_cipher_init(cx_cipher_context_t *ctx)
Initialize a cipher context as NONE.
Definition: cx_cipher.c:209
WARN_UNUSED_RESULT cx_err_t cx_cipher_setup(cx_cipher_context_t *ctx, const cx_cipher_id_t type, uint32_t mode)
Initialize and fill the context structure given the cipher info.
Definition: cx_cipher.c:218
CMAC (Cipher-based Message Authentication Code).
#define CX_CHAIN_CTR
Definition: lcx_common.h:148
#define CX_ENCRYPT
Definition: lcx_common.h:126
#define CX_DECRYPT
Definition: lcx_common.h:127
#define CX_CHAIN_ECB
Definition: lcx_common.h:146
unsigned char uint8_t
Definition: usbd_conf.h:53