Embedded SDK
Embedded SDK
cx_cmac.c
Go to the documentation of this file.
1 /* @BANNER@ */
2 
3 #ifdef HAVE_CMAC
4 #include "cx_utils.h"
5 #include "cx_ram.h"
6 #include "cx_cmac.h"
7 #include <string.h>
8 
9 #define CMAC_CONSTANT_R_64 (0x1B)
10 #define CMAC_CONSTANT_R_128 (0x87)
11 
12 cx_err_t cx_cmac_start(cx_cipher_context_t *ctx, const uint8_t *key, size_t key_bitlen)
13 {
14  cx_err_t error;
15 
16  if ((NULL == ctx) || (NULL == key)) {
17  return CX_INVALID_PARAMETER;
18  }
19 
20  CX_CHECK(cx_cipher_setkey(ctx, key, key_bitlen, CX_ENCRYPT));
21 
22  ctx->cmac_ctx = &G_cx.cmac;
23  memset(ctx->cmac_ctx, 0, sizeof(cx_cmac_context_t));
24 
25 end:
26  return error;
27 }
28 
29 cx_err_t cx_cmac_update(cx_cipher_context_t *ctx, const uint8_t *input, size_t in_len)
30 {
31  cx_err_t error;
32  size_t out_len = ctx->cipher_info->block_size;
33  size_t i, n;
34  size_t *current_len;
35 
36  if ((NULL == ctx) || (NULL == ctx->cipher_info) || (NULL == input) || (NULL == ctx->cmac_ctx)) {
37  return CX_INVALID_PARAMETER;
38  }
39 
40  current_len = &ctx->cmac_ctx->unprocessed_len;
41 
42  if ((*current_len > 0) && (in_len > ctx->cipher_info->block_size - *current_len)) {
43  memcpy(ctx->cmac_ctx->unprocessed_block + *current_len,
44  input,
45  ctx->cipher_info->block_size - *current_len);
46  cx_memxor(
47  ctx->cmac_ctx->state, ctx->cmac_ctx->unprocessed_block, ctx->cipher_info->block_size);
48  CX_CHECK(cx_cipher_update(ctx,
49  ctx->cmac_ctx->state,
50  ctx->cipher_info->block_size,
51  ctx->cmac_ctx->state,
52  &out_len));
53  input += ctx->cipher_info->block_size - *current_len;
54  in_len -= ctx->cipher_info->block_size - *current_len;
55  *current_len = 0;
56  }
57 
58  n = (in_len + ctx->cipher_info->block_size - 1) / ctx->cipher_info->block_size;
59 
60  for (i = 1; i < n; i++) {
61  cx_memxor(ctx->cmac_ctx->state, input, ctx->cipher_info->block_size);
62  CX_CHECK(cx_cipher_update(ctx,
63  ctx->cmac_ctx->state,
64  ctx->cipher_info->block_size,
65  ctx->cmac_ctx->state,
66  &out_len));
67  in_len -= ctx->cipher_info->block_size;
68  input += ctx->cipher_info->block_size;
69  }
70 
71  if (in_len > 0) {
72  memcpy(ctx->cmac_ctx->unprocessed_block + *current_len, input, in_len);
73  *current_len += in_len;
74  }
75 
76  error = CX_OK;
77 end:
78  return error;
79 }
80 
81 cx_err_t cx_cmac_shift_and_xor(uint8_t *output, uint8_t *input, size_t block_size)
82 {
83  uint8_t mask;
84  uint8_t constant = 0x00;
85  uint8_t msb = 0x00;
86  size_t i;
87 
88  switch (block_size) {
89 #ifdef HAVE_AES
90  case CX_AES_BLOCK_SIZE:
91  constant = CMAC_CONSTANT_R_128;
92  break;
93 #endif // HAVE_AES
94  default:
95  return CX_INVALID_PARAMETER_VALUE;
96  }
97 
98  for (i = 0; i < block_size; i++) {
99  output[block_size - 1 - i] = input[block_size - 1 - i] << 1 | msb;
100  msb = input[block_size - 1 - i] >> 7;
101  }
102 
103  mask = -(input[0] >> 7);
104  output[block_size - 1] ^= constant & mask;
105 
106  return CX_OK;
107 }
108 
109 static cx_err_t cx_cmac_generate_subkeys(cx_cipher_context_t *ctx,
110  uint8_t *sub_key1,
111  uint8_t *sub_key2)
112 {
113  cx_err_t error;
114  uint8_t L[CMAC_MAX_BLOCK_LENGTH];
115  size_t out_len = ctx->cipher_info->block_size;
116 
117  memset(L, 0, CMAC_MAX_BLOCK_LENGTH);
118  CX_CHECK(cx_cipher_update(ctx, L, ctx->cipher_info->block_size, L, &out_len));
119  CX_CHECK(cx_cmac_shift_and_xor(sub_key1, L, ctx->cipher_info->block_size));
120  CX_CHECK(cx_cmac_shift_and_xor(sub_key2, sub_key1, ctx->cipher_info->block_size));
121 
122 end:
123  memset(L, 0, CMAC_MAX_BLOCK_LENGTH);
124  return error;
125 }
126 
127 cx_err_t cx_cmac_finish(cx_cipher_context_t *ctx, uint8_t *output)
128 {
129  uint8_t sub_key1[CMAC_MAX_BLOCK_LENGTH];
130  uint8_t sub_key2[CMAC_MAX_BLOCK_LENGTH];
131  uint8_t last_block[CMAC_MAX_BLOCK_LENGTH];
132  cx_err_t error;
133  size_t out_len = ctx->cipher_info->block_size;
134 
135  if ((NULL == ctx) || (NULL == ctx->cipher_info) || (NULL == ctx->cmac_ctx)
136  || (NULL == output)) {
137  return CX_INVALID_PARAMETER;
138  }
139 
140  CX_CHECK(cx_cmac_generate_subkeys(ctx, sub_key1, sub_key2));
141 
142  if (ctx->cmac_ctx->unprocessed_len < ctx->cipher_info->block_size) {
143  memcpy(last_block, ctx->cmac_ctx->unprocessed_block, ctx->cmac_ctx->unprocessed_len);
145  last_block, ctx->cipher_info->block_size, ctx->cmac_ctx->unprocessed_len);
146  cx_memxor(last_block, sub_key2, ctx->cipher_info->block_size);
147  }
148  else {
149  cx_memxor(ctx->cmac_ctx->unprocessed_block, sub_key1, ctx->cipher_info->block_size);
150  memcpy(last_block, ctx->cmac_ctx->unprocessed_block, ctx->cipher_info->block_size);
151  }
152 
153  cx_memxor(ctx->cmac_ctx->state, last_block, ctx->cipher_info->block_size);
154  CX_CHECK(cx_cipher_update(
155  ctx, ctx->cmac_ctx->state, ctx->cipher_info->block_size, ctx->cmac_ctx->state, &out_len));
156 
157  memcpy(output, ctx->cmac_ctx->state, ctx->cipher_info->block_size);
158 
159 end:
160  memset(sub_key1, 0, CMAC_MAX_BLOCK_LENGTH);
161  memset(sub_key2, 0, CMAC_MAX_BLOCK_LENGTH);
162  explicit_bzero(ctx->cmac_ctx, sizeof(cx_cmac_context_t));
163  ctx->cipher_info->base->ctx_reset();
164  return error;
165 }
166 
167 cx_err_t cx_cmac(const cx_cipher_id_t type,
168  const uint8_t *key,
169  size_t key_bitlen,
170  const uint8_t *input,
171  size_t in_len,
172  uint8_t *output)
173 {
175  cx_err_t error;
176  cipher_key_t key_ctx;
177 
178  if ((NULL == key) || (NULL == input) || (NULL == output)) {
179  return CX_INVALID_PARAMETER;
180  }
181  CX_CHECK(cx_cipher_init(&ctx));
182  ctx.cipher_key = &key_ctx;
183  CX_CHECK(cx_cipher_setup(&ctx, type, CX_CHAIN_ECB));
184  CX_CHECK(cx_cmac_start(&ctx, key, key_bitlen));
185  CX_CHECK(cx_cmac_update(&ctx, input, in_len));
186  CX_CHECK(cx_cmac_finish(&ctx, output));
187 
188 end:
189  return error;
190 }
191 
192 #endif // HAVE_CMAC
union cx_u G_cx
Definition: cx_ram.c:21
void cx_memxor(uint8_t *buf1, const uint8_t *buf2, size_t len)
Definition: cx_utils.c:173
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
cx_cipher_id_t
Definition: lcx_cipher.h:36
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_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
#define CX_ENCRYPT
Definition: lcx_common.h:126
#define CX_CHAIN_ECB
Definition: lcx_common.h:146
cx_err_t(* ctx_reset)(void)
Reset.
Definition: lcx_cipher.h:64
const cipher_key_t * cipher_key
Cipher-specific context.
Definition: lcx_cipher.h:95
const cx_cipher_info_t * cipher_info
Cipher information.
Definition: lcx_cipher.h:82
size_t unprocessed_len
Length of data to process.
Definition: lcx_cipher.h:90
const cx_cipher_base_t * base
Definition: lcx_cipher.h:73
uint32_t block_size
Block size.
Definition: lcx_cipher.h:71
unsigned char uint8_t
Definition: usbd_conf.h:53
#define L(x)
Definition: ux_legacy.c:475