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