/src/strongswan/src/libstrongswan/plugins/cmac/cmac.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2012 Tobias Brunner |
3 | | * |
4 | | * Copyright (C) secunet Security Networks AG |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify it |
7 | | * under the terms of the GNU General Public License as published by the |
8 | | * Free Software Foundation; either version 2 of the License, or (at your |
9 | | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, but |
12 | | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
13 | | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | | * for more details. |
15 | | */ |
16 | | |
17 | | #include <string.h> |
18 | | |
19 | | #include "cmac.h" |
20 | | |
21 | | #include <utils/debug.h> |
22 | | #include <crypto/mac.h> |
23 | | #include <crypto/prfs/mac_prf.h> |
24 | | #include <crypto/signers/mac_signer.h> |
25 | | |
26 | | typedef struct private_mac_t private_mac_t; |
27 | | |
28 | | /** |
29 | | * Private data of a mac_t object. |
30 | | * |
31 | | * The variable names are the same as in the RFC. |
32 | | */ |
33 | | struct private_mac_t { |
34 | | |
35 | | /** |
36 | | * Public interface. |
37 | | */ |
38 | | mac_t public; |
39 | | |
40 | | /** |
41 | | * Block size, in bytes |
42 | | */ |
43 | | uint8_t b; |
44 | | |
45 | | /** |
46 | | * Crypter with key K |
47 | | */ |
48 | | crypter_t *k; |
49 | | |
50 | | /** |
51 | | * K1 |
52 | | */ |
53 | | uint8_t *k1; |
54 | | |
55 | | /** |
56 | | * K2 |
57 | | */ |
58 | | uint8_t *k2; |
59 | | |
60 | | /** |
61 | | * T |
62 | | */ |
63 | | uint8_t *t; |
64 | | |
65 | | /** |
66 | | * remaining, unprocessed bytes in append mode |
67 | | */ |
68 | | uint8_t *remaining; |
69 | | |
70 | | /** |
71 | | * number of bytes in remaining |
72 | | */ |
73 | | int remaining_bytes; |
74 | | }; |
75 | | |
76 | | /** |
77 | | * process supplied data, but do not run final operation |
78 | | */ |
79 | | static bool update(private_mac_t *this, chunk_t data) |
80 | 0 | { |
81 | 0 | chunk_t iv; |
82 | |
|
83 | 0 | if (this->remaining_bytes + data.len <= this->b) |
84 | 0 | { /* no complete block (or last block), just copy into remaining */ |
85 | 0 | memcpy(this->remaining + this->remaining_bytes, data.ptr, data.len); |
86 | 0 | this->remaining_bytes += data.len; |
87 | 0 | return TRUE; |
88 | 0 | } |
89 | | |
90 | 0 | iv = chunk_alloca(this->b); |
91 | 0 | memset(iv.ptr, 0, iv.len); |
92 | | |
93 | | /* T := 0x00000000000000000000000000000000 (initially) |
94 | | * for each block M_i (except the last) |
95 | | * X := T XOR M_i; |
96 | | * T := AES-128(K, X); |
97 | | */ |
98 | | |
99 | | /* append data to remaining bytes, process block M_1 */ |
100 | 0 | memcpy(this->remaining + this->remaining_bytes, data.ptr, |
101 | 0 | this->b - this->remaining_bytes); |
102 | 0 | data = chunk_skip(data, this->b - this->remaining_bytes); |
103 | 0 | memxor(this->t, this->remaining, this->b); |
104 | 0 | if (!this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL)) |
105 | 0 | { |
106 | 0 | return FALSE; |
107 | 0 | } |
108 | | |
109 | | /* process blocks M_2 ... M_n-1 */ |
110 | 0 | while (data.len > this->b) |
111 | 0 | { |
112 | 0 | memcpy(this->remaining, data.ptr, this->b); |
113 | 0 | data = chunk_skip(data, this->b); |
114 | 0 | memxor(this->t, this->remaining, this->b); |
115 | 0 | if (!this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL)) |
116 | 0 | { |
117 | 0 | return FALSE; |
118 | 0 | } |
119 | 0 | } |
120 | | |
121 | | /* store remaining bytes of block M_n */ |
122 | 0 | memcpy(this->remaining, data.ptr, data.len); |
123 | 0 | this->remaining_bytes = data.len; |
124 | |
|
125 | 0 | return TRUE; |
126 | 0 | } |
127 | | |
128 | | /** |
129 | | * process last block M_last |
130 | | */ |
131 | | static bool final(private_mac_t *this, uint8_t *out) |
132 | 0 | { |
133 | 0 | chunk_t iv; |
134 | |
|
135 | 0 | iv = chunk_alloca(this->b); |
136 | 0 | memset(iv.ptr, 0, iv.len); |
137 | | |
138 | | /* if last block is complete |
139 | | * M_last := M_n XOR K1; |
140 | | * else |
141 | | * M_last := padding(M_n) XOR K2; |
142 | | */ |
143 | 0 | if (this->remaining_bytes == this->b) |
144 | 0 | { |
145 | 0 | memxor(this->remaining, this->k1, this->b); |
146 | 0 | } |
147 | 0 | else |
148 | 0 | { |
149 | | /* padding(x) = x || 10^i where i is 128-8*r-1 |
150 | | * That is, padding(x) is the concatenation of x and a single '1', |
151 | | * followed by the minimum number of '0's, so that the total length is |
152 | | * equal to 128 bits. |
153 | | */ |
154 | 0 | if (this->remaining_bytes < this->b) |
155 | 0 | { |
156 | 0 | this->remaining[this->remaining_bytes] = 0x80; |
157 | 0 | while (++this->remaining_bytes < this->b) |
158 | 0 | { |
159 | 0 | this->remaining[this->remaining_bytes] = 0x00; |
160 | 0 | } |
161 | 0 | } |
162 | 0 | memxor(this->remaining, this->k2, this->b); |
163 | 0 | } |
164 | | /* T := M_last XOR T; |
165 | | * T := AES-128(K,T); |
166 | | */ |
167 | 0 | memxor(this->t, this->remaining, this->b); |
168 | 0 | if (!this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL)) |
169 | 0 | { |
170 | 0 | return FALSE; |
171 | 0 | } |
172 | | |
173 | 0 | memcpy(out, this->t, this->b); |
174 | | |
175 | | /* reset state */ |
176 | 0 | memset(this->t, 0, this->b); |
177 | 0 | this->remaining_bytes = 0; |
178 | |
|
179 | 0 | return TRUE; |
180 | 0 | } |
181 | | |
182 | | METHOD(mac_t, get_mac, bool, |
183 | | private_mac_t *this, chunk_t data, uint8_t *out) |
184 | 0 | { |
185 | | /* update T, do not process last block */ |
186 | 0 | if (!update(this, data)) |
187 | 0 | { |
188 | 0 | return FALSE; |
189 | 0 | } |
190 | | |
191 | 0 | if (out) |
192 | 0 | { /* if not in append mode, process last block and output result */ |
193 | 0 | return final(this, out); |
194 | 0 | } |
195 | 0 | return TRUE; |
196 | 0 | } |
197 | | |
198 | | METHOD(mac_t, get_mac_size, size_t, |
199 | | private_mac_t *this) |
200 | 0 | { |
201 | 0 | return this->b; |
202 | 0 | } |
203 | | |
204 | | /** |
205 | | * Left-shift the given chunk by one bit. |
206 | | */ |
207 | | static void bit_shift(chunk_t chunk) |
208 | 0 | { |
209 | 0 | size_t i; |
210 | |
|
211 | 0 | for (i = 0; i < chunk.len; i++) |
212 | 0 | { |
213 | 0 | chunk.ptr[i] <<= 1; |
214 | 0 | if (i < chunk.len - 1 && chunk.ptr[i + 1] & 0x80) |
215 | 0 | { |
216 | 0 | chunk.ptr[i] |= 0x01; |
217 | 0 | } |
218 | 0 | } |
219 | 0 | } |
220 | | |
221 | | /** |
222 | | * Apply the following key derivation (in-place): |
223 | | * if MSB(C) == 0 |
224 | | * C := C << 1 |
225 | | * else |
226 | | * C := (C << 1) XOR 0x00000000000000000000000000000087 |
227 | | */ |
228 | | static void derive_key(chunk_t chunk) |
229 | 0 | { |
230 | 0 | if (chunk.ptr[0] & 0x80) |
231 | 0 | { |
232 | 0 | chunk_t rb; |
233 | |
|
234 | 0 | rb = chunk_alloca(chunk.len); |
235 | 0 | memset(rb.ptr, 0, rb.len); |
236 | 0 | rb.ptr[rb.len - 1] = 0x87; |
237 | 0 | bit_shift(chunk); |
238 | 0 | memxor(chunk.ptr, rb.ptr, chunk.len); |
239 | 0 | } |
240 | 0 | else |
241 | 0 | { |
242 | 0 | bit_shift(chunk); |
243 | 0 | } |
244 | 0 | } |
245 | | |
246 | | METHOD(mac_t, set_key, bool, |
247 | | private_mac_t *this, chunk_t key) |
248 | 0 | { |
249 | 0 | chunk_t resized, iv, l; |
250 | |
|
251 | 0 | memset(this->t, 0, this->b); |
252 | 0 | this->remaining_bytes = 0; |
253 | | |
254 | | /* we support variable keys as defined in RFC 4615 */ |
255 | 0 | if (key.len == this->b) |
256 | 0 | { |
257 | 0 | resized = key; |
258 | 0 | } |
259 | 0 | else |
260 | 0 | { /* use cmac recursively to resize longer or shorter keys */ |
261 | 0 | resized = chunk_alloca(this->b); |
262 | 0 | memset(resized.ptr, 0, resized.len); |
263 | 0 | if (!set_key(this, resized) || |
264 | 0 | !get_mac(this, key, resized.ptr)) |
265 | 0 | { |
266 | 0 | return FALSE; |
267 | 0 | } |
268 | 0 | } |
269 | | |
270 | | /* |
271 | | * Rb = 0x00000000000000000000000000000087 |
272 | | * L = 0x00000000000000000000000000000000 encrypted with K |
273 | | * if MSB(L) == 0 |
274 | | * K1 = L << 1 |
275 | | * else |
276 | | * K1 = (L << 1) XOR Rb |
277 | | * if MSB(K1) == 0 |
278 | | * K2 = K1 << 1 |
279 | | * else |
280 | | * K2 = (K1 << 1) XOR Rb |
281 | | */ |
282 | 0 | iv = chunk_alloca(this->b); |
283 | 0 | memset(iv.ptr, 0, iv.len); |
284 | 0 | l = chunk_alloca(this->b); |
285 | 0 | memset(l.ptr, 0, l.len); |
286 | 0 | if (!this->k->set_key(this->k, resized) || |
287 | 0 | !this->k->encrypt(this->k, l, iv, NULL)) |
288 | 0 | { |
289 | 0 | return FALSE; |
290 | 0 | } |
291 | 0 | derive_key(l); |
292 | 0 | memcpy(this->k1, l.ptr, l.len); |
293 | 0 | derive_key(l); |
294 | 0 | memcpy(this->k2, l.ptr, l.len); |
295 | 0 | memwipe(l.ptr, l.len); |
296 | |
|
297 | 0 | return TRUE; |
298 | 0 | } |
299 | | |
300 | | METHOD(mac_t, destroy, void, |
301 | | private_mac_t *this) |
302 | 0 | { |
303 | 0 | this->k->destroy(this->k); |
304 | 0 | memwipe(this->k1, this->b); |
305 | 0 | free(this->k1); |
306 | 0 | memwipe(this->k2, this->b); |
307 | 0 | free(this->k2); |
308 | 0 | free(this->t); |
309 | 0 | free(this->remaining); |
310 | 0 | free(this); |
311 | 0 | } |
312 | | |
313 | | /** |
314 | | * Create a generic mac_t object |
315 | | */ |
316 | | static mac_t *cmac_create(encryption_algorithm_t algo, size_t key_size) |
317 | 0 | { |
318 | 0 | private_mac_t *this; |
319 | 0 | crypter_t *crypter; |
320 | 0 | uint8_t b; |
321 | |
|
322 | 0 | crypter = lib->crypto->create_crypter(lib->crypto, algo, key_size); |
323 | 0 | if (!crypter) |
324 | 0 | { |
325 | 0 | return NULL; |
326 | 0 | } |
327 | 0 | b = crypter->get_block_size(crypter); |
328 | | /* input and output of crypter must be equal for cmac */ |
329 | 0 | if (b != key_size) |
330 | 0 | { |
331 | 0 | crypter->destroy(crypter); |
332 | 0 | return NULL; |
333 | 0 | } |
334 | | |
335 | 0 | INIT(this, |
336 | 0 | .public = { |
337 | 0 | .get_mac = _get_mac, |
338 | 0 | .get_mac_size = _get_mac_size, |
339 | 0 | .set_key = _set_key, |
340 | 0 | .destroy = _destroy, |
341 | 0 | }, |
342 | 0 | .b = b, |
343 | 0 | .k = crypter, |
344 | 0 | .k1 = malloc(b), |
345 | 0 | .k2 = malloc(b), |
346 | 0 | .t = malloc(b), |
347 | 0 | .remaining = malloc(b), |
348 | 0 | ); |
349 | 0 | memset(this->t, 0, b); |
350 | |
|
351 | 0 | return &this->public; |
352 | 0 | } |
353 | | |
354 | | /* |
355 | | * Described in header. |
356 | | */ |
357 | | prf_t *cmac_prf_create(pseudo_random_function_t algo) |
358 | 0 | { |
359 | 0 | mac_t *cmac; |
360 | |
|
361 | 0 | switch (algo) |
362 | 0 | { |
363 | 0 | case PRF_AES128_CMAC: |
364 | 0 | cmac = cmac_create(ENCR_AES_CBC, 16); |
365 | 0 | break; |
366 | 0 | default: |
367 | 0 | return NULL; |
368 | 0 | } |
369 | 0 | if (cmac) |
370 | 0 | { |
371 | 0 | return mac_prf_create(cmac); |
372 | 0 | } |
373 | 0 | return NULL; |
374 | 0 | } |
375 | | |
376 | | /* |
377 | | * Described in header |
378 | | */ |
379 | | signer_t *cmac_signer_create(integrity_algorithm_t algo) |
380 | 0 | { |
381 | 0 | size_t truncation; |
382 | 0 | mac_t *cmac; |
383 | |
|
384 | 0 | switch (algo) |
385 | 0 | { |
386 | 0 | case AUTH_AES_CMAC_96: |
387 | 0 | cmac = cmac_create(ENCR_AES_CBC, 16); |
388 | 0 | truncation = 12; |
389 | 0 | break; |
390 | 0 | default: |
391 | 0 | return NULL; |
392 | 0 | } |
393 | 0 | if (cmac) |
394 | 0 | { |
395 | 0 | return mac_signer_create(cmac, truncation); |
396 | 0 | } |
397 | 0 | return NULL; |
398 | 0 | } |