Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
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
12cx_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
25end:
26 return error;
27}
28
29cx_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);
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,
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,
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;
77end:
78 return error;
79}
80
81cx_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
109static 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
122end:
123 memset(L, 0, CMAC_MAX_BLOCK_LENGTH);
124 return error;
125}
126
127cx_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
159end:
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
167cx_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
188end:
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