diff src/encauth/ccm/ccm_memory.c @ 192:9cc34777b479 libtomcrypt

propagate from branch 'au.asn.ucc.matt.ltc-orig' (head 9ba8f01f44320e9cb9f19881105ae84f84a43ea9) to branch 'au.asn.ucc.matt.dropbear.ltc' (head dbf51c569bc34956ad948e4cc87a0eeb2170b768)
author Matt Johnston <matt@ucc.asn.au>
date Sun, 08 May 2005 06:36:47 +0000
parents 1c15b283127b
children 39d5d58461d6
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/encauth/ccm/ccm_memory.c	Sun May 08 06:36:47 2005 +0000
@@ -0,0 +1,306 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, [email protected], http://libtomcrypt.org
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ccm_memory.c
+  CCM support, process a block of memory, Tom St Denis
+*/
+
+#ifdef CCM_MODE
+
+/**
+   CCM encrypt/decrypt and produce an authentication tag
+   @param cipher     The index of the cipher desired
+   @param key        The secret key to use
+   @param keylen     The length of the secret key (octets)
+   @param nonce      The session nonce [use once]
+   @param noncelen   The length of the nonce
+   @param header     The header for the session
+   @param headerlen  The length of the header (octets)
+   @param pt         [out] The plaintext
+   @param ptlen      The length of the plaintext (octets)
+   @param ct         [out] The ciphertext
+   @param tag        [out] The destination tag
+   @param taglen     [in/out] The max size and resulting size of the authentication tag
+   @param direction  Encrypt or Decrypt direction (0 or 1)
+   @return CRYPT_OK if successful
+*/
+int ccm_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *header, unsigned long headerlen,
+          unsigned char *pt,     unsigned long ptlen,
+          unsigned char *ct,
+          unsigned char *tag,    unsigned long *taglen,
+                    int  direction)
+{
+   unsigned char  PAD[16], ctr[16], CTRPAD[16], b;
+   symmetric_key *skey;
+   int            err;
+   unsigned long  len, L, x, y, z, CTRlen;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(nonce  != NULL);
+   if (headerlen > 0) {
+      LTC_ARGCHK(header != NULL);
+   }
+   LTC_ARGCHK(pt     != NULL);
+   LTC_ARGCHK(ct     != NULL);
+   LTC_ARGCHK(tag    != NULL);
+   LTC_ARGCHK(taglen != NULL);
+
+#ifdef LTC_FAST
+   if (16 % sizeof(LTC_FAST_TYPE)) {
+      return CRYPT_INVALID_ARG;
+   }
+#endif
+
+   /* check cipher input */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+   if (cipher_descriptor[cipher].block_length != 16) {
+      return CRYPT_INVALID_CIPHER;
+   }
+
+   /* make sure the taglen is even and <= 16 */
+   *taglen &= ~1;
+   if (*taglen > 16) {
+      *taglen = 16;
+   }
+
+   /* can't use < 4 */
+   if (*taglen < 4) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* is there an accelerator? */
+   if (cipher_descriptor[cipher].accel_ccm_memory != NULL) {
+       cipher_descriptor[cipher].accel_ccm_memory(
+           key,    keylen,
+           nonce,  noncelen,
+           header, headerlen,
+           pt,     ptlen,
+           ct, 
+           tag,    taglen,
+           direction);
+      return CRYPT_OK;
+   }
+
+   /* let's get the L value */
+   len = ptlen;
+   L   = 0;
+   while (len) {
+      ++L;
+      len >>= 8;
+   }
+   if (L <= 1) {
+      L = 2;
+   }
+
+   /* increase L to match the nonce len */
+   noncelen = (noncelen > 13) ? 13 : noncelen;
+   if ((15 - noncelen) > L) {
+      L = 15 - noncelen;
+   }
+
+   /* allocate mem for the symmetric key */
+   skey = XMALLOC(sizeof(*skey));
+   if (skey == NULL) {
+      return CRYPT_MEM;
+   }
+
+   /* initialize the cipher */
+   if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, skey)) != CRYPT_OK) {
+      XFREE(skey);
+      return err;
+   }
+
+   /* form B_0 == flags | Nonce N | l(m) */
+   x = 0;
+   PAD[x++] = ((headerlen > 0) ? (1<<6) : 0) |
+            (((*taglen - 2)>>1)<<3)        |
+            (L-1);
+
+   /* nonce */
+   for (y = 0; y < (16 - (L + 1)); y++) {
+       PAD[x++] = nonce[y];
+   }
+
+   /* store len */
+   len = ptlen;
+
+   /* shift len so the upper bytes of len are the contents of the length */
+   for (y = L; y < 4; y++) {
+       len <<= 8;
+   }
+
+   /* store l(m) (only store 32-bits) */
+   for (y = 0; L > 4 && (L-y)>4; y++) {
+       PAD[x++] = 0;
+   }
+   for (; y < L; y++) {
+       PAD[x++] = (len >> 24) & 255;
+       len <<= 8;
+   }
+
+   /* encrypt PAD */
+   cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey);
+
+   /* handle header */
+   if (headerlen > 0) {
+      x = 0;
+      
+      /* store length */
+      if (headerlen < ((1UL<<16) - (1UL<<8))) {
+         PAD[x++] ^= (headerlen>>8) & 255;
+         PAD[x++] ^= headerlen & 255;
+      } else {
+         PAD[x++] ^= 0xFF;
+         PAD[x++] ^= 0xFE;
+         PAD[x++] ^= (headerlen>>24) & 255;
+         PAD[x++] ^= (headerlen>>16) & 255;
+         PAD[x++] ^= (headerlen>>8) & 255;
+         PAD[x++] ^= headerlen & 255;
+      }
+
+      /* now add the data */
+      for (y = 0; y < headerlen; y++) {
+          if (x == 16) {
+             /* full block so let's encrypt it */
+             cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey);
+             x = 0;
+          }
+          PAD[x++] ^= header[y];
+      }
+
+      /* remainder? */
+      if (x != 0) {
+         cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey);
+      }
+   }
+
+   /* setup the ctr counter */
+   x = 0;
+
+   /* flags */
+   ctr[x++] = L-1;
+ 
+   /* nonce */
+   for (y = 0; y < (16 - (L+1)); ++y) {
+      ctr[x++] = nonce[y];
+   }
+   /* offset */
+   while (x < 16) {
+      ctr[x++] = 0;
+   }
+
+   x      = 0;
+   CTRlen = 16;
+
+   /* now handle the PT */
+   if (ptlen > 0) {
+      y = 0;
+#ifdef LTC_FAST
+      if (ptlen & ~15)  {
+          if (direction == CCM_ENCRYPT) {
+             for (; y < (ptlen & ~15); y += 16) {
+                /* increment the ctr? */
+                for (z = 15; z > 15-L; z--) {
+                    ctr[z] = (ctr[z] + 1) & 255;
+                    if (ctr[z]) break;
+                }
+                cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey);
+
+                /* xor the PT against the pad first */
+                for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
+                    *((LTC_FAST_TYPE*)(&PAD[z]))  ^= *((LTC_FAST_TYPE*)(&pt[y+z]));
+                    *((LTC_FAST_TYPE*)(&ct[y+z])) = *((LTC_FAST_TYPE*)(&pt[y+z])) ^ *((LTC_FAST_TYPE*)(&CTRPAD[z]));
+                }
+                cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey);
+             }
+         } else {
+             for (; y < (ptlen & ~15); y += 16) {
+                /* increment the ctr? */
+                for (z = 15; z > 15-L; z--) {
+                    ctr[z] = (ctr[z] + 1) & 255;
+                    if (ctr[z]) break;
+                }
+                cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey);
+
+                /* xor the PT against the pad last */
+                for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
+                    *((LTC_FAST_TYPE*)(&pt[y+z])) = *((LTC_FAST_TYPE*)(&ct[y+z])) ^ *((LTC_FAST_TYPE*)(&CTRPAD[z]));
+                    *((LTC_FAST_TYPE*)(&PAD[z]))  ^= *((LTC_FAST_TYPE*)(&pt[y+z]));
+                }
+                cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey);
+             }
+         }
+     }
+#endif
+
+      for (; y < ptlen; y++) {
+          /* increment the ctr? */
+          if (CTRlen == 16) {
+             for (z = 15; z > 15-L; z--) {
+                 ctr[z] = (ctr[z] + 1) & 255;
+                 if (ctr[z]) break;
+             }
+             cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey);
+             CTRlen = 0;
+          }
+
+          /* if we encrypt we add the bytes to the MAC first */
+          if (direction == CCM_ENCRYPT) {
+             b     = pt[y];
+             ct[y] = b ^ CTRPAD[CTRlen++];
+          } else {
+             b     = ct[y] ^ CTRPAD[CTRlen++];
+             pt[y] = b;
+          }
+
+          if (x == 16) {
+             cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey);
+             x = 0;
+          }
+          PAD[x++] ^= b;
+      }
+             
+      if (x != 0) {
+         cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey);
+      }
+   }
+
+   /* setup CTR for the TAG */
+   ctr[14] = ctr[15] = 0x00;
+   cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey);
+   cipher_descriptor[cipher].done(skey);
+
+   /* store the TAG */
+   for (x = 0; x < 16 && x < *taglen; x++) {
+       tag[x] = PAD[x] ^ CTRPAD[x];
+   }
+   *taglen = x;
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(skey,   sizeof(*skey));
+   zeromem(B,      sizeof(B));
+   zeromem(PAD,    sizeof(PAD));
+   zeromem(CTRPAD, sizeof(CTRPAD));
+#endif
+
+   XFREE(skey);
+
+   return CRYPT_OK;
+}
+
+#endif