Pārlūkot izejas kodu

OCBv3 according http://tools.ietf.org/html/draft-krovetz-ocb-03

karel-m 13 gadi atpakaļ
vecāks
revīzija
abab7089a3

+ 63 - 0
demos/tv_gen.c

@@ -516,6 +516,68 @@ void ocb_gen(void)
    fclose(out);
 }
 
+void ocb3_gen(void)
+{
+   int err, kl, x, y1, z;
+   FILE *out;
+   unsigned char key[MAXBLOCKSIZE], nonce[MAXBLOCKSIZE*2], 
+                 plaintext[MAXBLOCKSIZE*2], tag[MAXBLOCKSIZE];
+   unsigned long len;
+
+   out = fopen("ocb3_tv.txt", "w");
+   fprintf(out, "OCB3 Test Vectors.  Uses the 00010203...NN-1 pattern for nonce/plaintext/key.  The outputs\n"
+                "are of the form ciphertext,tag for a given NN.  The key for step N>1 is the tag of the previous\n"
+                "step repeated sufficiently.  The nonce is fixed throughout. AAD is fixed to 3 bytes (ASCII) 'AAD'.\n\n");
+
+   for (x = 0; cipher_descriptor[x].name != NULL; x++) {
+      kl = cipher_descriptor[x].block_length;
+
+      /* skip ciphers which do not have 64 or 128 bit block sizes */
+      if (kl != 8 && kl != 16) continue;
+
+      if (cipher_descriptor[x].keysize(&kl) != CRYPT_OK) {
+         kl = cipher_descriptor[x].max_key_length;
+      }
+      fprintf(out, "OCB-%s (%d byte key)\n", cipher_descriptor[x].name, kl);
+
+      /* the key */
+      for (z = 0; z < kl; z++) {
+          key[z] = (z & 255);
+      }
+
+      /* fixed nonce */
+      for (z = 0; z < cipher_descriptor[x].block_length; z++) {
+          nonce[z] = z;
+      }
+      
+      for (y1 = 0; y1 <= (int)(cipher_descriptor[x].block_length*2); y1++){
+         for (z = 0; z < y1; z++) {
+            plaintext[z] = (unsigned char)(z & 255);
+         }
+         len = sizeof(tag);
+         if ((err = ocb3_encrypt_authenticate_memory(x, key, kl, nonce, cipher_descriptor[x].block_length, "AAD", 3, plaintext, y1, plaintext, tag, &len)) != CRYPT_OK) {
+            printf("Error OCB'ing: %s\n", error_to_string(err));
+            exit(EXIT_FAILURE);
+         }
+         fprintf(out, "%3d: ", y1);
+         for (z = 0; z < y1; z++) {
+            fprintf(out, "%02X", plaintext[z]);
+         }
+         fprintf(out, ", ");
+         for (z = 0; z <(int)len; z++) {
+            fprintf(out, "%02X", tag[z]);
+         }
+         fprintf(out, "\n");
+
+         /* forward the key */
+         for (z = 0; z < kl; z++) {
+             key[z] = tag[z % len];
+         }
+      }
+      fprintf(out, "\n");
+   }
+   fclose(out);
+}
 
 void ccm_gen(void)
 {
@@ -775,6 +837,7 @@ int main(void)
    printf("Generating PMAC   vectors..."); fflush(stdout); pmac_gen();   printf("done\n");
    printf("Generating EAX    vectors..."); fflush(stdout); eax_gen();    printf("done\n");
    printf("Generating OCB    vectors..."); fflush(stdout); ocb_gen();    printf("done\n");
+   printf("Generating OCB3   vectors..."); fflush(stdout); ocb3_gen();   printf("done\n");
    printf("Generating CCM    vectors..."); fflush(stdout); ccm_gen();    printf("done\n");
    printf("Generating GCM    vectors..."); fflush(stdout); gcm_gen();    printf("done\n");
    printf("Generating BASE64 vectors..."); fflush(stdout); base64_gen(); printf("done\n");

+ 81 - 0
src/encauth/ocb3/ocb3_add_aad.c

@@ -0,0 +1,81 @@
+/* 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.
+ */
+
+/**
+   @file ocb3_add_aad.c
+   OCB implementation, add AAD data, by Karel Miko
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Add AAD - additional associated data
+   @param ocb       The OCB state
+   @param aad       The AAD data
+   @param aadlen    The size of AAD data (octets)
+   @return CRYPT_OK if successful
+*/
+int ocb3_add_aad(ocb3_state *ocb, const unsigned char *aad, unsigned long aadlen)
+{
+   int err, x, full_blocks, full_blocks_len, last_block_len;
+   unsigned char *data;
+   unsigned long datalen, l;
+
+   LTC_ARGCHK(ocb    != NULL);
+   LTC_ARGCHK(aad    != NULL);
+
+   if (aadlen == 0) return CRYPT_OK;
+
+   if (ocb->adata_buffer_bytes > 0) {
+     l = ocb->block_len - ocb->adata_buffer_bytes;
+     if (l > aadlen) l = aadlen;
+     XMEMCPY(ocb->adata_buffer+ocb->adata_buffer_bytes, aad, l);
+     ocb->adata_buffer_bytes += l;
+
+     if (ocb->adata_buffer_bytes == ocb->block_len) {
+       if ((err = ocb3_int_aad_add_block(ocb, ocb->adata_buffer)) != CRYPT_OK) {
+         return err;
+       }
+       ocb->adata_buffer_bytes = 0;
+     }
+
+     data = (unsigned char *)aad + l;
+     datalen = aadlen - l;
+   }
+   else {
+     data = (unsigned char *)aad;
+     datalen = aadlen;
+   }
+
+   if (datalen <= 0) return CRYPT_OK;
+
+   full_blocks = datalen/ocb->block_len;
+   full_blocks_len = full_blocks * ocb->block_len;
+   last_block_len = datalen - full_blocks_len;
+
+   for (x=0; x<full_blocks; x++) {
+     if ((err = ocb3_int_aad_add_block(ocb, data+x*ocb->block_len)) != CRYPT_OK) {
+       return err;
+     }
+   }
+
+   if (last_block_len>0) {
+     XMEMCPY(ocb->adata_buffer, data+full_blocks_len, last_block_len);
+     ocb->adata_buffer_bytes = last_block_len;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */

+ 86 - 0
src/encauth/ocb3/ocb3_decrypt.c

@@ -0,0 +1,86 @@
+/* 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://libtom.org
+ */
+
+/**
+   @file ocb3_decrypt.c
+   OCB implementation, decrypt data, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Decrypt blocks of ciphertext with OCB
+   @param ocb     The OCB state
+   @param ct      The ciphertext (length multiple of the block size of the block cipher)
+   @param ctlen   The length of the input (octets)
+   @param pt      [out] The plaintext (length of ct)
+   @return CRYPT_OK if successful
+*/
+int ocb3_decrypt(ocb3_state *ocb, const unsigned char *ct, unsigned long ctlen, unsigned char *pt)
+{
+   unsigned char tmp[MAXBLOCKSIZE];
+   int err, i, full_blocks;
+   unsigned char *pt_b, *ct_b;
+
+   LTC_ARGCHK(ocb != NULL);
+   LTC_ARGCHK(pt  != NULL);
+   LTC_ARGCHK(ct  != NULL);
+   if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) {
+      return err;
+   }
+   if (ocb->block_len != cipher_descriptor[ocb->cipher].block_length) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (ctlen % ocb->block_len) { /* ctlen has to bu multiple of block_len */
+      return CRYPT_INVALID_ARG;
+   }
+
+   full_blocks = ctlen/ocb->block_len;
+   for(i=0; i<full_blocks; i++) {
+     pt_b = (unsigned char *)pt+i*ocb->block_len;
+     ct_b = (unsigned char *)ct+i*ocb->block_len;
+
+     /* ocb->Offset_current[] = ocb->Offset_current[] ^ Offset_{ntz(block_index)} */
+     ocb3_int_xor_blocks(ocb->Offset_current, ocb->Offset_current, ocb->L_[ocb3_int_ntz(ocb->block_index)], ocb->block_len);
+
+     /* tmp[] = ct[] XOR ocb->Offset_current[] */
+     ocb3_int_xor_blocks(tmp, ct_b, ocb->Offset_current, ocb->block_len);
+
+     /* decrypt */
+     if ((err = cipher_descriptor[ocb->cipher].ecb_decrypt(tmp, tmp, &ocb->key)) != CRYPT_OK) {
+        goto LBL_ERR;
+     }
+
+     /* pt[] = tmp[] XOR ocb->Offset_current[] */
+     ocb3_int_xor_blocks(pt_b, tmp, ocb->Offset_current, ocb->block_len);
+
+     /* ocb->checksum[] = ocb->checksum[] XOR pt[] */
+     ocb3_int_xor_blocks(ocb->checksum, ocb->checksum, pt_b, ocb->block_len);
+
+     ocb->block_index++;
+   }
+
+   err = CRYPT_OK;
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(tmp, sizeof(tmp));
+#endif
+   return err;
+}
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */

+ 106 - 0
src/encauth/ocb3/ocb3_decrypt_last.c

@@ -0,0 +1,106 @@
+/* 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.
+ */
+
+/**
+   @file ocb3_decrypt_last.c
+   OCB implementation, internal helper, by Karel Miko
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Finish an OCB (decryption) stream
+   @param ocb    The OCB state
+   @param ct     The remaining ciphertext
+   @param ctlen  The length of the ciphertext (octets)
+   @param pt     [out] The output buffer
+   @return CRYPT_OK if successful
+*/
+int ocb3_decrypt_last(ocb3_state *ocb, const unsigned char *ct, unsigned long ctlen, unsigned char *pt)
+{
+   unsigned char iOffset_star[MAXBLOCKSIZE];
+   unsigned char iPad[MAXBLOCKSIZE];
+   int err, x, full_blocks, full_blocks_len, last_block_len;
+
+   LTC_ARGCHK(ocb != NULL);
+   LTC_ARGCHK(ct  != NULL);
+   if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   full_blocks = ctlen/ocb->block_len;
+   full_blocks_len = full_blocks * ocb->block_len;
+   last_block_len = ctlen - full_blocks_len;
+
+   /* process full blocks first */
+   if (full_blocks>0) {
+     if ((err = ocb3_decrypt(ocb, ct, full_blocks_len, pt)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+   }
+
+   if (last_block_len>0) {
+     /* Offset_* = Offset_m xor L_* */
+     ocb3_int_xor_blocks(iOffset_star, ocb->Offset_current, ocb->L_star, ocb->block_len);
+
+     /* Pad = ENCIPHER(K, Offset_*) */
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(iOffset_star, iPad, &ocb->key)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+
+     /* P_* = C_* xor Pad[1..bitlen(C_*)] */
+     ocb3_int_xor_blocks(pt+full_blocks_len, (unsigned char *)ct+full_blocks_len, iPad, last_block_len);
+
+     /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */
+     ocb3_int_xor_blocks(ocb->checksum, ocb->checksum, pt+full_blocks_len, last_block_len);
+     for(x=last_block_len; x<ocb->block_len; x++) {
+       if (x == last_block_len)
+         ocb->checksum[x] ^= 0x80;
+       else
+         ocb->checksum[x] ^= 0x00;
+     }
+
+     /* Tag = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) xor HASH(K,A) */
+     /* at this point we calculate only: Tag_part = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) */
+     for(x=0; x<ocb->block_len; x++) {
+       ocb->tag_part[x] = (ocb->checksum[x] ^ iOffset_star[x]) ^ ocb->L_dollar[x];
+     }
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(ocb->tag_part, ocb->tag_part, &ocb->key)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+   }
+   else {
+     /* Tag = ENCIPHER(K, Checksum_m xor Offset_m xor L_$) xor HASH(K,A) */
+     /* at this point we calculate only: Tag_part = ENCIPHER(K, Checksum_m xor Offset_m xor L_$) */
+     for(x=0; x<ocb->block_len; x++) {
+       ocb->tag_part[x] = (ocb->checksum[x] ^ ocb->Offset_current[x]) ^ ocb->L_dollar[x];
+     }
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(ocb->tag_part, ocb->tag_part, &ocb->key)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+   }
+
+   err = CRYPT_OK;
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(iOffset_star, MAXBLOCKSIZE);
+   zeromem(iPad, MAXBLOCKSIZE);
+   zeromem(ocb, sizeof(*ocb));
+#endif
+
+   return err;
+}
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */

+ 112 - 0
src/encauth/ocb3/ocb3_decrypt_verify_memory.c

@@ -0,0 +1,112 @@
+/* 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://libtom.org
+ */
+
+/**
+  @file ocb3_decrypt_verify_memory.c
+  OCB implementation, helper to decrypt block of memory, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Decrypt and compare the tag with OCB
+   @param cipher     The index of the cipher desired
+   @param key        The secret key
+   @param keylen     The length of the secret key (octets)
+   @param nonce      The session nonce (length of the block size of the block cipher)
+   @param noncelen   The length of the nonce (octets)
+   @param adata      The AAD - additional associated data
+   @param adatalen   The length of AAD (octets)
+   @param ct         The ciphertext
+   @param ctlen      The length of the ciphertext (octets)
+   @param pt         [out] The plaintext
+   @param tag        The tag to compare against
+   @param taglen     The length of the tag (octets)
+   @param stat       [out] The result of the tag comparison (1==valid, 0==invalid)
+   @return CRYPT_OK if successful regardless of the tag comparison
+*/
+int ocb3_decrypt_verify_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *adata,  unsigned long adatalen,
+    const unsigned char *ct,     unsigned long ctlen,
+          unsigned char *pt,
+    const unsigned char *tag,    unsigned long taglen,
+          int           *stat)
+{
+   int            err;
+   ocb3_state     *ocb;
+   unsigned char *buf;
+   unsigned long  buflen;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(nonce  != NULL);
+   LTC_ARGCHK(pt     != NULL);
+   LTC_ARGCHK(ct     != NULL);
+   LTC_ARGCHK(tag    != NULL);
+   LTC_ARGCHK(stat    != NULL);
+
+   /* default to zero */
+   *stat = 0;
+
+   /* allocate memory */
+   buf = XMALLOC(taglen);
+   ocb = XMALLOC(sizeof(ocb3_state));
+   if (ocb == NULL || buf == NULL) {
+      if (ocb != NULL) {
+         XFREE(ocb);
+      }
+      if (buf != NULL) {
+         XFREE(buf);
+      }
+      return CRYPT_MEM;
+   }
+
+   if ((err = ocb3_init(ocb, cipher, key, keylen, nonce, noncelen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   if ((err = ocb3_add_aad(ocb, adata, adatalen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   if ((err = ocb3_decrypt_last(ocb, ct, ctlen, pt)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   buflen = taglen;
+   if ((err = ocb3_done(ocb, buf, &buflen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* compare tags */
+   if (buflen >= taglen && XMEMCMP(buf, tag, taglen) == 0) {
+      *stat = 1;
+   }
+
+   err = CRYPT_OK;
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(ocb, sizeof(ocb3_state));
+#endif
+
+   XFREE(ocb);
+   XFREE(buf);
+   return err;
+}
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */

+ 92 - 0
src/encauth/ocb3/ocb3_done.c

@@ -0,0 +1,92 @@
+/* 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://libtom.org
+ */
+
+/**
+   @file ocb3_done.c
+   OCB implementation, INTERNAL ONLY helper, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Finish OCB processing and compute the tag
+   @param ocb     The OCB state
+   @param tag     [out] The destination for the authentication tag
+   @param taglen  [in/out] The max size and resulting size of the authentication tag
+   @return CRYPT_OK if successful
+*/
+int ocb3_done(ocb3_state *ocb, unsigned char *tag, unsigned long *taglen)
+{
+   unsigned char tmp[MAXBLOCKSIZE];
+   int err, x;
+
+   LTC_ARGCHK(ocb    != NULL);
+   LTC_ARGCHK(tag    != NULL);
+   LTC_ARGCHK(taglen != NULL);
+   if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* finalize AAD processing */
+
+   if (ocb->adata_buffer_bytes>0) {
+     /* Offset_* = Offset_m xor L_* */
+     ocb3_int_xor_blocks(ocb->aOffset_current, ocb->aOffset_current, ocb->L_star, ocb->block_len);
+
+     /* CipherInput = (A_* || 1 || zeros(127-bitlen(A_*))) xor Offset_* */
+     ocb3_int_xor_blocks(tmp, ocb->adata_buffer, ocb->aOffset_current, ocb->adata_buffer_bytes);
+     for(x=ocb->adata_buffer_bytes; x<ocb->block_len; x++) {
+       if (x == ocb->adata_buffer_bytes) {
+         tmp[x] = 0x80 ^ ocb->aOffset_current[x];
+       }
+       else {
+         tmp[x] = 0x00 ^ ocb->aOffset_current[x];
+       }
+     }
+
+     /* Sum = Sum_m xor ENCIPHER(K, CipherInput) */
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(tmp, tmp, &ocb->key)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+     ocb3_int_xor_blocks(ocb->aSum_current, ocb->aSum_current, tmp, ocb->block_len);
+   }
+
+   /* finalize TAG computing */
+
+   /* at this point ocb->aSum_current = HASH(K, A) */
+   /* tag = tag ^ HASH(K, A) */
+   ocb3_int_xor_blocks(tmp, ocb->tag_part, ocb->aSum_current, ocb->block_len);
+
+   /* fix taglen if needed */
+   if ((int)*taglen > ocb->block_len) {
+     *taglen = (unsigned long)ocb->block_len;
+   }
+
+   /* copy tag bytes */
+   for(x=0; x<(int)*taglen; x++) tag[x] = tmp[x];
+
+   err = CRYPT_OK;
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(tmp, MAXBLOCKSIZE);
+   zeromem(ocb, sizeof(*ocb));
+#endif
+
+   return err;
+}
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */

+ 86 - 0
src/encauth/ocb3/ocb3_encrypt.c

@@ -0,0 +1,86 @@
+/* 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://libtom.org
+ */
+
+/**
+   @file ocb3_encrypt.c
+   OCB implementation, encrypt data, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Encrypt blocks of data with OCB
+   @param ocb     The OCB state
+   @param pt      The plaintext (length multiple of the block size of the block cipher)
+   @param ptlen   The length of the input (octets)
+   @param ct      [out] The ciphertext (same size as the pt)
+   @return CRYPT_OK if successful
+*/
+int ocb3_encrypt(ocb3_state *ocb, const unsigned char *pt, unsigned long ptlen, unsigned char *ct)
+{
+   unsigned char tmp[MAXBLOCKSIZE];
+   int err, i, full_blocks;
+   unsigned char *pt_b, *ct_b;
+
+   LTC_ARGCHK(ocb != NULL);
+   LTC_ARGCHK(pt  != NULL);
+   LTC_ARGCHK(ct  != NULL);
+   if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) {
+      return err;
+   }
+   if (ocb->block_len != cipher_descriptor[ocb->cipher].block_length) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (ptlen % ocb->block_len) { /* ptlen has to bu multiple of block_len */
+      return CRYPT_INVALID_ARG;
+   }
+
+   full_blocks = ptlen/ocb->block_len;
+   for(i=0; i<full_blocks; i++) {
+     pt_b = (unsigned char *)pt+i*ocb->block_len;
+     ct_b = (unsigned char *)ct+i*ocb->block_len;
+
+     /* ocb->Offset_current[] = ocb->Offset_current[] ^ Offset_{ntz(block_index)} */
+     ocb3_int_xor_blocks(ocb->Offset_current, ocb->Offset_current, ocb->L_[ocb3_int_ntz(ocb->block_index)], ocb->block_len);
+
+     /* tmp[] = pt[] XOR ocb->Offset_current[] */
+     ocb3_int_xor_blocks(tmp, pt_b, ocb->Offset_current, ocb->block_len);
+
+     /* encrypt */
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(tmp, tmp, &ocb->key)) != CRYPT_OK) {
+        goto LBL_ERR;
+     }
+
+     /* ct[] = tmp[] XOR ocb->Offset_current[] */
+     ocb3_int_xor_blocks(ct_b, tmp, ocb->Offset_current, ocb->block_len);
+
+     /* ocb->checksum[] = ocb->checksum[] XOR pt[] */
+     ocb3_int_xor_blocks(ocb->checksum, ocb->checksum, pt_b, ocb->block_len);
+
+     ocb->block_index++;
+   }
+
+   err = CRYPT_OK;
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(tmp, sizeof(tmp));
+#endif
+   return err;
+}
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */

+ 87 - 0
src/encauth/ocb3/ocb3_encrypt_authenticate_memory.c

@@ -0,0 +1,87 @@
+/* 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://libtom.org
+ */
+
+/**
+  @file ocb3_encrypt_authenticate_memory.c
+  OCB implementation, encrypt block of memory, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Encrypt and generate an authentication code for a buffer of memory
+   @param cipher     The index of the cipher desired
+   @param key        The secret key
+   @param keylen     The length of the secret key (octets)
+   @param nonce      The session nonce (length of the block ciphers block size)
+   @param noncelen   The length of the nonce (octets)
+   @param adata      The AAD - additional associated data
+   @param adatalen   The length of AAD (octets)
+   @param pt         The plaintext
+   @param ptlen      The length of the plaintext (octets)
+   @param ct         [out] The ciphertext
+   @param tag        [out] The authentication tag
+   @param taglen     [in/out] The max size and resulting size of the authentication tag
+   @return CRYPT_OK if successful
+*/
+int ocb3_encrypt_authenticate_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *adata,  unsigned long adatalen,
+    const unsigned char *pt,     unsigned long ptlen,
+          unsigned char *ct,
+          unsigned char *tag,    unsigned long *taglen)
+{
+   int err;
+   ocb3_state *ocb;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(nonce  != NULL);
+   LTC_ARGCHK(pt     != NULL);
+   LTC_ARGCHK(ct     != NULL);
+   LTC_ARGCHK(tag    != NULL);
+   LTC_ARGCHK(taglen != NULL);
+
+   /* allocate memory */
+   ocb = XMALLOC(sizeof(ocb3_state));
+   if (ocb == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = ocb3_init(ocb, cipher, key, keylen, nonce, noncelen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   if ((err = ocb3_add_aad(ocb, adata, adatalen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   if ((err = ocb3_encrypt_last(ocb, pt, ptlen, ct)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   err = ocb3_done(ocb, tag, taglen);
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(ocb, sizeof(ocb3_state));
+#endif
+
+   XFREE(ocb);
+   return err;
+}
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */

+ 108 - 0
src/encauth/ocb3/ocb3_encrypt_last.c

@@ -0,0 +1,108 @@
+/* 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.
+ */
+
+/**
+   @file ocb3_encrypt_last.c
+   OCB implementation, internal helper, by Karel Miko
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Finish an OCB (encryption) stream
+   @param ocb    The OCB state
+   @param pt     The remaining plaintext
+   @param ptlen  The length of the plaintext (octets)
+   @param ct     [out] The output buffer
+   @return CRYPT_OK if successful
+*/
+int ocb3_encrypt_last(ocb3_state *ocb, const unsigned char *pt, unsigned long ptlen, unsigned char *ct)
+{
+   unsigned char iOffset_star[MAXBLOCKSIZE];
+   unsigned char iPad[MAXBLOCKSIZE];
+   int err, x, full_blocks, full_blocks_len, last_block_len;
+
+   LTC_ARGCHK(ocb != NULL);
+   LTC_ARGCHK(pt  != NULL);
+   if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   full_blocks = ptlen/ocb->block_len;
+   full_blocks_len = full_blocks * ocb->block_len;
+   last_block_len = ptlen - full_blocks_len;
+
+   /* process full blocks first */
+   if (full_blocks>0) {
+     if ((err = ocb3_encrypt(ocb, pt, full_blocks_len, ct)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+   }
+
+   /* at this point: m = ocb->block_index (last block index), Offset_m = ocb->Offset_current */
+
+   if (last_block_len>0) {
+     /* Offset_* = Offset_m xor L_* */
+     ocb3_int_xor_blocks(iOffset_star, ocb->Offset_current, ocb->L_star, ocb->block_len);
+
+     /* Pad = ENCIPHER(K, Offset_*) */
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(iOffset_star, iPad, &ocb->key)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+
+     /* C_* = P_* xor Pad[1..bitlen(P_*)] */
+     ocb3_int_xor_blocks(ct+full_blocks_len, pt+full_blocks_len, iPad, last_block_len);
+
+     /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */
+     ocb3_int_xor_blocks(ocb->checksum, ocb->checksum, pt+full_blocks_len, last_block_len);
+     for(x=last_block_len; x<ocb->block_len; x++) {
+       if (x == last_block_len)
+         ocb->checksum[x] ^= 0x80;
+       else
+         ocb->checksum[x] ^= 0x00;
+     }
+
+     /* Tag = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) xor HASH(K,A) */
+     /* at this point we calculate only: Tag_part = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) */
+     for(x=0; x<ocb->block_len; x++) {
+       ocb->tag_part[x] = (ocb->checksum[x] ^ iOffset_star[x]) ^ ocb->L_dollar[x];
+     }
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(ocb->tag_part, ocb->tag_part, &ocb->key)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+   }
+   else {
+     /* Tag = ENCIPHER(K, Checksum_m xor Offset_m xor L_$) xor HASH(K,A) */
+     /* at this point we calculate only: Tag_part = ENCIPHER(K, Checksum_m xor Offset_m xor L_$) */
+     for(x=0; x<ocb->block_len; x++) {
+       ocb->tag_part[x] = (ocb->checksum[x] ^ ocb->Offset_current[x]) ^ ocb->L_dollar[x];
+     }
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(ocb->tag_part, ocb->tag_part, &ocb->key)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+   }
+
+   err = CRYPT_OK;
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(iOffset_star, MAXBLOCKSIZE);
+   zeromem(iPad, MAXBLOCKSIZE);
+   zeromem(ocb, sizeof(*ocb));
+#endif
+
+   return err;
+}
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */

+ 134 - 0
src/encauth/ocb3/ocb3_init.c

@@ -0,0 +1,134 @@
+/* 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://libtom.org
+ */
+
+/**
+   @file ocb3_init.c
+   OCB implementation, initialize state, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+static const struct {
+    int           len;
+    unsigned char poly_div[MAXBLOCKSIZE],
+                  poly_mul[MAXBLOCKSIZE];
+} polys[] = {
+{
+    8,
+    { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D },
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B }
+}, {
+    16,
+    { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43 },
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 }
+}
+};
+
+/**
+   Initialize an OCB context
+   @param ocb       [out] The destination of the OCB state
+   @param cipher    The index of the desired cipher
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param nonce     The session nonce
+   @param noncelen  The length of the session nonce (octets)
+   @return CRYPT_OK if successful
+*/
+int ocb3_init(ocb3_state *ocb, int cipher,
+             const unsigned char *key, unsigned long keylen,
+             const unsigned char *nonce, unsigned long noncelen)
+{
+   int poly, x, y, m, err;
+   unsigned char *previous, *current;
+
+   LTC_ARGCHK(ocb   != NULL);
+   LTC_ARGCHK(key   != NULL);
+   LTC_ARGCHK(nonce != NULL);
+
+   /* valid cipher? */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+   ocb->cipher = cipher;
+
+   /* determine which polys to use */
+   ocb->block_len = cipher_descriptor[cipher].block_length;
+   for (poly = 0; poly < (int)(sizeof(polys)/sizeof(polys[0])); poly++) {
+       if (polys[poly].len == ocb->block_len) {
+          break;
+       }
+   }
+   if (polys[poly].len != ocb->block_len) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* schedule the key */
+   if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, &ocb->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* L_* = ENCIPHER(K, zeros(128)) */
+   zeromem(ocb->L_star, ocb->block_len);
+   if ((err = cipher_descriptor[cipher].ecb_encrypt(ocb->L_star, ocb->L_star, &ocb->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* compute L_$, L_0, L_1, ... */
+   for (x = -1; x < 32; x++) {
+       if (x == -1) {                /* gonna compute: L_$ = double(L_*) */
+         current  = ocb->L_dollar;
+         previous = ocb->L_star;
+       }
+       else if (x == 0) {            /* gonna compute: L_0 = double(L_$) */
+         current  = ocb->L_[0];
+         previous = ocb->L_dollar;
+       }
+       else {                        /* gonna compute: L_i = double(L_{i-1}) for every integer i > 0 */
+         current  = ocb->L_[x];
+         previous = ocb->L_[x-1];
+       }
+       m = previous[0] >> 7;
+       for (y = 0; y < ocb->block_len-1; y++) {
+           current[y] = ((previous[y] << 1) | (previous[y+1] >> 7)) & 255;
+       }
+       current[ocb->block_len-1] = (previous[ocb->block_len-1] << 1) & 255;
+       if (m == 1) {
+          /* current[] = current[] XOR polys[poly].poly_mul[]*/
+          ocb3_int_xor_blocks(current, current, polys[poly].poly_mul, ocb->block_len);
+       }
+    }
+
+    /* initialize ocb->Offset_current = Offset_0 */
+    ocb3_int_calc_offset_zero(ocb, nonce, noncelen);
+
+    /* initialize checksum to all zeros */
+    zeromem(ocb->checksum, ocb->block_len);
+
+    /* set block index */
+    ocb->block_index = 1;
+
+    /* initialize AAD related stuff */
+    ocb->ablock_index = 1;
+    ocb->adata_buffer_bytes = 0;
+    zeromem(ocb->aOffset_current, ocb->block_len);
+    zeromem(ocb->aSum_current, ocb->block_len);
+
+    return CRYPT_OK;
+}
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */

+ 49 - 0
src/encauth/ocb3/ocb3_int_aad_add_block.c

@@ -0,0 +1,49 @@
+/* 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.
+ */
+
+/**
+   @file ocb3_int_aad_add_block.c
+   OCB implementation, INTERNALL ONLY helper, by Karel Miko
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Add one block of AAD data (internal function)
+   @param ocb        The OCB state
+   @param aad_block  [in] AAD data (block_len size)
+   @return CRYPT_OK if successful
+*/
+int ocb3_int_aad_add_block(ocb3_state *ocb, const unsigned char *aad_block)
+{
+   unsigned char tmp[MAXBLOCKSIZE];
+   int err;
+
+   /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+   ocb3_int_xor_blocks(ocb->aOffset_current, ocb->aOffset_current, ocb->L_[ocb3_int_ntz(ocb->ablock_index)], ocb->block_len);
+
+   /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */
+   ocb3_int_xor_blocks(tmp, aad_block, ocb->aOffset_current, ocb->block_len);
+   if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(tmp, tmp, &ocb->key)) != CRYPT_OK) {
+     return err;
+   }
+   ocb3_int_xor_blocks(ocb->aSum_current, ocb->aSum_current, tmp, ocb->block_len);
+
+   ocb->ablock_index++;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */

+ 72 - 0
src/encauth/ocb3/ocb3_int_calc_offset_zero.c

@@ -0,0 +1,72 @@
+/* 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.
+ */
+
+/**
+   @file ocb3_int_calc_offset_zero.c
+   OCB implementation, INTERNAL ONLY helper, by Karel Miko
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Sets 'ocb->Offset_current' to 'Offset_0' value (internal function)
+   @param ocb       The OCB state
+   @param nonce     The session nonce
+   @param noncelen  The length of the session nonce (octets)
+*/
+void ocb3_int_calc_offset_zero(ocb3_state *ocb, const unsigned char *nonce, unsigned long noncelen)
+{
+   int x, y, bottom;
+   int idx, shift;
+   unsigned char iNonce[MAXBLOCKSIZE];
+   unsigned char iKtop[MAXBLOCKSIZE];
+   unsigned char iStretch[MAXBLOCKSIZE+8];
+
+   /* Nonce = zeros(127-bitlen(N)) || 1 || N          */
+   zeromem(iNonce, sizeof(iNonce));
+   for (x = ocb->block_len-1, y=0; y<(int)noncelen; x--, y++) {
+     iNonce[x] = nonce[noncelen-y-1];
+   }
+   iNonce[x] = 0x01;
+
+   /* bottom = str2num(Nonce[123..128])               */
+   bottom = iNonce[ocb->block_len-1] & 0x3F;
+
+   /* Ktop = ENCIPHER(K, Nonce[1..122] || zeros(6))   */
+   iNonce[ocb->block_len-1] = iNonce[ocb->block_len-1] & 0xC0;
+   if ((cipher_descriptor[ocb->cipher].ecb_encrypt(iNonce, iKtop, &ocb->key)) != CRYPT_OK) {
+      zeromem(ocb->Offset_current, ocb->block_len);
+      return;
+   }
+
+   /* Stretch = Ktop || (Ktop[1..64] xor Ktop[9..72]) */
+   for (x = 0; x < ocb->block_len; x++) {
+     iStretch[x] = iKtop[x];
+   }
+   for (y = 0; y < 8; y++) {
+     iStretch[x+y] = iKtop[y] ^ iKtop[y+1];
+   }
+
+   /* Offset_0 = Stretch[1+bottom..128+bottom]        */
+   idx = bottom / 8;
+   shift = (bottom % 8);
+   for (x = 0; x < ocb->block_len; x++) {
+      ocb->Offset_current[x] = iStretch[idx+x] << shift;
+      if (shift > 0) {
+        ocb->Offset_current[x] |= iStretch[idx+x+1] >> (8-shift);
+      }
+   }
+}
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */

+ 41 - 0
src/encauth/ocb3/ocb3_int_ntz.c

@@ -0,0 +1,41 @@
+/* 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://libtom.org
+ */
+
+/**
+   @file ocb3_int_ntz.c
+   OCB implementation, INTERNAL ONLY helper, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Returns the number of leading zero bits [from lsb up] (internal function)
+   @param x  The 32-bit value to observe
+   @return The number of bits [from the lsb up] that are zero
+*/
+int ocb3_int_ntz(unsigned long x)
+{
+   int c;
+   x &= 0xFFFFFFFFUL;
+   c = 0;
+   while ((x & 1) == 0) {
+      ++c;
+      x >>= 1;
+   }
+   return c;
+}
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */

+ 40 - 0
src/encauth/ocb3/ocb3_int_xor_blocks.c

@@ -0,0 +1,40 @@
+/* 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.
+ */
+
+/**
+   @file ocb3_int_xor_blocks.c
+   OCB implementation, INTERNAL ONLY helper, by Karel Miko
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Compute xor for two blocks of bytes 'out = block_a XOR block_b' (internal function)
+   @param out        The block of bytes (output)
+   @param block_a    The block of bytes (input)
+   @param block_b    The block of bytes (input)
+   @param block_len  The size of block_a, block_b, out
+*/
+void ocb3_int_xor_blocks(unsigned char *out, const unsigned char *block_a, const unsigned char *block_b, unsigned long block_len)
+{
+   int x;
+   if (out == block_a) {
+     for (x = 0; x < (int)block_len; x++) out[x] ^= block_b[x];
+   }
+   else {
+     for (x = 0; x < (int)block_len; x++) out[x] = block_a[x] ^ block_b[x];
+   }
+}
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */

+ 246 - 0
src/encauth/ocb3/ocb3_test.c

@@ -0,0 +1,246 @@
+/* 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://libtom.org
+ */
+
+/**
+   @file ocb3_test.c
+   OCB implementation, self-test by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Test the OCB protocol
+   @return CRYPT_OK if successful
+*/
+int ocb3_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   /* test vectors from: http://tools.ietf.org/html/draft-krovetz-ocb-03 */
+   unsigned char key[16]   = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F };
+   unsigned char nonce[12] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B };
+   static const struct {
+         int ptlen;
+         int aadlen;
+         unsigned char pt[64], aad[64], ct[64], tag[16];
+   } tests[] = {
+
+	{ /* index:0 */
+	  0, /* PLAINTEXT length */
+	  0, /* AAD length */
+	  {  }, /* PLAINTEXT */
+	  {  }, /* AAD */
+	  {  }, /* CIPHERTEXT */
+	  { 0x19,0x7b,0x9c,0x3c,0x44,0x1d,0x3c,0x83,0xea,0xfb,0x2b,0xef,0x63,0x3b,0x91,0x82 }, /* TAG */
+	},
+	{ /* index:1 */
+	  8, /* PLAINTEXT length */
+	  8, /* AAD length */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 }, /* PLAINTEXT */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 }, /* AAD */
+	  { 0x92,0xb6,0x57,0x13,0x0a,0x74,0xb8,0x5a }, /* CIPHERTEXT */
+	  { 0x16,0xdc,0x76,0xa4,0x6d,0x47,0xe1,0xea,0xd5,0x37,0x20,0x9e,0x8a,0x96,0xd1,0x4e }, /* TAG */
+	},
+	{ /* index:2 */
+	  0, /* PLAINTEXT length */
+	  8, /* AAD length */
+	  {  }, /* PLAINTEXT */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 }, /* AAD */
+	  {  }, /* CIPHERTEXT */
+	  { 0x98,0xb9,0x15,0x52,0xc8,0xc0,0x09,0x18,0x50,0x44,0xe3,0x0a,0x6e,0xb2,0xfe,0x21 }, /* TAG */
+	},
+	{ /* index:3 */
+	  8, /* PLAINTEXT length */
+	  0, /* AAD length */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 }, /* PLAINTEXT */
+	  {  }, /* AAD */
+	  { 0x92,0xb6,0x57,0x13,0x0a,0x74,0xb8,0x5a }, /* CIPHERTEXT */
+	  { 0x97,0x1e,0xff,0xca,0xe1,0x9a,0xd4,0x71,0x6f,0x88,0xe8,0x7b,0x87,0x1f,0xbe,0xed }, /* TAG */
+	},
+	{ /* index:4 */
+	  16, /* PLAINTEXT length */
+	  16, /* AAD length */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }, /* PLAINTEXT */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }, /* AAD */
+	  { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22 }, /* CIPHERTEXT */
+	  { 0x77,0x6c,0x99,0x24,0xd6,0x72,0x3a,0x1f,0xc4,0x52,0x45,0x32,0xac,0x3e,0x5b,0xeb }, /* TAG */
+	},
+	{ /* index:5 */
+	  0, /* PLAINTEXT length */
+	  16, /* AAD length */
+	  {  }, /* PLAINTEXT */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }, /* AAD */
+	  {  }, /* CIPHERTEXT */
+	  { 0x7d,0xdb,0x8e,0x6c,0xea,0x68,0x14,0x86,0x62,0x12,0x50,0x96,0x19,0xb1,0x9c,0xc6 }, /* TAG */
+	},
+	{ /* index:6 */
+	  16, /* PLAINTEXT length */
+	  0, /* AAD length */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }, /* PLAINTEXT */
+	  {  }, /* AAD */
+	  { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22 }, /* CIPHERTEXT */
+	  { 0x13,0xcc,0x8b,0x74,0x78,0x07,0x12,0x1a,0x4c,0xbb,0x3e,0x4b,0xd6,0xb4,0x56,0xaf }, /* TAG */
+	},
+	{ /* index:7 */
+	  24, /* PLAINTEXT length */
+	  24, /* AAD length */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 }, /* PLAINTEXT */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 }, /* AAD */
+	  { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22,0xfc,0xfc,0xee,0x7a,0x2a,0x8d,0x4d,0x48 }, /* CIPHERTEXT */
+	  { 0x5f,0xa9,0x4f,0xc3,0xf3,0x88,0x20,0xf1,0xdc,0x3f,0x3d,0x1f,0xd4,0xe5,0x5e,0x1c }, /* TAG */
+	},
+	{ /* index:8 */
+	  0, /* PLAINTEXT length */
+	  24, /* AAD length */
+	  {  }, /* PLAINTEXT */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 }, /* AAD */
+	  {  }, /* CIPHERTEXT */
+	  { 0x28,0x20,0x26,0xda,0x30,0x68,0xbc,0x9f,0xa1,0x18,0x68,0x1d,0x55,0x9f,0x10,0xf6 }, /* TAG */
+	},
+	{ /* index:9 */
+	  24, /* PLAINTEXT length */
+	  0, /* AAD length */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 }, /* PLAINTEXT */
+	  {  }, /* AAD */
+	  { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22,0xfc,0xfc,0xee,0x7a,0x2a,0x8d,0x4d,0x48 }, /* CIPHERTEXT */
+	  { 0x6e,0xf2,0xf5,0x25,0x87,0xfd,0xa0,0xed,0x97,0xdc,0x7e,0xed,0xe2,0x41,0xdf,0x68 }, /* TAG */
+	},
+	{ /* index:10 */
+	  32, /* PLAINTEXT length */
+	  32, /* AAD length */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f }, /* PLAINTEXT */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f }, /* AAD */
+	  { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22,0xce,0xaa,0xb9,0xb0,0x5d,0xf7,0x71,0xa6,0x57,0x14,0x9d,0x53,0x77,0x34,0x63,0xcb }, /* CIPHERTEXT */
+	  { 0xb2,0xa0,0x40,0xdd,0x3b,0xd5,0x16,0x43,0x72,0xd7,0x6d,0x7b,0xb6,0x82,0x42,0x40 }, /* TAG */
+	},
+	{ /* index:11 */
+	  0, /* PLAINTEXT length */
+	  32, /* AAD length */
+	  {  }, /* PLAINTEXT */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f }, /* AAD */
+	  {  }, /* CIPHERTEXT */
+	  { 0xe1,0xe0,0x72,0x63,0x3b,0xad,0xe5,0x1a,0x60,0xe8,0x59,0x51,0xd9,0xc4,0x2a,0x1b }, /* TAG */
+	},
+	{ /* index:12 */
+	  32, /* PLAINTEXT length */
+	  0, /* AAD length */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f }, /* PLAINTEXT */
+	  {  }, /* AAD */
+	  { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22,0xce,0xaa,0xb9,0xb0,0x5d,0xf7,0x71,0xa6,0x57,0x14,0x9d,0x53,0x77,0x34,0x63,0xcb }, /* CIPHERTEXT */
+	  { 0x4a,0x3b,0xae,0x82,0x44,0x65,0xcf,0xda,0xf8,0xc4,0x1f,0xc5,0x0c,0x7d,0xf9,0xd9 }, /* TAG */
+	},
+	{ /* index:13 */
+	  40, /* PLAINTEXT length */
+	  40, /* AAD length */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 }, /* PLAINTEXT */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 }, /* AAD */
+	  { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22,0xce,0xaa,0xb9,0xb0,0x5d,0xf7,0x71,0xa6,0x57,0x14,0x9d,0x53,0x77,0x34,0x63,0xcb,0x68,0xc6,0x57,0x78,0xb0,0x58,0xa6,0x35 }, /* CIPHERTEXT */
+	  { 0x65,0x9c,0x62,0x32,0x11,0xde,0xea,0x0d,0xe3,0x0d,0x2c,0x38,0x18,0x79,0xf4,0xc8 }, /* TAG */
+	},
+	{ /* index:14 */
+	  0, /* PLAINTEXT length */
+	  40, /* AAD length */
+	  {  }, /* PLAINTEXT */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 }, /* AAD */
+	  {  }, /* CIPHERTEXT */
+	  { 0x7a,0xeb,0x7a,0x69,0xa1,0x68,0x7d,0xd0,0x82,0xca,0x27,0xb0,0xd9,0xa3,0x70,0x96 }, /* TAG */
+	},
+	{ /* index:15 */
+	  40, /* PLAINTEXT length */
+	  0, /* AAD length */
+	  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 }, /* PLAINTEXT */
+	  {  }, /* AAD */
+	  { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22,0xce,0xaa,0xb9,0xb0,0x5d,0xf7,0x71,0xa6,0x57,0x14,0x9d,0x53,0x77,0x34,0x63,0xcb,0x68,0xc6,0x57,0x78,0xb0,0x58,0xa6,0x35 }, /* CIPHERTEXT */
+	  { 0x06,0x0c,0x84,0x67,0xf4,0xab,0xab,0x5e,0x8b,0x3c,0x20,0x67,0xa2,0xe1,0x15,0xdc }, /* TAG */
+	},
+
+};
+
+   int err, x, idx, res;
+   unsigned long len;
+   unsigned char outct[MAXBLOCKSIZE], outtag[MAXBLOCKSIZE];
+
+    /* AES can be under rijndael or aes... try to find it */
+    if ((idx = find_cipher("aes")) == -1) {
+       if ((idx = find_cipher("rijndael")) == -1) {
+          return CRYPT_NOP;
+       }
+    }
+
+    for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+        len = sizeof(outtag);
+        if ((err = ocb3_encrypt_authenticate_memory(idx,
+                                                   key, sizeof(key),
+                                                   nonce, sizeof(nonce),
+                                                   tests[x].aad, tests[x].aadlen,
+                                                   tests[x].pt, tests[x].ptlen,
+                                                   outct, outtag, &len)) != CRYPT_OK) {
+           return err;
+        }
+
+        if (XMEMCMP(outtag, tests[x].tag, len) || XMEMCMP(outct, tests[x].ct, tests[x].ptlen)) {
+#if 0
+           unsigned long y;
+           printf("\n\nFailure: \nCT:\n");
+           for (y = 0; y < (unsigned long)tests[x].ptlen; ) {
+               printf("0x%02x", outct[y]);
+               if (y < (unsigned long)(tests[x].ptlen-1)) printf(", ");
+               if (!(++y % 8)) printf("\n");
+           }
+           printf("\nTAG:\n");
+           for (y = 0; y < len; ) {
+               printf("0x%02x", outtag[y]);
+               if (y < len-1) printf(", ");
+               if (!(++y % 8)) printf("\n");
+           }
+#endif
+           return CRYPT_FAIL_TESTVECTOR;
+        }
+
+        if ((err = ocb3_decrypt_verify_memory(idx,
+                                             key, sizeof(key),
+                                             nonce, sizeof(nonce),
+                                             tests[x].aad, tests[x].aadlen,
+                                             outct, tests[x].ptlen,
+             outct, tests[x].tag, len, &res)) != CRYPT_OK) {
+           return err;
+        }
+        if ((res != 1) || XMEMCMP(tests[x].pt, outct, tests[x].ptlen)) {
+#if 0
+           unsigned long y;
+           printf("\n\nFailure-decrypt: \nPT:\n");
+           for (y = 0; y < (unsigned long)tests[x].ptlen; ) {
+               printf("0x%02x", outct[y]);
+               if (y < (unsigned long)(tests[x].ptlen-1)) printf(", ");
+               if (!(++y % 8)) printf("\n");
+           }
+           printf("\nres = %d\n\n", res);
+#endif
+        }
+    }
+    return CRYPT_OK;
+#endif /* LTC_TEST */
+}
+
+#endif /* LTC_OCB3_MODE */
+
+/* some comments
+
+   -- it's hard to seek
+   -- hard to stream [you can't emit ciphertext until full block]
+   -- The setup is somewhat complicated...
+*/
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */

