1/* LibTomCrypt, modular cryptographic library -- Tom St Denis 2 * 3 * LibTomCrypt is a library that provides various cryptographic 4 * algorithms in a highly modular and flexible manner. 5 * 6 * The library is free for all purposes without any express 7 * guarantee it works. 8 * 9 * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com 10 */ 11#include "tomcrypt.h" 12 13/** 14 @file ccm_memory.c 15 CCM support, process a block of memory, Tom St Denis 16*/ 17 18#ifdef CCM_MODE 19 20/** 21 CCM encrypt/decrypt and produce an authentication tag 22 @param cipher The index of the cipher desired 23 @param key The secret key to use 24 @param keylen The length of the secret key (octets) 25 @param uskey A previously scheduled key [optional can be NULL] 26 @param nonce The session nonce [use once] 27 @param noncelen The length of the nonce 28 @param header The header for the session 29 @param headerlen The length of the header (octets) 30 @param pt [out] The plaintext 31 @param ptlen The length of the plaintext (octets) 32 @param ct [out] The ciphertext 33 @param tag [out] The destination tag 34 @param taglen [in/out] The max size and resulting size of the authentication tag 35 @param direction Encrypt or Decrypt direction (0 or 1) 36 @return CRYPT_OK if successful 37*/ 38int ccm_memory(int cipher, 39 const unsigned char *key, unsigned long keylen, 40 symmetric_key *uskey, 41 const unsigned char *nonce, unsigned long noncelen, 42 const unsigned char *header, unsigned long headerlen, 43 unsigned char *pt, unsigned long ptlen, 44 unsigned char *ct, 45 unsigned char *tag, unsigned long *taglen, 46 int direction) 47{ 48 unsigned char PAD[16], ctr[16], CTRPAD[16], b; 49 symmetric_key *skey; 50 int err; 51 unsigned long len, L, x, y, z, CTRlen; 52 53 if (uskey == NULL) { 54 LTC_ARGCHK(key != NULL); 55 } 56 LTC_ARGCHK(nonce != NULL); 57 if (headerlen > 0) { 58 LTC_ARGCHK(header != NULL); 59 } 60 LTC_ARGCHK(pt != NULL); 61 LTC_ARGCHK(ct != NULL); 62 LTC_ARGCHK(tag != NULL); 63 LTC_ARGCHK(taglen != NULL); 64 65#ifdef LTC_FAST 66 if (16 % sizeof(LTC_FAST_TYPE)) { 67 return CRYPT_INVALID_ARG; 68 } 69#endif 70 71 /* check cipher input */ 72 if ((err = cipher_is_valid(cipher)) != CRYPT_OK) { 73 return err; 74 } 75 if (cipher_descriptor[cipher].block_length != 16) { 76 return CRYPT_INVALID_CIPHER; 77 } 78 79 /* make sure the taglen is even and <= 16 */ 80 *taglen &= ~1; 81 if (*taglen > 16) { 82 *taglen = 16; 83 } 84 85 /* can't use < 4 */ 86 if (*taglen < 4) { 87 return CRYPT_INVALID_ARG; 88 } 89 90 /* is there an accelerator? */ 91 if (cipher_descriptor[cipher].accel_ccm_memory != NULL) { 92 return cipher_descriptor[cipher].accel_ccm_memory( 93 key, keylen, 94 uskey, 95 nonce, noncelen, 96 header, headerlen, 97 pt, ptlen, 98 ct, 99 tag, taglen, 100 direction); 101 } 102 103 /* let's get the L value */ 104 len = ptlen; 105 L = 0; 106 while (len) { 107 ++L; 108 len >>= 8; 109 } 110 if (L <= 1) { 111 L = 2; 112 } 113 114 /* increase L to match the nonce len */ 115 noncelen = (noncelen > 13) ? 13 : noncelen; 116 if ((15 - noncelen) > L) { 117 L = 15 - noncelen; 118 } 119 120 /* decrease noncelen to match L */ 121 if ((noncelen + L) > 15) { 122 noncelen = 15 - L; 123 } 124 125 /* allocate mem for the symmetric key */ 126 if (uskey == NULL) { 127 skey = XMALLOC(sizeof(*skey)); 128 if (skey == NULL) { 129 return CRYPT_MEM; 130 } 131 132 /* initialize the cipher */ 133 if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, skey)) != CRYPT_OK) { 134 XFREE(skey); 135 return err; 136 } 137 } else { 138 skey = uskey; 139 } 140 141 /* form B_0 == flags | Nonce N | l(m) */ 142 x = 0; 143 PAD[x++] = (unsigned char)(((headerlen > 0) ? (1<<6) : 0) | 144 (((*taglen - 2)>>1)<<3) | 145 (L-1)); 146 147 /* nonce */ 148 for (y = 0; y < (16 - (L + 1)); y++) { 149 PAD[x++] = nonce[y]; 150 } 151 152 /* store len */ 153 len = ptlen; 154 155 /* shift len so the upper bytes of len are the contents of the length */ 156 for (y = L; y < 4; y++) { 157 len <<= 8; 158 } 159 160 /* store l(m) (only store 32-bits) */ 161 for (y = 0; L > 4 && (L-y)>4; y++) { 162 PAD[x++] = 0; 163 } 164 for (; y < L; y++) { 165 PAD[x++] = (unsigned char)((len >> 24) & 255); 166 len <<= 8; 167 } 168 169 /* encrypt PAD */ 170 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) { 171 goto error; 172 } 173 174 /* handle header */ 175 if (headerlen > 0) { 176 x = 0; 177 178 /* store length */ 179 if (headerlen < ((1UL<<16) - (1UL<<8))) { 180 PAD[x++] ^= (headerlen>>8) & 255; 181 PAD[x++] ^= headerlen & 255; 182 } else { 183 PAD[x++] ^= 0xFF; 184 PAD[x++] ^= 0xFE; 185 PAD[x++] ^= (headerlen>>24) & 255; 186 PAD[x++] ^= (headerlen>>16) & 255; 187 PAD[x++] ^= (headerlen>>8) & 255; 188 PAD[x++] ^= headerlen & 255; 189 } 190 191 /* now add the data */ 192 for (y = 0; y < headerlen; y++) { 193 if (x == 16) { 194 /* full block so let's encrypt it */ 195 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) { 196 goto error; 197 } 198 x = 0; 199 } 200 PAD[x++] ^= header[y]; 201 } 202 203 /* remainder? */ 204 if (x != 0) { 205 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) { 206 goto error; 207 } 208 } 209 } 210 211 /* setup the ctr counter */ 212 x = 0; 213 214 /* flags */ 215 ctr[x++] = (unsigned char)L-1; 216 217 /* nonce */ 218 for (y = 0; y < (16 - (L+1)); ++y) { 219 ctr[x++] = nonce[y]; 220 } 221 /* offset */ 222 while (x < 16) { 223 ctr[x++] = 0; 224 } 225 226 x = 0; 227 CTRlen = 16; 228 229 /* now handle the PT */ 230 if (ptlen > 0) { 231 y = 0; 232#ifdef LTC_FAST 233 if (ptlen & ~15) { 234 if (direction == CCM_ENCRYPT) { 235 for (; y < (ptlen & ~15); y += 16) { 236 /* increment the ctr? */ 237 for (z = 15; z > 15-L; z--) { 238 ctr[z] = (ctr[z] + 1) & 255; 239 if (ctr[z]) break; 240 } 241 if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) { 242 goto error; 243 } 244 245 /* xor the PT against the pad first */ 246 for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) { 247 *((LTC_FAST_TYPE*)(&PAD[z])) ^= *((LTC_FAST_TYPE*)(&pt[y+z])); 248 *((LTC_FAST_TYPE*)(&ct[y+z])) = *((LTC_FAST_TYPE*)(&pt[y+z])) ^ *((LTC_FAST_TYPE*)(&CTRPAD[z])); 249 } 250 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) { 251 goto error; 252 } 253 } 254 } else { 255 for (; y < (ptlen & ~15); y += 16) { 256 /* increment the ctr? */ 257 for (z = 15; z > 15-L; z--) { 258 ctr[z] = (ctr[z] + 1) & 255; 259 if (ctr[z]) break; 260 } 261 if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) { 262 goto error; 263 } 264 265 /* xor the PT against the pad last */ 266 for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) { 267 *((LTC_FAST_TYPE*)(&pt[y+z])) = *((LTC_FAST_TYPE*)(&ct[y+z])) ^ *((LTC_FAST_TYPE*)(&CTRPAD[z])); 268 *((LTC_FAST_TYPE*)(&PAD[z])) ^= *((LTC_FAST_TYPE*)(&pt[y+z])); 269 } 270 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) { 271 goto error; 272 } 273 } 274 } 275 } 276#endif 277 278 for (; y < ptlen; y++) { 279 /* increment the ctr? */ 280 if (CTRlen == 16) { 281 for (z = 15; z > 15-L; z--) { 282 ctr[z] = (ctr[z] + 1) & 255; 283 if (ctr[z]) break; 284 } 285 if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) { 286 goto error; 287 } 288 CTRlen = 0; 289 } 290 291 /* if we encrypt we add the bytes to the MAC first */ 292 if (direction == CCM_ENCRYPT) { 293 b = pt[y]; 294 ct[y] = b ^ CTRPAD[CTRlen++]; 295 } else { 296 b = ct[y] ^ CTRPAD[CTRlen++]; 297 pt[y] = b; 298 } 299 300 if (x == 16) { 301 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) { 302 goto error; 303 } 304 x = 0; 305 } 306 PAD[x++] ^= b; 307 } 308 309 if (x != 0) { 310 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) { 311 goto error; 312 } 313 } 314 } 315 316 /* setup CTR for the TAG (zero the count) */ 317 for (y = 15; y > 15 - L; y--) { 318 ctr[y] = 0x00; 319 } 320 if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) { 321 goto error; 322 } 323 324 if (skey != uskey) { 325 cipher_descriptor[cipher].done(skey); 326 } 327 328 /* store the TAG */ 329 for (x = 0; x < 16 && x < *taglen; x++) { 330 tag[x] = PAD[x] ^ CTRPAD[x]; 331 } 332 *taglen = x; 333 334#ifdef LTC_CLEAN_STACK 335 zeromem(skey, sizeof(*skey)); 336 zeromem(PAD, sizeof(PAD)); 337 zeromem(CTRPAD, sizeof(CTRPAD)); 338#endif 339error: 340 if (skey != uskey) { 341 XFREE(skey); 342 } 343 344 return err; 345} 346 347#endif 348 349/* $Source: /cvs/libtom/libtomcrypt/src/encauth/ccm/ccm_memory.c,v $ */ 350/* $Revision: 1.18 $ */ 351/* $Date: 2006/12/04 21:34:03 $ */ 352