// SPDX-License-Identifier: BSD-2-Clause /* 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 info@cryptico.com * * 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_private.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; } /* 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; /* --- Test 4 (crypt in a single call) ------------------------------------ */ if ((err = rabbit_memory(k, sizeof(k), iv, sizeof(iv), (unsigned char*)pt, sizeof(pt), out)) != CRYPT_OK) return err; if (compare_testvector(out, ptlen, ct, ptlen, "RABBIT-TV4", 1)) return CRYPT_FAIL_TESTVECTOR; /* use 'out' (ciphertext) in the next decryption test */ /* --- Test 5 (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-TV5", 1)) return CRYPT_FAIL_TESTVECTOR; /* --- Test 6 (wipe state, incl key) ---------------------------------- */ if ((err = rabbit_done(&st)) != CRYPT_OK) return err; if (compare_testvector(&st, sizeof(st), nulls, sizeof(st), "RABBIT-TV6", 1)) return CRYPT_FAIL_TESTVECTOR; } return CRYPT_OK; } #endif } /* -------------------------------------------------------------------------- */ #endif /* ref: $Format:%D$ */ /* git commit: $Format:%H$ */ /* commit time: $Format:%ai$ */