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