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_set_key(cx_aes_siv_context_t *ctx, const uint8_t *key, size_t key_bitlen)
26 {
27  // AES SIV uses two keys of either 128, 192 or 256 bits each
28  if (key_bitlen > AES_SIV_MAX_KEY_LEN * AES_SIV_KEY_NUMBER * 8) {
29  return CX_INVALID_PARAMETER_SIZE;
30  }
31 
32  ctx->key_len = key_bitlen / 2;
33  memcpy(ctx->key1, key, ctx->key_len / 8);
34  memcpy(ctx->key2, key + ctx->key_len / 8, ctx->key_len / 8);
35  return CX_OK;
36 }
37 
38 cx_err_t cx_aes_siv_start(cx_aes_siv_context_t *ctx,
39  uint32_t mode,
40  const uint8_t *iv,
41  size_t iv_len)
42 {
43  uint8_t iv_used[CX_AES_BLOCK_SIZE] = {0};
44  cx_err_t error;
45 
46  // Set up cipher to be used for CMAC computation
47  CX_CHECK(cx_cipher_setup(ctx->cipher_ctx, ctx->cipher_type, CX_CHAIN_ECB));
48  CX_CHECK(cx_cmac_start(ctx->cipher_ctx, ctx->key1, ctx->key_len));
49  CX_CHECK(cx_cmac_update(ctx->cipher_ctx, iv_used, CX_AES_BLOCK_SIZE));
50  CX_CHECK(cx_cmac_finish(ctx->cipher_ctx, ctx->tag_state));
51 
52  if (CX_DECRYPT == mode) {
53  // Prepare for the AES-CTR computation
54  memcpy(iv_used, iv, iv_len);
55  cx_clear_bits(iv_used);
56  CX_CHECK(cx_cipher_setup(ctx->cipher_ctx, ctx->cipher_type, CX_CHAIN_CTR));
57  CX_CHECK(cx_cipher_setkey(ctx->cipher_ctx, ctx->key2, ctx->key_len, CX_ENCRYPT));
58  CX_CHECK(cx_cipher_setiv(ctx->cipher_ctx, iv_used, CX_AES_BLOCK_SIZE));
59  }
60  ctx->mode = mode;
61 
62 end:
63  return error;
64 }
65 
66 cx_err_t cx_aes_siv_update_aad(cx_aes_siv_context_t *ctx, const uint8_t *aad, size_t aad_len)
67 {
68  uint8_t tmp[CX_AES_BLOCK_SIZE] = {0};
69  cx_err_t error;
70 
71  CX_CHECK(cx_cipher_setup(ctx->cipher_ctx, ctx->cipher_type, CX_CHAIN_ECB));
72  CX_CHECK(cx_cmac_start(ctx->cipher_ctx, ctx->key1, ctx->key_len));
73 
74  if (NULL == aad) {
75  return CX_OK;
76  }
77 
78  CX_CHECK(cx_cmac_shift_and_xor(tmp, ctx->tag_state, CX_AES_BLOCK_SIZE));
79  CX_CHECK(cx_cmac_update(ctx->cipher_ctx, aad, aad_len));
80  CX_CHECK(cx_cmac_finish(ctx->cipher_ctx, ctx->tag_state));
81  cx_memxor(ctx->tag_state, tmp, CX_AES_BLOCK_SIZE);
82  CX_CHECK(cx_cmac_start(ctx->cipher_ctx, ctx->key1, ctx->key_len));
83 
84 end:
85  return error;
86 }
87 
88 cx_err_t cx_aes_siv_update_mac(cx_aes_siv_context_t *ctx, const uint8_t *input, size_t in_len)
89 {
90  return cx_cmac_update(ctx->cipher_ctx, input, in_len);
91 }
92 
93 cx_err_t cx_aes_siv_update(cx_aes_siv_context_t *ctx,
94  const uint8_t *input,
95  uint8_t *output,
96  size_t len)
97 {
98  size_t out_len = len;
99  cx_err_t error;
100  CX_CHECK(cx_cipher_update(ctx->cipher_ctx, input, len, output, &out_len));
101 
102 end:
103  return error;
104 }
105 
106 static cx_err_t cx_aes_siv_check_tag(cx_aes_siv_context_t *ctx, const uint8_t *tag)
107 {
108  uint8_t diff;
109  diff = cx_constant_time_eq(tag, ctx->tag_state, CX_AES_BLOCK_SIZE);
110  return diff * CX_INVALID_PARAMETER_VALUE + (1 - diff) * CX_OK;
111 }
112 
113 cx_err_t cx_aes_siv_finish(cx_aes_siv_context_t *ctx,
114  const uint8_t *input,
115  size_t in_len,
116  uint8_t *tag)
117 {
118  uint8_t tmp[CX_AES_BLOCK_SIZE] = {0};
119  cx_err_t error;
120 
121  if (in_len < CX_AES_BLOCK_SIZE) {
122  CX_CHECK(cx_cmac_shift_and_xor(tmp, ctx->tag_state, CX_AES_BLOCK_SIZE));
123  memset(ctx->tag_state, 0, CX_AES_BLOCK_SIZE);
124  memcpy(ctx->tag_state, input, in_len);
125  add_one_and_zeros_padding(ctx->tag_state, CX_AES_BLOCK_SIZE, in_len);
126  cx_memxor(tmp, ctx->tag_state, CX_AES_BLOCK_SIZE);
127  CX_CHECK(cx_cmac_update(ctx->cipher_ctx, tmp, CX_AES_BLOCK_SIZE));
128  CX_CHECK(cx_cmac_finish(ctx->cipher_ctx, ctx->tag_state));
129  }
130  else {
131  CX_CHECK(cx_cmac_update(ctx->cipher_ctx, input, in_len - CX_AES_BLOCK_SIZE));
132  cx_memxor(ctx->tag_state, input + in_len - CX_AES_BLOCK_SIZE, CX_AES_BLOCK_SIZE);
133  CX_CHECK(cx_cmac_update(ctx->cipher_ctx, ctx->tag_state, CX_AES_BLOCK_SIZE));
134  CX_CHECK(cx_cmac_finish(ctx->cipher_ctx, ctx->tag_state));
135  }
136  if (CX_DECRYPT == ctx->mode) {
137  return cx_aes_siv_check_tag(ctx, tag);
138  }
139  memcpy(tag, ctx->tag_state, CX_AES_BLOCK_SIZE);
140  // Prepare for the AES-CTR computation
141  cx_clear_bits(ctx->tag_state);
142  CX_CHECK(cx_cipher_setup(ctx->cipher_ctx, ctx->cipher_type, CX_CHAIN_CTR));
143  CX_CHECK(cx_cipher_setkey(ctx->cipher_ctx, ctx->key2, ctx->key_len, CX_ENCRYPT));
144  CX_CHECK(cx_cipher_setiv(ctx->cipher_ctx, ctx->tag_state, CX_AES_BLOCK_SIZE));
145 
146 end:
147  return error;
148 }
149 
150 cx_err_t cx_aes_siv_encrypt(cx_aes_siv_context_t *ctx,
151  const uint8_t *input,
152  size_t in_len,
153  const uint8_t *aad,
154  size_t aad_len,
155  uint8_t *output,
156  uint8_t *tag)
157 {
158  cx_err_t error;
159  CX_CHECK(cx_aes_siv_start(ctx, CX_ENCRYPT, NULL, 0));
160  CX_CHECK(cx_aes_siv_update_aad(ctx, aad, aad_len));
161  CX_CHECK(cx_aes_siv_finish(ctx, input, in_len, tag));
162  CX_CHECK(cx_aes_siv_update(ctx, input, output, in_len));
163 end:
164  return error;
165 }
166 
167 cx_err_t cx_aes_siv_decrypt(cx_aes_siv_context_t *ctx,
168  const uint8_t *input,
169  size_t in_len,
170  const uint8_t *aad,
171  size_t aad_len,
172  uint8_t *output,
173  uint8_t *tag)
174 {
175  cx_err_t error;
176  CX_CHECK(cx_aes_siv_start(ctx, CX_DECRYPT, tag, CX_AES_BLOCK_SIZE));
177  CX_CHECK(cx_aes_siv_update(ctx, input, output, in_len));
178  cx_cipher_reset(ctx->cipher_ctx);
179  CX_CHECK(cx_aes_siv_update_aad(ctx, aad, aad_len));
180  CX_CHECK(cx_aes_siv_finish(ctx, output, in_len, tag));
181 
182 end:
183  return error;
184 }
185 
186 #endif // HAVE_AES && HAVE_CMAC
187 #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