+ 1 - 0
src/headers/tomcrypt_custom.h

@@ -231,6 +231,7 @@
 #endif
 
 #define LTC_OCB_MODE
+#define LTC_OCB3_MODE
 #define LTC_CCM_MODE
 #define LTC_GCM_MODE
 

+ 61 - 0
src/headers/tomcrypt_mac.h

@@ -193,6 +193,67 @@ int s_ocb_done(ocb_state *ocb, const unsigned char *pt, unsigned long ptlen,
 
 #endif /* LTC_OCB_MODE */
 
+#ifdef LTC_OCB3_MODE
+typedef struct {
+   unsigned char     Offset_0[MAXBLOCKSIZE],       /* Offset_0 value */
+                     Offset_current[MAXBLOCKSIZE], /* Offset_{current_block_index} value */
+                     L_dollar[MAXBLOCKSIZE],       /* L_$ value */
+                     L_star[MAXBLOCKSIZE],         /* L_* value */
+                     L_[32][MAXBLOCKSIZE],         /* L_{i} values */
+                     tag_part[MAXBLOCKSIZE],       /* intermediate result of tag calculation */
+                     checksum[MAXBLOCKSIZE];       /* current checksum */
+
+   /* AAD related members */
+   unsigned char     aSum_current[MAXBLOCKSIZE],    /* AAD related helper variable */
+                     aOffset_current[MAXBLOCKSIZE], /* AAD related helper variable */
+                     adata_buffer[MAXBLOCKSIZE];    /* AAD buffer */
+   int               adata_buffer_bytes;            /* bytes in AAD buffer */
+   unsigned long     ablock_index;                  /* index # for current adata (AAD) block */
+
+   symmetric_key     key;                     /* scheduled key for cipher */
+   unsigned long     block_index;             /* index # for current data block */
+   int               cipher,                  /* cipher idx */
+                     block_len;               /* length of block */
+} ocb3_state;
+
+int ocb3_init(ocb3_state *ocb, int cipher,
+             const unsigned char *key, unsigned long keylen,
+             const unsigned char *nonce, unsigned long noncelen);
+
+int ocb3_encrypt(ocb3_state *ocb, const unsigned char *pt, unsigned long ptlen, unsigned char *ct);
+int ocb3_decrypt(ocb3_state *ocb, const unsigned char *ct, unsigned long ctlen, unsigned char *pt);
+int ocb3_encrypt_last(ocb3_state *ocb, const unsigned char *pt, unsigned long ptlen, unsigned char *ct);
+int ocb3_decrypt_last(ocb3_state *ocb, const unsigned char *ct, unsigned long ctlen, unsigned char *pt);
+int ocb3_add_aad(ocb3_state *ocb, const unsigned char *aad, unsigned long aadlen);
+int ocb3_done(ocb3_state *ocb, unsigned char *tag, unsigned long *taglen);
+
+int ocb3_encrypt_authenticate_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *adata,  unsigned long adatalen,
+    const unsigned char *pt,     unsigned long ptlen,
+          unsigned char *ct,
+          unsigned char *tag,    unsigned long *taglen);
+
+int ocb3_decrypt_verify_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *adata,  unsigned long adatalen,
+    const unsigned char *ct,     unsigned long ctlen,
+          unsigned char *pt,
+    const unsigned char *tag,    unsigned long taglen,
+          int           *stat);
+
+int ocb3_test(void);
+
+/* internal helper functions */
+int ocb3_int_aad_add_block(ocb3_state *ocb, const unsigned char *aad_block);
+void ocb3_int_calc_offset_zero(ocb3_state *ocb, const unsigned char *nonce, unsigned long noncelen);
+int ocb3_int_ntz(unsigned long x);
+void ocb3_int_xor_blocks(unsigned char *out, const unsigned char *block_a, const unsigned char *block_b, unsigned long block_len);
+
+#endif /* LTC_OCB3_MODE */
+
 #ifdef LTC_CCM_MODE
 
 #define CCM_ENCRYPT 0

