blob: 7b6d485666eb8a9a69c08939ce8c055b39038982 [file] [log] [blame]
David Brownfecda2d2017-09-07 10:20:34 -06001/* ccm_mode.c - TinyCrypt implementation of CCM mode */
2
3/*
4 * Copyright (C) 2015 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
39int32_t tc_ccm_config(TCCcmMode_t c, TCAesKeySched_t sched, uint8_t *nonce,
40 uint32_t nlen, uint32_t 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 */
64static void ccm_cbc_mac(uint8_t *T, const uint8_t *data, uint32_t dlen,
65 uint32_t flag, TCAesKeySched_t sched)
66{
67
68 uint32_t 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 */
93static int32_t ccm_ctr_mode(uint8_t *out, uint32_t outlen, const uint8_t *in,
94 uint32_t 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 uint32_t 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
137int32_t tc_ccm_generation_encryption(uint8_t *out, const uint8_t *associated_data,
138 uint32_t alen, const uint8_t *payload,
139 uint32_t plen, TCCcmMode_t c)
140{
141 /* input sanity check: */
142 if ((out == (uint8_t *) 0) ||
143 (c == (TCCcmMode_t) 0) ||
144 ((plen > 0) && (payload == (uint8_t *) 0)) ||
145 ((alen > 0) && (associated_data == (uint8_t *) 0)) ||
146 (alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */
147 (plen >= TC_CCM_PAYLOAD_MAX_BYTES)) { /* payload size unsupported */
148 return TC_CRYPTO_FAIL;
149 }
150
151 uint8_t b[Nb * Nk];
152 uint8_t tag[Nb * Nk];
153 uint32_t i;
154
155 /* GENERATING THE AUTHENTICATION TAG: */
156
157 /* formatting the sequence b for authentication: */
158 b[0] = ((alen > 0) ? 0x40:0) | (((c->mlen - 2) / 2 << 3)) | (1);
159 for (i = 1; i <= 13; ++i) {
160 b[i] = c->nonce[i - 1];
161 }
162 b[14] = (uint8_t)(plen >> 8);
163 b[15] = (uint8_t)(plen);
164
165 /* computing the authentication tag using cbc-mac: */
166 (void) tc_aes_encrypt(tag, b, c->sched);
167 if (alen > 0) {
168 ccm_cbc_mac(tag, associated_data, alen, 1, c->sched);
169 }
170 if (plen > 0) {
171 ccm_cbc_mac(tag, payload, plen, 0, c->sched);
172 }
173
174 /* ENCRYPTION: */
175
176 /* formatting the sequence b for encryption: */
177 b[0] = 1; /* q - 1 = 2 - 1 = 1 */
178 b[14] = b[15] = TC_ZERO_BYTE;
179
180 /* encrypting payload using ctr mode: */
181 ccm_ctr_mode(out, plen, payload, plen, b, c->sched);
182
183 b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter for ctr_mode (0):*/
184
185 /* encrypting b and adding the tag to the output: */
186 (void) tc_aes_encrypt(b, b, c->sched);
187 out += plen;
188 for (i = 0; i < c->mlen; ++i) {
189 *out++ = tag[i] ^ b[i];
190 }
191
192 return TC_CRYPTO_SUCCESS;
193}
194
195int32_t tc_ccm_decryption_verification(uint8_t *out, const uint8_t *associated_data,
196 uint32_t alen, const uint8_t *payload,
197 uint32_t plen, TCCcmMode_t c)
198{
199 /* input sanity check: */
200 if ((out == (uint8_t *) 0) ||
201 (c == (TCCcmMode_t) 0) ||
202 ((plen > 0) && (payload == (uint8_t *) 0)) ||
203 ((alen > 0) && (associated_data == (uint8_t *) 0)) ||
204 (alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */
205 (plen >= TC_CCM_PAYLOAD_MAX_BYTES)) { /* payload size unsupported */
206 return TC_CRYPTO_FAIL;
207 }
208
209 uint8_t b[Nb * Nk];
210 uint8_t tag[Nb * Nk];
211 uint32_t i;
212
213 /* DECRYPTION: */
214
215 /* formatting the sequence b for decryption: */
216 b[0] = 1; /* q - 1 = 2 - 1 = 1 */
217 for (i = 1; i < 14; ++i) {
218 b[i] = c->nonce[i - 1];
219 }
220 b[14] = b[15] = TC_ZERO_BYTE; /* initial counter value is 0 */
221
222 /* decrypting payload using ctr mode: */
223 ccm_ctr_mode(out, plen - c->mlen, payload, plen - c->mlen, b, c->sched);
224
225 b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter value (0) */
226
227 /* encrypting b and restoring the tag from input: */
228 (void) tc_aes_encrypt(b, b, c->sched);
229 for (i = 0; i < c->mlen; ++i) {
230 tag[i] = *(payload + plen - c->mlen + i) ^ b[i];
231 }
232
233 /* VERIFYING THE AUTHENTICATION TAG: */
234
235 /* formatting the sequence b for authentication: */
236 b[0] = ((alen > 0) ? 0x40:0)|(((c->mlen - 2) / 2 << 3)) | (1);
237 for (i = 1; i < 14; ++i) {
238 b[i] = c->nonce[i - 1];
239 }
240 b[14] = (uint8_t)((plen - c->mlen) >> 8);
241 b[15] = (uint8_t)(plen - c->mlen);
242
243 /* computing the authentication tag using cbc-mac: */
244 (void) tc_aes_encrypt(b, b, c->sched);
245 if (alen > 0) {
246 ccm_cbc_mac(b, associated_data, alen, 1, c->sched);
247 }
248 if (plen > 0) {
249 ccm_cbc_mac(b, out, plen - c->mlen, 0, c->sched);
250 }
251
252 /* comparing the received tag and the computed one: */
253 if (_compare(b, tag, c->mlen) != 0) {
254 /* erase the decrypted buffer in case of mac validation failure: */
255 _set(out, 0, sizeof(*out));
256 return TC_CRYPTO_FAIL;
257 }
258
259 return TC_CRYPTO_SUCCESS;
260}