Path: blob/master/libs/tomcrypt/src/encauth/ccm/ccm_memory.c
5972 views
/* LibTomCrypt, modular cryptographic library -- Tom St Denis1*2* LibTomCrypt is a library that provides various cryptographic3* algorithms in a highly modular and flexible manner.4*5* The library is free for all purposes without any express6* guarantee it works.7*/8#include "tomcrypt.h"910/**11@file ccm_memory.c12CCM support, process a block of memory, Tom St Denis13*/1415#ifdef LTC_CCM_MODE1617/**18CCM encrypt/decrypt and produce an authentication tag1920*1 'pt', 'ct' and 'tag' can both be 'in' or 'out', depending on 'direction'2122@param cipher The index of the cipher desired23@param key The secret key to use24@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 nonce28@param header The header for the session29@param headerlen The length of the header (octets)30@param pt [*1] The plaintext31@param ptlen The length of the plaintext (octets)32@param ct [*1] The ciphertext33@param tag [*1] The destination tag34@param taglen The max size and resulting size of the authentication tag35@param direction Encrypt or Decrypt direction (0 or 1)36@return CRYPT_OK if successful37*/38int ccm_memory(int cipher,39const unsigned char *key, unsigned long keylen,40symmetric_key *uskey,41const unsigned char *nonce, unsigned long noncelen,42const unsigned char *header, unsigned long headerlen,43unsigned char *pt, unsigned long ptlen,44unsigned char *ct,45unsigned char *tag, unsigned long *taglen,46int direction)47{48unsigned char PAD[16], ctr[16], CTRPAD[16], ptTag[16], b, *pt_real;49unsigned char *pt_work = NULL;50symmetric_key *skey;51int err;52unsigned long len, L, x, y, z, CTRlen;53#ifdef LTC_FAST54LTC_FAST_TYPE fastMask = ~(LTC_FAST_TYPE)0; /* initialize fastMask at all zeroes */55#endif56unsigned char mask = 0xff; /* initialize mask at all zeroes */5758if (uskey == NULL) {59LTC_ARGCHK(key != NULL);60}61LTC_ARGCHK(nonce != NULL);62if (headerlen > 0) {63LTC_ARGCHK(header != NULL);64}65LTC_ARGCHK(pt != NULL);66LTC_ARGCHK(ct != NULL);67LTC_ARGCHK(tag != NULL);68LTC_ARGCHK(taglen != NULL);6970pt_real = pt;7172#ifdef LTC_FAST73if (16 % sizeof(LTC_FAST_TYPE)) {74return CRYPT_INVALID_ARG;75}76#endif7778/* check cipher input */79if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {80return err;81}82if (cipher_descriptor[cipher].block_length != 16) {83return CRYPT_INVALID_CIPHER;84}8586/* make sure the taglen is even and <= 16 */87*taglen &= ~1;88if (*taglen > 16) {89*taglen = 16;90}9192/* can't use < 4 */93if (*taglen < 4) {94return CRYPT_INVALID_ARG;95}9697/* is there an accelerator? */98if (cipher_descriptor[cipher].accel_ccm_memory != NULL) {99return cipher_descriptor[cipher].accel_ccm_memory(100key, keylen,101uskey,102nonce, noncelen,103header, headerlen,104pt, ptlen,105ct,106tag, taglen,107direction);108}109110/* let's get the L value */111len = ptlen;112L = 0;113while (len) {114++L;115len >>= 8;116}117if (L <= 1) {118L = 2;119}120121/* increase L to match the nonce len */122noncelen = (noncelen > 13) ? 13 : noncelen;123if ((15 - noncelen) > L) {124L = 15 - noncelen;125}126127/* allocate mem for the symmetric key */128if (uskey == NULL) {129skey = XMALLOC(sizeof(*skey));130if (skey == NULL) {131return CRYPT_MEM;132}133134/* initialize the cipher */135if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, skey)) != CRYPT_OK) {136XFREE(skey);137return err;138}139} else {140skey = uskey;141}142143/* initialize buffer for pt */144if (direction == CCM_DECRYPT && ptlen > 0) {145pt_work = XMALLOC(ptlen);146if (pt_work == NULL) {147goto error;148}149pt = pt_work;150}151152/* form B_0 == flags | Nonce N | l(m) */153x = 0;154PAD[x++] = (unsigned char)(((headerlen > 0) ? (1<<6) : 0) |155(((*taglen - 2)>>1)<<3) |156(L-1));157158/* nonce */159for (y = 0; y < (16 - (L + 1)); y++) {160PAD[x++] = nonce[y];161}162163/* store len */164len = ptlen;165166/* shift len so the upper bytes of len are the contents of the length */167for (y = L; y < 4; y++) {168len <<= 8;169}170171/* store l(m) (only store 32-bits) */172for (y = 0; L > 4 && (L-y)>4; y++) {173PAD[x++] = 0;174}175for (; y < L; y++) {176PAD[x++] = (unsigned char)((len >> 24) & 255);177len <<= 8;178}179180/* encrypt PAD */181if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {182goto error;183}184185/* handle header */186if (headerlen > 0) {187x = 0;188189/* store length */190if (headerlen < ((1UL<<16) - (1UL<<8))) {191PAD[x++] ^= (headerlen>>8) & 255;192PAD[x++] ^= headerlen & 255;193} else {194PAD[x++] ^= 0xFF;195PAD[x++] ^= 0xFE;196PAD[x++] ^= (headerlen>>24) & 255;197PAD[x++] ^= (headerlen>>16) & 255;198PAD[x++] ^= (headerlen>>8) & 255;199PAD[x++] ^= headerlen & 255;200}201202/* now add the data */203for (y = 0; y < headerlen; y++) {204if (x == 16) {205/* full block so let's encrypt it */206if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {207goto error;208}209x = 0;210}211PAD[x++] ^= header[y];212}213214/* remainder */215if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {216goto error;217}218}219220/* setup the ctr counter */221x = 0;222223/* flags */224ctr[x++] = (unsigned char)L-1;225226/* nonce */227for (y = 0; y < (16 - (L+1)); ++y) {228ctr[x++] = nonce[y];229}230/* offset */231while (x < 16) {232ctr[x++] = 0;233}234235x = 0;236CTRlen = 16;237238/* now handle the PT */239if (ptlen > 0) {240y = 0;241#ifdef LTC_FAST242if (ptlen & ~15) {243if (direction == CCM_ENCRYPT) {244for (; y < (ptlen & ~15); y += 16) {245/* increment the ctr? */246for (z = 15; z > 15-L; z--) {247ctr[z] = (ctr[z] + 1) & 255;248if (ctr[z]) break;249}250if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {251goto error;252}253254/* xor the PT against the pad first */255for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {256*(LTC_FAST_TYPE_PTR_CAST(&PAD[z])) ^= *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z]));257*(LTC_FAST_TYPE_PTR_CAST(&ct[y+z])) = *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z])) ^ *(LTC_FAST_TYPE_PTR_CAST(&CTRPAD[z]));258}259if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {260goto error;261}262}263} else { /* direction == CCM_DECRYPT */264for (; y < (ptlen & ~15); y += 16) {265/* increment the ctr? */266for (z = 15; z > 15-L; z--) {267ctr[z] = (ctr[z] + 1) & 255;268if (ctr[z]) break;269}270if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {271goto error;272}273274/* xor the PT against the pad last */275for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {276*(LTC_FAST_TYPE_PTR_CAST(&pt[y+z])) = *(LTC_FAST_TYPE_PTR_CAST(&ct[y+z])) ^ *(LTC_FAST_TYPE_PTR_CAST(&CTRPAD[z]));277*(LTC_FAST_TYPE_PTR_CAST(&PAD[z])) ^= *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z]));278}279if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {280goto error;281}282}283}284}285#endif286287for (; y < ptlen; y++) {288/* increment the ctr? */289if (CTRlen == 16) {290for (z = 15; z > 15-L; z--) {291ctr[z] = (ctr[z] + 1) & 255;292if (ctr[z]) break;293}294if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {295goto error;296}297CTRlen = 0;298}299300/* if we encrypt we add the bytes to the MAC first */301if (direction == CCM_ENCRYPT) {302b = pt[y];303ct[y] = b ^ CTRPAD[CTRlen++];304} else {305b = ct[y] ^ CTRPAD[CTRlen++];306pt[y] = b;307}308309if (x == 16) {310if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {311goto error;312}313x = 0;314}315PAD[x++] ^= b;316}317318if (x != 0) {319if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {320goto error;321}322}323}324325/* setup CTR for the TAG (zero the count) */326for (y = 15; y > 15 - L; y--) {327ctr[y] = 0x00;328}329if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {330goto error;331}332333if (skey != uskey) {334cipher_descriptor[cipher].done(skey);335#ifdef LTC_CLEAN_STACK336zeromem(skey, sizeof(*skey));337#endif338}339340if (direction == CCM_ENCRYPT) {341/* store the TAG */342for (x = 0; x < 16 && x < *taglen; x++) {343tag[x] = PAD[x] ^ CTRPAD[x];344}345*taglen = x;346} else { /* direction == CCM_DECRYPT */347/* decrypt the tag */348for (x = 0; x < 16 && x < *taglen; x++) {349ptTag[x] = tag[x] ^ CTRPAD[x];350}351*taglen = x;352353/* check validity of the decrypted tag against the computed PAD (in constant time) */354/* HACK: the boolean value of XMEM_NEQ becomes either 0 (CRYPT_OK) or 1 (CRYPT_ERR).355* there should be a better way of setting the correct error code in constant356* time.357*/358err = XMEM_NEQ(ptTag, PAD, *taglen);359360/* Zero the plaintext if the tag was invalid (in constant time) */361if (ptlen > 0) {362y = 0;363mask *= 1 - err; /* mask = ( err ? 0 : 0xff ) */364#ifdef LTC_FAST365fastMask *= 1 - err;366if (ptlen & ~15) {367for (; y < (ptlen & ~15); y += 16) {368for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {369*(LTC_FAST_TYPE_PTR_CAST(&pt_real[y+z])) = *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z])) & fastMask;370}371}372}373#endif374for (; y < ptlen; y++) {375pt_real[y] = pt[y] & mask;376}377}378}379380#ifdef LTC_CLEAN_STACK381#ifdef LTC_FAST382fastMask = 0;383#endif384mask = 0;385zeromem(PAD, sizeof(PAD));386zeromem(CTRPAD, sizeof(CTRPAD));387if (pt_work != NULL) {388zeromem(pt_work, ptlen);389}390#endif391error:392if (pt_work) {393XFREE(pt_work);394}395if (skey != uskey) {396XFREE(skey);397}398399return err;400}401402#endif403404405