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