tinydtls  0.8.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
ccm.c
Go to the documentation of this file.
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
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 
83 static void
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
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
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
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
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 }
static void block0(size_t M, size_t L, size_t la, size_t lm, unsigned char nonce[DTLS_CCM_BLOCKSIZE], unsigned char *result)
Definition: ccm.c:50
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)
Definition: ccm.c:240
#define min(a, b)
Definition: debug.c:114
static void memxor(unsigned char *x, const unsigned char *y, size_t n)
Definition: global.h:109
static 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])
Definition: ccm.c:149
#define CCM_FLAGS(A, M, L)
Definition: ccm.c:37
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)
Definition: ccm.c:176
static int dtls_int_to_uint64(unsigned char *field, uint64_t value)
Definition: numeric.h:81
static int dtls_int_to_uint16(unsigned char *field, uint16_t value)
Definition: numeric.h:46
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])
Definition: ccm.c:84
static int dtls_int_to_uint32(unsigned char *field, uint32_t value)
Definition: numeric.h:61
static void mac(rijndael_ctx *ctx, unsigned char *msg, size_t len, unsigned char B[DTLS_CCM_BLOCKSIZE], unsigned char X[DTLS_CCM_BLOCKSIZE])
Definition: ccm.c:162
#define DTLS_CCM_BLOCKSIZE
Definition: ccm.h:33
static int equals(unsigned char *a, unsigned char *b, size_t len)
Definition: global.h:127
#define SET_COUNTER(A, L, cnt, C)
Definition: ccm.c:41