12c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org/* ====================================================================
22c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * Copyright (c) 2011 The OpenSSL Project.  All rights reserved.
32c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
42c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * Redistribution and use in source and binary forms, with or without
52c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * modification, are permitted provided that the following conditions
62c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * are met:
72c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
82c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * 1. Redistributions of source code must retain the above copyright
92c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    notice, this list of conditions and the following disclaimer.
102c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
112c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * 2. Redistributions in binary form must reproduce the above copyright
122c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    notice, this list of conditions and the following disclaimer in
132c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    the documentation and/or other materials provided with the
142c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    distribution.
152c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
162c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * 3. All advertising materials mentioning features or use of this
172c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    software must display the following acknowledgment:
182c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    "This product includes software developed by the OpenSSL Project
192c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
202c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
212c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
222c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    endorse or promote products derived from this software without
232c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    prior written permission. For written permission, please contact
242c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    openssl-core@openssl.org.
252c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
262c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * 5. Products derived from this software may not be called "OpenSSL"
272c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    nor may "OpenSSL" appear in their names without prior written
282c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    permission of the OpenSSL Project.
292c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
302c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * 6. Redistributions of any form whatsoever must retain the following
312c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    acknowledgment:
322c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    "This product includes software developed by the OpenSSL Project
332c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
342c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org *
352c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
362c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
372c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
382c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
392c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
402c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
412c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
422c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
432c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
442c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
452c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
462c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * OF THE POSSIBILITY OF SUCH DAMAGE.
472c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * ====================================================================
482c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org */
492c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
502c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#include <openssl/crypto.h>
512c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#include "modes_lcl.h"
522c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#include <string.h>
532c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
542c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#ifndef MODES_DEBUG
552c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org# ifndef NDEBUG
562c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#  define NDEBUG
572c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org# endif
582c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#endif
592c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#include <assert.h>
602c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
612c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org/* First you setup M and L parameters and pass the key schedule.
622c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * This is called once per session setup... */
632c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgvoid CRYPTO_ccm128_init(CCM128_CONTEXT *ctx,
642c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	unsigned int M,unsigned int L,void *key,block128_f block)
652c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org{
662c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	memset(ctx->nonce.c,0,sizeof(ctx->nonce.c));
672c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[0] = ((u8)(L-1)&7) | (u8)(((M-2)/2)&7)<<3;
682c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->blocks = 0;
692c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->block = block;
702c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->key = key;
712c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org}
722c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
732c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org/* !!! Following interfaces are to be called *once* per packet !!! */
742c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
752c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org/* Then you setup per-message nonce and pass the length of the message */
762c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgint CRYPTO_ccm128_setiv(CCM128_CONTEXT *ctx,
772c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	const unsigned char *nonce,size_t nlen,size_t mlen)
782c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org{
792c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	unsigned int L = ctx->nonce.c[0]&7;	/* the L parameter */
802c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
812c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (nlen<(14-L)) return -1;		/* nonce is too short */
822c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
832c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (sizeof(mlen)==8 && L>=3) {
842c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->nonce.c[8]  = (u8)(mlen>>(56%(sizeof(mlen)*8)));
852c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->nonce.c[9]  = (u8)(mlen>>(48%(sizeof(mlen)*8)));
862c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->nonce.c[10] = (u8)(mlen>>(40%(sizeof(mlen)*8)));
872c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->nonce.c[11] = (u8)(mlen>>(32%(sizeof(mlen)*8)));
882c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
892c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	else
902c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		*(u32*)(&ctx->nonce.c[8]) = 0;
912c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
922c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[12] = (u8)(mlen>>24);
932c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[13] = (u8)(mlen>>16);
942c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[14] = (u8)(mlen>>8);
952c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[15] = (u8)mlen;
962c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
972c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[0] &= ~0x40;	/* clear Adata flag */
982c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	memcpy(&ctx->nonce.c[1],nonce,14-L);
992c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1002c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	return 0;
1012c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org}
1022c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1032c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org/* Then you pass additional authentication data, this is optional */
1042c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgvoid CRYPTO_ccm128_aad(CCM128_CONTEXT *ctx,
1052c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	const unsigned char *aad,size_t alen)
1062c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org{	unsigned int i;
1072c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	block128_f block = ctx->block;
1082c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1092c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (alen==0) return;
1102c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1112c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[0] |= 0x40;	/* set Adata flag */
1122c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	(*block)(ctx->nonce.c,ctx->cmac.c,ctx->key),
1132c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->blocks++;
1142c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1152c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (alen<(0x10000-0x100)) {
1162c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[0] ^= (u8)(alen>>8);
1172c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[1] ^= (u8)alen;
1182c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		i=2;
1192c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
1202c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	else if (sizeof(alen)==8 && alen>=(size_t)1<<(32%(sizeof(alen)*8))) {
1212c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[0] ^= 0xFF;
1222c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[1] ^= 0xFF;
1232c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[2] ^= (u8)(alen>>(56%(sizeof(alen)*8)));
1242c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[3] ^= (u8)(alen>>(48%(sizeof(alen)*8)));
1252c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[4] ^= (u8)(alen>>(40%(sizeof(alen)*8)));
1262c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[5] ^= (u8)(alen>>(32%(sizeof(alen)*8)));
1272c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[6] ^= (u8)(alen>>24);
1282c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[7] ^= (u8)(alen>>16);
1292c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[8] ^= (u8)(alen>>8);
1302c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[9] ^= (u8)alen;
1312c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		i=10;
1322c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
1332c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	else {
1342c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[0] ^= 0xFF;
1352c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[1] ^= 0xFE;
1362c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[2] ^= (u8)(alen>>24);
1372c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[3] ^= (u8)(alen>>16);
1382c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[4] ^= (u8)(alen>>8);
1392c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.c[5] ^= (u8)alen;
1402c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		i=6;
1412c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
1422c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1432c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	do {
1442c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		for(;i<16 && alen;++i,++aad,--alen)
1452c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			ctx->cmac.c[i] ^= *aad;
1462c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->cmac.c,ctx->cmac.c,ctx->key),
1472c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->blocks++;
1482c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		i=0;
1492c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	} while (alen);
1502c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org}
1512c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1522c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org/* Finally you encrypt or decrypt the message */
1532c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1542c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org/* counter part of nonce may not be larger than L*8 bits,
1552c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org * L is not larger than 8, therefore 64-bit counter... */
1562c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgstatic void ctr64_inc(unsigned char *counter) {
1572c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	unsigned int n=8;
1582c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	u8  c;
1592c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1602c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	counter += 8;
1612c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	do {
1622c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		--n;
1632c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		c = counter[n];
1642c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		++c;
1652c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		counter[n] = c;
1662c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		if (c) return;
1672c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	} while (n);
1682c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org}
1692c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1702c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgint CRYPTO_ccm128_encrypt(CCM128_CONTEXT *ctx,
1712c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	const unsigned char *inp, unsigned char *out,
1722c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	size_t len)
1732c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org{
1742c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	size_t		n;
1752c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	unsigned int	i,L;
1762c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	unsigned char	flags0	= ctx->nonce.c[0];
1772c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	block128_f	block	= ctx->block;
1782c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	void *		key	= ctx->key;
1792c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	union { u64 u[2]; u8 c[16]; } scratch;
1802c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1812c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (!(flags0&0x40))
1822c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->nonce.c,ctx->cmac.c,key),
1832c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->blocks++;
1842c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1852c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[0] = L = flags0&7;
1862c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	for (n=0,i=15-L;i<15;++i) {
1872c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		n |= ctx->nonce.c[i];
1882c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->nonce.c[i]=0;
1892c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		n <<= 8;
1902c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
1912c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	n |= ctx->nonce.c[15];	/* reconstructed length */
1922c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[15]=1;
1932c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1942c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (n!=len) return -1;	/* length mismatch */
1952c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1962c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->blocks += ((len+15)>>3)|1;
1972c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (ctx->blocks > (U64(1)<<61))	return -2; /* too much data */
1982c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
1992c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	while (len>=16) {
2002c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#if defined(STRICT_ALIGNMENT)
2012c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		union { u64 u[2]; u8 c[16]; } temp;
2022c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2032c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		memcpy (temp.c,inp,16);
2042c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.u[0] ^= temp.u[0];
2052c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.u[1] ^= temp.u[1];
2062c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#else
2072c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.u[0] ^= ((u64*)inp)[0];
2082c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.u[1] ^= ((u64*)inp)[1];
2092c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#endif
2102c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->cmac.c,ctx->cmac.c,key);
2112c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->nonce.c,scratch.c,key);
2122c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctr64_inc(ctx->nonce.c);
2132c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#if defined(STRICT_ALIGNMENT)
2142c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		temp.u[0] ^= scratch.u[0];
2152c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		temp.u[1] ^= scratch.u[1];
2162c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		memcpy(out,temp.c,16);
2172c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#else
2182c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		((u64*)out)[0] = scratch.u[0]^((u64*)inp)[0];
2192c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		((u64*)out)[1] = scratch.u[1]^((u64*)inp)[1];
2202c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#endif
2212c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		inp += 16;
2222c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		out += 16;
2232c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		len -= 16;
2242c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
2252c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2262c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (len) {
2272c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		for (i=0; i<len; ++i) ctx->cmac.c[i] ^= inp[i];
2282c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->cmac.c,ctx->cmac.c,key);
2292c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->nonce.c,scratch.c,key);
2302c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		for (i=0; i<len; ++i) out[i] = scratch.c[i]^inp[i];
2312c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
2322c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2332c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	for (i=15-L;i<16;++i)
2342c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->nonce.c[i]=0;
2352c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2362c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	(*block)(ctx->nonce.c,scratch.c,key);
2372c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->cmac.u[0] ^= scratch.u[0];
2382c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->cmac.u[1] ^= scratch.u[1];
2392c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2402c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[0] = flags0;
2412c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2422c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	return 0;
2432c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org}
2442c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2452c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgint CRYPTO_ccm128_decrypt(CCM128_CONTEXT *ctx,
2462c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	const unsigned char *inp, unsigned char *out,
2472c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	size_t len)
2482c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org{
2492c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	size_t		n;
2502c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	unsigned int	i,L;
2512c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	unsigned char	flags0	= ctx->nonce.c[0];
2522c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	block128_f	block	= ctx->block;
2532c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	void *		key	= ctx->key;
2542c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	union { u64 u[2]; u8 c[16]; } scratch;
2552c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2562c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (!(flags0&0x40))
2572c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->nonce.c,ctx->cmac.c,key);
2582c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2592c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[0] = L = flags0&7;
2602c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	for (n=0,i=15-L;i<15;++i) {
2612c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		n |= ctx->nonce.c[i];
2622c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->nonce.c[i]=0;
2632c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		n <<= 8;
2642c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
2652c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	n |= ctx->nonce.c[15];	/* reconstructed length */
2662c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[15]=1;
2672c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2682c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (n!=len) return -1;
2692c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2702c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	while (len>=16) {
2712c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#if defined(STRICT_ALIGNMENT)
2722c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		union { u64 u[2]; u8 c[16]; } temp;
2732c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#endif
2742c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->nonce.c,scratch.c,key);
2752c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctr64_inc(ctx->nonce.c);
2762c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#if defined(STRICT_ALIGNMENT)
2772c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		memcpy (temp.c,inp,16);
2782c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.u[0] ^= (scratch.u[0] ^= temp.u[0]);
2792c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.u[1] ^= (scratch.u[1] ^= temp.u[1]);
2802c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		memcpy (out,scratch.c,16);
2812c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#else
2822c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.u[0] ^= (((u64*)out)[0] = scratch.u[0]^((u64*)inp)[0]);
2832c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->cmac.u[1] ^= (((u64*)out)[1] = scratch.u[1]^((u64*)inp)[1]);
2842c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org#endif
2852c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->cmac.c,ctx->cmac.c,key);
2862c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2872c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		inp += 16;
2882c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		out += 16;
2892c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		len -= 16;
2902c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
2912c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2922c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (len) {
2932c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->nonce.c,scratch.c,key);
2942c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		for (i=0; i<len; ++i)
2952c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			ctx->cmac.c[i] ^= (out[i] = scratch.c[i]^inp[i]);
2962c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->cmac.c,ctx->cmac.c,key);
2972c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
2982c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
2992c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	for (i=15-L;i<16;++i)
3002c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->nonce.c[i]=0;
3012c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3022c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	(*block)(ctx->nonce.c,scratch.c,key);
3032c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->cmac.u[0] ^= scratch.u[0];
3042c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->cmac.u[1] ^= scratch.u[1];
3052c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3062c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[0] = flags0;
3072c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3082c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	return 0;
3092c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org}
3102c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3112c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgstatic void ctr64_add (unsigned char *counter,size_t inc)
3122c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org{	size_t n=8, val=0;
3132c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3142c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	counter += 8;
3152c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	do {
3162c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		--n;
3172c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		val += counter[n] + (inc&0xff);
3182c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		counter[n] = (unsigned char)val;
3192c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		val >>= 8;	/* carry bit */
3202c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		inc >>= 8;
3212c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	} while(n && (inc || val));
3222c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org}
3232c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3242c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgint CRYPTO_ccm128_encrypt_ccm64(CCM128_CONTEXT *ctx,
3252c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	const unsigned char *inp, unsigned char *out,
3262c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	size_t len,ccm128_f stream)
3272c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org{
3282c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	size_t		n;
3292c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	unsigned int	i,L;
3302c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	unsigned char	flags0	= ctx->nonce.c[0];
3312c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	block128_f	block	= ctx->block;
3322c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	void *		key	= ctx->key;
3332c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	union { u64 u[2]; u8 c[16]; } scratch;
3342c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3352c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (!(flags0&0x40))
3362c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->nonce.c,ctx->cmac.c,key),
3372c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->blocks++;
3382c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3392c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[0] = L = flags0&7;
3402c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	for (n=0,i=15-L;i<15;++i) {
3412c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		n |= ctx->nonce.c[i];
3422c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->nonce.c[i]=0;
3432c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		n <<= 8;
3442c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
3452c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	n |= ctx->nonce.c[15];	/* reconstructed length */
3462c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[15]=1;
3472c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3482c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (n!=len) return -1;	/* length mismatch */
3492c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3502c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->blocks += ((len+15)>>3)|1;
3512c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (ctx->blocks > (U64(1)<<61))	return -2; /* too much data */
3522c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3532c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if ((n=len/16)) {
3542c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*stream)(inp,out,n,key,ctx->nonce.c,ctx->cmac.c);
3552c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		n   *= 16;
3562c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		inp += n;
3572c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		out += n;
3582c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		len -= n;
3592c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		if (len) ctr64_add(ctx->nonce.c,n/16);
3602c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
3612c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3622c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (len) {
3632c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		for (i=0; i<len; ++i) ctx->cmac.c[i] ^= inp[i];
3642c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->cmac.c,ctx->cmac.c,key);
3652c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->nonce.c,scratch.c,key);
3662c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		for (i=0; i<len; ++i) out[i] = scratch.c[i]^inp[i];
3672c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
3682c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3692c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	for (i=15-L;i<16;++i)
3702c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->nonce.c[i]=0;
3712c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3722c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	(*block)(ctx->nonce.c,scratch.c,key);
3732c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->cmac.u[0] ^= scratch.u[0];
3742c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->cmac.u[1] ^= scratch.u[1];
3752c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3762c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[0] = flags0;
3772c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3782c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	return 0;
3792c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org}
3802c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3812c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgint CRYPTO_ccm128_decrypt_ccm64(CCM128_CONTEXT *ctx,
3822c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	const unsigned char *inp, unsigned char *out,
3832c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	size_t len,ccm128_f stream)
3842c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org{
3852c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	size_t		n;
3862c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	unsigned int	i,L;
3872c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	unsigned char	flags0	= ctx->nonce.c[0];
3882c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	block128_f	block	= ctx->block;
3892c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	void *		key	= ctx->key;
3902c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	union { u64 u[2]; u8 c[16]; } scratch;
3912c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3922c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (!(flags0&0x40))
3932c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->nonce.c,ctx->cmac.c,key);
3942c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
3952c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[0] = L = flags0&7;
3962c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	for (n=0,i=15-L;i<15;++i) {
3972c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		n |= ctx->nonce.c[i];
3982c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->nonce.c[i]=0;
3992c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		n <<= 8;
4002c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
4012c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	n |= ctx->nonce.c[15];	/* reconstructed length */
4022c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[15]=1;
4032c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
4042c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (n!=len) return -1;
4052c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
4062c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if ((n=len/16)) {
4072c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*stream)(inp,out,n,key,ctx->nonce.c,ctx->cmac.c);
4082c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		n   *= 16;
4092c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		inp += n;
4102c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		out += n;
4112c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		len -= n;
4122c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		if (len) ctr64_add(ctx->nonce.c,n/16);
4132c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
4142c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
4152c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (len) {
4162c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->nonce.c,scratch.c,key);
4172c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		for (i=0; i<len; ++i)
4182c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org			ctx->cmac.c[i] ^= (out[i] = scratch.c[i]^inp[i]);
4192c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		(*block)(ctx->cmac.c,ctx->cmac.c,key);
4202c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	}
4212c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
4222c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	for (i=15-L;i<16;++i)
4232c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org		ctx->nonce.c[i]=0;
4242c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
4252c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	(*block)(ctx->nonce.c,scratch.c,key);
4262c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->cmac.u[0] ^= scratch.u[0];
4272c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->cmac.u[1] ^= scratch.u[1];
4282c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
4292c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	ctx->nonce.c[0] = flags0;
4302c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
4312c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	return 0;
4322c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org}
4332c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
4342c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.orgsize_t CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx,unsigned char *tag,size_t len)
4352c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org{	unsigned int M = (ctx->nonce.c[0]>>3)&7;	/* the M parameter */
4362c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org
4372c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	M *= 2; M += 2;
4382c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	if (len<M)	return 0;
4392c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	memcpy(tag,ctx->cmac.c,M);
4402c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org	return M;
4412c4508dfe2bc5b6296c01114ed11ddc64b7718c6digit@chromium.org}
442