1*0e3d1220Sbeck /* $OpenBSD: ccm128.c,v 1.8 2023/07/08 14:56:54 beck Exp $ */
2ec07fdf1Sdjm /* ====================================================================
3ec07fdf1Sdjm * Copyright (c) 2011 The OpenSSL Project. All rights reserved.
4ec07fdf1Sdjm *
5ec07fdf1Sdjm * Redistribution and use in source and binary forms, with or without
6ec07fdf1Sdjm * modification, are permitted provided that the following conditions
7ec07fdf1Sdjm * are met:
8ec07fdf1Sdjm *
9ec07fdf1Sdjm * 1. Redistributions of source code must retain the above copyright
10ec07fdf1Sdjm * notice, this list of conditions and the following disclaimer.
11ec07fdf1Sdjm *
12ec07fdf1Sdjm * 2. Redistributions in binary form must reproduce the above copyright
13ec07fdf1Sdjm * notice, this list of conditions and the following disclaimer in
14ec07fdf1Sdjm * the documentation and/or other materials provided with the
15ec07fdf1Sdjm * distribution.
16ec07fdf1Sdjm *
17ec07fdf1Sdjm * 3. All advertising materials mentioning features or use of this
18ec07fdf1Sdjm * software must display the following acknowledgment:
19ec07fdf1Sdjm * "This product includes software developed by the OpenSSL Project
20ec07fdf1Sdjm * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21ec07fdf1Sdjm *
22ec07fdf1Sdjm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23ec07fdf1Sdjm * endorse or promote products derived from this software without
24ec07fdf1Sdjm * prior written permission. For written permission, please contact
25ec07fdf1Sdjm * openssl-core@openssl.org.
26ec07fdf1Sdjm *
27ec07fdf1Sdjm * 5. Products derived from this software may not be called "OpenSSL"
28ec07fdf1Sdjm * nor may "OpenSSL" appear in their names without prior written
29ec07fdf1Sdjm * permission of the OpenSSL Project.
30ec07fdf1Sdjm *
31ec07fdf1Sdjm * 6. Redistributions of any form whatsoever must retain the following
32ec07fdf1Sdjm * acknowledgment:
33ec07fdf1Sdjm * "This product includes software developed by the OpenSSL Project
34ec07fdf1Sdjm * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35ec07fdf1Sdjm *
36ec07fdf1Sdjm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37ec07fdf1Sdjm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38ec07fdf1Sdjm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39ec07fdf1Sdjm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
40ec07fdf1Sdjm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41ec07fdf1Sdjm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42ec07fdf1Sdjm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43ec07fdf1Sdjm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44ec07fdf1Sdjm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45ec07fdf1Sdjm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46ec07fdf1Sdjm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47ec07fdf1Sdjm * OF THE POSSIBILITY OF SUCH DAMAGE.
48ec07fdf1Sdjm * ====================================================================
49ec07fdf1Sdjm */
50ec07fdf1Sdjm
51ec07fdf1Sdjm #include <openssl/crypto.h>
52c9675a23Stb #include "modes_local.h"
53ec07fdf1Sdjm #include <string.h>
54ec07fdf1Sdjm
55ec07fdf1Sdjm #ifndef MODES_DEBUG
56ec07fdf1Sdjm # ifndef NDEBUG
57ec07fdf1Sdjm # define NDEBUG
58ec07fdf1Sdjm # endif
59ec07fdf1Sdjm #endif
60ec07fdf1Sdjm
61ec07fdf1Sdjm /* First you setup M and L parameters and pass the key schedule.
62ec07fdf1Sdjm * This is called once per session setup... */
630451f6ceSbeck void
CRYPTO_ccm128_init(CCM128_CONTEXT * ctx,unsigned int M,unsigned int L,void * key,block128_f block)640451f6ceSbeck CRYPTO_ccm128_init(CCM128_CONTEXT *ctx,
65ec07fdf1Sdjm unsigned int M, unsigned int L, void *key, block128_f block)
66ec07fdf1Sdjm {
67ec07fdf1Sdjm memset(ctx->nonce.c, 0, sizeof(ctx->nonce.c));
68ec07fdf1Sdjm ctx->nonce.c[0] = ((u8)(L - 1) & 7) | (u8)(((M - 2)/2) & 7) << 3;
69ec07fdf1Sdjm ctx->blocks = 0;
70ec07fdf1Sdjm ctx->block = block;
71ec07fdf1Sdjm ctx->key = key;
72ec07fdf1Sdjm }
73*0e3d1220Sbeck LCRYPTO_ALIAS(CRYPTO_ccm128_init);
74ec07fdf1Sdjm
75ec07fdf1Sdjm /* !!! Following interfaces are to be called *once* per packet !!! */
76ec07fdf1Sdjm
77ec07fdf1Sdjm /* Then you setup per-message nonce and pass the length of the message */
780451f6ceSbeck int
CRYPTO_ccm128_setiv(CCM128_CONTEXT * ctx,const unsigned char * nonce,size_t nlen,size_t mlen)790451f6ceSbeck CRYPTO_ccm128_setiv(CCM128_CONTEXT *ctx,
80ec07fdf1Sdjm const unsigned char *nonce, size_t nlen, size_t mlen)
81ec07fdf1Sdjm {
82ec07fdf1Sdjm unsigned int L = ctx->nonce.c[0] & 7; /* the L parameter */
83ec07fdf1Sdjm
840451f6ceSbeck if (nlen < (14 - L))
850451f6ceSbeck return -1; /* nonce is too short */
86ec07fdf1Sdjm
87ec07fdf1Sdjm if (sizeof(mlen) == 8 && L >= 3) {
88ec07fdf1Sdjm ctx->nonce.c[8] = (u8)(mlen >> (56 % (sizeof(mlen)*8)));
89ec07fdf1Sdjm ctx->nonce.c[9] = (u8)(mlen >> (48 % (sizeof(mlen)*8)));
90ec07fdf1Sdjm ctx->nonce.c[10] = (u8)(mlen >> (40 % (sizeof(mlen)*8)));
91ec07fdf1Sdjm ctx->nonce.c[11] = (u8)(mlen >> (32 % (sizeof(mlen)*8)));
920451f6ceSbeck } else
939eac5592Smiod ctx->nonce.u[1] = 0;
94ec07fdf1Sdjm
95ec07fdf1Sdjm ctx->nonce.c[12] = (u8)(mlen >> 24);
96ec07fdf1Sdjm ctx->nonce.c[13] = (u8)(mlen >> 16);
97ec07fdf1Sdjm ctx->nonce.c[14] = (u8)(mlen >> 8);
98ec07fdf1Sdjm ctx->nonce.c[15] = (u8)mlen;
99ec07fdf1Sdjm
100ec07fdf1Sdjm ctx->nonce.c[0] &= ~0x40; /* clear Adata flag */
101ec07fdf1Sdjm memcpy(&ctx->nonce.c[1], nonce, 14 - L);
102ec07fdf1Sdjm
103ec07fdf1Sdjm return 0;
104ec07fdf1Sdjm }
105*0e3d1220Sbeck LCRYPTO_ALIAS(CRYPTO_ccm128_setiv);
106ec07fdf1Sdjm
107ec07fdf1Sdjm /* Then you pass additional authentication data, this is optional */
1080451f6ceSbeck void
CRYPTO_ccm128_aad(CCM128_CONTEXT * ctx,const unsigned char * aad,size_t alen)1090451f6ceSbeck CRYPTO_ccm128_aad(CCM128_CONTEXT *ctx,
110ec07fdf1Sdjm const unsigned char *aad, size_t alen)
1110451f6ceSbeck {
1120451f6ceSbeck unsigned int i;
113ec07fdf1Sdjm block128_f block = ctx->block;
114ec07fdf1Sdjm
1150451f6ceSbeck if (alen == 0)
1160451f6ceSbeck return;
117ec07fdf1Sdjm
118ec07fdf1Sdjm ctx->nonce.c[0] |= 0x40; /* set Adata flag */
119ec07fdf1Sdjm (*block)(ctx->nonce.c, ctx->cmac.c, ctx->key),
120ec07fdf1Sdjm ctx->blocks++;
121ec07fdf1Sdjm
122ec07fdf1Sdjm if (alen < (0x10000 - 0x100)) {
123ec07fdf1Sdjm ctx->cmac.c[0] ^= (u8)(alen >> 8);
124ec07fdf1Sdjm ctx->cmac.c[1] ^= (u8)alen;
125ec07fdf1Sdjm i = 2;
1260451f6ceSbeck } else if (sizeof(alen) == 8 &&
1270451f6ceSbeck alen >= (size_t)1 << (32 % (sizeof(alen)*8))) {
128ec07fdf1Sdjm ctx->cmac.c[0] ^= 0xFF;
129ec07fdf1Sdjm ctx->cmac.c[1] ^= 0xFF;
130ec07fdf1Sdjm ctx->cmac.c[2] ^= (u8)(alen >> (56 % (sizeof(alen)*8)));
131ec07fdf1Sdjm ctx->cmac.c[3] ^= (u8)(alen >> (48 % (sizeof(alen)*8)));
132ec07fdf1Sdjm ctx->cmac.c[4] ^= (u8)(alen >> (40 % (sizeof(alen)*8)));
133ec07fdf1Sdjm ctx->cmac.c[5] ^= (u8)(alen >> (32 % (sizeof(alen)*8)));
134ec07fdf1Sdjm ctx->cmac.c[6] ^= (u8)(alen >> 24);
135ec07fdf1Sdjm ctx->cmac.c[7] ^= (u8)(alen >> 16);
136ec07fdf1Sdjm ctx->cmac.c[8] ^= (u8)(alen >> 8);
137ec07fdf1Sdjm ctx->cmac.c[9] ^= (u8)alen;
138ec07fdf1Sdjm i = 10;
1390451f6ceSbeck } else {
140ec07fdf1Sdjm ctx->cmac.c[0] ^= 0xFF;
141ec07fdf1Sdjm ctx->cmac.c[1] ^= 0xFE;
142ec07fdf1Sdjm ctx->cmac.c[2] ^= (u8)(alen >> 24);
143ec07fdf1Sdjm ctx->cmac.c[3] ^= (u8)(alen >> 16);
144ec07fdf1Sdjm ctx->cmac.c[4] ^= (u8)(alen >> 8);
145ec07fdf1Sdjm ctx->cmac.c[5] ^= (u8)alen;
146ec07fdf1Sdjm i = 6;
147ec07fdf1Sdjm }
148ec07fdf1Sdjm
149ec07fdf1Sdjm do {
150ec07fdf1Sdjm for (; i < 16 && alen; ++i, ++aad, --alen)
151ec07fdf1Sdjm ctx->cmac.c[i] ^= *aad;
152ec07fdf1Sdjm (*block)(ctx->cmac.c, ctx->cmac.c, ctx->key),
153ec07fdf1Sdjm ctx->blocks++;
154ec07fdf1Sdjm i = 0;
155ec07fdf1Sdjm } while (alen);
156ec07fdf1Sdjm }
157*0e3d1220Sbeck LCRYPTO_ALIAS(CRYPTO_ccm128_aad);
158ec07fdf1Sdjm
159ec07fdf1Sdjm /* Finally you encrypt or decrypt the message */
160ec07fdf1Sdjm
161ec07fdf1Sdjm /* counter part of nonce may not be larger than L*8 bits,
162ec07fdf1Sdjm * L is not larger than 8, therefore 64-bit counter... */
1630451f6ceSbeck static void
ctr64_inc(unsigned char * counter)1640451f6ceSbeck ctr64_inc(unsigned char *counter)
1650451f6ceSbeck {
166ec07fdf1Sdjm unsigned int n = 8;
167ec07fdf1Sdjm u8 c;
168ec07fdf1Sdjm
169ec07fdf1Sdjm counter += 8;
170ec07fdf1Sdjm do {
171ec07fdf1Sdjm --n;
172ec07fdf1Sdjm c = counter[n];
173ec07fdf1Sdjm ++c;
174ec07fdf1Sdjm counter[n] = c;
1750451f6ceSbeck if (c)
1760451f6ceSbeck return;
177ec07fdf1Sdjm } while (n);
178ec07fdf1Sdjm }
179ec07fdf1Sdjm
1800451f6ceSbeck int
CRYPTO_ccm128_encrypt(CCM128_CONTEXT * ctx,const unsigned char * inp,unsigned char * out,size_t len)1810451f6ceSbeck CRYPTO_ccm128_encrypt(CCM128_CONTEXT *ctx,
182ec07fdf1Sdjm const unsigned char *inp, unsigned char *out,
183ec07fdf1Sdjm size_t len)
184ec07fdf1Sdjm {
185ec07fdf1Sdjm size_t n;
186ec07fdf1Sdjm unsigned int i, L;
187ec07fdf1Sdjm unsigned char flags0 = ctx->nonce.c[0];
188ec07fdf1Sdjm block128_f block = ctx->block;
189ec07fdf1Sdjm void *key = ctx->key;
1900451f6ceSbeck union {
1910451f6ceSbeck u64 u[2];
1920451f6ceSbeck u8 c[16];
1930451f6ceSbeck } scratch;
194ec07fdf1Sdjm
195ec07fdf1Sdjm if (!(flags0 & 0x40))
196ec07fdf1Sdjm (*block)(ctx->nonce.c, ctx->cmac.c, key),
197ec07fdf1Sdjm ctx->blocks++;
198ec07fdf1Sdjm
199ec07fdf1Sdjm ctx->nonce.c[0] = L = flags0 & 7;
200ec07fdf1Sdjm for (n = 0, i = 15 - L; i < 15; ++i) {
201ec07fdf1Sdjm n |= ctx->nonce.c[i];
202ec07fdf1Sdjm ctx->nonce.c[i] = 0;
203ec07fdf1Sdjm n <<= 8;
204ec07fdf1Sdjm }
205ec07fdf1Sdjm n |= ctx->nonce.c[15]; /* reconstructed length */
206ec07fdf1Sdjm ctx->nonce.c[15] = 1;
207ec07fdf1Sdjm
2080451f6ceSbeck if (n != len)
2090451f6ceSbeck return -1; /* length mismatch */
210ec07fdf1Sdjm
211ec07fdf1Sdjm ctx->blocks += ((len + 15) >> 3)|1;
2120451f6ceSbeck if (ctx->blocks > (U64(1) << 61))
2130451f6ceSbeck return -2; /* too much data */
214ec07fdf1Sdjm
215ec07fdf1Sdjm while (len >= 16) {
216d57444e6Smiod #ifdef __STRICT_ALIGNMENT
2170451f6ceSbeck union {
2180451f6ceSbeck u64 u[2];
2190451f6ceSbeck u8 c[16];
2200451f6ceSbeck } temp;
221ec07fdf1Sdjm
222ec07fdf1Sdjm memcpy(temp.c, inp, 16);
223ec07fdf1Sdjm ctx->cmac.u[0] ^= temp.u[0];
224ec07fdf1Sdjm ctx->cmac.u[1] ^= temp.u[1];
225ec07fdf1Sdjm #else
226ec07fdf1Sdjm ctx->cmac.u[0] ^= ((u64 *)inp)[0];
227ec07fdf1Sdjm ctx->cmac.u[1] ^= ((u64 *)inp)[1];
228ec07fdf1Sdjm #endif
229ec07fdf1Sdjm (*block)(ctx->cmac.c, ctx->cmac.c, key);
230ec07fdf1Sdjm (*block)(ctx->nonce.c, scratch.c, key);
231ec07fdf1Sdjm ctr64_inc(ctx->nonce.c);
232d57444e6Smiod #ifdef __STRICT_ALIGNMENT
233ec07fdf1Sdjm temp.u[0] ^= scratch.u[0];
234ec07fdf1Sdjm temp.u[1] ^= scratch.u[1];
235ec07fdf1Sdjm memcpy(out, temp.c, 16);
236ec07fdf1Sdjm #else
237ec07fdf1Sdjm ((u64 *)out)[0] = scratch.u[0] ^ ((u64 *)inp)[0];
238ec07fdf1Sdjm ((u64 *)out)[1] = scratch.u[1] ^ ((u64 *)inp)[1];
239ec07fdf1Sdjm #endif
240ec07fdf1Sdjm inp += 16;
241ec07fdf1Sdjm out += 16;
242ec07fdf1Sdjm len -= 16;
243ec07fdf1Sdjm }
244ec07fdf1Sdjm
245ec07fdf1Sdjm if (len) {
2460451f6ceSbeck for (i = 0; i < len; ++i)
2470451f6ceSbeck ctx->cmac.c[i] ^= inp[i];
248ec07fdf1Sdjm (*block)(ctx->cmac.c, ctx->cmac.c, key);
249ec07fdf1Sdjm (*block)(ctx->nonce.c, scratch.c, key);
2500451f6ceSbeck for (i = 0; i < len; ++i)
2510451f6ceSbeck out[i] = scratch.c[i] ^ inp[i];
252ec07fdf1Sdjm }
253ec07fdf1Sdjm
254ec07fdf1Sdjm for (i = 15 - L; i < 16; ++i)
255ec07fdf1Sdjm ctx->nonce.c[i] = 0;
256ec07fdf1Sdjm
257ec07fdf1Sdjm (*block)(ctx->nonce.c, scratch.c, key);
258ec07fdf1Sdjm ctx->cmac.u[0] ^= scratch.u[0];
259ec07fdf1Sdjm ctx->cmac.u[1] ^= scratch.u[1];
260ec07fdf1Sdjm
261ec07fdf1Sdjm ctx->nonce.c[0] = flags0;
262ec07fdf1Sdjm
263ec07fdf1Sdjm return 0;
264ec07fdf1Sdjm }
265*0e3d1220Sbeck LCRYPTO_ALIAS(CRYPTO_ccm128_encrypt);
266ec07fdf1Sdjm
2670451f6ceSbeck int
CRYPTO_ccm128_decrypt(CCM128_CONTEXT * ctx,const unsigned char * inp,unsigned char * out,size_t len)2680451f6ceSbeck CRYPTO_ccm128_decrypt(CCM128_CONTEXT *ctx,
269ec07fdf1Sdjm const unsigned char *inp, unsigned char *out,
270ec07fdf1Sdjm size_t len)
271ec07fdf1Sdjm {
272ec07fdf1Sdjm size_t n;
273ec07fdf1Sdjm unsigned int i, L;
274ec07fdf1Sdjm unsigned char flags0 = ctx->nonce.c[0];
275ec07fdf1Sdjm block128_f block = ctx->block;
276ec07fdf1Sdjm void *key = ctx->key;
2770451f6ceSbeck union {
2780451f6ceSbeck u64 u[2];
2790451f6ceSbeck u8 c[16];
2800451f6ceSbeck } scratch;
281ec07fdf1Sdjm
282ec07fdf1Sdjm if (!(flags0 & 0x40))
283ec07fdf1Sdjm (*block)(ctx->nonce.c, ctx->cmac.c, key);
284ec07fdf1Sdjm
285ec07fdf1Sdjm ctx->nonce.c[0] = L = flags0 & 7;
286ec07fdf1Sdjm for (n = 0, i = 15 - L; i < 15; ++i) {
287ec07fdf1Sdjm n |= ctx->nonce.c[i];
288ec07fdf1Sdjm ctx->nonce.c[i] = 0;
289ec07fdf1Sdjm n <<= 8;
290ec07fdf1Sdjm }
291ec07fdf1Sdjm n |= ctx->nonce.c[15]; /* reconstructed length */
292ec07fdf1Sdjm ctx->nonce.c[15] = 1;
293ec07fdf1Sdjm
2940451f6ceSbeck if (n != len)
2950451f6ceSbeck return -1;
296ec07fdf1Sdjm
297ec07fdf1Sdjm while (len >= 16) {
298d57444e6Smiod #ifdef __STRICT_ALIGNMENT
2990451f6ceSbeck union {
3000451f6ceSbeck u64 u[2];
3010451f6ceSbeck u8 c[16];
3020451f6ceSbeck } temp;
303ec07fdf1Sdjm #endif
304ec07fdf1Sdjm (*block)(ctx->nonce.c, scratch.c, key);
305ec07fdf1Sdjm ctr64_inc(ctx->nonce.c);
306d57444e6Smiod #ifdef __STRICT_ALIGNMENT
307ec07fdf1Sdjm memcpy(temp.c, inp, 16);
308ec07fdf1Sdjm ctx->cmac.u[0] ^= (scratch.u[0] ^= temp.u[0]);
309ec07fdf1Sdjm ctx->cmac.u[1] ^= (scratch.u[1] ^= temp.u[1]);
310ec07fdf1Sdjm memcpy(out, scratch.c, 16);
311ec07fdf1Sdjm #else
3120451f6ceSbeck ctx->cmac.u[0] ^= (((u64 *)out)[0] = scratch.u[0] ^
3130451f6ceSbeck ((u64 *)inp)[0]);
3140451f6ceSbeck ctx->cmac.u[1] ^= (((u64 *)out)[1] = scratch.u[1] ^
3150451f6ceSbeck ((u64 *)inp)[1]);
316ec07fdf1Sdjm #endif
317ec07fdf1Sdjm (*block)(ctx->cmac.c, ctx->cmac.c, key);
318ec07fdf1Sdjm
319ec07fdf1Sdjm inp += 16;
320ec07fdf1Sdjm out += 16;
321ec07fdf1Sdjm len -= 16;
322ec07fdf1Sdjm }
323ec07fdf1Sdjm
324ec07fdf1Sdjm if (len) {
325ec07fdf1Sdjm (*block)(ctx->nonce.c, scratch.c, key);
326ec07fdf1Sdjm for (i = 0; i < len; ++i)
327ec07fdf1Sdjm ctx->cmac.c[i] ^= (out[i] = scratch.c[i] ^ inp[i]);
328ec07fdf1Sdjm (*block)(ctx->cmac.c, ctx->cmac.c, key);
329ec07fdf1Sdjm }
330ec07fdf1Sdjm
331ec07fdf1Sdjm for (i = 15 - L; i < 16; ++i)
332ec07fdf1Sdjm ctx->nonce.c[i] = 0;
333ec07fdf1Sdjm
334ec07fdf1Sdjm (*block)(ctx->nonce.c, scratch.c, key);
335ec07fdf1Sdjm ctx->cmac.u[0] ^= scratch.u[0];
336ec07fdf1Sdjm ctx->cmac.u[1] ^= scratch.u[1];
337ec07fdf1Sdjm
338ec07fdf1Sdjm ctx->nonce.c[0] = flags0;
339ec07fdf1Sdjm
340ec07fdf1Sdjm return 0;
341ec07fdf1Sdjm }
342*0e3d1220Sbeck LCRYPTO_ALIAS(CRYPTO_ccm128_decrypt);
343ec07fdf1Sdjm
3440451f6ceSbeck static void
ctr64_add(unsigned char * counter,size_t inc)3450451f6ceSbeck ctr64_add(unsigned char *counter, size_t inc)
3460451f6ceSbeck {
3470451f6ceSbeck size_t n = 8, val = 0;
348ec07fdf1Sdjm
349ec07fdf1Sdjm counter += 8;
350ec07fdf1Sdjm do {
351ec07fdf1Sdjm --n;
352ec07fdf1Sdjm val += counter[n] + (inc & 0xff);
353ec07fdf1Sdjm counter[n] = (unsigned char)val;
354ec07fdf1Sdjm val >>= 8; /* carry bit */
355ec07fdf1Sdjm inc >>= 8;
356ec07fdf1Sdjm } while (n && (inc || val));
357ec07fdf1Sdjm }
358ec07fdf1Sdjm
3590451f6ceSbeck int
CRYPTO_ccm128_encrypt_ccm64(CCM128_CONTEXT * ctx,const unsigned char * inp,unsigned char * out,size_t len,ccm128_f stream)3600451f6ceSbeck CRYPTO_ccm128_encrypt_ccm64(CCM128_CONTEXT *ctx,
361ec07fdf1Sdjm const unsigned char *inp, unsigned char *out,
362ec07fdf1Sdjm size_t len, ccm128_f stream)
363ec07fdf1Sdjm {
364ec07fdf1Sdjm size_t n;
365ec07fdf1Sdjm unsigned int i, L;
366ec07fdf1Sdjm unsigned char flags0 = ctx->nonce.c[0];
367ec07fdf1Sdjm block128_f block = ctx->block;
368ec07fdf1Sdjm void *key = ctx->key;
3690451f6ceSbeck union {
3700451f6ceSbeck u64 u[2];
3710451f6ceSbeck u8 c[16];
3720451f6ceSbeck } scratch;
373ec07fdf1Sdjm
374ec07fdf1Sdjm if (!(flags0 & 0x40))
375ec07fdf1Sdjm (*block)(ctx->nonce.c, ctx->cmac.c, key),
376ec07fdf1Sdjm ctx->blocks++;
377ec07fdf1Sdjm
378ec07fdf1Sdjm ctx->nonce.c[0] = L = flags0 & 7;
379ec07fdf1Sdjm for (n = 0, i = 15 - L; i < 15; ++i) {
380ec07fdf1Sdjm n |= ctx->nonce.c[i];
381ec07fdf1Sdjm ctx->nonce.c[i] = 0;
382ec07fdf1Sdjm n <<= 8;
383ec07fdf1Sdjm }
384ec07fdf1Sdjm n |= ctx->nonce.c[15]; /* reconstructed length */
385ec07fdf1Sdjm ctx->nonce.c[15] = 1;
386ec07fdf1Sdjm
3870451f6ceSbeck if (n != len)
3880451f6ceSbeck return -1; /* length mismatch */
389ec07fdf1Sdjm
390ec07fdf1Sdjm ctx->blocks += ((len + 15) >> 3)|1;
3910451f6ceSbeck if (ctx->blocks > (U64(1) << 61))
3920451f6ceSbeck return -2; /* too much data */
393ec07fdf1Sdjm
394ec07fdf1Sdjm if ((n = len/16)) {
395ec07fdf1Sdjm (*stream)(inp, out, n, key, ctx->nonce.c, ctx->cmac.c);
396ec07fdf1Sdjm n *= 16;
397ec07fdf1Sdjm inp += n;
398ec07fdf1Sdjm out += n;
399ec07fdf1Sdjm len -= n;
4000451f6ceSbeck if (len)
4010451f6ceSbeck ctr64_add(ctx->nonce.c, n/16);
402ec07fdf1Sdjm }
403ec07fdf1Sdjm
404ec07fdf1Sdjm if (len) {
4050451f6ceSbeck for (i = 0; i < len; ++i)
4060451f6ceSbeck ctx->cmac.c[i] ^= inp[i];
407ec07fdf1Sdjm (*block)(ctx->cmac.c, ctx->cmac.c, key);
408ec07fdf1Sdjm (*block)(ctx->nonce.c, scratch.c, key);
4090451f6ceSbeck for (i = 0; i < len; ++i)
4100451f6ceSbeck out[i] = scratch.c[i] ^ inp[i];
411ec07fdf1Sdjm }
412ec07fdf1Sdjm
413ec07fdf1Sdjm for (i = 15 - L; i < 16; ++i)
414ec07fdf1Sdjm ctx->nonce.c[i] = 0;
415ec07fdf1Sdjm
416ec07fdf1Sdjm (*block)(ctx->nonce.c, scratch.c, key);
417ec07fdf1Sdjm ctx->cmac.u[0] ^= scratch.u[0];
418ec07fdf1Sdjm ctx->cmac.u[1] ^= scratch.u[1];
419ec07fdf1Sdjm
420ec07fdf1Sdjm ctx->nonce.c[0] = flags0;
421ec07fdf1Sdjm
422ec07fdf1Sdjm return 0;
423ec07fdf1Sdjm }
424*0e3d1220Sbeck LCRYPTO_ALIAS(CRYPTO_ccm128_encrypt_ccm64);
425ec07fdf1Sdjm
4260451f6ceSbeck int
CRYPTO_ccm128_decrypt_ccm64(CCM128_CONTEXT * ctx,const unsigned char * inp,unsigned char * out,size_t len,ccm128_f stream)4270451f6ceSbeck CRYPTO_ccm128_decrypt_ccm64(CCM128_CONTEXT *ctx,
428ec07fdf1Sdjm const unsigned char *inp, unsigned char *out,
429ec07fdf1Sdjm size_t len, ccm128_f stream)
430ec07fdf1Sdjm {
431ec07fdf1Sdjm size_t n;
432ec07fdf1Sdjm unsigned int i, L;
433ec07fdf1Sdjm unsigned char flags0 = ctx->nonce.c[0];
434ec07fdf1Sdjm block128_f block = ctx->block;
435ec07fdf1Sdjm void *key = ctx->key;
4360451f6ceSbeck union {
4370451f6ceSbeck u64 u[2];
4380451f6ceSbeck u8 c[16];
4390451f6ceSbeck } scratch;
440ec07fdf1Sdjm
441ec07fdf1Sdjm if (!(flags0 & 0x40))
442ec07fdf1Sdjm (*block)(ctx->nonce.c, ctx->cmac.c, key);
443ec07fdf1Sdjm
444ec07fdf1Sdjm ctx->nonce.c[0] = L = flags0 & 7;
445ec07fdf1Sdjm for (n = 0, i = 15 - L; i < 15; ++i) {
446ec07fdf1Sdjm n |= ctx->nonce.c[i];
447ec07fdf1Sdjm ctx->nonce.c[i] = 0;
448ec07fdf1Sdjm n <<= 8;
449ec07fdf1Sdjm }
450ec07fdf1Sdjm n |= ctx->nonce.c[15]; /* reconstructed length */
451ec07fdf1Sdjm ctx->nonce.c[15] = 1;
452ec07fdf1Sdjm
4530451f6ceSbeck if (n != len)
4540451f6ceSbeck return -1;
455ec07fdf1Sdjm
456ec07fdf1Sdjm if ((n = len/16)) {
457ec07fdf1Sdjm (*stream)(inp, out, n, key, ctx->nonce.c, ctx->cmac.c);
458ec07fdf1Sdjm n *= 16;
459ec07fdf1Sdjm inp += n;
460ec07fdf1Sdjm out += n;
461ec07fdf1Sdjm len -= n;
4620451f6ceSbeck if (len)
4630451f6ceSbeck ctr64_add(ctx->nonce.c, n/16);
464ec07fdf1Sdjm }
465ec07fdf1Sdjm
466ec07fdf1Sdjm if (len) {
467ec07fdf1Sdjm (*block)(ctx->nonce.c, scratch.c, key);
468ec07fdf1Sdjm for (i = 0; i < len; ++i)
469ec07fdf1Sdjm ctx->cmac.c[i] ^= (out[i] = scratch.c[i] ^ inp[i]);
470ec07fdf1Sdjm (*block)(ctx->cmac.c, ctx->cmac.c, key);
471ec07fdf1Sdjm }
472ec07fdf1Sdjm
473ec07fdf1Sdjm for (i = 15 - L; i < 16; ++i)
474ec07fdf1Sdjm ctx->nonce.c[i] = 0;
475ec07fdf1Sdjm
476ec07fdf1Sdjm (*block)(ctx->nonce.c, scratch.c, key);
477ec07fdf1Sdjm ctx->cmac.u[0] ^= scratch.u[0];
478ec07fdf1Sdjm ctx->cmac.u[1] ^= scratch.u[1];
479ec07fdf1Sdjm
480ec07fdf1Sdjm ctx->nonce.c[0] = flags0;
481ec07fdf1Sdjm
482ec07fdf1Sdjm return 0;
483ec07fdf1Sdjm }
484*0e3d1220Sbeck LCRYPTO_ALIAS(CRYPTO_ccm128_decrypt_ccm64);
485ec07fdf1Sdjm
4860451f6ceSbeck size_t
CRYPTO_ccm128_tag(CCM128_CONTEXT * ctx,unsigned char * tag,size_t len)4870451f6ceSbeck CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx, unsigned char *tag, size_t len)
4880451f6ceSbeck {
4890451f6ceSbeck unsigned int M = (ctx->nonce.c[0] >> 3) & 7; /* the M parameter */
490ec07fdf1Sdjm
4910451f6ceSbeck M *= 2;
4920451f6ceSbeck M += 2;
4930451f6ceSbeck if (len != M)
4940451f6ceSbeck return 0;
495ec07fdf1Sdjm memcpy(tag, ctx->cmac.c, M);
496ec07fdf1Sdjm return M;
497ec07fdf1Sdjm }
498*0e3d1220Sbeck LCRYPTO_ALIAS(CRYPTO_ccm128_tag);
499