Version 0.5.0 of tinydtls
Dependents: tinydtls_test_cellular tinydtls_test_ethernet tiny-dtls
ccm.c
00001 /* dtls -- a very basic DTLS implementation 00002 * 00003 * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org> 00004 * 00005 * Permission is hereby granted, free of charge, to any person 00006 * obtaining a copy of this software and associated documentation 00007 * files (the "Software"), to deal in the Software without 00008 * restriction, including without limitation the rights to use, copy, 00009 * modify, merge, publish, distribute, sublicense, and/or sell copies 00010 * of the Software, and to permit persons to whom the Software is 00011 * furnished to do so, subject to the following conditions: 00012 * 00013 * The above copyright notice and this permission notice shall be 00014 * included in all copies or substantial portions of the Software. 00015 * 00016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00017 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 00020 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 00021 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00022 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00023 * SOFTWARE. 00024 */ 00025 00026 #include <string.h> 00027 00028 #include "global.h" 00029 #include "numeric.h" 00030 #include "ccm.h" 00031 00032 #define CCM_FLAGS(A,M,L) (((A > 0) << 6) | (((M - 2)/2) << 3) | (L - 1)) 00033 00034 #define MASK_L(_L) ((1 << 8 * _L) - 1) 00035 00036 #define SET_COUNTER(A,L,cnt,C) { \ 00037 int i; \ 00038 memset((A) + DTLS_CCM_BLOCKSIZE - (L), 0, (L)); \ 00039 (C) = (cnt) & MASK_L(L); \ 00040 for (i = DTLS_CCM_BLOCKSIZE - 1; (C) && (i > (L)); --i, (C) >>= 8) \ 00041 (A)[i] |= (C) & 0xFF; \ 00042 } 00043 00044 static inline void 00045 block0(size_t M, /* number of auth bytes */ 00046 size_t L, /* number of bytes to encode message length */ 00047 size_t la, /* l(a) octets additional authenticated data */ 00048 size_t lm, /* l(m) message length */ 00049 unsigned char nonce[DTLS_CCM_BLOCKSIZE], 00050 unsigned char *result) { 00051 int i; 00052 00053 result[0] = CCM_FLAGS(la, M, L); 00054 00055 /* copy the nonce */ 00056 memcpy(result + 1, nonce, DTLS_CCM_BLOCKSIZE - L); 00057 00058 for (i=0; i < L; i++) { 00059 result[15-i] = lm & 0xff; 00060 lm >>= 8; 00061 } 00062 } 00063 00064 /** 00065 * Creates the CBC-MAC for the additional authentication data that 00066 * is sent in cleartext. 00067 * 00068 * \param ctx The crypto context for the AES encryption. 00069 * \param msg The message starting with the additional authentication data. 00070 * \param la The number of additional authentication bytes in \p msg. 00071 * \param B The input buffer for crypto operations. When this function 00072 * is called, \p B must be initialized with \c B0 (the first 00073 * authentication block. 00074 * \param X The output buffer where the result of the CBC calculation 00075 * is placed. 00076 * \return The result is written to \p X. 00077 */ 00078 static void 00079 add_auth_data(rijndael_ctx *ctx, const unsigned char *msg, size_t la, 00080 unsigned char B[DTLS_CCM_BLOCKSIZE], 00081 unsigned char X[DTLS_CCM_BLOCKSIZE]) { 00082 size_t i,j; 00083 00084 rijndael_encrypt(ctx, B, X); 00085 00086 memset(B, 0, DTLS_CCM_BLOCKSIZE); 00087 00088 if (!la) 00089 return; 00090 00091 #ifndef WITH_CONTIKI 00092 if (la < 0xFF00) { /* 2^16 - 2^8 */ 00093 j = 2; 00094 dtls_int_to_uint16(B, la); 00095 } else if (la <= UINT32_MAX) { 00096 j = 6; 00097 dtls_int_to_uint16(B, 0xFFFE); 00098 dtls_int_to_uint32(B+2, la); 00099 } else { 00100 j = 10; 00101 dtls_int_to_uint16(B, 0xFFFF); 00102 dtls_ulong_to_uint64(B+2, la); 00103 } 00104 #else /* WITH_CONTIKI */ 00105 /* With Contiki, we are building for small devices and thus 00106 * anticipate that the number of additional authentication bytes 00107 * will not exceed 65280 bytes (0xFF00) and we can skip the 00108 * workarounds required for j=6 and j=10 on devices with a word size 00109 * of 32 bits or 64 bits, respectively. 00110 */ 00111 00112 assert(la < 0xFF00); 00113 j = 2; 00114 dtls_int_to_uint16(B, la); 00115 #endif /* WITH_CONTIKI */ 00116 00117 i = min(DTLS_CCM_BLOCKSIZE - j, la); 00118 memcpy(B + j, msg, i); 00119 la -= i; 00120 msg += i; 00121 00122 memxor(B, X, DTLS_CCM_BLOCKSIZE); 00123 00124 rijndael_encrypt(ctx, B, X); 00125 00126 while (la > DTLS_CCM_BLOCKSIZE) { 00127 for (i = 0; i < DTLS_CCM_BLOCKSIZE; ++i) 00128 B[i] = X[i] ^ *msg++; 00129 la -= DTLS_CCM_BLOCKSIZE; 00130 00131 rijndael_encrypt(ctx, B, X); 00132 } 00133 00134 if (la) { 00135 memset(B, 0, DTLS_CCM_BLOCKSIZE); 00136 memcpy(B, msg, la); 00137 memxor(B, X, DTLS_CCM_BLOCKSIZE); 00138 00139 rijndael_encrypt(ctx, B, X); 00140 } 00141 } 00142 00143 static inline void 00144 encrypt(rijndael_ctx *ctx, size_t L, unsigned long counter, 00145 unsigned char *msg, size_t len, 00146 unsigned char A[DTLS_CCM_BLOCKSIZE], 00147 unsigned char S[DTLS_CCM_BLOCKSIZE]) { 00148 00149 static unsigned long counter_tmp; 00150 00151 SET_COUNTER(A, L, counter, counter_tmp); 00152 rijndael_encrypt(ctx, A, S); 00153 memxor(msg, S, len); 00154 } 00155 00156 static inline void 00157 mac(rijndael_ctx *ctx, 00158 unsigned char *msg, size_t len, 00159 unsigned char B[DTLS_CCM_BLOCKSIZE], 00160 unsigned char X[DTLS_CCM_BLOCKSIZE]) { 00161 size_t i; 00162 00163 for (i = 0; i < len; ++i) 00164 B[i] = X[i] ^ msg[i]; 00165 00166 rijndael_encrypt(ctx, B, X); 00167 00168 } 00169 00170 long int 00171 dtls_ccm_encrypt_message(rijndael_ctx *ctx, size_t M, size_t L, 00172 unsigned char nonce[DTLS_CCM_BLOCKSIZE], 00173 unsigned char *msg, size_t lm, 00174 const unsigned char *aad, size_t la) { 00175 size_t i, len; 00176 unsigned long counter_tmp; 00177 unsigned long counter = 1; /* \bug does not work correctly on ia32 when 00178 lm >= 2^16 */ 00179 unsigned char A[DTLS_CCM_BLOCKSIZE]; /* A_i blocks for encryption input */ 00180 unsigned char B[DTLS_CCM_BLOCKSIZE]; /* B_i blocks for CBC-MAC input */ 00181 unsigned char S[DTLS_CCM_BLOCKSIZE]; /* S_i = encrypted A_i blocks */ 00182 unsigned char X[DTLS_CCM_BLOCKSIZE]; /* X_i = encrypted B_i blocks */ 00183 00184 len = lm; /* save original length */ 00185 /* create the initial authentication block B0 */ 00186 block0(M, L, la, lm, nonce, B); 00187 add_auth_data(ctx, aad, la, B, X); 00188 00189 /* initialize block template */ 00190 A[0] = L-1; 00191 00192 /* copy the nonce */ 00193 memcpy(A + 1, nonce, DTLS_CCM_BLOCKSIZE - L); 00194 00195 while (lm >= DTLS_CCM_BLOCKSIZE) { 00196 /* calculate MAC */ 00197 mac(ctx, msg, DTLS_CCM_BLOCKSIZE, B, X); 00198 00199 /* encrypt */ 00200 encrypt(ctx, L, counter, msg, DTLS_CCM_BLOCKSIZE, A, S); 00201 00202 /* update local pointers */ 00203 lm -= DTLS_CCM_BLOCKSIZE; 00204 msg += DTLS_CCM_BLOCKSIZE; 00205 counter++; 00206 } 00207 00208 if (lm) { 00209 /* Calculate MAC. The remainder of B must be padded with zeroes, so 00210 * B is constructed to contain X ^ msg for the first lm bytes (done in 00211 * mac() and X ^ 0 for the remaining DTLS_CCM_BLOCKSIZE - lm bytes 00212 * (i.e., we can use memcpy() here). 00213 */ 00214 memcpy(B + lm, X + lm, DTLS_CCM_BLOCKSIZE - lm); 00215 mac(ctx, msg, lm, B, X); 00216 00217 /* encrypt */ 00218 encrypt(ctx, L, counter, msg, lm, A, S); 00219 00220 /* update local pointers */ 00221 msg += lm; 00222 } 00223 00224 /* calculate S_0 */ 00225 SET_COUNTER(A, L, 0, counter_tmp); 00226 rijndael_encrypt(ctx, A, S); 00227 00228 for (i = 0; i < M; ++i) 00229 *msg++ = X[i] ^ S[i]; 00230 00231 return len + M; 00232 } 00233 00234 long int 00235 dtls_ccm_decrypt_message(rijndael_ctx *ctx, size_t M, size_t L, 00236 unsigned char nonce[DTLS_CCM_BLOCKSIZE], 00237 unsigned char *msg, size_t lm, 00238 const unsigned char *aad, size_t la) { 00239 00240 size_t len; 00241 unsigned long counter_tmp; 00242 unsigned long counter = 1; /* \bug does not work correctly on ia32 when 00243 lm >= 2^16 */ 00244 unsigned char A[DTLS_CCM_BLOCKSIZE]; /* A_i blocks for encryption input */ 00245 unsigned char B[DTLS_CCM_BLOCKSIZE]; /* B_i blocks for CBC-MAC input */ 00246 unsigned char S[DTLS_CCM_BLOCKSIZE]; /* S_i = encrypted A_i blocks */ 00247 unsigned char X[DTLS_CCM_BLOCKSIZE]; /* X_i = encrypted B_i blocks */ 00248 00249 if (lm < M) 00250 goto error; 00251 00252 len = lm; /* save original length */ 00253 lm -= M; /* detract MAC size*/ 00254 00255 /* create the initial authentication block B0 */ 00256 block0(M, L, la, lm, nonce, B); 00257 add_auth_data(ctx, aad, la, B, X); 00258 00259 /* initialize block template */ 00260 A[0] = L-1; 00261 00262 /* copy the nonce */ 00263 memcpy(A + 1, nonce, DTLS_CCM_BLOCKSIZE - L); 00264 00265 while (lm >= DTLS_CCM_BLOCKSIZE) { 00266 /* decrypt */ 00267 encrypt(ctx, L, counter, msg, DTLS_CCM_BLOCKSIZE, A, S); 00268 00269 /* calculate MAC */ 00270 mac(ctx, msg, DTLS_CCM_BLOCKSIZE, B, X); 00271 00272 /* update local pointers */ 00273 lm -= DTLS_CCM_BLOCKSIZE; 00274 msg += DTLS_CCM_BLOCKSIZE; 00275 counter++; 00276 } 00277 00278 if (lm) { 00279 /* decrypt */ 00280 encrypt(ctx, L, counter, msg, lm, A, S); 00281 00282 /* Calculate MAC. Note that msg ends in the MAC so we must 00283 * construct B to contain X ^ msg for the first lm bytes (done in 00284 * mac() and X ^ 0 for the remaining DTLS_CCM_BLOCKSIZE - lm bytes 00285 * (i.e., we can use memcpy() here). 00286 */ 00287 memcpy(B + lm, X + lm, DTLS_CCM_BLOCKSIZE - lm); 00288 mac(ctx, msg, lm, B, X); 00289 00290 /* update local pointers */ 00291 msg += lm; 00292 } 00293 00294 /* calculate S_0 */ 00295 SET_COUNTER(A, L, 0, counter_tmp); 00296 rijndael_encrypt(ctx, A, S); 00297 00298 memxor(msg, S, M); 00299 00300 /* return length if MAC is valid, otherwise continue with error handling */ 00301 if (memcmp(X, msg, M) == 0) 00302 return len - M; 00303 00304 error: 00305 return -1; 00306 }
Generated on Tue Jul 12 2022 21:37:38 by 1.7.2