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 }