• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     /* input sanity check: */
43     if (c == (TCCcmMode_t) 0 ||
44             sched == (TCAesKeySched_t) 0 ||
45             nonce == (uint8_t *) 0) {
46         return TC_CRYPTO_FAIL;
47     } else if (nlen != 13) { // 13:Analyzing conditions
48         return TC_CRYPTO_FAIL; /* The allowed nonce size is: 13. See documentation. */
49     } else if ((mlen < 4) || (mlen > 16) || (mlen & 1)) { // 4:Analyzing conditions, 16:Analyzing conditions
50         return TC_CRYPTO_FAIL; /* The allowed mac sizes are: 4, 6, 8, 10, 12, 14, 16. */
51     }
52 
53     c->mlen = mlen;
54     c->sched = sched;
55     c->nonce = nonce;
56     return TC_CRYPTO_SUCCESS;
57 }
58 
59 /**
60  * Variation of CBC-MAC mode used in CCM.
61  */
ccm_cbc_mac(uint8_t * T,const uint8_t * data,unsigned int dlen,unsigned int flag,TCAesKeySched_t sched)62 static void ccm_cbc_mac(uint8_t *T, const uint8_t *data, unsigned int dlen,
63                         unsigned int flag, TCAesKeySched_t sched)
64 {
65     unsigned int i;
66     unsigned int Dlen = dlen;
67 
68     if (flag > 0) {
69         T[0] ^= (uint8_t)(Dlen >> 8); // 8:byte alignment
70         T[1] ^= (uint8_t)(Dlen);
71         Dlen += 2; // 2:byte alignment
72         i = 2; // 2:byte alignment
73     } else {
74         i = 0;
75     }
76 
77     while (i < Dlen) {
78         T[i++ % (Nb * Nk)] ^= *data++;
79 
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     uint8_t buffer[TC_AES_BLOCK_SIZE];
97     uint8_t nonce[TC_AES_BLOCK_SIZE];
98     uint16_t block_num;
99     unsigned int i;
100 
101     /* input sanity check: */
102     if (out == (uint8_t *) 0 ||
103             in == (uint8_t *) 0 ||
104             ctr == (uint8_t *) 0 ||
105             sched == (TCAesKeySched_t) 0 ||
106             inlen == 0 ||
107             outlen == 0 ||
108             outlen != inlen) {
109         return TC_CRYPTO_FAIL;
110     }
111 
112     /* copy the counter to the nonce */
113     (void) _copy(nonce, sizeof(nonce), ctr, sizeof(nonce));
114     /* select the last 2 bytes of the nonce to be incremented */
115     block_num = (uint16_t)((nonce[14] << 8) | (nonce[15])); // 14:array element, 8:byte alignment, 15:array element
116 
117     for (i = 0; i < inlen; ++i) {
118         if ((i % (TC_AES_BLOCK_SIZE)) == 0) {
119             block_num++;
120             nonce[14] = (uint8_t)(block_num >> 8); // 14:array element
121             nonce[15] = (uint8_t)(block_num); // 15:array element
122 
123             if (!tc_aes_encrypt(buffer, nonce, sched)) {
124                 return TC_CRYPTO_FAIL;
125             }
126         }
127 
128         /* update the output */
129         *out++ = buffer[i % (TC_AES_BLOCK_SIZE)] ^ *in++;
130     }
131 
132     /* update the counter */
133     ctr[14] = nonce[14]; // 14:array element
134     ctr[15] = nonce[15]; // 15:array element
135     return TC_CRYPTO_SUCCESS;
136 }
137 
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)138 int tc_ccm_generation_encryption(uint8_t *out, unsigned int olen,
139                                  const uint8_t *associated_data,
140                                  unsigned int alen, const uint8_t *payload,
141                                  unsigned int plen, TCCcmMode_t c)
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     /* GENERATING THE AUTHENTICATION TAG: */
158     /* formatting the sequence b for authentication: */
159     b[0] = ((alen > 0) ? 0x40 : 0) | (((c->mlen - 2) / 2 << 3)) | (1); // 2:byte alignment, 3:byte alignment
160 
161     for (i = 1; i <= 13; ++i) { // 13:Analyzing conditions
162         b[i] = c->nonce[i - 1];
163     }
164 
165     b[14] = (uint8_t)(plen >> 8); // 14:array element, 8:byte alignment
166     b[15] = (uint8_t)(plen); // 15:array element
167     /* computing the authentication tag using cbc-mac: */
168     (void) tc_aes_encrypt(tag, b, c->sched);
169 
170     if (alen > 0) {
171         ccm_cbc_mac(tag, associated_data, alen, 1, c->sched);
172     }
173 
174     if (plen > 0) {
175         ccm_cbc_mac(tag, payload, plen, 0, c->sched);
176     }
177 
178     /* ENCRYPTION: */
179     /* formatting the sequence b for encryption: */
180     b[0] = 1; /* q - 1 = 2 - 1 = 1 */
181     b[14] = b[15] = TC_ZERO_BYTE; // 14:array element, 15:array element
182     /* encrypting payload using ctr mode: */
183     ccm_ctr_mode(out, plen, payload, plen, b, c->sched);
184     b[14] = b[15] = TC_ZERO_BYTE; // 14:array element, 15:array element
185     /* encrypting b and adding the tag to the output: */
186     (void)tc_aes_encrypt(b, b, c->sched);
187     out += plen;
188 
189     for (i = 0; i < c->mlen; ++i) {
190         *out++ = tag[i] ^ b[i];
191     }
192 
193     return TC_CRYPTO_SUCCESS;
194 }
195 
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)196 int tc_ccm_decryption_verification(uint8_t *out, unsigned int olen,
197                                    const uint8_t *associated_data,
198                                    unsigned int alen, const uint8_t *payload,
199                                    unsigned int plen, TCCcmMode_t c)
200 {
201     /* input sanity check: */
202     if ((out == (uint8_t *) 0) ||
203         (c == (TCCcmMode_t) 0) ||
204         ((plen > 0) && (payload == (uint8_t *) 0)) ||
205         ((alen > 0) && (associated_data == (uint8_t *) 0)) ||
206         (alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */
207         (plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */
208         (olen < plen - c->mlen)) { /* invalid output buffer size */
209         return TC_CRYPTO_FAIL;
210     }
211 
212     uint8_t b[Nb * Nk];
213     uint8_t tag[Nb * Nk];
214     unsigned int i;
215     /* DECRYPTION: */
216     /* formatting the sequence b for decryption: */
217     b[0] = 1; /* q - 1 = 2 - 1 = 1 */
218 
219     for (i = 1; i < 14; ++i) { // 14:Analyzing conditions
220         b[i] = c->nonce[i - 1];
221     }
222 
223     b[14] = b[15] = TC_ZERO_BYTE; /* initial counter value is 0 */  // 14:array element, 15:array element
224     /* decrypting payload using ctr mode: */
225     ccm_ctr_mode(out, plen - c->mlen, payload, plen - c->mlen, b, c->sched);
226     b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter value (0) */  // 14:array element, 15:array element
227     /* encrypting b and restoring the tag from input: */
228     (void) tc_aes_encrypt(b, b, c->sched);
229 
230     for (i = 0; i < c->mlen; ++i) {
231         tag[i] = *(payload + plen - c->mlen + i) ^ b[i];
232     }
233 
234     /* VERIFYING THE AUTHENTICATION TAG: */
235     /* formatting the sequence b for authentication: */
236     b[0] = ((alen > 0) ? 0x40 : 0) | (((c->mlen - 2) / 2 << 3)) | (1); // 2:byte alignment, 3:byte alignment
237 
238     for (i = 1; i < 14; ++i) { // 14:Analyzing conditions
239         b[i] = c->nonce[i - 1];
240     }
241 
242     b[14] = (uint8_t)((plen - c->mlen) >> 8); // 14:array element, 8:byte alignment
243     b[15] = (uint8_t)(plen - c->mlen); // 15:array element
244     /* computing the authentication tag using cbc-mac: */
245     (void) tc_aes_encrypt(b, b, c->sched);
246 
247     if (alen > 0) {
248         ccm_cbc_mac(b, associated_data, alen, 1, c->sched);
249     }
250 
251     if (plen > 0) {
252         ccm_cbc_mac(b, out, plen - c->mlen, 0, c->sched);
253     }
254 
255     /* comparing the received tag and the computed one: */
256     if (_compare(b, tag, c->mlen) == 0) {
257         return TC_CRYPTO_SUCCESS;
258     } else {
259         /* erase the decrypted buffer in case of mac validation failure: */
260         _set(out, 0, plen - c->mlen);
261         return TC_CRYPTO_FAIL;
262     }
263 }