1 /* dtls -- a very basic DTLS implementation
2  *
3  * Copyright (C) 2011--2014 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * Permission is hereby granted, free of charge, to any person
6  * obtaining a copy of this software and associated documentation
7  * files (the "Software"), to deal in the Software without
8  * restriction, including without limitation the rights to use, copy,
9  * modify, merge, publish, distribute, sublicense, and/or sell copies
10  * of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 #include <string.h>
27 
28 #include "dtls_config.h"
29 #include "global.h"
30 #include "numeric.h"
31 #include "ccm.h"
32 
33 #ifdef HAVE_ASSERT_H
34 # include <assert.h>
35 #endif
36 
37 #define CCM_FLAGS(A,M,L) (((A > 0) << 6) | (((M - 2)/2) << 3) | (L - 1))
38 
39 #define MASK_L(_L) ((1 << 8 * _L) - 1)
40 
41 #define SET_COUNTER(A,L,cnt,C) {					\
42     int i;								\
43     memset((A) + DTLS_CCM_BLOCKSIZE - (L), 0, (L));			\
44     (C) = (cnt) & MASK_L(L);						\
45     for (i = DTLS_CCM_BLOCKSIZE - 1; (C) && (i > (L)); --i, (C) >>= 8)	\
46       (A)[i] |= (C) & 0xFF;						\
47   }
48 
49 static inline void
block0(size_t M,size_t L,size_t la,size_t lm,unsigned char nonce[DTLS_CCM_BLOCKSIZE],unsigned char * result)50 block0(size_t M,       /* number of auth bytes */
51        size_t L,       /* number of bytes to encode message length */
52        size_t la,      /* l(a) octets additional authenticated data */
53        size_t lm,      /* l(m) message length */
54        unsigned char nonce[DTLS_CCM_BLOCKSIZE],
55        unsigned char *result) {
56   int i;
57 
58   result[0] = CCM_FLAGS(la, M, L);
59 
60   /* copy the nonce */
61   memcpy(result + 1, nonce, DTLS_CCM_BLOCKSIZE - L);
62 
63   for (i=0; i < L; i++) {
64     result[15-i] = lm & 0xff;
65     lm >>= 8;
66   }
67 }
68 
69 /**
70  * Creates the CBC-MAC for the additional authentication data that
71  * is sent in cleartext.
72  *
73  * \param ctx  The crypto context for the AES encryption.
74  * \param msg  The message starting with the additional authentication data.
75  * \param la   The number of additional authentication bytes in \p msg.
76  * \param B    The input buffer for crypto operations. When this function
77  *             is called, \p B must be initialized with \c B0 (the first
78  *             authentication block.
79  * \param X    The output buffer where the result of the CBC calculation
80  *             is placed.
81  * \return     The result is written to \p X.
82  */
83 static void
add_auth_data(rijndael_ctx * ctx,const unsigned char * msg,size_t la,unsigned char B[DTLS_CCM_BLOCKSIZE],unsigned char X[DTLS_CCM_BLOCKSIZE])84 add_auth_data(rijndael_ctx *ctx, const unsigned char *msg, size_t la,
85 	      unsigned char B[DTLS_CCM_BLOCKSIZE],
86 	      unsigned char X[DTLS_CCM_BLOCKSIZE]) {
87   size_t i,j;
88 
89   rijndael_encrypt(ctx, B, X);
90 
91   memset(B, 0, DTLS_CCM_BLOCKSIZE);
92 
93   if (!la)
94     return;
95 
96 #ifndef WITH_CONTIKI
97     if (la < 0xFF00) {		/* 2^16 - 2^8 */
98       j = 2;
99       dtls_int_to_uint16(B, la);
100   } else if (la <= UINT32_MAX) {
101       j = 6;
102       dtls_int_to_uint16(B, 0xFFFE);
103       dtls_int_to_uint32(B+2, la);
104     } else {
105       j = 10;
106       dtls_int_to_uint16(B, 0xFFFF);
107       dtls_int_to_uint64(B+2, la);
108     }
109 #else /* WITH_CONTIKI */
110   /* With Contiki, we are building for small devices and thus
111    * anticipate that the number of additional authentication bytes
112    * will not exceed 65280 bytes (0xFF00) and we can skip the
113    * workarounds required for j=6 and j=10 on devices with a word size
114    * of 32 bits or 64 bits, respectively.
115    */
116 
117   assert(la < 0xFF00);
118   j = 2;
119   dtls_int_to_uint16(B, la);
120 #endif /* WITH_CONTIKI */
121 
122     i = min(DTLS_CCM_BLOCKSIZE - j, la);
123     memcpy(B + j, msg, i);
124     la -= i;
125     msg += i;
126 
127     memxor(B, X, DTLS_CCM_BLOCKSIZE);
128 
129   rijndael_encrypt(ctx, B, X);
130 
131   while (la > DTLS_CCM_BLOCKSIZE) {
132     for (i = 0; i < DTLS_CCM_BLOCKSIZE; ++i)
133       B[i] = X[i] ^ *msg++;
134     la -= DTLS_CCM_BLOCKSIZE;
135 
136     rijndael_encrypt(ctx, B, X);
137   }
138 
139   if (la) {
140     memset(B, 0, DTLS_CCM_BLOCKSIZE);
141     memcpy(B, msg, la);
142     memxor(B, X, DTLS_CCM_BLOCKSIZE);
143 
144     rijndael_encrypt(ctx, B, X);
145   }
146 }
147 
148 static inline void
encrypt(rijndael_ctx * ctx,size_t L,unsigned long counter,unsigned char * msg,size_t len,unsigned char A[DTLS_CCM_BLOCKSIZE],unsigned char S[DTLS_CCM_BLOCKSIZE])149 encrypt(rijndael_ctx *ctx, size_t L, unsigned long counter,
150 	unsigned char *msg, size_t len,
151 	unsigned char A[DTLS_CCM_BLOCKSIZE],
152 	unsigned char S[DTLS_CCM_BLOCKSIZE]) {
153 
154   static unsigned long counter_tmp;
155 
156   SET_COUNTER(A, L, counter, counter_tmp);
157   rijndael_encrypt(ctx, A, S);
158   memxor(msg, S, len);
159 }
160 
161 static inline void
mac(rijndael_ctx * ctx,unsigned char * msg,size_t len,unsigned char B[DTLS_CCM_BLOCKSIZE],unsigned char X[DTLS_CCM_BLOCKSIZE])162 mac(rijndael_ctx *ctx,
163     unsigned char *msg, size_t len,
164     unsigned char B[DTLS_CCM_BLOCKSIZE],
165     unsigned char X[DTLS_CCM_BLOCKSIZE]) {
166   size_t i;
167 
168   for (i = 0; i < len; ++i)
169     B[i] = X[i] ^ msg[i];
170 
171   rijndael_encrypt(ctx, B, X);
172 
173 }
174 
175 long int
dtls_ccm_encrypt_message(rijndael_ctx * ctx,size_t M,size_t L,unsigned char nonce[DTLS_CCM_BLOCKSIZE],unsigned char * msg,size_t lm,const unsigned char * aad,size_t la)176 dtls_ccm_encrypt_message(rijndael_ctx *ctx, size_t M, size_t L,
177 			 unsigned char nonce[DTLS_CCM_BLOCKSIZE],
178 			 unsigned char *msg, size_t lm,
179 			 const unsigned char *aad, size_t la) {
180   size_t i, len;
181   unsigned long counter_tmp;
182   unsigned long counter = 1; /* \bug does not work correctly on ia32 when
183 			             lm >= 2^16 */
184   unsigned char A[DTLS_CCM_BLOCKSIZE]; /* A_i blocks for encryption input */
185   unsigned char B[DTLS_CCM_BLOCKSIZE]; /* B_i blocks for CBC-MAC input */
186   unsigned char S[DTLS_CCM_BLOCKSIZE]; /* S_i = encrypted A_i blocks */
187   unsigned char X[DTLS_CCM_BLOCKSIZE]; /* X_i = encrypted B_i blocks */
188 
189   len = lm;			/* save original length */
190   /* create the initial authentication block B0 */
191   block0(M, L, la, lm, nonce, B);
192   add_auth_data(ctx, aad, la, B, X);
193 
194   /* initialize block template */
195   A[0] = L-1;
196 
197   /* copy the nonce */
198   memcpy(A + 1, nonce, DTLS_CCM_BLOCKSIZE - L);
199 
200   while (lm >= DTLS_CCM_BLOCKSIZE) {
201     /* calculate MAC */
202     mac(ctx, msg, DTLS_CCM_BLOCKSIZE, B, X);
203 
204     /* encrypt */
205     encrypt(ctx, L, counter, msg, DTLS_CCM_BLOCKSIZE, A, S);
206 
207     /* update local pointers */
208     lm -= DTLS_CCM_BLOCKSIZE;
209     msg += DTLS_CCM_BLOCKSIZE;
210     counter++;
211   }
212 
213   if (lm) {
214     /* Calculate MAC. The remainder of B must be padded with zeroes, so
215      * B is constructed to contain X ^ msg for the first lm bytes (done in
216      * mac() and X ^ 0 for the remaining DTLS_CCM_BLOCKSIZE - lm bytes
217      * (i.e., we can use memcpy() here).
218      */
219     memcpy(B + lm, X + lm, DTLS_CCM_BLOCKSIZE - lm);
220     mac(ctx, msg, lm, B, X);
221 
222     /* encrypt */
223     encrypt(ctx, L, counter, msg, lm, A, S);
224 
225     /* update local pointers */
226     msg += lm;
227   }
228 
229   /* calculate S_0 */
230   SET_COUNTER(A, L, 0, counter_tmp);
231   rijndael_encrypt(ctx, A, S);
232 
233   for (i = 0; i < M; ++i)
234     *msg++ = X[i] ^ S[i];
235 
236   return len + M;
237 }
238 
239 long int
dtls_ccm_decrypt_message(rijndael_ctx * ctx,size_t M,size_t L,unsigned char nonce[DTLS_CCM_BLOCKSIZE],unsigned char * msg,size_t lm,const unsigned char * aad,size_t la)240 dtls_ccm_decrypt_message(rijndael_ctx *ctx, size_t M, size_t L,
241 			 unsigned char nonce[DTLS_CCM_BLOCKSIZE],
242 			 unsigned char *msg, size_t lm,
243 			 const unsigned char *aad, size_t la) {
244 
245   size_t len;
246   unsigned long counter_tmp;
247   unsigned long counter = 1; /* \bug does not work correctly on ia32 when
248 			             lm >= 2^16 */
249   unsigned char A[DTLS_CCM_BLOCKSIZE]; /* A_i blocks for encryption input */
250   unsigned char B[DTLS_CCM_BLOCKSIZE]; /* B_i blocks for CBC-MAC input */
251   unsigned char S[DTLS_CCM_BLOCKSIZE]; /* S_i = encrypted A_i blocks */
252   unsigned char X[DTLS_CCM_BLOCKSIZE]; /* X_i = encrypted B_i blocks */
253 
254   if (lm < M)
255     goto error;
256 
257   len = lm;	      /* save original length */
258   lm -= M;	      /* detract MAC size*/
259 
260   /* create the initial authentication block B0 */
261   block0(M, L, la, lm, nonce, B);
262   add_auth_data(ctx, aad, la, B, X);
263 
264   /* initialize block template */
265   A[0] = L-1;
266 
267   /* copy the nonce */
268   memcpy(A + 1, nonce, DTLS_CCM_BLOCKSIZE - L);
269 
270   while (lm >= DTLS_CCM_BLOCKSIZE) {
271     /* decrypt */
272     encrypt(ctx, L, counter, msg, DTLS_CCM_BLOCKSIZE, A, S);
273 
274     /* calculate MAC */
275     mac(ctx, msg, DTLS_CCM_BLOCKSIZE, B, X);
276 
277     /* update local pointers */
278     lm -= DTLS_CCM_BLOCKSIZE;
279     msg += DTLS_CCM_BLOCKSIZE;
280     counter++;
281   }
282 
283   if (lm) {
284     /* decrypt */
285     encrypt(ctx, L, counter, msg, lm, A, S);
286 
287     /* Calculate MAC. Note that msg ends in the MAC so we must
288      * construct B to contain X ^ msg for the first lm bytes (done in
289      * mac() and X ^ 0 for the remaining DTLS_CCM_BLOCKSIZE - lm bytes
290      * (i.e., we can use memcpy() here).
291      */
292     memcpy(B + lm, X + lm, DTLS_CCM_BLOCKSIZE - lm);
293     mac(ctx, msg, lm, B, X);
294 
295     /* update local pointers */
296     msg += lm;
297   }
298 
299   /* calculate S_0 */
300   SET_COUNTER(A, L, 0, counter_tmp);
301   rijndael_encrypt(ctx, A, S);
302 
303   memxor(msg, S, M);
304 
305   /* return length if MAC is valid, otherwise continue with error handling */
306   if (equals(X, msg, M))
307     return len - M;
308 
309  error:
310   return -1;
311 }
312