Branch data Line data Source code
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 : :
39 : 0 : 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 : 0 : if (c == (TCCcmMode_t) 0 ||
45 [ # # # # ]: 0 : sched == (TCAesKeySched_t) 0 ||
46 : : nonce == (uint8_t *) 0) {
47 : : return TC_CRYPTO_FAIL;
48 [ # # ]: 0 : } else if (nlen != 13) {
49 : : return TC_CRYPTO_FAIL; /* The allowed nonce size is: 13. See documentation.*/
50 [ # # # # ]: 0 : } 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 : 0 : c->mlen = mlen;
55 : 0 : c->sched = sched;
56 : 0 : c->nonce = nonce;
57 : :
58 : 0 : return TC_CRYPTO_SUCCESS;
59 : : }
60 : :
61 : : /**
62 : : * Variation of CBC-MAC mode used in CCM.
63 : : */
64 : 0 : 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 : 0 : unsigned int i;
69 : :
70 [ # # ]: 0 : if (flag > 0) {
71 : 0 : T[0] ^= (uint8_t)(dlen >> 8);
72 : 0 : T[1] ^= (uint8_t)(dlen);
73 : 0 : dlen += 2; i = 2;
74 : : } else {
75 : 0 : i = 0;
76 : : }
77 : :
78 [ # # ]: 0 : while (i < dlen) {
79 : 0 : T[i++ % (Nb * Nk)] ^= *data++;
80 [ # # # # ]: 0 : if (((i % (Nb * Nk)) == 0) || dlen == i) {
81 : 0 : (void) tc_aes_encrypt(T, T, sched);
82 : : }
83 : : }
84 : 0 : }
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 : : */
93 : 0 : 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 : 0 : uint8_t buffer[TC_AES_BLOCK_SIZE];
98 : 0 : uint8_t nonce[TC_AES_BLOCK_SIZE];
99 : 0 : uint16_t block_num;
100 : 0 : unsigned int i;
101 : :
102 : : /* input sanity check: */
103 : 0 : if (out == (uint8_t *) 0 ||
104 [ # # ]: 0 : in == (uint8_t *) 0 ||
105 : 0 : ctr == (uint8_t *) 0 ||
106 [ # # ]: 0 : sched == (TCAesKeySched_t) 0 ||
107 : 0 : inlen == 0 ||
108 [ # # # # ]: 0 : outlen == 0 ||
109 : : outlen != inlen) {
110 : : return TC_CRYPTO_FAIL;
111 : : }
112 : :
113 : : /* copy the counter to the nonce */
114 : 0 : (void) _copy(nonce, sizeof(nonce), ctr, sizeof(nonce));
115 : :
116 : : /* select the last 2 bytes of the nonce to be incremented */
117 : 0 : block_num = (uint16_t) ((nonce[14] << 8)|(nonce[15]));
118 [ # # ]: 0 : for (i = 0; i < inlen; ++i) {
119 [ # # ]: 0 : if ((i % (TC_AES_BLOCK_SIZE)) == 0) {
120 : 0 : block_num++;
121 : 0 : nonce[14] = (uint8_t)(block_num >> 8);
122 : 0 : nonce[15] = (uint8_t)(block_num);
123 [ # # ]: 0 : if (!tc_aes_encrypt(buffer, nonce, sched)) {
124 : : return TC_CRYPTO_FAIL;
125 : : }
126 : : }
127 : : /* update the output */
128 : 0 : *out++ = buffer[i % (TC_AES_BLOCK_SIZE)] ^ *in++;
129 : : }
130 : :
131 : : /* update the counter */
132 : 0 : ctr[14] = nonce[14]; ctr[15] = nonce[15];
133 : :
134 : 0 : return TC_CRYPTO_SUCCESS;
135 : : }
136 : :
137 : 0 : 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 : 0 : if ((out == (uint8_t *) 0) ||
145 [ # # ]: 0 : (c == (TCCcmMode_t) 0) ||
146 [ # # ]: 0 : ((plen > 0) && (payload == (uint8_t *) 0)) ||
147 [ # # ]: 0 : ((alen > 0) && (associated_data == (uint8_t *) 0)) ||
148 : 0 : (alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */
149 [ # # ]: 0 : (plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */
150 [ # # ]: 0 : (olen < (plen + c->mlen))) { /* invalid output buffer size */
151 : : return TC_CRYPTO_FAIL;
152 : : }
153 : :
154 : 0 : uint8_t b[Nb * Nk];
155 : 0 : uint8_t tag[Nb * Nk];
156 : 0 : unsigned int i;
157 : :
158 : : /* GENERATING THE AUTHENTICATION TAG: */
159 : :
160 : : /* formatting the sequence b for authentication: */
161 [ # # ]: 0 : b[0] = ((alen > 0) ? 0x40:0) | (((c->mlen - 2) / 2 << 3)) | (1);
162 [ # # ]: 0 : for (i = 1; i <= 13; ++i) {
163 : 0 : b[i] = c->nonce[i - 1];
164 : : }
165 : 0 : b[14] = (uint8_t)(plen >> 8);
166 : 0 : b[15] = (uint8_t)(plen);
167 : :
168 : : /* computing the authentication tag using cbc-mac: */
169 : 0 : (void) tc_aes_encrypt(tag, b, c->sched);
170 [ # # ]: 0 : if (alen > 0) {
171 : 0 : ccm_cbc_mac(tag, associated_data, alen, 1, c->sched);
172 : : }
173 [ # # ]: 0 : if (plen > 0) {
174 : 0 : ccm_cbc_mac(tag, payload, plen, 0, c->sched);
175 : : }
176 : :
177 : : /* ENCRYPTION: */
178 : :
179 : : /* formatting the sequence b for encryption: */
180 : 0 : b[0] = 1; /* q - 1 = 2 - 1 = 1 */
181 : 0 : b[14] = b[15] = TC_ZERO_BYTE;
182 : :
183 : : /* encrypting payload using ctr mode: */
184 : 0 : ccm_ctr_mode(out, plen, payload, plen, b, c->sched);
185 : :
186 : 0 : 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 : 0 : (void) tc_aes_encrypt(b, b, c->sched);
190 : 0 : out += plen;
191 [ # # ]: 0 : for (i = 0; i < c->mlen; ++i) {
192 : 0 : *out++ = tag[i] ^ b[i];
193 : : }
194 : :
195 : : return TC_CRYPTO_SUCCESS;
196 : : }
197 : :
198 : 0 : 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 : 0 : if ((out == (uint8_t *) 0) ||
206 [ # # ]: 0 : (c == (TCCcmMode_t) 0) ||
207 [ # # ]: 0 : ((plen > 0) && (payload == (uint8_t *) 0)) ||
208 [ # # ]: 0 : ((alen > 0) && (associated_data == (uint8_t *) 0)) ||
209 : 0 : (alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */
210 [ # # ]: 0 : (plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */
211 [ # # ]: 0 : (olen < plen - c->mlen)) { /* invalid output buffer size */
212 : : return TC_CRYPTO_FAIL;
213 : : }
214 : :
215 : 0 : uint8_t b[Nb * Nk];
216 : 0 : uint8_t tag[Nb * Nk];
217 : 0 : unsigned int i;
218 : :
219 : : /* DECRYPTION: */
220 : :
221 : : /* formatting the sequence b for decryption: */
222 : 0 : b[0] = 1; /* q - 1 = 2 - 1 = 1 */
223 [ # # ]: 0 : for (i = 1; i < 14; ++i) {
224 : 0 : b[i] = c->nonce[i - 1];
225 : : }
226 : 0 : b[14] = b[15] = TC_ZERO_BYTE; /* initial counter value is 0 */
227 : :
228 : : /* decrypting payload using ctr mode: */
229 : 0 : ccm_ctr_mode(out, plen - c->mlen, payload, plen - c->mlen, b, c->sched);
230 : :
231 : 0 : b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter value (0) */
232 : :
233 : : /* encrypting b and restoring the tag from input: */
234 : 0 : (void) tc_aes_encrypt(b, b, c->sched);
235 [ # # ]: 0 : for (i = 0; i < c->mlen; ++i) {
236 : 0 : 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 [ # # ]: 0 : b[0] = ((alen > 0) ? 0x40:0)|(((c->mlen - 2) / 2 << 3)) | (1);
243 [ # # ]: 0 : for (i = 1; i < 14; ++i) {
244 : 0 : b[i] = c->nonce[i - 1];
245 : : }
246 : 0 : b[14] = (uint8_t)((plen - c->mlen) >> 8);
247 : 0 : b[15] = (uint8_t)(plen - c->mlen);
248 : :
249 : : /* computing the authentication tag using cbc-mac: */
250 : 0 : (void) tc_aes_encrypt(b, b, c->sched);
251 [ # # ]: 0 : if (alen > 0) {
252 : 0 : ccm_cbc_mac(b, associated_data, alen, 1, c->sched);
253 : : }
254 [ # # ]: 0 : if (plen > 0) {
255 : 0 : ccm_cbc_mac(b, out, plen - c->mlen, 0, c->sched);
256 : : }
257 : :
258 : : /* comparing the received tag and the computed one: */
259 [ # # ]: 0 : 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 : 0 : _set(out, 0, plen - c->mlen);
264 : 0 : return TC_CRYPTO_FAIL;
265 : : }
266 : : }
|