tinydtls  0.8.6
ccm.c
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * Copyright (c) 2011, 2012, 2013, 2014, 2015 Olaf Bergmann (TZI) and others.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
7  *
8  * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
9  * and the Eclipse Distribution License is available at
10  * http://www.eclipse.org/org/documents/edl-v10.php.
11  *
12  * Contributors:
13  * Olaf Bergmann - initial API and implementation
14  * Hauke Mehrtens - memory optimization, ECC integration
15  *
16  *******************************************************************************/
17 
18 #include <string.h>
19 
20 #include "tinydtls.h"
21 #include "global.h"
22 #include "numeric.h"
23 #include "ccm.h"
24 
25 #ifdef HAVE_ASSERT_H
26 # include <assert.h>
27 #endif
28 
29 #define CCM_FLAGS(A,M,L) (((A > 0) << 6) | (((M - 2)/2) << 3) | (L - 1))
30 
31 #define MASK_L(_L) ((1 << 8 * _L) - 1)
32 
33 #define SET_COUNTER(A,L,cnt,C) { \
34  unsigned int i_; \
35  memset((A) + DTLS_CCM_BLOCKSIZE - (L), 0, (L)); \
36  (C) = (cnt) & MASK_L(L); \
37  for (i_ = DTLS_CCM_BLOCKSIZE - 1; (C) && (i_ > (L)); --i_, (C) >>= 8) \
38  (A)[i_] |= (C) & 0xFF; \
39  }
40 
41 static inline void
42 block0(size_t M, /* number of auth bytes */
43  size_t L, /* number of bytes to encode message length */
44  size_t la, /* l(a) octets additional authenticated data */
45  size_t lm, /* l(m) message length */
46  unsigned char nonce[DTLS_CCM_BLOCKSIZE],
47  unsigned char *result) {
48  unsigned int i;
49 
50  result[0] = CCM_FLAGS(la, M, L);
51 
52  /* copy the nonce */
53  memcpy(result + 1, nonce, DTLS_CCM_BLOCKSIZE - L - 1);
54 
55  for (i=0; i < L; i++) {
56  result[15-i] = lm & 0xff;
57  lm >>= 8;
58  }
59 }
60 
75 static void
76 add_auth_data(rijndael_ctx *ctx, const unsigned char *msg, size_t la,
77  unsigned char B[DTLS_CCM_BLOCKSIZE],
78  unsigned char X[DTLS_CCM_BLOCKSIZE]) {
79  size_t i,j;
80 
81  rijndael_encrypt(ctx, B, X);
82 
83  memset(B, 0, DTLS_CCM_BLOCKSIZE);
84 
85  if (!la)
86  return;
87 
88 #ifndef WITH_CONTIKI
89  if (la < 0xFF00) { /* 2^16 - 2^8 */
90  j = 2;
91  dtls_int_to_uint16(B, la);
92  } else if (la <= UINT32_MAX) {
93  j = 6;
94  dtls_int_to_uint16(B, 0xFFFE);
95  dtls_int_to_uint32(B+2, la);
96  } else {
97  j = 10;
98  dtls_int_to_uint16(B, 0xFFFF);
99  dtls_int_to_uint64(B+2, la);
100  }
101 #else /* WITH_CONTIKI */
102  /* With Contiki, we are building for small devices and thus
103  * anticipate that the number of additional authentication bytes
104  * will not exceed 65280 bytes (0xFF00) and we can skip the
105  * workarounds required for j=6 and j=10 on devices with a word size
106  * of 32 bits or 64 bits, respectively.
107  */
108 
109  assert(la < 0xFF00);
110  j = 2;
111  dtls_int_to_uint16(B, la);
112 #endif /* WITH_CONTIKI */
113 
114  i = min(DTLS_CCM_BLOCKSIZE - j, la);
115  memcpy(B + j, msg, i);
116  la -= i;
117  msg += i;
118 
119  memxor(B, X, DTLS_CCM_BLOCKSIZE);
120 
121  rijndael_encrypt(ctx, B, X);
122 
123  while (la > DTLS_CCM_BLOCKSIZE) {
124  for (i = 0; i < DTLS_CCM_BLOCKSIZE; ++i)
125  B[i] = X[i] ^ *msg++;
126  la -= DTLS_CCM_BLOCKSIZE;
127 
128  rijndael_encrypt(ctx, B, X);
129  }
130 
131  if (la) {
132  memset(B, 0, DTLS_CCM_BLOCKSIZE);
133  memcpy(B, msg, la);
134  memxor(B, X, DTLS_CCM_BLOCKSIZE);
135 
136  rijndael_encrypt(ctx, B, X);
137  }
138 }
139 
140 static inline void
141 encrypt(rijndael_ctx *ctx, size_t L, unsigned long counter,
142  unsigned char *msg, size_t len,
143  unsigned char A[DTLS_CCM_BLOCKSIZE],
144  unsigned char S[DTLS_CCM_BLOCKSIZE]) {
145 
146  static unsigned long counter_tmp;
147 
148  SET_COUNTER(A, L, counter, counter_tmp);
149  rijndael_encrypt(ctx, A, S);
150  memxor(msg, S, len);
151 }
152 
153 static inline void
154 mac(rijndael_ctx *ctx,
155  unsigned char *msg, size_t len,
156  unsigned char B[DTLS_CCM_BLOCKSIZE],
157  unsigned char X[DTLS_CCM_BLOCKSIZE]) {
158  size_t i;
159 
160  for (i = 0; i < len; ++i)
161  B[i] = X[i] ^ msg[i];
162 
163  rijndael_encrypt(ctx, B, X);
164 
165 }
166 
167 long int
168 dtls_ccm_encrypt_message(rijndael_ctx *ctx, size_t M, size_t L,
169  unsigned char nonce[DTLS_CCM_BLOCKSIZE],
170  unsigned char *msg, size_t lm,
171  const unsigned char *aad, size_t la) {
172  size_t i, len;
173  unsigned long counter_tmp;
174  unsigned long counter = 1; /* \bug does not work correctly on ia32 when
175  lm >= 2^16 */
176  unsigned char A[DTLS_CCM_BLOCKSIZE]; /* A_i blocks for encryption input */
177  unsigned char B[DTLS_CCM_BLOCKSIZE]; /* B_i blocks for CBC-MAC input */
178  unsigned char S[DTLS_CCM_BLOCKSIZE]; /* S_i = encrypted A_i blocks */
179  unsigned char X[DTLS_CCM_BLOCKSIZE]; /* X_i = encrypted B_i blocks */
180 
181  len = lm; /* save original length */
182  /* create the initial authentication block B0 */
183  block0(M, L, la, lm, nonce, B);
184  add_auth_data(ctx, aad, la, B, X);
185 
186  /* initialize block template */
187  A[0] = L-1;
188 
189  /* copy the nonce */
190  memcpy(A + 1, nonce, DTLS_CCM_BLOCKSIZE - L - 1);
191 
192  while (lm >= DTLS_CCM_BLOCKSIZE) {
193  /* calculate MAC */
194  mac(ctx, msg, DTLS_CCM_BLOCKSIZE, B, X);
195 
196  /* encrypt */
197  encrypt(ctx, L, counter, msg, DTLS_CCM_BLOCKSIZE, A, S);
198 
199  /* update local pointers */
200  lm -= DTLS_CCM_BLOCKSIZE;
201  msg += DTLS_CCM_BLOCKSIZE;
202  counter++;
203  }
204 
205  if (lm) {
206  /* Calculate MAC. The remainder of B must be padded with zeroes, so
207  * B is constructed to contain X ^ msg for the first lm bytes (done in
208  * mac() and X ^ 0 for the remaining DTLS_CCM_BLOCKSIZE - lm bytes
209  * (i.e., we can use memcpy() here).
210  */
211  memcpy(B + lm, X + lm, DTLS_CCM_BLOCKSIZE - lm);
212  mac(ctx, msg, lm, B, X);
213 
214  /* encrypt */
215  encrypt(ctx, L, counter, msg, lm, A, S);
216 
217  /* update local pointers */
218  msg += lm;
219  }
220 
221  /* calculate S_0 */
222  SET_COUNTER(A, L, 0, counter_tmp);
223  rijndael_encrypt(ctx, A, S);
224 
225  for (i = 0; i < M; ++i)
226  *msg++ = X[i] ^ S[i];
227 
228  return len + M;
229 }
230 
231 long int
232 dtls_ccm_decrypt_message(rijndael_ctx *ctx, size_t M, size_t L,
233  unsigned char nonce[DTLS_CCM_BLOCKSIZE],
234  unsigned char *msg, size_t lm,
235  const unsigned char *aad, size_t la) {
236 
237  size_t len;
238  unsigned long counter_tmp;
239  unsigned long counter = 1; /* \bug does not work correctly on ia32 when
240  lm >= 2^16 */
241  unsigned char A[DTLS_CCM_BLOCKSIZE]; /* A_i blocks for encryption input */
242  unsigned char B[DTLS_CCM_BLOCKSIZE]; /* B_i blocks for CBC-MAC input */
243  unsigned char S[DTLS_CCM_BLOCKSIZE]; /* S_i = encrypted A_i blocks */
244  unsigned char X[DTLS_CCM_BLOCKSIZE]; /* X_i = encrypted B_i blocks */
245 
246  if (lm < M)
247  goto error;
248 
249  len = lm; /* save original length */
250  lm -= M; /* detract MAC size*/
251 
252  /* create the initial authentication block B0 */
253  block0(M, L, la, lm, nonce, B);
254  add_auth_data(ctx, aad, la, B, X);
255 
256  /* initialize block template */
257  A[0] = L-1;
258 
259  /* copy the nonce */
260  memcpy(A + 1, nonce, DTLS_CCM_BLOCKSIZE - L - 1);
261 
262  while (lm >= DTLS_CCM_BLOCKSIZE) {
263  /* decrypt */
264  encrypt(ctx, L, counter, msg, DTLS_CCM_BLOCKSIZE, A, S);
265 
266  /* calculate MAC */
267  mac(ctx, msg, DTLS_CCM_BLOCKSIZE, B, X);
268 
269  /* update local pointers */
270  lm -= DTLS_CCM_BLOCKSIZE;
271  msg += DTLS_CCM_BLOCKSIZE;
272  counter++;
273  }
274 
275  if (lm) {
276  /* decrypt */
277  encrypt(ctx, L, counter, msg, lm, A, S);
278 
279  /* Calculate MAC. Note that msg ends in the MAC so we must
280  * construct B to contain X ^ msg for the first lm bytes (done in
281  * mac() and X ^ 0 for the remaining DTLS_CCM_BLOCKSIZE - lm bytes
282  * (i.e., we can use memcpy() here).
283  */
284  memcpy(B + lm, X + lm, DTLS_CCM_BLOCKSIZE - lm);
285  mac(ctx, msg, lm, B, X);
286 
287  /* update local pointers */
288  msg += lm;
289  }
290 
291  /* calculate S_0 */
292  SET_COUNTER(A, L, 0, counter_tmp);
293  rijndael_encrypt(ctx, A, S);
294 
295  memxor(msg, S, M);
296 
297  /* return length if MAC is valid, otherwise continue with error handling */
298  if (equals(X, msg, M))
299  return len - M;
300 
301  error:
302  return -1;
303 }
public tinydtls API
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:42
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:232
static void memxor(unsigned char *x, const unsigned char *y, size_t n)
Definition: global.h:101
#define assert(x)
Definition: hmac.c:25
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:141
#define CCM_FLAGS(A, M, L)
Definition: ccm.c:29
#define min(a, b)
Definition: dtls_debug.c:39
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:168
static int dtls_int_to_uint64(unsigned char *field, uint64_t value)
Definition: numeric.h:73
static int dtls_int_to_uint16(unsigned char *field, uint16_t value)
Definition: numeric.h:38
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:76
static int dtls_int_to_uint32(unsigned char *field, uint32_t value)
Definition: numeric.h:53
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:154
#define DTLS_CCM_BLOCKSIZE
Definition: ccm.h:25
static int equals(unsigned char *a, unsigned char *b, size_t len)
Definition: global.h:119
#define SET_COUNTER(A, L, cnt, C)
Definition: ccm.c:33