+ 3 - 0
src/misc/crypt/crypt.c

@@ -231,6 +231,9 @@ const char *crypt_build_settings =
 #if defined(LTC_OCB_MODE)
     "   LTC_OCB_MODE\n"
 #endif
+#if defined(LTC_OCB3_MODE)
+    "   LTC_OCB3_MODE\n"
+#endif
 #if defined(LTC_CCM_MODE)
     "   LTC_CCM_MODE\n"
 #endif

+ 3 - 0
testprof/mac_test.c

@@ -24,6 +24,9 @@ int mac_test(void)
 #ifdef LTC_OCB_MODE
    DO(ocb_test());  
 #endif
+#ifdef LTC_OCB3_MODE
+   DO(ocb3_test());  
+#endif
 #ifdef LTC_CCM_MODE
    DO(ccm_test());
 #endif

+ 16 - 0
testprof/x86_prof.c

@@ -1339,6 +1339,22 @@ void time_encmacs_(unsigned long MAC_SIZE)
    fprintf(stderr, "OCB \t\t\t%9llu\n", t2/(ulong64)(MAC_SIZE*1024));
 #endif
 
+#ifdef LTC_OCB3_MODE
+   t2 = -1;
+   for (x = 0; x < 10000; x++) {
+        t_start();
+        t1 = t_read();
+        z = 16;
+        if ((err = ocb3_encrypt_authenticate_memory(cipher_idx, key, 16, IV, 16, "", 0, buf, MAC_SIZE*1024, buf, tag, &z)) != CRYPT_OK) {
+           fprintf(stderr, "\nOCB3 error... %s\n", error_to_string(err));
+           exit(EXIT_FAILURE);
+        }
+        t1 = t_read() - t1;
+        if (t1 < t2) t2 = t1;
+   }
+   fprintf(stderr, "OCB3 \t\t\t%9llu\n", t2/(ulong64)(MAC_SIZE*1024));
+#endif
+
 #ifdef LTC_CCM_MODE
    t2 = -1;
    for (x = 0; x < 10000; x++) {