mbed port of tinydtls

Committer:
ashleymills
Date:
Fri Oct 11 08:46:21 2013 +0000
Revision:
1:bc8a649bad13
Parent:
0:04990d454f45
Cleaned up all the debug stuff I added finding the hash table bug.

Who changed what in which revision?

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