1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3 * LibTomCrypt is a library that provides various cryptographic
4 * algorithms in a highly modular and flexible manner.
6 * The library is free for all purposes without any express
13 CCM support, process a block of memory, Tom St Denis
19 CCM encrypt/decrypt and produce an authentication tag
21 *1 'pt', 'ct' and 'tag' can both be 'in' or 'out', depending on 'direction'
23 @param cipher The index of the cipher desired
24 @param key The secret key to use
25 @param keylen The length of the secret key (octets)
26 @param uskey A previously scheduled key [optional can be NULL]
27 @param nonce The session nonce [use once]
28 @param noncelen The length of the nonce
29 @param header The header for the session
30 @param headerlen The length of the header (octets)
31 @param pt [*1] The plaintext
32 @param ptlen The length of the plaintext (octets)
33 @param ct [*1] The ciphertext
34 @param tag [*1] The destination tag
35 @param taglen The max size and resulting size of the authentication tag
36 @param direction Encrypt or Decrypt direction (0 or 1)
37 @return CRYPT_OK if successful
39 int ccm_memory(int cipher,
40 const unsigned char *key, unsigned long keylen,
42 const unsigned char *nonce, unsigned long noncelen,
43 const unsigned char *header, unsigned long headerlen,
44 unsigned char *pt, unsigned long ptlen,
46 unsigned char *tag, unsigned long *taglen,
49 unsigned char PAD[16], ctr[16], CTRPAD[16], ptTag[16], b, *pt_real;
50 unsigned char *pt_work = NULL;
53 unsigned long len, L, x, y, z, CTRlen;
55 LTC_FAST_TYPE fastMask = ~(LTC_FAST_TYPE)0; /* initialize fastMask at all zeroes */
57 unsigned char mask = 0xff; /* initialize mask at all zeroes */
60 LTC_ARGCHK(key != NULL);
62 LTC_ARGCHK(nonce != NULL);
64 LTC_ARGCHK(header != NULL);
66 LTC_ARGCHK(pt != NULL);
67 LTC_ARGCHK(ct != NULL);
68 LTC_ARGCHK(tag != NULL);
69 LTC_ARGCHK(taglen != NULL);
74 if (16 % sizeof(LTC_FAST_TYPE)) {
75 return CRYPT_INVALID_ARG;
79 /* check cipher input */
80 if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
83 if (cipher_descriptor[cipher].block_length != 16) {
84 return CRYPT_INVALID_CIPHER;
87 /* make sure the taglen is even and <= 16 */
95 return CRYPT_INVALID_ARG;
98 /* is there an accelerator? */
99 if (cipher_descriptor[cipher].accel_ccm_memory != NULL) {
100 return cipher_descriptor[cipher].accel_ccm_memory(
111 /* let's get the L value */
122 /* increase L to match the nonce len */
123 noncelen = (noncelen > 13) ? 13 : noncelen;
124 if ((15 - noncelen) > L) {
128 /* allocate mem for the symmetric key */
130 skey = XMALLOC(sizeof(*skey));
135 /* initialize the cipher */
136 if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, skey)) != CRYPT_OK) {
144 /* initialize buffer for pt */
145 if (direction == CCM_DECRYPT && ptlen > 0) {
146 pt_work = XMALLOC(ptlen);
147 if (pt_work == NULL) {
153 /* form B_0 == flags | Nonce N | l(m) */
155 PAD[x++] = (unsigned char)(((headerlen > 0) ? (1<<6) : 0) |
156 (((*taglen - 2)>>1)<<3) |
160 for (y = 0; y < (16 - (L + 1)); y++) {
167 /* shift len so the upper bytes of len are the contents of the length */
168 for (y = L; y < 4; y++) {
172 /* store l(m) (only store 32-bits) */
173 for (y = 0; L > 4 && (L-y)>4; y++) {
177 PAD[x++] = (unsigned char)((len >> 24) & 255);
182 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
191 if (headerlen < ((1UL<<16) - (1UL<<8))) {
192 PAD[x++] ^= (headerlen>>8) & 255;
193 PAD[x++] ^= headerlen & 255;
197 PAD[x++] ^= (headerlen>>24) & 255;
198 PAD[x++] ^= (headerlen>>16) & 255;
199 PAD[x++] ^= (headerlen>>8) & 255;
200 PAD[x++] ^= headerlen & 255;
203 /* now add the data */
204 for (y = 0; y < headerlen; y++) {
206 /* full block so let's encrypt it */
207 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
212 PAD[x++] ^= header[y];
216 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
221 /* setup the ctr counter */
225 ctr[x++] = (unsigned char)L-1;
228 for (y = 0; y < (16 - (L+1)); ++y) {
239 /* now handle the PT */
244 if (direction == CCM_ENCRYPT) {
245 for (; y < (ptlen & ~15); y += 16) {
246 /* increment the ctr? */
247 for (z = 15; z > 15-L; z--) {
248 ctr[z] = (ctr[z] + 1) & 255;
251 if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
255 /* xor the PT against the pad first */
256 for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
257 *(LTC_FAST_TYPE_PTR_CAST(&PAD[z])) ^= *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z]));
258 *(LTC_FAST_TYPE_PTR_CAST(&ct[y+z])) = *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z])) ^ *(LTC_FAST_TYPE_PTR_CAST(&CTRPAD[z]));
260 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
264 } else { /* direction == CCM_DECRYPT */
265 for (; y < (ptlen & ~15); y += 16) {
266 /* increment the ctr? */
267 for (z = 15; z > 15-L; z--) {
268 ctr[z] = (ctr[z] + 1) & 255;
271 if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
275 /* xor the PT against the pad last */
276 for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
277 *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z])) = *(LTC_FAST_TYPE_PTR_CAST(&ct[y+z])) ^ *(LTC_FAST_TYPE_PTR_CAST(&CTRPAD[z]));
278 *(LTC_FAST_TYPE_PTR_CAST(&PAD[z])) ^= *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z]));
280 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
288 for (; y < ptlen; y++) {
289 /* increment the ctr? */
291 for (z = 15; z > 15-L; z--) {
292 ctr[z] = (ctr[z] + 1) & 255;
295 if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
301 /* if we encrypt we add the bytes to the MAC first */
302 if (direction == CCM_ENCRYPT) {
304 ct[y] = b ^ CTRPAD[CTRlen++];
306 b = ct[y] ^ CTRPAD[CTRlen++];
311 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
320 if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
326 /* setup CTR for the TAG (zero the count) */
327 for (y = 15; y > 15 - L; y--) {
330 if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
335 cipher_descriptor[cipher].done(skey);
336 #ifdef LTC_CLEAN_STACK
337 zeromem(skey, sizeof(*skey));
341 if (direction == CCM_ENCRYPT) {
343 for (x = 0; x < 16 && x < *taglen; x++) {
344 tag[x] = PAD[x] ^ CTRPAD[x];
347 } else { /* direction == CCM_DECRYPT */
348 /* decrypt the tag */
349 for (x = 0; x < 16 && x < *taglen; x++) {
350 ptTag[x] = tag[x] ^ CTRPAD[x];
354 /* check validity of the decrypted tag against the computed PAD (in constant time) */
355 /* HACK: the boolean value of XMEM_NEQ becomes either 0 (CRYPT_OK) or 1 (CRYPT_ERR).
356 * there should be a better way of setting the correct error code in constant
359 err = XMEM_NEQ(ptTag, PAD, *taglen);
361 /* Zero the plaintext if the tag was invalid (in constant time) */
364 mask *= 1 - err; /* mask = ( err ? 0 : 0xff ) */
368 for (; y < (ptlen & ~15); y += 16) {
369 for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
370 *(LTC_FAST_TYPE_PTR_CAST(&pt_real[y+z])) = *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z])) & fastMask;
375 for (; y < ptlen; y++) {
376 pt_real[y] = pt[y] & mask;
381 #ifdef LTC_CLEAN_STACK
386 zeromem(PAD, sizeof(PAD));
387 zeromem(CTRPAD, sizeof(CTRPAD));
388 if (pt_work != NULL) {
389 zeromem(pt_work, ptlen);
405 /* ref: $Format:%D$ */
406 /* git commit: $Format:%H$ */
407 /* commit time: $Format:%ai$ */