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