Larry Bugbee 7 лет назад
Родитель
Сommit
8ef60f7b47

+ 62 - 2
doc/crypt.tex

@@ -1391,6 +1391,65 @@ To do multiple encryptions and decryptions with the same key, you will want to s
 you do not need to re-run \textit{sosemanuk\_setup()} again, unless of course, you called
 \textit{sosemanuk\_done()}.
 
+\mysection{Rabbit}
+
+\textit{Rabbit}, along with Salsa20, Sosemanuk, and HC-128, was named one of the winners
+in the EU eSTREAM competition.  Rabbit is a simple and fast cipher suitable for resource
+constrained platforms.
+
+This implementation of Rabbit will accept a key of up to 16 bytes (128 bits), and an
+initialization vector of up to 8 bytes (64 bits).  If the provided key or IV is shorter,
+they will be null padded to that length.  There is no rounds option.
+
+The calls to \textit{rabbit\_crypt()} or \textit{rabbit\_keystream()} may be for any
+number bytes although their generation will be more efficient if the requests are for
+multiples of 16 bytes.
+
+You begin initializing Rabbit by creating a state and calling \textit{rabbit\_setup()}
+with a 128-bit key.
+\begin{verbatim}
+rabbit_state st;
+err = rabbit_setup(&st, key, keylen);
+\end{verbatim}
+
+Set the IV using \textit{rabbit\_setiv() with a 64-bit IV.
+\begin{verbatim}
+err = rabbit_setiv(&st, iv, iv_len);
+\end{verbatim}
+
+For the actual encryption or decryption, call:
+\begin{verbatim}
+err = rabbit_crypt(&st, in_buffer, inlen, out_buffer);
+\end{verbatim}
+
+If you just want a random stream of bytes initialize the cipher with a truly random \textit{key}
+(16 bytes), a truly random \textit{iv} (8 bytes). After that you can
+get a stream of pseudo--random bytes via:
+\begin{verbatim}
+err = rabbit_keystream(&st, out_buffer, length);
+\end{verbatim}
+
+When finished you should wipe the key and the state:
+\begin{verbatim}
+err = rabbit_done(&st);
+\end{verbatim}
+
+Technically, it is possible to initialize Rabbit with only a call to \textit{rabbit\_setup()},
+skipping the call to \textit{rabbit\_setiv()}.  This is not recommended for interoperability reasons,
+but there may be special cases like closed systems or custom protocols where doing so might be
+appropriate.  Please note that skipping \textit{rabbit\_setiv()} will give results different than
+calling \textit{rabbit\_setiv()} passing a zero-valued IV.  You should call rabbit_setiv() unless
+you have a special reason for not doing so.
+
+To do multiple encryptions and decryptions with the same key, you can reset the algorithm
+using \textit{rabbit\_setiv()} if you saved the state and did not wipe it with \textit{rabbit\_done()}.
+You will want to use a different IV but you do not need to call \textit{rabbit\_setup()} a 2nd time,
+unless of course, you skipped calling \textit{rabbit\_setiv()}.
+
+For more information, see: \newline
+\hspace{4em}- \url{http://www.ecrypt.eu.org/stream/p3ciphers/rabbit/rabbit_p3.pdf} \newline
+\hspace{4em}- \url{https://tools.ietf.org/html/rfc4503}
+
 \mysection{RC4}
 
 For more information about RC4 see \url{https://en.wikipedia.org/wiki/RC4}.
@@ -6568,8 +6627,9 @@ This ensures that \textit{N} is set to a random MPI in the range $1 \le N < limi
 
 \subsection{Zero'ing data}
 
-As widely know optimizing-compilers are sometimes allowed to remove an invocation of \textit{memset(out, 0, outlen)}, which could result
-in sensitive data beeing not zero'ed out. Therefore LibTomCrypt implements a variant of this routine which won't be optimized-away.
+Optimizing compilers are sometimes allowed to remove an invocation of \textit{memset(out, 0, outlen)},
+which could result in sensitive data not being zero'ed out. LibTomCrypt, therefore, implements a variant
+of this routine, \textit{zeromem(out, outlen)}, which won't be optimized away.
 
 \index{zeromem()}
 \begin{verbatim}

+ 22 - 2
src/headers/tomcrypt_cipher.h

@@ -1031,8 +1031,6 @@ int salsa20_test(void);
 
 #endif /* LTC_SALSA20 */
 
-
-
 #ifdef LTC_SOSEMANUK
 
 typedef struct {
@@ -1057,7 +1055,29 @@ int sosemanuk_test(void);
 
 #endif /* LTC_SOSEMANUK */
 
+#ifdef LTC_RABBIT
 
+typedef struct {
+   ulong32 x[8];
+   ulong32 c[8];
+   ulong32 carry;
+} rabbit_ctx;
+
+typedef struct {
+   rabbit_ctx master_ctx;
+   rabbit_ctx work_ctx;
+   unsigned char block[16];     /* last keystream block containing unused bytes */
+   ulong32       unused;        /* count fm right */
+} rabbit_state;
+
+int rabbit_setup(rabbit_state* st, const unsigned char *key, unsigned long keylen);
+int rabbit_setiv(rabbit_state* st, const unsigned char *iv, unsigned long ivlen);
+int rabbit_crypt(rabbit_state* st, const unsigned char *in, unsigned long inlen, unsigned char *out);
+int rabbit_keystream(rabbit_state* st, unsigned char *out, unsigned long outlen);
+int rabbit_done(rabbit_state *st);
+int rabbit_test(void);
+
+#endif /* LTC_RABBIT */
 
 #ifdef LTC_RC4_STREAM
 

+ 1 - 0
src/headers/tomcrypt_custom.h

@@ -209,6 +209,7 @@
 #define LTC_CHACHA
 #define LTC_SALSA20
 #define LTC_SOSEMANUK
+#define LTC_RABBIT
 #define LTC_RC4_STREAM
 #define LTC_SOBER128_STREAM
 

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

@@ -138,6 +138,9 @@ const char *crypt_build_settings =
 #if defined(LTC_SOSEMANUK)
    "   Sosemanuk\n"
 #endif
+#if defined(LTC_RABBIT)
+   "   Rabbit\n"
+#endif
 #if defined(LTC_RC4_STREAM)
    "   RC4\n"
 #endif

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

@@ -183,6 +183,9 @@ static const crypt_size _crypt_sizes[] = {
 #ifdef LTC_SOSEMANUK
     _SZ_STRINGIFY_T(sosemanuk_state),
 #endif
+#ifdef LTC_RABBIT
+    _SZ_STRINGIFY_T(rabbit_state),
+#endif
 #ifdef LTC_RC4_STREAM
     _SZ_STRINGIFY_T(rc4_state),
 #endif

+ 446 - 0
src/stream/rabbit/rabbit.c

@@ -0,0 +1,446 @@
+/* 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.
+ */
+
+/******************************************************************************
+ * This Rabbit C source code was morphed fm the EU eSTREAM ECRYPT submission
+ * and should run on any conforming C implementation (C90 or later).
+ *
+ * This implementation supports any key length up to 128 bits (16 bytes) and
+ * works in increments of 8-bit bytes.  Keys must be submitted as whole bytes
+ * and shorter keys will be right-null-padded to 16 bytes.  Likewise, an iv
+ * may be any length up to 8 bytes and will be padded out to 8 bytes.
+ *
+ * The eSTREAM submission was rather picky about the calling sequence of
+ * ECRYPT_process_blocks() and ECRYPT_process_bytes().  That version allowed
+ * calling ECRYPT_process_blocks() multiple times for a multiple of whole
+ * 16-byte blocks, but once ECRYPT_process_bytes() was called. no more calls
+ * were supported correctly.  This implementation handles the keystream
+ * differently and rabbit_crypt() may be called as many times as desired,
+ * crypting any number of bytes each time.
+ *
+ *   http://www.ecrypt.eu.org/stream/e2-rabbit.html
+ *
+ * NB: One of the test vectors distributed by the eSTREAM site in the file
+ *     "rabbit_p3source.zip" is in error.  Referring to "test-vectors.txt"
+ *     in that ZIP file, the 3rd line in "out1" should be
+ *     "96 D6 73 16 88 D1 68 DA 51 D4 0C 70 C3 A1 16 F4".
+ *
+ * Here is the original legal notice accompanying the Rabbit submission
+ * to the EU eSTREAM competition.
+ *---------------------------------------------------------------------------
+ * Copyright (C) Cryptico A/S. All rights reserved.
+ *
+ * YOU SHOULD CAREFULLY READ THIS LEGAL NOTICE BEFORE USING THIS SOFTWARE.
+ *
+ * This software is developed by Cryptico A/S and/or its suppliers.
+ * All title and intellectual property rights in and to the software,
+ * including but not limited to patent rights and copyrights, are owned
+ * by Cryptico A/S and/or its suppliers.
+ *
+ * The software may be used solely for non-commercial purposes
+ * without the prior written consent of Cryptico A/S. For further
+ * information on licensing terms and conditions please contact
+ * Cryptico A/S at [email protected]
+ *
+ * Cryptico, CryptiCore, the Cryptico logo and "Re-thinking encryption"
+ * are either trademarks or registered trademarks of Cryptico A/S.
+ *
+ * Cryptico A/S shall not in any way be liable for any use of this
+ * software. The software is provided "as is" without any express or
+ * implied warranty.
+ *---------------------------------------------------------------------------
+ * On October 6, 2008, Rabbit was "released into the public domain and
+ * may be used freely for any purpose."
+ *   http://www.ecrypt.eu.org/stream/rabbitpf.html
+ *   https://web.archive.org/web/20090630021733/http://www.ecrypt.eu.org/stream/phorum/read.php?1,1244
+ ******************************************************************************/
+
+
+#include "tomcrypt.h"
+
+#ifdef LTC_RABBIT
+
+/* local/private prototypes  (NB: rabbit_ctx and rabbit_state are different)  */
+static LTC_INLINE ulong32 _rabbit_g_func(ulong32 x);
+static LTC_INLINE void _rabbit_next_state(rabbit_ctx *p_instance);
+static LTC_INLINE void _rabbit_gen_1_block(rabbit_state* st, unsigned char *out);
+
+/* -------------------------------------------------------------------------- */
+
+/* Square a 32-bit unsigned integer to obtain the 64-bit result and return */
+/* the upper 32 bits XOR the lower 32 bits */
+static LTC_INLINE ulong32 _rabbit_g_func(ulong32 x)
+{
+   ulong32 a, b, h, l;
+
+   /* Construct high and low argument for squaring */
+   a = x &  0xFFFF;
+   b = x >> 16;
+
+   /* Calculate high and low result of squaring */
+   h = ((((ulong32)(a*a)>>17) + (ulong32)(a*b))>>15) + b*b;
+   l = x * x;
+
+   /* Return high XOR low */
+   return (ulong32)(h^l);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Calculate the next internal state */
+static LTC_INLINE void _rabbit_next_state(rabbit_ctx *p_instance)
+{
+   ulong32 g[8], c_old[8], i;
+
+   /* Save old counter values */
+   for (i=0; i<8; i++)
+      c_old[i] = p_instance->c[i];
+
+   /* Calculate new counter values */
+   p_instance->c[0] = (ulong32)(p_instance->c[0] + 0x4D34D34D + p_instance->carry);
+   p_instance->c[1] = (ulong32)(p_instance->c[1] + 0xD34D34D3 + (p_instance->c[0] < c_old[0]));
+   p_instance->c[2] = (ulong32)(p_instance->c[2] + 0x34D34D34 + (p_instance->c[1] < c_old[1]));
+   p_instance->c[3] = (ulong32)(p_instance->c[3] + 0x4D34D34D + (p_instance->c[2] < c_old[2]));
+   p_instance->c[4] = (ulong32)(p_instance->c[4] + 0xD34D34D3 + (p_instance->c[3] < c_old[3]));
+   p_instance->c[5] = (ulong32)(p_instance->c[5] + 0x34D34D34 + (p_instance->c[4] < c_old[4]));
+   p_instance->c[6] = (ulong32)(p_instance->c[6] + 0x4D34D34D + (p_instance->c[5] < c_old[5]));
+   p_instance->c[7] = (ulong32)(p_instance->c[7] + 0xD34D34D3 + (p_instance->c[6] < c_old[6]));
+   p_instance->carry = (p_instance->c[7] < c_old[7]);
+
+   /* Calculate the g-values */
+   for (i=0;i<8;i++)
+      g[i] = _rabbit_g_func((ulong32)(p_instance->x[i] + p_instance->c[i]));
+
+   /* Calculate new state values */
+   p_instance->x[0] = (ulong32)(g[0] + ROLc(g[7],16) + ROLc(g[6], 16));
+   p_instance->x[1] = (ulong32)(g[1] + ROLc(g[0], 8) + g[7]);
+   p_instance->x[2] = (ulong32)(g[2] + ROLc(g[1],16) + ROLc(g[0], 16));
+   p_instance->x[3] = (ulong32)(g[3] + ROLc(g[2], 8) + g[1]);
+   p_instance->x[4] = (ulong32)(g[4] + ROLc(g[3],16) + ROLc(g[2], 16));
+   p_instance->x[5] = (ulong32)(g[5] + ROLc(g[4], 8) + g[3]);
+   p_instance->x[6] = (ulong32)(g[6] + ROLc(g[5],16) + ROLc(g[4], 16));
+   p_instance->x[7] = (ulong32)(g[7] + ROLc(g[6], 8) + g[5]);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static LTC_INLINE void _rabbit_gen_1_block(rabbit_state* st, unsigned char *out)
+{
+    ulong32 *ptr;
+
+    /* Iterate the work context once */
+    _rabbit_next_state(&(st->work_ctx));
+
+    /* Generate 16 bytes of pseudo-random data */
+    ptr = (ulong32*)&(st->work_ctx.x);
+    STORE32L((ptr[0] ^ (ptr[5]>>16) ^ (ulong32)(ptr[3]<<16)), out+ 0);
+    STORE32L((ptr[2] ^ (ptr[7]>>16) ^ (ulong32)(ptr[5]<<16)), out+ 4);
+    STORE32L((ptr[4] ^ (ptr[1]>>16) ^ (ulong32)(ptr[7]<<16)), out+ 8);
+    STORE32L((ptr[6] ^ (ptr[3]>>16) ^ (ulong32)(ptr[1]<<16)), out+12);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Key setup */
+int rabbit_setup(rabbit_state* st, const unsigned char *key, unsigned long keylen)
+{
+   ulong32 k0, k1, k2, k3, i;
+   unsigned char  tmpkey[16] = {0};
+
+   LTC_ARGCHK(st != NULL);
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(keylen <= 16);
+
+   /* init state */
+   XMEMSET(st, 0, sizeof(rabbit_state));
+
+   /* pad key in tmpkey */
+   XMEMCPY(tmpkey, key, keylen);
+
+   /* Generate four subkeys */
+   LOAD32L(k0, tmpkey+ 0);
+   LOAD32L(k1, tmpkey+ 4);
+   LOAD32L(k2, tmpkey+ 8);
+   LOAD32L(k3, tmpkey+12);
+
+#ifdef LTC_CLEAN_STACK
+   /* done with tmpkey, wipe it */
+   zeromem(tmpkey, sizeof(tmpkey));
+#endif
+
+   /* Generate initial state variables */
+   st->master_ctx.x[0] = k0;
+   st->master_ctx.x[2] = k1;
+   st->master_ctx.x[4] = k2;
+   st->master_ctx.x[6] = k3;
+   st->master_ctx.x[1] = (ulong32)(k3<<16) | (k2>>16);
+   st->master_ctx.x[3] = (ulong32)(k0<<16) | (k3>>16);
+   st->master_ctx.x[5] = (ulong32)(k1<<16) | (k0>>16);
+   st->master_ctx.x[7] = (ulong32)(k2<<16) | (k1>>16);
+
+   /* Generate initial counter values */
+   st->master_ctx.c[0] = ROLc(k2, 16);
+   st->master_ctx.c[2] = ROLc(k3, 16);
+   st->master_ctx.c[4] = ROLc(k0, 16);
+   st->master_ctx.c[6] = ROLc(k1, 16);
+   st->master_ctx.c[1] = (k0&0xFFFF0000) | (k1&0xFFFF);
+   st->master_ctx.c[3] = (k1&0xFFFF0000) | (k2&0xFFFF);
+   st->master_ctx.c[5] = (k2&0xFFFF0000) | (k3&0xFFFF);
+   st->master_ctx.c[7] = (k3&0xFFFF0000) | (k0&0xFFFF);
+
+   /* Clear carry bit */
+   st->master_ctx.carry = 0;
+
+   /* Iterate the master context four times */
+   for (i=0; i<4; i++)
+      _rabbit_next_state(&(st->master_ctx));
+
+   /* Modify the counters */
+   for (i=0; i<8; i++)
+      st->master_ctx.c[i] ^= st->master_ctx.x[(i+4)&0x7];
+
+   /* Copy master instance to work instance */
+   for (i=0; i<8; i++) {
+      st->work_ctx.x[i] = st->master_ctx.x[i];
+      st->work_ctx.c[i] = st->master_ctx.c[i];
+   }
+   st->work_ctx.carry = st->master_ctx.carry;
+   /* ...and prepare block for crypt() */
+   XMEMSET(&(st->block), 0, sizeof(st->block));
+   st->unused = 0;
+
+   return CRYPT_OK;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* IV setup */
+int rabbit_setiv(rabbit_state* st, const unsigned char *iv, unsigned long ivlen)
+{
+   ulong32 i0, i1, i2, i3, i;
+   unsigned char  tmpiv[8] = {0};
+
+   LTC_ARGCHK(st != NULL);
+   LTC_ARGCHK(iv != NULL || ivlen == 0);
+   LTC_ARGCHK(ivlen <= 8);
+
+   /* pad iv in tmpiv */
+   if (iv && ivlen > 0) XMEMCPY(tmpiv, iv, ivlen);
+
+   /* Generate four subvectors */
+   LOAD32L(i0, tmpiv+0);
+   LOAD32L(i2, tmpiv+4);
+   i1 = (i0>>16) | (i2&0xFFFF0000);
+   i3 = (i2<<16) | (i0&0x0000FFFF);
+
+   /* Modify counter values */
+   st->work_ctx.c[0] = st->master_ctx.c[0] ^ i0;
+   st->work_ctx.c[1] = st->master_ctx.c[1] ^ i1;
+   st->work_ctx.c[2] = st->master_ctx.c[2] ^ i2;
+   st->work_ctx.c[3] = st->master_ctx.c[3] ^ i3;
+   st->work_ctx.c[4] = st->master_ctx.c[4] ^ i0;
+   st->work_ctx.c[5] = st->master_ctx.c[5] ^ i1;
+   st->work_ctx.c[6] = st->master_ctx.c[6] ^ i2;
+   st->work_ctx.c[7] = st->master_ctx.c[7] ^ i3;
+
+   /* Copy state variables */
+   for (i=0; i<8; i++)
+      st->work_ctx.x[i] = st->master_ctx.x[i];
+   st->work_ctx.carry = st->master_ctx.carry;
+
+   /* Iterate the work context four times */
+   for (i=0; i<4; i++)
+      _rabbit_next_state(&(st->work_ctx));
+
+   /* reset keystream buffer and unused count */
+   XMEMSET(&(st->block), 0, sizeof(st->block));
+   st->unused = 0;
+
+   return CRYPT_OK;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Crypt a chunk of any size (encrypt/decrypt) */
+int rabbit_crypt(rabbit_state* st, const unsigned char *in, unsigned long inlen, unsigned char *out)
+{
+   unsigned char buf[16];
+   unsigned long i, j;
+
+   if (inlen == 0) return CRYPT_OK; /* nothing to do */
+
+   LTC_ARGCHK(st        != NULL);
+   LTC_ARGCHK(in        != NULL);
+   LTC_ARGCHK(out       != NULL);
+
+   if (st->unused > 0) {
+      j = MIN(st->unused, inlen);
+      for (i = 0; i < j; ++i, st->unused--) out[i] = in[i] ^ st->block[16 - st->unused];
+      inlen -= j;
+      if (inlen == 0) return CRYPT_OK;
+      out += j;
+      in  += j;
+   }
+   for (;;) {
+     /* gen a block for buf */
+     _rabbit_gen_1_block(st, buf);
+     if (inlen <= 16) {
+       /* XOR and send to out */
+       for (i = 0; i < inlen; ++i) out[i] = in[i] ^ buf[i];
+       st->unused = 16 - inlen;
+       /* copy remainder to block */
+       for (i = inlen; i < 16; ++i) st->block[i] = buf[i];
+       return CRYPT_OK;
+     } else {
+       /* XOR entire buf and send to out */
+       for (i = 0; i < 16; ++i) out[i] = in[i] ^ buf[i];
+       inlen -= 16;
+       out += 16;
+       in  += 16;
+     }
+   }
+}
+
+/* ------------------------------------------------------------------------- */
+
+int rabbit_keystream(rabbit_state *st, unsigned char *out, unsigned long outlen)
+{
+   if (outlen == 0) return CRYPT_OK; /* nothing to do */
+
+   LTC_ARGCHK(out != NULL);
+
+   XMEMSET(out, 0, outlen);
+   return rabbit_crypt(st, out, outlen, out);
+}
+
+/* -------------------------------------------------------------------------- */
+
+int rabbit_done(rabbit_state *st)
+{
+   LTC_ARGCHK(st != NULL);
+
+   zeromem(st, sizeof(rabbit_state));
+   return CRYPT_OK;
+}
+
+/* -------------------------------------------------------------------------- */
+
+int rabbit_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   rabbit_state st;
+   int err;
+   unsigned char out[1000] = { 0 };
+   {
+      /* all 3 tests use key and iv fm set 6, vector 3, the last vector in:
+         http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/rabbit/verified.test-vectors?rev=210&view=log
+      */
+
+      /* --- Test 1 (generate whole blocks) --------------------------------- */
+
+      {
+         unsigned char k[]  = { 0x0F, 0x62, 0xB5, 0x08, 0x5B, 0xAE, 0x01, 0x54,
+                                0xA7, 0xFA, 0x4D, 0xA0, 0xF3, 0x46, 0x99, 0xEC };
+         unsigned char iv[] = { 0x28, 0x8F, 0xF6, 0x5D, 0xC4, 0x2B, 0x92, 0xF9 };
+         char pt[64]        = { 0 };
+         unsigned char ct[] = { 0x61, 0x3C, 0xB0, 0xBA, 0x96, 0xAF, 0xF6, 0xCA,
+                                0xCF, 0x2A, 0x45, 0x9A, 0x10, 0x2A, 0x7F, 0x78,
+                                0xCA, 0x98, 0x5C, 0xF8, 0xFD, 0xD1, 0x47, 0x40,
+                                0x18, 0x75, 0x8E, 0x36, 0xAE, 0x99, 0x23, 0xF5,
+                                0x19, 0xD1, 0x3D, 0x71, 0x8D, 0xAF, 0x8D, 0x7C,
+                                0x0C, 0x10, 0x9B, 0x79, 0xD5, 0x74, 0x94, 0x39,
+                                0xB7, 0xEF, 0xA4, 0xC4, 0xC9, 0xC8, 0xD2, 0x9D,
+                                0xC5, 0xB3, 0x88, 0x83, 0x14, 0xA6, 0x81, 0x6F };
+         unsigned long ptlen = sizeof(pt);
+
+         /* crypt 64 nulls */
+         if ((err = rabbit_setup(&st, k, sizeof(k)))                   != CRYPT_OK) return err;
+         if ((err = rabbit_setiv(&st, iv, sizeof(iv)))                 != CRYPT_OK) return err;
+         if ((err = rabbit_crypt(&st, (unsigned char*)pt, ptlen, out)) != CRYPT_OK) return err;
+         if (compare_testvector(out, ptlen, ct, ptlen, "RABBIT-TV1", 1))   return CRYPT_FAIL_TESTVECTOR;
+      }
+
+      /* --- Test 2 (generate unusual number of bytes each time) ------------ */
+
+      {
+         unsigned char k[]  = { 0x0F, 0x62, 0xB5, 0x08, 0x5B, 0xAE, 0x01, 0x54,
+                                0xA7, 0xFA, 0x4D, 0xA0, 0xF3, 0x46, 0x99, 0xEC };
+         unsigned char iv[] = { 0x28, 0x8F, 0xF6, 0x5D, 0xC4, 0x2B, 0x92, 0xF9 };
+         char          pt[39] = { 0 };
+         unsigned char ct[] = { 0x61, 0x3C, 0xB0, 0xBA,   0x96, 0xAF, 0xF6, 0xCA,
+                                0xCF, 0x2A, 0x45, 0x9A,   0x10, 0x2A, 0x7F, 0x78,
+                                0xCA, 0x98, 0x5C, 0xF8,   0xFD, 0xD1, 0x47, 0x40,
+                                0x18, 0x75, 0x8E, 0x36,   0xAE, 0x99, 0x23, 0xF5,
+                                0x19, 0xD1, 0x3D, 0x71,   0x8D, 0xAF, 0x8D };
+         unsigned long ptlen = sizeof(pt);
+
+         /* crypt piece by piece (hit at least one 16-byte boundary) */
+         if ((err = rabbit_setup(&st, k, sizeof(k)))                          != CRYPT_OK) return err;
+         if ((err = rabbit_setiv(&st, iv, sizeof(iv)))                        != CRYPT_OK) return err;
+         if ((err = rabbit_crypt(&st, (unsigned char*)pt,       5, out))      != CRYPT_OK) return err;
+         if ((err = rabbit_crypt(&st, (unsigned char*)pt +  5, 11, out +  5)) != CRYPT_OK) return err;
+         if ((err = rabbit_crypt(&st, (unsigned char*)pt + 16, 14, out + 16)) != CRYPT_OK) return err;
+         if ((err = rabbit_crypt(&st, (unsigned char*)pt + 30,  2, out + 30)) != CRYPT_OK) return err;
+         if ((err = rabbit_crypt(&st, (unsigned char*)pt + 32,  7, out + 32)) != CRYPT_OK) return err;
+         if (compare_testvector(out, ptlen, ct, ptlen, "RABBIT-TV2", 1))   return CRYPT_FAIL_TESTVECTOR;
+      }
+
+      /* --- Test 3 (use non-null data) ------------------------------------- */
+
+      {
+         unsigned char k[]  = { 0x0F, 0x62, 0xB5, 0x08, 0x5B, 0xAE, 0x01, 0x54,
+                                0xA7, 0xFA, 0x4D, 0xA0, 0xF3, 0x46, 0x99, 0xEC };
+         unsigned char iv[] = { 0x28, 0x8F, 0xF6, 0x5D, 0xC4, 0x2B, 0x92, 0xF9 };
+         char          pt[] = "Kilroy was here, there, and everywhere!";
+         unsigned char ct[] = { 0x2a, 0x55, 0xdc, 0xc8,   0xf9, 0xd6, 0xd6, 0xbd,
+                                0xae, 0x59, 0x65, 0xf2,   0x75, 0x58, 0x1a, 0x54,
+                                0xea, 0xec, 0x34, 0x9d,   0x8f, 0xb4, 0x6b, 0x60,
+                                0x79, 0x1b, 0xea, 0x16,   0xcb, 0xef, 0x46, 0x87,
+                                0x60, 0xa6, 0x55, 0x14,   0xff, 0xca, 0xac };
+         unsigned long ptlen = strlen(pt);
+         unsigned char out2[1000] = { 0 };
+         unsigned char nulls[1000] = { 0 };
+
+         /* crypt piece by piece */
+         if ((err = rabbit_setup(&st, k, sizeof(k)))                          != CRYPT_OK) return err;
+         if ((err = rabbit_setiv(&st, iv, sizeof(iv)))                        != CRYPT_OK) return err;
+         if ((err = rabbit_crypt(&st, (unsigned char*)pt,       5, out))      != CRYPT_OK) return err;
+         if ((err = rabbit_crypt(&st, (unsigned char*)pt +  5, 29, out +  5)) != CRYPT_OK) return err;
+         if ((err = rabbit_crypt(&st, (unsigned char*)pt + 34,  5, out + 34)) != CRYPT_OK) return err;
+         if (compare_testvector(out, ptlen, ct, ptlen, "RABBIT-TV3", 1))   return CRYPT_FAIL_TESTVECTOR;
+         /* use 'out' (ciphertext) in the next decryption test */
+
+      /* --- Test 4 (decrypt ciphertext) ------------------------------------ */
+
+         /* decrypt ct (out) and compare with pt (start with only setiv() to reset) */
+         if ((err = rabbit_setiv(&st, iv, sizeof(iv)))                        != CRYPT_OK) return err;
+         if ((err = rabbit_crypt(&st, out, ptlen, out2))                      != CRYPT_OK) return err;
+         if (compare_testvector(out2, ptlen, pt, ptlen, "RABBIT-TV4", 1))  return CRYPT_FAIL_TESTVECTOR;
+
+      /* --- Test 5 (wipe state, incl key) ---------------------------------- */
+
+         if ((err = rabbit_done(&st))                      != CRYPT_OK) return err;
+         if (compare_testvector(&st, sizeof(st), nulls, sizeof(st), "RABBIT-TV5", 1))  return CRYPT_FAIL_TESTVECTOR;
+
+      }
+
+      return CRYPT_OK;
+   }
+#endif
+}
+
+/* -------------------------------------------------------------------------- */
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 3 - 0
tests/cipher_hash_test.c

@@ -29,6 +29,9 @@ int cipher_hash_test(void)
 #ifdef LTC_SOSEMANUK
    DO(sosemanuk_test());
 #endif
+#ifdef LTC_RABBIT
+   DO(rabbit_test());
+#endif
 #ifdef LTC_RC4_STREAM
    DO(rc4_stream_test());
 #endif