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