xref: /nrf52832-nimble/packages/NimBLE-latest/ext/tinycrypt/src/ccm_mode.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1*042d53a7SEvalZero /* ccm_mode.c - TinyCrypt implementation of CCM mode */
2*042d53a7SEvalZero 
3*042d53a7SEvalZero /*
4*042d53a7SEvalZero  *  Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
5*042d53a7SEvalZero  *
6*042d53a7SEvalZero  *  Redistribution and use in source and binary forms, with or without
7*042d53a7SEvalZero  *  modification, are permitted provided that the following conditions are met:
8*042d53a7SEvalZero  *
9*042d53a7SEvalZero  *    - Redistributions of source code must retain the above copyright notice,
10*042d53a7SEvalZero  *     this list of conditions and the following disclaimer.
11*042d53a7SEvalZero  *
12*042d53a7SEvalZero  *    - Redistributions in binary form must reproduce the above copyright
13*042d53a7SEvalZero  *    notice, this list of conditions and the following disclaimer in the
14*042d53a7SEvalZero  *    documentation and/or other materials provided with the distribution.
15*042d53a7SEvalZero  *
16*042d53a7SEvalZero  *    - Neither the name of Intel Corporation nor the names of its contributors
17*042d53a7SEvalZero  *    may be used to endorse or promote products derived from this software
18*042d53a7SEvalZero  *    without specific prior written permission.
19*042d53a7SEvalZero  *
20*042d53a7SEvalZero  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21*042d53a7SEvalZero  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*042d53a7SEvalZero  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*042d53a7SEvalZero  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24*042d53a7SEvalZero  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25*042d53a7SEvalZero  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26*042d53a7SEvalZero  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27*042d53a7SEvalZero  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28*042d53a7SEvalZero  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29*042d53a7SEvalZero  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30*042d53a7SEvalZero  *  POSSIBILITY OF SUCH DAMAGE.
31*042d53a7SEvalZero  */
32*042d53a7SEvalZero 
33*042d53a7SEvalZero #include <tinycrypt/ccm_mode.h>
34*042d53a7SEvalZero #include <tinycrypt/constants.h>
35*042d53a7SEvalZero #include <tinycrypt/utils.h>
36*042d53a7SEvalZero 
37*042d53a7SEvalZero #include <stdio.h>
38*042d53a7SEvalZero 
tc_ccm_config(TCCcmMode_t c,TCAesKeySched_t sched,uint8_t * nonce,unsigned int nlen,unsigned int mlen)39*042d53a7SEvalZero int tc_ccm_config(TCCcmMode_t c, TCAesKeySched_t sched, uint8_t *nonce,
40*042d53a7SEvalZero 		  unsigned int nlen, unsigned int mlen)
41*042d53a7SEvalZero {
42*042d53a7SEvalZero 
43*042d53a7SEvalZero 	/* input sanity check: */
44*042d53a7SEvalZero 	if (c == (TCCcmMode_t) 0 ||
45*042d53a7SEvalZero 	    sched == (TCAesKeySched_t) 0 ||
46*042d53a7SEvalZero 	    nonce == (uint8_t *) 0) {
47*042d53a7SEvalZero 		return TC_CRYPTO_FAIL;
48*042d53a7SEvalZero 	} else if (nlen != 13) {
49*042d53a7SEvalZero 		return TC_CRYPTO_FAIL; /* The allowed nonce size is: 13. See documentation.*/
50*042d53a7SEvalZero 	} else if ((mlen < 4) || (mlen > 16) || (mlen & 1)) {
51*042d53a7SEvalZero 		return TC_CRYPTO_FAIL; /* The allowed mac sizes are: 4, 6, 8, 10, 12, 14, 16.*/
52*042d53a7SEvalZero 	}
53*042d53a7SEvalZero 
54*042d53a7SEvalZero 	c->mlen = mlen;
55*042d53a7SEvalZero 	c->sched = sched;
56*042d53a7SEvalZero 	c->nonce = nonce;
57*042d53a7SEvalZero 
58*042d53a7SEvalZero 	return TC_CRYPTO_SUCCESS;
59*042d53a7SEvalZero }
60*042d53a7SEvalZero 
61*042d53a7SEvalZero /**
62*042d53a7SEvalZero  * Variation of CBC-MAC mode used in CCM.
63*042d53a7SEvalZero  */
ccm_cbc_mac(uint8_t * T,const uint8_t * data,unsigned int dlen,unsigned int flag,TCAesKeySched_t sched)64*042d53a7SEvalZero static void ccm_cbc_mac(uint8_t *T, const uint8_t *data, unsigned int dlen,
65*042d53a7SEvalZero 			unsigned int flag, TCAesKeySched_t sched)
66*042d53a7SEvalZero {
67*042d53a7SEvalZero 
68*042d53a7SEvalZero 	unsigned int i;
69*042d53a7SEvalZero 
70*042d53a7SEvalZero 	if (flag > 0) {
71*042d53a7SEvalZero 		T[0] ^= (uint8_t)(dlen >> 8);
72*042d53a7SEvalZero 		T[1] ^= (uint8_t)(dlen);
73*042d53a7SEvalZero 		dlen += 2; i = 2;
74*042d53a7SEvalZero 	} else {
75*042d53a7SEvalZero 		i = 0;
76*042d53a7SEvalZero 	}
77*042d53a7SEvalZero 
78*042d53a7SEvalZero 	while (i < dlen) {
79*042d53a7SEvalZero 		T[i++ % (Nb * Nk)] ^= *data++;
80*042d53a7SEvalZero 		if (((i % (Nb * Nk)) == 0) || dlen == i) {
81*042d53a7SEvalZero 			(void) tc_aes_encrypt(T, T, sched);
82*042d53a7SEvalZero 		}
83*042d53a7SEvalZero 	}
84*042d53a7SEvalZero }
85*042d53a7SEvalZero 
86*042d53a7SEvalZero /**
87*042d53a7SEvalZero  * Variation of CTR mode used in CCM.
88*042d53a7SEvalZero  * The CTR mode used by CCM is slightly different than the conventional CTR
89*042d53a7SEvalZero  * mode (the counter is increased before encryption, instead of after
90*042d53a7SEvalZero  * encryption). Besides, it is assumed that the counter is stored in the last
91*042d53a7SEvalZero  * 2 bytes of the nonce.
92*042d53a7SEvalZero  */
ccm_ctr_mode(uint8_t * out,unsigned int outlen,const uint8_t * in,unsigned int inlen,uint8_t * ctr,const TCAesKeySched_t sched)93*042d53a7SEvalZero static int ccm_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in,
94*042d53a7SEvalZero 			unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched)
95*042d53a7SEvalZero {
96*042d53a7SEvalZero 
97*042d53a7SEvalZero 	uint8_t buffer[TC_AES_BLOCK_SIZE];
98*042d53a7SEvalZero 	uint8_t nonce[TC_AES_BLOCK_SIZE];
99*042d53a7SEvalZero 	uint16_t block_num;
100*042d53a7SEvalZero 	unsigned int i;
101*042d53a7SEvalZero 
102*042d53a7SEvalZero 	/* input sanity check: */
103*042d53a7SEvalZero 	if (out == (uint8_t *) 0 ||
104*042d53a7SEvalZero 	    in == (uint8_t *) 0 ||
105*042d53a7SEvalZero 	    ctr == (uint8_t *) 0 ||
106*042d53a7SEvalZero 	    sched == (TCAesKeySched_t) 0 ||
107*042d53a7SEvalZero 	    inlen == 0 ||
108*042d53a7SEvalZero 	    outlen == 0 ||
109*042d53a7SEvalZero 	    outlen != inlen) {
110*042d53a7SEvalZero 		return TC_CRYPTO_FAIL;
111*042d53a7SEvalZero 	}
112*042d53a7SEvalZero 
113*042d53a7SEvalZero 	/* copy the counter to the nonce */
114*042d53a7SEvalZero 	(void) _copy(nonce, sizeof(nonce), ctr, sizeof(nonce));
115*042d53a7SEvalZero 
116*042d53a7SEvalZero 	/* select the last 2 bytes of the nonce to be incremented */
117*042d53a7SEvalZero 	block_num = (uint16_t) ((nonce[14] << 8)|(nonce[15]));
118*042d53a7SEvalZero 	for (i = 0; i < inlen; ++i) {
119*042d53a7SEvalZero 		if ((i % (TC_AES_BLOCK_SIZE)) == 0) {
120*042d53a7SEvalZero 			block_num++;
121*042d53a7SEvalZero 			nonce[14] = (uint8_t)(block_num >> 8);
122*042d53a7SEvalZero 			nonce[15] = (uint8_t)(block_num);
123*042d53a7SEvalZero 			if (!tc_aes_encrypt(buffer, nonce, sched)) {
124*042d53a7SEvalZero 				return TC_CRYPTO_FAIL;
125*042d53a7SEvalZero 			}
126*042d53a7SEvalZero 		}
127*042d53a7SEvalZero 		/* update the output */
128*042d53a7SEvalZero 		*out++ = buffer[i % (TC_AES_BLOCK_SIZE)] ^ *in++;
129*042d53a7SEvalZero 	}
130*042d53a7SEvalZero 
131*042d53a7SEvalZero 	/* update the counter */
132*042d53a7SEvalZero 	ctr[14] = nonce[14]; ctr[15] = nonce[15];
133*042d53a7SEvalZero 
134*042d53a7SEvalZero 	return TC_CRYPTO_SUCCESS;
135*042d53a7SEvalZero }
136*042d53a7SEvalZero 
tc_ccm_generation_encryption(uint8_t * out,unsigned int olen,const uint8_t * associated_data,unsigned int alen,const uint8_t * payload,unsigned int plen,TCCcmMode_t c)137*042d53a7SEvalZero int tc_ccm_generation_encryption(uint8_t *out, unsigned int olen,
138*042d53a7SEvalZero 				 const uint8_t *associated_data,
139*042d53a7SEvalZero 				 unsigned int alen, const uint8_t *payload,
140*042d53a7SEvalZero 				 unsigned int plen, TCCcmMode_t c)
141*042d53a7SEvalZero {
142*042d53a7SEvalZero 
143*042d53a7SEvalZero 	/* input sanity check: */
144*042d53a7SEvalZero 	if ((out == (uint8_t *) 0) ||
145*042d53a7SEvalZero 		(c == (TCCcmMode_t) 0) ||
146*042d53a7SEvalZero 		((plen > 0) && (payload == (uint8_t *) 0)) ||
147*042d53a7SEvalZero 		((alen > 0) && (associated_data == (uint8_t *) 0)) ||
148*042d53a7SEvalZero 		(alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */
149*042d53a7SEvalZero 		(plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */
150*042d53a7SEvalZero 		(olen < (plen + c->mlen))) {  /* invalid output buffer size */
151*042d53a7SEvalZero 		return TC_CRYPTO_FAIL;
152*042d53a7SEvalZero 	}
153*042d53a7SEvalZero 
154*042d53a7SEvalZero 	uint8_t b[Nb * Nk];
155*042d53a7SEvalZero 	uint8_t tag[Nb * Nk];
156*042d53a7SEvalZero 	unsigned int i;
157*042d53a7SEvalZero 
158*042d53a7SEvalZero 	/* GENERATING THE AUTHENTICATION TAG: */
159*042d53a7SEvalZero 
160*042d53a7SEvalZero 	/* formatting the sequence b for authentication: */
161*042d53a7SEvalZero 	b[0] = ((alen > 0) ? 0x40:0) | (((c->mlen - 2) / 2 << 3)) | (1);
162*042d53a7SEvalZero 	for (i = 1; i <= 13; ++i) {
163*042d53a7SEvalZero 		b[i] = c->nonce[i - 1];
164*042d53a7SEvalZero 	}
165*042d53a7SEvalZero 	b[14] = (uint8_t)(plen >> 8);
166*042d53a7SEvalZero 	b[15] = (uint8_t)(plen);
167*042d53a7SEvalZero 
168*042d53a7SEvalZero 	/* computing the authentication tag using cbc-mac: */
169*042d53a7SEvalZero 	(void) tc_aes_encrypt(tag, b, c->sched);
170*042d53a7SEvalZero 	if (alen > 0) {
171*042d53a7SEvalZero 		ccm_cbc_mac(tag, associated_data, alen, 1, c->sched);
172*042d53a7SEvalZero 	}
173*042d53a7SEvalZero 	if (plen > 0) {
174*042d53a7SEvalZero 		ccm_cbc_mac(tag, payload, plen, 0, c->sched);
175*042d53a7SEvalZero 	}
176*042d53a7SEvalZero 
177*042d53a7SEvalZero 	/* ENCRYPTION: */
178*042d53a7SEvalZero 
179*042d53a7SEvalZero 	/* formatting the sequence b for encryption: */
180*042d53a7SEvalZero 	b[0] = 1; /* q - 1 = 2 - 1 = 1 */
181*042d53a7SEvalZero 	b[14] = b[15] = TC_ZERO_BYTE;
182*042d53a7SEvalZero 
183*042d53a7SEvalZero 	/* encrypting payload using ctr mode: */
184*042d53a7SEvalZero 	ccm_ctr_mode(out, plen, payload, plen, b, c->sched);
185*042d53a7SEvalZero 
186*042d53a7SEvalZero 	b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter for ctr_mode (0):*/
187*042d53a7SEvalZero 
188*042d53a7SEvalZero 	/* encrypting b and adding the tag to the output: */
189*042d53a7SEvalZero 	(void) tc_aes_encrypt(b, b, c->sched);
190*042d53a7SEvalZero 	out += plen;
191*042d53a7SEvalZero 	for (i = 0; i < c->mlen; ++i) {
192*042d53a7SEvalZero 		*out++ = tag[i] ^ b[i];
193*042d53a7SEvalZero 	}
194*042d53a7SEvalZero 
195*042d53a7SEvalZero 	return TC_CRYPTO_SUCCESS;
196*042d53a7SEvalZero }
197*042d53a7SEvalZero 
tc_ccm_decryption_verification(uint8_t * out,unsigned int olen,const uint8_t * associated_data,unsigned int alen,const uint8_t * payload,unsigned int plen,TCCcmMode_t c)198*042d53a7SEvalZero int tc_ccm_decryption_verification(uint8_t *out, unsigned int olen,
199*042d53a7SEvalZero 				   const uint8_t *associated_data,
200*042d53a7SEvalZero 				   unsigned int alen, const uint8_t *payload,
201*042d53a7SEvalZero 				   unsigned int plen, TCCcmMode_t c)
202*042d53a7SEvalZero {
203*042d53a7SEvalZero 
204*042d53a7SEvalZero 	/* input sanity check: */
205*042d53a7SEvalZero 	if ((out == (uint8_t *) 0) ||
206*042d53a7SEvalZero 	    (c == (TCCcmMode_t) 0) ||
207*042d53a7SEvalZero 	    ((plen > 0) && (payload == (uint8_t *) 0)) ||
208*042d53a7SEvalZero 	    ((alen > 0) && (associated_data == (uint8_t *) 0)) ||
209*042d53a7SEvalZero 	    (alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */
210*042d53a7SEvalZero 	    (plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */
211*042d53a7SEvalZero 	    (olen < plen - c->mlen)) { /* invalid output buffer size */
212*042d53a7SEvalZero 		return TC_CRYPTO_FAIL;
213*042d53a7SEvalZero   }
214*042d53a7SEvalZero 
215*042d53a7SEvalZero 	uint8_t b[Nb * Nk];
216*042d53a7SEvalZero 	uint8_t tag[Nb * Nk];
217*042d53a7SEvalZero 	unsigned int i;
218*042d53a7SEvalZero 
219*042d53a7SEvalZero 	/* DECRYPTION: */
220*042d53a7SEvalZero 
221*042d53a7SEvalZero 	/* formatting the sequence b for decryption: */
222*042d53a7SEvalZero 	b[0] = 1; /* q - 1 = 2 - 1 = 1 */
223*042d53a7SEvalZero 	for (i = 1; i < 14; ++i) {
224*042d53a7SEvalZero 		b[i] = c->nonce[i - 1];
225*042d53a7SEvalZero 	}
226*042d53a7SEvalZero 	b[14] = b[15] = TC_ZERO_BYTE; /* initial counter value is 0 */
227*042d53a7SEvalZero 
228*042d53a7SEvalZero 	/* decrypting payload using ctr mode: */
229*042d53a7SEvalZero 	ccm_ctr_mode(out, plen - c->mlen, payload, plen - c->mlen, b, c->sched);
230*042d53a7SEvalZero 
231*042d53a7SEvalZero 	b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter value (0) */
232*042d53a7SEvalZero 
233*042d53a7SEvalZero 	/* encrypting b and restoring the tag from input: */
234*042d53a7SEvalZero 	(void) tc_aes_encrypt(b, b, c->sched);
235*042d53a7SEvalZero 	for (i = 0; i < c->mlen; ++i) {
236*042d53a7SEvalZero 		tag[i] = *(payload + plen - c->mlen + i) ^ b[i];
237*042d53a7SEvalZero 	}
238*042d53a7SEvalZero 
239*042d53a7SEvalZero 	/* VERIFYING THE AUTHENTICATION TAG: */
240*042d53a7SEvalZero 
241*042d53a7SEvalZero 	/* formatting the sequence b for authentication: */
242*042d53a7SEvalZero 	b[0] = ((alen > 0) ? 0x40:0)|(((c->mlen - 2) / 2 << 3)) | (1);
243*042d53a7SEvalZero 	for (i = 1; i < 14; ++i) {
244*042d53a7SEvalZero 		b[i] = c->nonce[i - 1];
245*042d53a7SEvalZero 	}
246*042d53a7SEvalZero 	b[14] = (uint8_t)((plen - c->mlen) >> 8);
247*042d53a7SEvalZero 	b[15] = (uint8_t)(plen - c->mlen);
248*042d53a7SEvalZero 
249*042d53a7SEvalZero 	/* computing the authentication tag using cbc-mac: */
250*042d53a7SEvalZero 	(void) tc_aes_encrypt(b, b, c->sched);
251*042d53a7SEvalZero 	if (alen > 0) {
252*042d53a7SEvalZero 		ccm_cbc_mac(b, associated_data, alen, 1, c->sched);
253*042d53a7SEvalZero 	}
254*042d53a7SEvalZero 	if (plen > 0) {
255*042d53a7SEvalZero 		ccm_cbc_mac(b, out, plen - c->mlen, 0, c->sched);
256*042d53a7SEvalZero 	}
257*042d53a7SEvalZero 
258*042d53a7SEvalZero 	/* comparing the received tag and the computed one: */
259*042d53a7SEvalZero 	if (_compare(b, tag, c->mlen) == 0) {
260*042d53a7SEvalZero 		return TC_CRYPTO_SUCCESS;
261*042d53a7SEvalZero   	} else {
262*042d53a7SEvalZero 		/* erase the decrypted buffer in case of mac validation failure: */
263*042d53a7SEvalZero 		_set(out, 0, plen - c->mlen);
264*042d53a7SEvalZero 		return TC_CRYPTO_FAIL;
265*042d53a7SEvalZero 	}
266*042d53a7SEvalZero }
267