Replaced system SQLite with SQLCipher to support encrypted database

This commit is contained in:
Oleksii Zghurskyi
2025-06-07 18:11:17 +03:00
parent f4198d62a7
commit 177d74700f
534 changed files with 362771 additions and 21 deletions

View File

@@ -0,0 +1,93 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* The implementation is based on:
* chacha-ref.c version 20080118
* Public domain from D. J. Bernstein
*/
#include "tomcrypt_private.h"
#ifdef LTC_CHACHA
#define QUARTERROUND(a,b,c,d) \
x[a] += x[b]; x[d] = ROL(x[d] ^ x[a], 16); \
x[c] += x[d]; x[b] = ROL(x[b] ^ x[c], 12); \
x[a] += x[b]; x[d] = ROL(x[d] ^ x[a], 8); \
x[c] += x[d]; x[b] = ROL(x[b] ^ x[c], 7);
static void s_chacha_block(unsigned char *output, const ulong32 *input, int rounds)
{
ulong32 x[16];
int i;
XMEMCPY(x, input, sizeof(x));
for (i = rounds; i > 0; i -= 2) {
QUARTERROUND(0, 4, 8,12)
QUARTERROUND(1, 5, 9,13)
QUARTERROUND(2, 6,10,14)
QUARTERROUND(3, 7,11,15)
QUARTERROUND(0, 5,10,15)
QUARTERROUND(1, 6,11,12)
QUARTERROUND(2, 7, 8,13)
QUARTERROUND(3, 4, 9,14)
}
for (i = 0; i < 16; ++i) {
x[i] += input[i];
STORE32L(x[i], output + 4 * i);
}
}
/**
Encrypt (or decrypt) bytes of ciphertext (or plaintext) with ChaCha
@param st The ChaCha state
@param in The plaintext (or ciphertext)
@param inlen The length of the input (octets)
@param out [out] The ciphertext (or plaintext), length inlen
@return CRYPT_OK if successful
*/
int chacha_crypt(chacha_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out)
{
unsigned char buf[64];
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);
LTC_ARGCHK(st->ivlen != 0);
if (st->ksleft > 0) {
j = MIN(st->ksleft, inlen);
for (i = 0; i < j; ++i, st->ksleft--) out[i] = in[i] ^ st->kstream[64 - st->ksleft];
inlen -= j;
if (inlen == 0) return CRYPT_OK;
out += j;
in += j;
}
for (;;) {
s_chacha_block(buf, st->input, st->rounds);
if (st->ivlen == 8) {
/* IV-64bit, increment 64bit counter */
if (0 == ++st->input[12] && 0 == ++st->input[13]) return CRYPT_OVERFLOW;
}
else {
/* IV-96bit, increment 32bit counter */
if (0 == ++st->input[12]) return CRYPT_OVERFLOW;
}
if (inlen <= 64) {
for (i = 0; i < inlen; ++i) out[i] = in[i] ^ buf[i];
st->ksleft = 64 - inlen;
for (i = inlen; i < 64; ++i) st->kstream[i] = buf[i];
return CRYPT_OK;
}
for (i = 0; i < 64; ++i) out[i] = in[i] ^ buf[i];
inlen -= 64;
out += 64;
in += 64;
}
}
#undef QUARTERROUND
#endif

View File

@@ -0,0 +1,20 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_CHACHA
/**
Terminate and clear ChaCha state
@param st The ChaCha state
@return CRYPT_OK on success
*/
int chacha_done(chacha_state *st)
{
LTC_ARGCHK(st != NULL);
zeromem(st, sizeof(chacha_state));
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,37 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* The implementation is based on:
* chacha-ref.c version 20080118
* Public domain from D. J. Bernstein
*/
#include "tomcrypt_private.h"
#ifdef LTC_CHACHA
/**
Set IV + counter data to the ChaCha state
@param st The ChaCha20 state
@param iv The IV data to add
@param ivlen The length of the IV (must be 12)
@param counter 32bit (unsigned) initial counter value
@return CRYPT_OK on success
*/
int chacha_ivctr32(chacha_state *st, const unsigned char *iv, unsigned long ivlen, ulong32 counter)
{
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(iv != NULL);
/* 96bit IV + 32bit counter */
LTC_ARGCHK(ivlen == 12);
st->input[12] = counter;
LOAD32L(st->input[13], iv + 0);
LOAD32L(st->input[14], iv + 4);
LOAD32L(st->input[15], iv + 8);
st->ksleft = 0;
st->ivlen = ivlen;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,37 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* The implementation is based on:
* chacha-ref.c version 20080118
* Public domain from D. J. Bernstein
*/
#include "tomcrypt_private.h"
#ifdef LTC_CHACHA
/**
Set IV + counter data to the ChaCha state
@param st The ChaCha20 state
@param iv The IV data to add
@param ivlen The length of the IV (must be 8)
@param counter 64bit (unsigned) initial counter value
@return CRYPT_OK on success
*/
int chacha_ivctr64(chacha_state *st, const unsigned char *iv, unsigned long ivlen, ulong64 counter)
{
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(iv != NULL);
/* 64bit IV + 64bit counter */
LTC_ARGCHK(ivlen == 8);
st->input[12] = (ulong32)(counter & 0xFFFFFFFF);
st->input[13] = (ulong32)(counter >> 32);
LOAD32L(st->input[14], iv + 0);
LOAD32L(st->input[15], iv + 4);
st->ksleft = 0;
st->ivlen = ivlen;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,28 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* The implementation is based on:
* chacha-ref.c version 20080118
* Public domain from D. J. Bernstein
*/
#include "tomcrypt_private.h"
#ifdef LTC_CHACHA
/**
Generate a stream of random bytes via ChaCha
@param st The ChaCha20 state
@param out [out] The output buffer
@param outlen The output length
@return CRYPT_OK on success
*/
int chacha_keystream(chacha_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 chacha_crypt(st, out, outlen, out);
}
#endif

View File

@@ -0,0 +1,57 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#ifdef LTC_CHACHA
/**
Encrypt (or decrypt) bytes of ciphertext (or plaintext) with ChaCha
@param key The key
@param keylen The key length
@param rounds The number of rounds
@param iv The initial vector
@param ivlen The initial vector length
@param counter initial counter value, either ignored, 32- or 64-bit, depending on ivlen
@param datain The plaintext (or ciphertext)
@param datalen The length of the input and output (octets)
@param dataout [out] The ciphertext (or plaintext)
@return CRYPT_OK if successful
*/
int chacha_memory(const unsigned char *key, unsigned long keylen, unsigned long rounds,
const unsigned char *iv, unsigned long ivlen, ulong64 counter,
const unsigned char *datain, unsigned long datalen, unsigned char *dataout)
{
chacha_state st;
int err;
const unsigned char *iv_ = iv;
unsigned long ivlen_ = ivlen;
ulong64 counter_ = counter;
if (ivlen == 16) {
LOAD64L(counter_, iv);
iv_ += 8;
ivlen_ -=8;
}
LTC_ARGCHK(ivlen_ <= 8 || counter_ < CONST64(4294967296)); /* 2**32 */
if ((err = chacha_setup(&st, key, keylen, rounds)) != CRYPT_OK) goto WIPE_KEY;
if (ivlen_ > 8) {
if ((err = chacha_ivctr32(&st, iv_, ivlen_, (ulong32)counter_)) != CRYPT_OK) goto WIPE_KEY;
} else {
if ((err = chacha_ivctr64(&st, iv_, ivlen_, counter_)) != CRYPT_OK) goto WIPE_KEY;
}
err = chacha_crypt(&st, datain, datalen, dataout);
WIPE_KEY:
chacha_done(&st);
return err;
}
#endif /* LTC_CHACHA */
#pragma clang diagnostic pop

View File

@@ -0,0 +1,56 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* The implementation is based on:
* chacha-ref.c version 20080118
* Public domain from D. J. Bernstein
*/
#include "tomcrypt_private.h"
#ifdef LTC_CHACHA
/**
Initialize an ChaCha context (only the key)
@param st [out] The destination of the ChaCha state
@param key The secret key
@param keylen The length of the secret key (octets)
@param rounds Number of rounds (e.g. 20 for ChaCha20)
@return CRYPT_OK if successful
*/
int chacha_setup(chacha_state *st, const unsigned char *key, unsigned long keylen, int rounds)
{
const char * const sigma = "expand 32-byte k";
const char * const tau = "expand 16-byte k";
const char *constants;
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(keylen == 32 || keylen == 16);
if (rounds == 0) rounds = 20;
LOAD32L(st->input[4], key + 0);
LOAD32L(st->input[5], key + 4);
LOAD32L(st->input[6], key + 8);
LOAD32L(st->input[7], key + 12);
if (keylen == 32) { /* 256bit */
key += 16;
constants = sigma;
} else { /* 128bit */
constants = tau;
}
LOAD32L(st->input[8], key + 0);
LOAD32L(st->input[9], key + 4);
LOAD32L(st->input[10], key + 8);
LOAD32L(st->input[11], key + 12);
LOAD32L(st->input[0], constants + 0);
LOAD32L(st->input[1], constants + 4);
LOAD32L(st->input[2], constants + 8);
LOAD32L(st->input[3], constants + 12);
st->rounds = rounds; /* e.g. 20 for chacha20 */
st->ivlen = 0; /* will be set later by chacha_ivctr(32|64) */
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,74 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* The implementation is based on:
* chacha-ref.c version 20080118
* Public domain from D. J. Bernstein
*/
#include "tomcrypt_private.h"
#ifdef LTC_CHACHA
int chacha_test(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
unsigned long len;
unsigned char out[1000];
/* https://tools.ietf.org/html/rfc7539#section-2.4.2 */
unsigned char k[] = { 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 };
unsigned char n[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00 };
unsigned char ct[] = { 0x6E, 0x2E, 0x35, 0x9A, 0x25, 0x68, 0xF9, 0x80, 0x41, 0xBA, 0x07, 0x28, 0xDD, 0x0D, 0x69, 0x81,
0xE9, 0x7E, 0x7A, 0xEC, 0x1D, 0x43, 0x60, 0xC2, 0x0A, 0x27, 0xAF, 0xCC, 0xFD, 0x9F, 0xAE, 0x0B,
0xF9, 0x1B, 0x65, 0xC5, 0x52, 0x47, 0x33, 0xAB, 0x8F, 0x59, 0x3D, 0xAB, 0xCD, 0x62, 0xB3, 0x57,
0x16, 0x39, 0xD6, 0x24, 0xE6, 0x51, 0x52, 0xAB, 0x8F, 0x53, 0x0C, 0x35, 0x9F, 0x08, 0x61, 0xD8,
0x07, 0xCA, 0x0D, 0xBF, 0x50, 0x0D, 0x6A, 0x61, 0x56, 0xA3, 0x8E, 0x08, 0x8A, 0x22, 0xB6, 0x5E,
0x52, 0xBC, 0x51, 0x4D, 0x16, 0xCC, 0xF8, 0x06, 0x81, 0x8C, 0xE9, 0x1A, 0xB7, 0x79, 0x37, 0x36,
0x5A, 0xF9, 0x0B, 0xBF, 0x74, 0xA3, 0x5B, 0xE6, 0xB4, 0x0B, 0x8E, 0xED, 0xF2, 0x78, 0x5E, 0x42,
0x87, 0x4D };
char pt[] = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
chacha_state st;
int err;
len = XSTRLEN(pt);
/* crypt piece by piece - using chacha_ivctr32() */
if ((err = chacha_setup(&st, k, sizeof(k), 20)) != CRYPT_OK) return err;
if ((err = chacha_ivctr32(&st, n, sizeof(n), 1)) != CRYPT_OK) return err;
if ((err = chacha_crypt(&st, (unsigned char*)pt, 35, out )) != CRYPT_OK) return err;
if ((err = chacha_crypt(&st, (unsigned char*)pt + 35, 35, out + 35)) != CRYPT_OK) return err;
if ((err = chacha_crypt(&st, (unsigned char*)pt + 70, 5, out + 70)) != CRYPT_OK) return err;
if ((err = chacha_crypt(&st, (unsigned char*)pt + 75, 5, out + 75)) != CRYPT_OK) return err;
if ((err = chacha_crypt(&st, (unsigned char*)pt + 80, len - 80, out + 80)) != CRYPT_OK) return err;
if (compare_testvector(out, len, ct, sizeof(ct), "CHACHA-TV1", 1)) return CRYPT_FAIL_TESTVECTOR;
/* crypt in one go - using chacha_ivctr32() */
if ((err = chacha_setup(&st, k, sizeof(k), 20)) != CRYPT_OK) return err;
if ((err = chacha_ivctr32(&st, n, sizeof(n), 1)) != CRYPT_OK) return err;
if ((err = chacha_crypt(&st, (unsigned char*)pt, len, out)) != CRYPT_OK) return err;
if (compare_testvector(out, len, ct, sizeof(ct), "CHACHA-TV2", 1)) return CRYPT_FAIL_TESTVECTOR;
/* crypt in one go - using chacha_ivctr64() */
if ((err = chacha_setup(&st, k, sizeof(k), 20)) != CRYPT_OK) return err;
if ((err = chacha_ivctr64(&st, n + 4, sizeof(n) - 4, 1)) != CRYPT_OK) return err;
if ((err = chacha_crypt(&st, (unsigned char*)pt, len, out)) != CRYPT_OK) return err;
if (compare_testvector(out, len, ct, sizeof(ct), "CHACHA-TV3", 1)) return CRYPT_FAIL_TESTVECTOR;
/* crypt in a single call using 32-bit counter with a value of 1 */
if ((err = chacha_memory(k, sizeof(k), 20,
n, sizeof(n), 1, (unsigned char*)pt, len, out)) != CRYPT_OK) return err;
if (compare_testvector(out, len, ct, sizeof(ct), "CHACHA-TV4", 1)) return CRYPT_FAIL_TESTVECTOR;
/* crypt in a single call using 64-bit counter with a value of 1 */
if ((err = chacha_memory(k, sizeof(k), 20,
n + 4, sizeof(n) - 4, 1, (unsigned char*)pt, len, out)) != CRYPT_OK) return err;
if (compare_testvector(out, len, ct, sizeof(ct), "CHACHA-TV5", 1)) return CRYPT_FAIL_TESTVECTOR;
return CRYPT_OK;
#endif
}
#endif

View File

@@ -0,0 +1,453 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/******************************************************************************
* 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"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#ifdef LTC_RABBIT
/* local/private prototypes (NB: rabbit_ctx and rabbit_state are different) */
static LTC_INLINE ulong32 ss_rabbit_g_func(ulong32 x);
static LTC_INLINE void ss_rabbit_next_state(rabbit_ctx *p_instance);
static LTC_INLINE void ss_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 ss_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 ss_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] = ss_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 ss_rabbit_gen_1_block(rabbit_state* st, unsigned char *out)
{
ulong32 *ptr;
/* Iterate the work context once */
ss_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++) {
ss_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++) {
ss_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 */
ss_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 = XSTRLEN(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
#pragma clang diagnostic pop

View File

@@ -0,0 +1,40 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* The implementation is based on:
* chacha-ref.c version 20080118
* Public domain from D. J. Bernstein
*/
#include "tomcrypt_private.h"
#ifdef LTC_RABBIT
/**
Encrypt (or decrypt) bytes of ciphertext (or plaintext) with Rabbit
@param key The key
@param keylen The key length
@param iv The initial vector
@param ivlen The initial vector length
@param datain The plaintext (or ciphertext)
@param datalen The length of the input and output (octets)
@param dataout [out] The ciphertext (or plaintext)
@return CRYPT_OK if successful
*/
int rabbit_memory(const unsigned char *key, unsigned long keylen,
const unsigned char *iv, unsigned long ivlen,
const unsigned char *datain, unsigned long datalen,
unsigned char *dataout)
{
rabbit_state st;
int err;
if ((err = rabbit_setup(&st, key, keylen)) != CRYPT_OK) goto WIPE_KEY;
if ((err = rabbit_setiv(&st, iv, ivlen)) != CRYPT_OK) goto WIPE_KEY;
err = rabbit_crypt(&st, datain, datalen, dataout);
WIPE_KEY:
rabbit_done(&st);
return err;
}
#endif /* LTC_RABBIT */

View File

@@ -0,0 +1,101 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_RC4_STREAM
/**
Initialize an RC4 context (only the key)
@param st [out] The destination of the RC4 state
@param key The secret key
@param keylen The length of the secret key (8 - 256 bytes)
@return CRYPT_OK if successful
*/
int rc4_stream_setup(rc4_state *st, const unsigned char *key, unsigned long keylen)
{
unsigned char tmp, *s;
int x, y;
unsigned long j;
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(keylen >= 5); /* 40-2048 bits */
s = st->buf;
for (x = 0; x < 256; x++) {
s[x] = x;
}
for (j = x = y = 0; x < 256; x++) {
y = (y + s[x] + key[j++]) & 255;
if (j == keylen) {
j = 0;
}
tmp = s[x]; s[x] = s[y]; s[y] = tmp;
}
st->x = 0;
st->y = 0;
return CRYPT_OK;
}
/**
Encrypt (or decrypt) bytes of ciphertext (or plaintext) with RC4
@param st The RC4 state
@param in The plaintext (or ciphertext)
@param inlen The length of the input (octets)
@param out [out] The ciphertext (or plaintext), length inlen
@return CRYPT_OK if successful
*/
int rc4_stream_crypt(rc4_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out)
{
unsigned char x, y, *s, tmp;
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
x = st->x;
y = st->y;
s = st->buf;
while (inlen--) {
x = (x + 1) & 255;
y = (y + s[x]) & 255;
tmp = s[x]; s[x] = s[y]; s[y] = tmp;
tmp = (s[x] + s[y]) & 255;
*out++ = *in++ ^ s[tmp];
}
st->x = x;
st->y = y;
return CRYPT_OK;
}
/**
Generate a stream of random bytes via RC4
@param st The RC420 state
@param out [out] The output buffer
@param outlen The output length
@return CRYPT_OK on success
*/
int rc4_stream_keystream(rc4_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 rc4_stream_crypt(st, out, outlen, out);
}
/**
Terminate and clear RC4 state
@param st The RC4 state
@return CRYPT_OK on success
*/
int rc4_stream_done(rc4_state *st)
{
LTC_ARGCHK(st != NULL);
zeromem(st, sizeof(rc4_state));
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,31 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_RC4_STREAM
/**
Encrypt (or decrypt) bytes of ciphertext (or plaintext) with RC4
@param key The key
@param keylen The key length
@param datain The plaintext (or ciphertext)
@param datalen The length of the input and output (octets)
@param dataout [out] The ciphertext (or plaintext)
@return CRYPT_OK if successful
*/
int rc4_stream_memory(const unsigned char *key, unsigned long keylen,
const unsigned char *datain, unsigned long datalen,
unsigned char *dataout)
{
rc4_state st;
int err;
if ((err = rc4_stream_setup(&st, key, keylen)) != CRYPT_OK) goto WIPE_KEY;
err = rc4_stream_crypt(&st, datain, datalen, dataout);
WIPE_KEY:
rc4_stream_done(&st);
return err;
}
#endif /* LTC_RC4_STREAM */

View File

@@ -0,0 +1,33 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_RC4_STREAM
int rc4_stream_test(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
rc4_state st;
int err;
const unsigned char key[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
const unsigned char pt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
const unsigned char ct[] = { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 };
unsigned char buf[10];
if ((err = rc4_stream_setup(&st, key, sizeof(key))) != CRYPT_OK) return err;
if ((err = rc4_stream_crypt(&st, pt, sizeof(pt), buf)) != CRYPT_OK) return err;
if (compare_testvector(buf, sizeof(ct), ct, sizeof(ct), "RC4-TV1", 0)) return CRYPT_FAIL_TESTVECTOR;
if ((err = rc4_stream_done(&st)) != CRYPT_OK) return err;
/* crypt in a single call */
if ((err = rc4_stream_memory(key, sizeof(key), pt, sizeof(pt), buf)) != CRYPT_OK) return err;
if (compare_testvector(buf, sizeof(ct), ct, sizeof(ct), "RC4-TV2", 0)) return CRYPT_FAIL_TESTVECTOR;
return CRYPT_OK;
#endif
}
#endif

View File

@@ -0,0 +1,88 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* The implementation is based on:
* "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
* and salsa20-ref.c version 20051118
* Public domain from D. J. Bernstein
*/
#include "tomcrypt_private.h"
#ifdef LTC_SALSA20
#define QUARTERROUND(a,b,c,d) \
x[b] ^= (ROL((x[a] + x[d]), 7)); \
x[c] ^= (ROL((x[b] + x[a]), 9)); \
x[d] ^= (ROL((x[c] + x[b]), 13)); \
x[a] ^= (ROL((x[d] + x[c]), 18));
static void s_salsa20_block(unsigned char *output, const ulong32 *input, int rounds)
{
ulong32 x[16];
int i;
XMEMCPY(x, input, sizeof(x));
for (i = rounds; i > 0; i -= 2) {
QUARTERROUND( 0, 4, 8,12)
QUARTERROUND( 5, 9,13, 1)
QUARTERROUND(10,14, 2, 6)
QUARTERROUND(15, 3, 7,11)
QUARTERROUND( 0, 1, 2, 3)
QUARTERROUND( 5, 6, 7, 4)
QUARTERROUND(10,11, 8, 9)
QUARTERROUND(15,12,13,14)
}
for (i = 0; i < 16; ++i) {
x[i] += input[i];
STORE32L(x[i], output + 4 * i);
}
}
/**
Encrypt (or decrypt) bytes of ciphertext (or plaintext) with Salsa20
@param st The Salsa20 state
@param in The plaintext (or ciphertext)
@param inlen The length of the input (octets)
@param out [out] The ciphertext (or plaintext), length inlen
@return CRYPT_OK if successful
*/
int salsa20_crypt(salsa20_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out)
{
unsigned char buf[64];
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);
LTC_ARGCHK(st->ivlen == 8 || st->ivlen == 24);
if (st->ksleft > 0) {
j = MIN(st->ksleft, inlen);
for (i = 0; i < j; ++i, st->ksleft--) out[i] = in[i] ^ st->kstream[64 - st->ksleft];
inlen -= j;
if (inlen == 0) return CRYPT_OK;
out += j;
in += j;
}
for (;;) {
s_salsa20_block(buf, st->input, st->rounds);
/* Salsa20: 64-bit IV, increment 64-bit counter */
if (0 == ++st->input[8] && 0 == ++st->input[9]) return CRYPT_OVERFLOW;
if (inlen <= 64) {
for (i = 0; i < inlen; ++i) out[i] = in[i] ^ buf[i];
st->ksleft = 64 - inlen;
for (i = inlen; i < 64; ++i) st->kstream[i] = buf[i];
return CRYPT_OK;
}
for (i = 0; i < 64; ++i) out[i] = in[i] ^ buf[i];
inlen -= 64;
out += 64;
in += 64;
}
}
#undef QUARTERROUND
#endif

View File

@@ -0,0 +1,20 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_SALSA20
/**
Terminate and clear Salsa20 state
@param st The Salsa20 state
@return CRYPT_OK on success
*/
int salsa20_done(salsa20_state *st)
{
LTC_ARGCHK(st != NULL);
zeromem(st, sizeof(salsa20_state));
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,38 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* The implementation is based on:
* "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
* and salsa20-ref.c version 20051118
* Public domain from D. J. Bernstein
*/
#include "tomcrypt_private.h"
#ifdef LTC_SALSA20
/**
Set IV + counter data to the Salsa20 state
@param st The Salsa20 state
@param iv The IV data to add
@param ivlen The length of the IV (must be 8)
@param counter 64bit (unsigned) initial counter value
@return CRYPT_OK on success
*/
int salsa20_ivctr64(salsa20_state *st, const unsigned char *iv, unsigned long ivlen, ulong64 counter)
{
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(iv != NULL);
/* Salsa20: 64-bit IV (nonce) + 64-bit counter */
LTC_ARGCHK(ivlen == 8);
LOAD32L(st->input[6], iv + 0);
LOAD32L(st->input[7], iv + 4);
st->input[8] = (ulong32)(counter & 0xFFFFFFFF);
st->input[9] = (ulong32)(counter >> 32);
st->ksleft = 0;
st->ivlen = ivlen;
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,29 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* The implementation is based on:
* "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
* and salsa20-ref.c version 20051118
* Public domain from D. J. Bernstein
*/
#include "tomcrypt_private.h"
#ifdef LTC_SALSA20
/**
Generate a stream of random bytes via Salsa20
@param st The Salsa20 state
@param out [out] The output buffer
@param outlen The output length
@return CRYPT_OK on success
*/
int salsa20_keystream(salsa20_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 salsa20_crypt(st, out, outlen, out);
}
#endif

View File

@@ -0,0 +1,41 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#ifdef LTC_SALSA20
/**
Encrypt (or decrypt) bytes of ciphertext (or plaintext) with Salsa20
@param key The key
@param keylen The key length
@param iv The initial vector
@param ivlen The initial vector length
@param datain The plaintext (or ciphertext)
@param datalen The length of the input and output (octets)
@param rounds The number of rounds
@param dataout [out] The ciphertext (or plaintext)
@return CRYPT_OK if successful
*/
int salsa20_memory(const unsigned char *key, unsigned long keylen, unsigned long rounds,
const unsigned char *iv, unsigned long ivlen, ulong64 counter,
const unsigned char *datain, unsigned long datalen, unsigned char *dataout)
{
salsa20_state st;
int err;
if ((err = salsa20_setup(&st, key, keylen, rounds)) != CRYPT_OK) goto WIPE_KEY;
if ((err = salsa20_ivctr64(&st, iv, ivlen, counter)) != CRYPT_OK) goto WIPE_KEY;
err = salsa20_crypt(&st, datain, datalen, dataout);
WIPE_KEY:
salsa20_done(&st);
return err;
}
#endif /* LTC_SALSA20 */
#pragma clang diagnostic pop

View File

@@ -0,0 +1,58 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* The implementation is based on:
* "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
* and salsa20-ref.c version 20051118
* Public domain from D. J. Bernstein
*/
#include "tomcrypt_private.h"
#ifdef LTC_SALSA20
/**
Initialize an Salsa20 context (only the key)
@param st [out] The destination of the Salsa20 state
@param key The secret key
@param keylen The length of the secret key (octets)
@param rounds Number of rounds (e.g. 20 for Salsa20)
@return CRYPT_OK if successful
*/
int salsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen, int rounds)
{
const char * const sigma = "expand 32-byte k";
const char * const tau = "expand 16-byte k";
const char *constants;
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(keylen == 32 || keylen == 16);
if (rounds == 0) rounds = 20;
LTC_ARGCHK(rounds % 2 == 0); /* number of rounds must be evenly divisible by 2 */
LOAD32L(st->input[1], key + 0);
LOAD32L(st->input[2], key + 4);
LOAD32L(st->input[3], key + 8);
LOAD32L(st->input[4], key + 12);
if (keylen == 32) { /* 256bit */
key += 16;
constants = sigma;
} else { /* 128bit */
constants = tau;
}
LOAD32L(st->input[11], key + 0);
LOAD32L(st->input[12], key + 4);
LOAD32L(st->input[13], key + 8);
LOAD32L(st->input[14], key + 12);
LOAD32L(st->input[ 0], constants + 0);
LOAD32L(st->input[ 5], constants + 4);
LOAD32L(st->input[10], constants + 8);
LOAD32L(st->input[15], constants + 12);
st->rounds = rounds; /* default is 20 for salsa20 */
st->ivlen = 0; /* will be set later by salsa20_ivctr(32|64) */
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,86 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* The implementation is based on:
* "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
* and salsa20-ref.c version 20051118
* Public domain from D. J. Bernstein
*/
#include "tomcrypt_private.h"
#ifdef LTC_SALSA20
int salsa20_test(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
salsa20_state st;
unsigned char k[] = { 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 };
unsigned char n[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a };
unsigned char ct[] = { 0x37, 0x37, 0x2e, 0x60, 0xb8, 0xae, 0x88, 0x1f, 0xf8, 0xdf, 0x00, 0x26, 0x6c, 0x30, 0x34, 0x2d,
0xa1, 0xd7, 0x79, 0x60, 0x67, 0x72, 0xe0, 0x67, 0x26, 0x22, 0xad, 0x00, 0x9e, 0xd5, 0x59, 0x44,
0x51, 0xd9, 0xe6, 0xaa, 0xc9, 0x59, 0x9e, 0x60, 0xff, 0x87, 0x90, 0xc1, 0xc9, 0x1e };
unsigned char ct2[] = { 0xec, 0x06, 0x32, 0xb3, 0x83, 0x5c, 0xae, 0x91, 0x01, 0x82, 0x7a, 0x71, 0xd9, 0x7d, 0x45, 0xd7,
0xa6, 0x5b, 0xa0, 0x89, 0x9d, 0xd2, 0x6c, 0xaa, 0xbb, 0x2f, 0x5f, 0x30, 0x89, 0x54, 0xff, 0x3e,
0x83, 0xc3, 0x34, 0x10, 0xb6, 0xe1, 0xab, 0xe7, 0xf5, 0xab, 0xab, 0xed, 0xa4, 0xff };
char pt[] = "Kilroy was here, and there. ...and everywhere!"; /* len = 46 bytes */
unsigned long len;
unsigned char out[1000];
int counter;
int rounds;
int err;
len = XSTRLEN(pt);
/* crypt piece by piece */
counter = 0;
rounds = 12;
if ((err = salsa20_setup(&st, k, sizeof(k), rounds)) != CRYPT_OK) return err;
if ((err = salsa20_ivctr64(&st, n, sizeof(n), counter)) != CRYPT_OK) return err;
if ((err = salsa20_crypt(&st, (unsigned char*)pt, 5, out)) != CRYPT_OK) return err;
if ((err = salsa20_crypt(&st, (unsigned char*)pt + 5, 25, out + 5)) != CRYPT_OK) return err;
if ((err = salsa20_crypt(&st, (unsigned char*)pt + 30, 10, out + 30)) != CRYPT_OK) return err;
if ((err = salsa20_crypt(&st, (unsigned char*)pt + 40, len - 40, out + 40)) != CRYPT_OK) return err;
if (compare_testvector(out, len, ct, sizeof(ct), "SALSA20-TV1", 1)) return CRYPT_FAIL_TESTVECTOR;
/* crypt in one go - using salsa20_ivctr64() */
counter = 0;
rounds = 20;
if ((err = salsa20_setup(&st, k, sizeof(k), rounds)) != CRYPT_OK) return err;
if ((err = salsa20_ivctr64(&st, n, sizeof(n), counter)) != CRYPT_OK) return err;
if ((err = salsa20_crypt(&st, (unsigned char*)pt, len, out)) != CRYPT_OK) return err;
if (compare_testvector(out, len, ct2, sizeof(ct2), "SALSA20-TV2", 1)) return CRYPT_FAIL_TESTVECTOR;
/* crypt in a single call */
if ((err = salsa20_memory(k, sizeof(k), rounds, n, sizeof(n), counter,
(unsigned char*)pt, len, out)) != CRYPT_OK) return err;
if (compare_testvector(out, len, ct2, sizeof(ct2), "SALSA20-TV3", 1)) return CRYPT_FAIL_TESTVECTOR;
{
/* keystream
* http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/salsa20/full/verified.test-vectors?rev=161&view=markup
* Set 6, vector 0
*/
unsigned char k3[] = { 0x00, 0x53, 0xA6, 0xF9, 0x4C, 0x9F, 0xF2, 0x45, 0x98, 0xEB, 0x3E, 0x91, 0xE4, 0x37, 0x8A, 0xDD,
0x30, 0x83, 0xD6, 0x29, 0x7C, 0xCF, 0x22, 0x75, 0xC8, 0x1B, 0x6E, 0xC1, 0x14, 0x67, 0xBA, 0x0D };
unsigned char n3[] = { 0x0D, 0x74, 0xDB, 0x42, 0xA9, 0x10, 0x77, 0xDE };
unsigned char ct3[] = { 0xF5, 0xFA, 0xD5, 0x3F, 0x79, 0xF9, 0xDF, 0x58, 0xC4, 0xAE, 0xA0, 0xD0, 0xED, 0x9A, 0x96, 0x01,
0xF2, 0x78, 0x11, 0x2C, 0xA7, 0x18, 0x0D, 0x56, 0x5B, 0x42, 0x0A, 0x48, 0x01, 0x96, 0x70, 0xEA,
0xF2, 0x4C, 0xE4, 0x93, 0xA8, 0x62, 0x63, 0xF6, 0x77, 0xB4, 0x6A, 0xCE, 0x19, 0x24, 0x77, 0x3D,
0x2B, 0xB2, 0x55, 0x71, 0xE1, 0xAA, 0x85, 0x93, 0x75, 0x8F, 0xC3, 0x82, 0xB1, 0x28, 0x0B, 0x71 };
int counter3 = 0;
int rounds3 = 20;
if ((err = salsa20_setup(&st, k3, sizeof(k3), rounds3)) != CRYPT_OK) return err;
if ((err = salsa20_ivctr64(&st, n3, sizeof(n3), counter3)) != CRYPT_OK) return err;
if ((err = salsa20_keystream(&st, out, 64)) != CRYPT_OK) return err;
if ((err = salsa20_done(&st)) != CRYPT_OK) return err;
if (compare_testvector(out, 64, ct3, sizeof(ct3), "SALSA20-TV4", 1)) return CRYPT_FAIL_TESTVECTOR;
}
return CRYPT_OK;
#endif
}
#endif

View File

@@ -0,0 +1,40 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#ifdef LTC_XSALSA20
/**
Encrypt (or decrypt) bytes of ciphertext (or plaintext) with XSalsa20
@param key The key
@param keylen The key length
@param nonce The initial vector
@param noncelen The initial vector length
@param datain The plaintext (or ciphertext)
@param datalen The length of the input and output (octets)
@param rounds The number of rounds
@param dataout [out] The ciphertext (or plaintext)
@return CRYPT_OK if successful
*/
int xsalsa20_memory(const unsigned char *key, unsigned long keylen, unsigned long rounds,
const unsigned char *nonce, unsigned long noncelen,
const unsigned char *datain, unsigned long datalen, unsigned char *dataout)
{
salsa20_state st;
int err;
if ((err = xsalsa20_setup(&st, key, keylen, nonce, noncelen, rounds)) != CRYPT_OK) goto WIPE_KEY;
err = salsa20_crypt(&st, datain, datalen, dataout);
WIPE_KEY:
salsa20_done(&st);
return err;
}
#endif /* LTC_XSALSA20 */
#pragma clang diagnostic pop

View File

@@ -0,0 +1,126 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* The implementation is based on:
* "Extending the Salsa20 nonce", https://cr.yp.to/snuffle/xsalsa-20081128.pdf
* "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
* and salsa20-ref.c version 20051118
* Public domain from D. J. Bernstein
*/
#include "tomcrypt.h"
#ifdef LTC_XSALSA20
#define QUARTERROUND(a,b,c,d) \
x[b] ^= (ROL((x[a] + x[d]), 7)); \
x[c] ^= (ROL((x[b] + x[a]), 9)); \
x[d] ^= (ROL((x[c] + x[b]), 13)); \
x[a] ^= (ROL((x[d] + x[c]), 18));
/* use modified salsa20 doubleround (no final addition as in salsa20) */
static void s_xsalsa20_doubleround(ulong32 *x, int rounds)
{
int i;
for (i = rounds; i > 0; i -= 2) {
/* columnround */
QUARTERROUND( 0, 4, 8,12)
QUARTERROUND( 5, 9,13, 1)
QUARTERROUND(10,14, 2, 6)
QUARTERROUND(15, 3, 7,11)
/* rowround */
QUARTERROUND( 0, 1, 2, 3)
QUARTERROUND( 5, 6, 7, 4)
QUARTERROUND(10,11, 8, 9)
QUARTERROUND(15,12,13,14)
}
}
#undef QUARTERROUND
/**
Initialize an XSalsa20 context
@param st [out] The destination of the XSalsa20 state
@param key The secret key
@param keylen The length of the secret key, must be 32 (octets)
@param nonce The nonce
@param noncelen The length of the nonce, must be 24 (octets)
@param rounds Number of rounds (must be evenly divisible by 2, default is 20)
@return CRYPT_OK if successful
*/
int xsalsa20_setup(salsa20_state *st, const unsigned char *key, unsigned long keylen,
const unsigned char *nonce, unsigned long noncelen,
int rounds)
{
const char * const constants = "expand 32-byte k";
const int sti[] = {0, 5, 10, 15, 6, 7, 8, 9}; /* indices used to build subkey fm x */
ulong32 x[64]; /* input to & output fm doubleround */
unsigned char subkey[32];
int i;
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(keylen == 32);
LTC_ARGCHK(nonce != NULL);
LTC_ARGCHK(noncelen == 24);
if (rounds == 0) rounds = 20;
LTC_ARGCHK(rounds % 2 == 0); /* number of rounds must be evenly divisible by 2 */
/* load the state to "hash" the key */
LOAD32L(x[ 0], constants + 0);
LOAD32L(x[ 5], constants + 4);
LOAD32L(x[10], constants + 8);
LOAD32L(x[15], constants + 12);
LOAD32L(x[ 1], key + 0);
LOAD32L(x[ 2], key + 4);
LOAD32L(x[ 3], key + 8);
LOAD32L(x[ 4], key + 12);
LOAD32L(x[11], key + 16);
LOAD32L(x[12], key + 20);
LOAD32L(x[13], key + 24);
LOAD32L(x[14], key + 28);
LOAD32L(x[ 6], nonce + 0);
LOAD32L(x[ 7], nonce + 4);
LOAD32L(x[ 8], nonce + 8);
LOAD32L(x[ 9], nonce + 12);
/* use modified salsa20 doubleround (no final addition) */
s_xsalsa20_doubleround(x, rounds);
/* extract the subkey */
for (i = 0; i < 8; ++i) {
STORE32L(x[sti[i]], subkey + 4 * i);
}
/* load the final initial state */
LOAD32L(st->input[ 0], constants + 0);
LOAD32L(st->input[ 5], constants + 4);
LOAD32L(st->input[10], constants + 8);
LOAD32L(st->input[15], constants + 12);
LOAD32L(st->input[ 1], subkey + 0);
LOAD32L(st->input[ 2], subkey + 4);
LOAD32L(st->input[ 3], subkey + 8);
LOAD32L(st->input[ 4], subkey + 12);
LOAD32L(st->input[11], subkey + 16);
LOAD32L(st->input[12], subkey + 20);
LOAD32L(st->input[13], subkey + 24);
LOAD32L(st->input[14], subkey + 28);
LOAD32L(st->input[ 6], &(nonce[16]) + 0);
LOAD32L(st->input[ 7], &(nonce[16]) + 4);
st->input[ 8] = 0;
st->input[ 9] = 0;
st->rounds = rounds;
st->ksleft = 0;
st->ivlen = 24; /* set switch to say nonce/IV has been loaded */
#ifdef LTC_CLEAN_STACK
zeromem(x, sizeof(x));
zeromem(subkey, sizeof(subkey));
#endif
return CRYPT_OK;
}
#endif

View File

@@ -0,0 +1,90 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/* The implementation is based on:
* "Extending the Salsa20 nonce", https://cr.yp.to/snuffle/xsalsa-20081128.pdf
* "Salsa20 specification", http://cr.yp.to/snuffle/spec.pdf
* and salsa20-ref.c version 20051118
* Public domain from D. J. Bernstein
*/
#include "tomcrypt.h"
#ifdef LTC_XSALSA20
#if defined(LTC_SHA256) && defined(LTC_TEST)
static int s_sha256(unsigned char *hash, const unsigned char *data, const int datalen) {
hash_state md;
sha256_init(&md);
sha256_process(&md, data, datalen);
sha256_done(&md, hash);
return CRYPT_OK;
}
#endif
int xsalsa20_test(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
/***************************************************************************
* verify a round trip:
*/
{
const unsigned char key[] = {0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89};
const unsigned char nonce[] = {0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37};
const void *msg = "Kilroy was here!";
unsigned char msglen = 17; /* includes trailing NULL */
int rounds = 20;
unsigned char ciphertext[17];
unsigned char msg2[17];
salsa20_state st;
int err;
if ((err = xsalsa20_setup(&st, key, 32, nonce, 24, rounds)) != CRYPT_OK) return err;
if ((err = salsa20_crypt(&st, msg, msglen, ciphertext)) != CRYPT_OK) return err;
if ((err = salsa20_done(&st)) != CRYPT_OK) return err;
if ((err = xsalsa20_setup(&st, key, 32, nonce, 24, rounds)) != CRYPT_OK) return err;
if ((err = salsa20_crypt(&st, ciphertext, msglen, msg2)) != CRYPT_OK) return err;
if ((err = salsa20_done(&st)) != CRYPT_OK) return err;
if (compare_testvector(msg, msglen, msg2, msglen, "XSALSA20-TV1", 1)) return CRYPT_FAIL_TESTVECTOR;
/* round trip with two single function calls */
if ((err = xsalsa20_memory(key, sizeof(key), 20, nonce, sizeof(nonce), msg, msglen, ciphertext)) != CRYPT_OK) return err;
if ((err = xsalsa20_memory(key, sizeof(key), 20, nonce, sizeof(nonce), ciphertext, msglen, msg2)) != CRYPT_OK) return err;
if (compare_testvector(msg, msglen, msg2, msglen, "XSALSA20-TV2", 1)) return CRYPT_FAIL_TESTVECTOR;
}
#ifdef LTC_SHA256
/***************************************************************************
* verify correct generation of a keystream
*/
{
const unsigned char key[] = {0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89};
const unsigned char nonce[] = {0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37};
const unsigned char expecthash[] = {0x6a,0x60,0x57,0x65,0x27,0xe0,0x00,0x51,0x6d,0xb0,0xda,0x60,0x46,0x20,0xf6,0xd0,0x95,0x65,0x45,0x39,0xf4,0x86,0x83,0x43,0x64,0xdf,0xd9,0x5a,0x6f,0x3f,0xbe,0xb7};
int rounds = 20;
unsigned char keystream[91101];
unsigned long keystreamlen = 91101;
unsigned char hash[32];
salsa20_state st;
int err;
if ((err = xsalsa20_setup(&st, key, 32, nonce, 24, rounds)) != CRYPT_OK) return err;
if ((err = salsa20_keystream(&st, keystream, keystreamlen)) != CRYPT_OK) return err;
if ((err = salsa20_done(&st)) != CRYPT_OK) return err;
if ((err = s_sha256(hash, keystream, keystreamlen)) != CRYPT_OK) return err;
if (compare_testvector(hash, sizeof(hash), expecthash, sizeof(expecthash), "XSALSA20-TV3", 1)) return CRYPT_FAIL_TESTVECTOR;
}
#endif
return CRYPT_OK;
#endif
}
#endif

View File

@@ -0,0 +1,347 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
/**
@file sober128_stream.c
Implementation of SOBER-128 by Tom St Denis.
Based on s128fast.c reference code supplied by Greg Rose of QUALCOMM.
*/
#ifdef LTC_SOBER128
#ifndef LTC_SOBER128TAB_C
#define LTC_SOBER128TAB_C
#include "sober128tab.c"
#endif
/* don't change these... */
#define N 17
#define INITKONST 0x6996c53a /* value of KONST to use during key loading */
#define KEYP 15 /* where to insert key words */
#define FOLDP 4 /* where to insert non-linear feedback */
static ulong32 BYTE2WORD(const unsigned char *b)
{
ulong32 t;
LOAD32L(t, b);
return t;
}
static void XORWORD(ulong32 w, const unsigned char *in, unsigned char *out)
{
ulong32 t;
LOAD32L(t, in);
t ^= w;
STORE32L(t, out);
}
/* give correct offset for the current position of the register,
* where logically R[0] is at position "zero".
*/
#define OFF(zero, i) (((zero)+(i)) % N)
/* step the LFSR */
/* After stepping, "zero" moves right one place */
#define STEP(R,z) \
R[OFF(z,0)] = R[OFF(z,15)] ^ R[OFF(z,4)] ^ (R[OFF(z,0)] << 8) ^ Multab[(R[OFF(z,0)] >> 24) & 0xFF];
static void cycle(ulong32 *R)
{
ulong32 t;
int i;
STEP(R,0);
t = R[0];
for (i = 1; i < N; ++i) {
R[i-1] = R[i];
}
R[N-1] = t;
}
/* Return a non-linear function of some parts of the register.
*/
#define NLFUNC(st,z) \
{ \
t = st->R[OFF(z,0)] + st->R[OFF(z,16)]; \
t ^= Sbox[(t >> 24) & 0xFF]; \
t = RORc(t, 8); \
t = ((t + st->R[OFF(z,1)]) ^ st->konst) + st->R[OFF(z,6)]; \
t ^= Sbox[(t >> 24) & 0xFF]; \
t = t + st->R[OFF(z,13)]; \
}
static ulong32 nltap(const sober128_state *st)
{
ulong32 t;
NLFUNC(st, 0);
return t;
}
/* Save the current register state
*/
static void s128_savestate(sober128_state *st)
{
int i;
for (i = 0; i < N; ++i) {
st->initR[i] = st->R[i];
}
}
/* initialise to previously saved register state
*/
static void s128_reloadstate(sober128_state *st)
{
int i;
for (i = 0; i < N; ++i) {
st->R[i] = st->initR[i];
}
}
/* Initialise "konst"
*/
static void s128_genkonst(sober128_state *st)
{
ulong32 newkonst;
do {
cycle(st->R);
newkonst = nltap(st);
} while ((newkonst & 0xFF000000) == 0);
st->konst = newkonst;
}
/* Load key material into the register
*/
#define ADDKEY(k) \
st->R[KEYP] += (k);
#define XORNL(nl) \
st->R[FOLDP] ^= (nl);
/* nonlinear diffusion of register for key */
#define DROUND(z) STEP(st->R,z); NLFUNC(st,(z+1)); st->R[OFF((z+1),FOLDP)] ^= t;
static void s128_diffuse(sober128_state *st)
{
ulong32 t;
/* relies on FOLD == N == 17! */
DROUND(0);
DROUND(1);
DROUND(2);
DROUND(3);
DROUND(4);
DROUND(5);
DROUND(6);
DROUND(7);
DROUND(8);
DROUND(9);
DROUND(10);
DROUND(11);
DROUND(12);
DROUND(13);
DROUND(14);
DROUND(15);
DROUND(16);
}
/**
Initialize an Sober128 context (only the key)
@param st [out] The destination of the Sober128 state
@param key The secret key
@param keylen The length of the secret key (octets)
@return CRYPT_OK if successful
*/
int sober128_stream_setup(sober128_state *st, const unsigned char *key, unsigned long keylen)
{
ulong32 i, k;
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(keylen > 0);
/* keylen must be multiple of 4 bytes */
if ((keylen & 3) != 0) {
return CRYPT_INVALID_KEYSIZE;
}
/* Register initialised to Fibonacci numbers */
st->R[0] = 1;
st->R[1] = 1;
for (i = 2; i < N; ++i) {
st->R[i] = st->R[i-1] + st->R[i-2];
}
st->konst = INITKONST;
for (i = 0; i < keylen; i += 4) {
k = BYTE2WORD(&key[i]);
ADDKEY(k);
cycle(st->R);
XORNL(nltap(st));
}
/* also fold in the length of the key */
ADDKEY(keylen);
/* now diffuse */
s128_diffuse(st);
s128_genkonst(st);
s128_savestate(st);
st->nbuf = 0;
return CRYPT_OK;
}
/**
Set IV to the Sober128 state
@param st The Sober12820 state
@param iv The IV data to add
@param ivlen The length of the IV (must be 12)
@return CRYPT_OK on success
*/
int sober128_stream_setiv(sober128_state *st, const unsigned char *iv, unsigned long ivlen)
{
ulong32 i, k;
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(iv != NULL);
LTC_ARGCHK(ivlen > 0);
/* ok we are adding an IV then... */
s128_reloadstate(st);
/* ivlen must be multiple of 4 bytes */
if ((ivlen & 3) != 0) {
return CRYPT_INVALID_KEYSIZE;
}
for (i = 0; i < ivlen; i += 4) {
k = BYTE2WORD(&iv[i]);
ADDKEY(k);
cycle(st->R);
XORNL(nltap(st));
}
/* also fold in the length of the key */
ADDKEY(ivlen);
/* now diffuse */
s128_diffuse(st);
st->nbuf = 0;
return CRYPT_OK;
}
/* XOR pseudo-random bytes into buffer
*/
#define SROUND(z) STEP(st->R,z); NLFUNC(st,(z+1)); XORWORD(t, in+(z*4), out+(z*4));
/**
Encrypt (or decrypt) bytes of ciphertext (or plaintext) with Sober128
@param st The Sober128 state
@param in The plaintext (or ciphertext)
@param inlen The length of the input (octets)
@param out [out] The ciphertext (or plaintext), length inlen
@return CRYPT_OK if successful
*/
int sober128_stream_crypt(sober128_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out)
{
ulong32 t;
if (inlen == 0) return CRYPT_OK; /* nothing to do */
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(st != NULL);
/* handle any previously buffered bytes */
while (st->nbuf != 0 && inlen != 0) {
*out++ = *in++ ^ (unsigned char)(st->sbuf & 0xFF);
st->sbuf >>= 8;
st->nbuf -= 8;
--inlen;
}
#ifndef LTC_SMALL_CODE
/* do lots at a time, if there's enough to do */
while (inlen >= N*4) {
SROUND(0);
SROUND(1);
SROUND(2);
SROUND(3);
SROUND(4);
SROUND(5);
SROUND(6);
SROUND(7);
SROUND(8);
SROUND(9);
SROUND(10);
SROUND(11);
SROUND(12);
SROUND(13);
SROUND(14);
SROUND(15);
SROUND(16);
out += 4*N;
in += 4*N;
inlen -= 4*N;
}
#endif
/* do small or odd size buffers the slow way */
while (4 <= inlen) {
cycle(st->R);
t = nltap(st);
XORWORD(t, in, out);
out += 4;
in += 4;
inlen -= 4;
}
/* handle any trailing bytes */
if (inlen != 0) {
cycle(st->R);
st->sbuf = nltap(st);
st->nbuf = 32;
while (st->nbuf != 0 && inlen != 0) {
*out++ = *in++ ^ (unsigned char)(st->sbuf & 0xFF);
st->sbuf >>= 8;
st->nbuf -= 8;
--inlen;
}
}
return CRYPT_OK;
}
int sober128_stream_keystream(sober128_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 sober128_stream_crypt(st, out, outlen, out);
}
/**
Terminate and clear Sober128 state
@param st The Sober128 state
@return CRYPT_OK on success
*/
int sober128_stream_done(sober128_state *st)
{
LTC_ARGCHK(st != NULL);
zeromem(st, sizeof(sober128_state));
return CRYPT_OK;
}
#undef N
#undef INITKONST
#undef KEYP
#undef FOLDP
#undef OFF
#undef STEP
#undef NLFUNC
#undef ADDKEY
#undef XORNL
#undef DROUND
#undef SROUND
#endif

View File

@@ -0,0 +1,35 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_SOBER128_STREAM
/**
Encrypt (or decrypt) bytes of ciphertext (or plaintext) with SOBER128
@param key The key
@param keylen The key length
@param iv The initial vector
@param ivlen The initial vector length
@param datain The plaintext (or ciphertext)
@param datalen The length of the input and output (octets)
@param dataout [out] The ciphertext (or plaintext)
@return CRYPT_OK if successful
*/
int sober128_stream_memory(const unsigned char *key, unsigned long keylen,
const unsigned char *iv, unsigned long ivlen,
const unsigned char *datain, unsigned long datalen,
unsigned char *dataout)
{
sober128_state st;
int err;
if ((err = sober128_stream_setup(&st, key, keylen)) != CRYPT_OK) goto WIPE_KEY;
if ((err = sober128_stream_setiv(&st, iv, ivlen)) != CRYPT_OK) goto WIPE_KEY;
err = sober128_stream_crypt(&st, datain, datalen, dataout);
WIPE_KEY:
sober128_stream_done(&st);
return err;
}
#endif /* LTC_SOBER128_STREAM */

View File

@@ -0,0 +1,43 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_SOBER128
int sober128_stream_test(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
unsigned char key[16] = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6b, 0x65, 0x79,
0x20, 0x31, 0x32, 0x38, 0x62, 0x69, 0x74, 0x73 };
unsigned char iv[4] = { 0x00, 0x00, 0x00, 0x00 };
unsigned char out[20] = { 0x43, 0x50, 0x0c, 0xcf, 0x89, 0x91, 0x9f, 0x1d,
0xaa, 0x37, 0x74, 0x95, 0xf4, 0xb4, 0x58, 0xc2,
0x40, 0x37, 0x8b, 0xbb };
int err, len = 20;
unsigned char src[20], dst[20];
sober128_state st;
XMEMSET(src, 0, len); /* input */
if ((err = sober128_stream_setup(&st, key, sizeof(key))) != CRYPT_OK) return err;
if ((err = sober128_stream_setiv(&st, iv, sizeof(iv))) != CRYPT_OK) return err;
if ((err = sober128_stream_crypt(&st, src, len, dst)) != CRYPT_OK) return err;
if ((err = sober128_stream_done(&st)) != CRYPT_OK) return err;
if (compare_testvector(dst, len, out, len, "SOBER-128-TV1", 0)) {
return CRYPT_FAIL_TESTVECTOR;
}
/* crypt in a single call */
if ((err = sober128_stream_memory(key, sizeof(key), iv, sizeof(iv),
src, len, dst)) != CRYPT_OK) return err;
if (compare_testvector(dst, len, out, len, "SOBER-128-TV2", 0)) {
return CRYPT_FAIL_TESTVECTOR;
}
return CRYPT_OK;
#endif
}
#endif

View File

@@ -0,0 +1,166 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/**
@file sober128tab.c
SOBER-128 Tables
*/
#ifdef LTC_SOBER128TAB_C
/* $ID$ */
/* @(#)TuringMultab.h 1.3 (QUALCOMM) 02/09/03 */
/* Multiplication table for Turing using 0xD02B4367 */
static const ulong32 Multab[256] = {
0x00000000, 0xD02B4367, 0xED5686CE, 0x3D7DC5A9,
0x97AC41D1, 0x478702B6, 0x7AFAC71F, 0xAAD18478,
0x631582EF, 0xB33EC188, 0x8E430421, 0x5E684746,
0xF4B9C33E, 0x24928059, 0x19EF45F0, 0xC9C40697,
0xC62A4993, 0x16010AF4, 0x2B7CCF5D, 0xFB578C3A,
0x51860842, 0x81AD4B25, 0xBCD08E8C, 0x6CFBCDEB,
0xA53FCB7C, 0x7514881B, 0x48694DB2, 0x98420ED5,
0x32938AAD, 0xE2B8C9CA, 0xDFC50C63, 0x0FEE4F04,
0xC154926B, 0x117FD10C, 0x2C0214A5, 0xFC2957C2,
0x56F8D3BA, 0x86D390DD, 0xBBAE5574, 0x6B851613,
0xA2411084, 0x726A53E3, 0x4F17964A, 0x9F3CD52D,
0x35ED5155, 0xE5C61232, 0xD8BBD79B, 0x089094FC,
0x077EDBF8, 0xD755989F, 0xEA285D36, 0x3A031E51,
0x90D29A29, 0x40F9D94E, 0x7D841CE7, 0xADAF5F80,
0x646B5917, 0xB4401A70, 0x893DDFD9, 0x59169CBE,
0xF3C718C6, 0x23EC5BA1, 0x1E919E08, 0xCEBADD6F,
0xCFA869D6, 0x1F832AB1, 0x22FEEF18, 0xF2D5AC7F,
0x58042807, 0x882F6B60, 0xB552AEC9, 0x6579EDAE,
0xACBDEB39, 0x7C96A85E, 0x41EB6DF7, 0x91C02E90,
0x3B11AAE8, 0xEB3AE98F, 0xD6472C26, 0x066C6F41,
0x09822045, 0xD9A96322, 0xE4D4A68B, 0x34FFE5EC,
0x9E2E6194, 0x4E0522F3, 0x7378E75A, 0xA353A43D,
0x6A97A2AA, 0xBABCE1CD, 0x87C12464, 0x57EA6703,
0xFD3BE37B, 0x2D10A01C, 0x106D65B5, 0xC04626D2,
0x0EFCFBBD, 0xDED7B8DA, 0xE3AA7D73, 0x33813E14,
0x9950BA6C, 0x497BF90B, 0x74063CA2, 0xA42D7FC5,
0x6DE97952, 0xBDC23A35, 0x80BFFF9C, 0x5094BCFB,
0xFA453883, 0x2A6E7BE4, 0x1713BE4D, 0xC738FD2A,
0xC8D6B22E, 0x18FDF149, 0x258034E0, 0xF5AB7787,
0x5F7AF3FF, 0x8F51B098, 0xB22C7531, 0x62073656,
0xABC330C1, 0x7BE873A6, 0x4695B60F, 0x96BEF568,
0x3C6F7110, 0xEC443277, 0xD139F7DE, 0x0112B4B9,
0xD31DD2E1, 0x03369186, 0x3E4B542F, 0xEE601748,
0x44B19330, 0x949AD057, 0xA9E715FE, 0x79CC5699,
0xB008500E, 0x60231369, 0x5D5ED6C0, 0x8D7595A7,
0x27A411DF, 0xF78F52B8, 0xCAF29711, 0x1AD9D476,
0x15379B72, 0xC51CD815, 0xF8611DBC, 0x284A5EDB,
0x829BDAA3, 0x52B099C4, 0x6FCD5C6D, 0xBFE61F0A,
0x7622199D, 0xA6095AFA, 0x9B749F53, 0x4B5FDC34,
0xE18E584C, 0x31A51B2B, 0x0CD8DE82, 0xDCF39DE5,
0x1249408A, 0xC26203ED, 0xFF1FC644, 0x2F348523,
0x85E5015B, 0x55CE423C, 0x68B38795, 0xB898C4F2,
0x715CC265, 0xA1778102, 0x9C0A44AB, 0x4C2107CC,
0xE6F083B4, 0x36DBC0D3, 0x0BA6057A, 0xDB8D461D,
0xD4630919, 0x04484A7E, 0x39358FD7, 0xE91ECCB0,
0x43CF48C8, 0x93E40BAF, 0xAE99CE06, 0x7EB28D61,
0xB7768BF6, 0x675DC891, 0x5A200D38, 0x8A0B4E5F,
0x20DACA27, 0xF0F18940, 0xCD8C4CE9, 0x1DA70F8E,
0x1CB5BB37, 0xCC9EF850, 0xF1E33DF9, 0x21C87E9E,
0x8B19FAE6, 0x5B32B981, 0x664F7C28, 0xB6643F4F,
0x7FA039D8, 0xAF8B7ABF, 0x92F6BF16, 0x42DDFC71,
0xE80C7809, 0x38273B6E, 0x055AFEC7, 0xD571BDA0,
0xDA9FF2A4, 0x0AB4B1C3, 0x37C9746A, 0xE7E2370D,
0x4D33B375, 0x9D18F012, 0xA06535BB, 0x704E76DC,
0xB98A704B, 0x69A1332C, 0x54DCF685, 0x84F7B5E2,
0x2E26319A, 0xFE0D72FD, 0xC370B754, 0x135BF433,
0xDDE1295C, 0x0DCA6A3B, 0x30B7AF92, 0xE09CECF5,
0x4A4D688D, 0x9A662BEA, 0xA71BEE43, 0x7730AD24,
0xBEF4ABB3, 0x6EDFE8D4, 0x53A22D7D, 0x83896E1A,
0x2958EA62, 0xF973A905, 0xC40E6CAC, 0x14252FCB,
0x1BCB60CF, 0xCBE023A8, 0xF69DE601, 0x26B6A566,
0x8C67211E, 0x5C4C6279, 0x6131A7D0, 0xB11AE4B7,
0x78DEE220, 0xA8F5A147, 0x958864EE, 0x45A32789,
0xEF72A3F1, 0x3F59E096, 0x0224253F, 0xD20F6658,
};
/* $ID$ */
/* Sbox for SOBER-128 */
/*
* This is really the combination of two SBoxes; the least significant
* 24 bits comes from:
* 8->32 Sbox generated by Millan et. al. at Queensland University of
* Technology. See: E. Dawson, W. Millan, L. Burnett, G. Carter,
* "On the Design of 8*32 S-boxes". Unpublished report, by the
* Information Systems Research Centre,
* Queensland University of Technology, 1999.
*
* The most significant 8 bits are the Skipjack "F table", which can be
* found at http://csrc.nist.gov/CryptoToolkit/skipjack/skipjack.pdf .
* In this optimised table, though, the intent is to XOR the word from
* the table selected by the high byte with the input word. Thus, the
* high byte is actually the Skipjack F-table entry XORED with its
* table index.
*/
static const ulong32 Sbox[256] = {
0xa3aa1887, 0xd65e435c, 0x0b65c042, 0x800e6ef4,
0xfc57ee20, 0x4d84fed3, 0xf066c502, 0xf354e8ae,
0xbb2ee9d9, 0x281f38d4, 0x1f829b5d, 0x735cdf3c,
0x95864249, 0xbc2e3963, 0xa1f4429f, 0xf6432c35,
0xf7f40325, 0x3cc0dd70, 0x5f973ded, 0x9902dc5e,
0xda175b42, 0x590012bf, 0xdc94d78c, 0x39aab26b,
0x4ac11b9a, 0x8c168146, 0xc3ea8ec5, 0x058ac28f,
0x52ed5c0f, 0x25b4101c, 0x5a2db082, 0x370929e1,
0x2a1843de, 0xfe8299fc, 0x202fbc4b, 0x833915dd,
0x33a803fa, 0xd446b2de, 0x46233342, 0x4fcee7c3,
0x3ad607ef, 0x9e97ebab, 0x507f859b, 0xe81f2e2f,
0xc55b71da, 0xd7e2269a, 0x1339c3d1, 0x7ca56b36,
0xa6c9def2, 0xb5c9fc5f, 0x5927b3a3, 0x89a56ddf,
0xc625b510, 0x560f85a7, 0xace82e71, 0x2ecb8816,
0x44951e2a, 0x97f5f6af, 0xdfcbc2b3, 0xce4ff55d,
0xcb6b6214, 0x2b0b83e3, 0x549ea6f5, 0x9de041af,
0x792f1f17, 0xf73b99ee, 0x39a65ec0, 0x4c7016c6,
0x857709a4, 0xd6326e01, 0xc7b280d9, 0x5cfb1418,
0xa6aff227, 0xfd548203, 0x506b9d96, 0xa117a8c0,
0x9cd5bf6e, 0xdcee7888, 0x61fcfe64, 0xf7a193cd,
0x050d0184, 0xe8ae4930, 0x88014f36, 0xd6a87088,
0x6bad6c2a, 0x1422c678, 0xe9204de7, 0xb7c2e759,
0x0200248e, 0x013b446b, 0xda0d9fc2, 0x0414a895,
0x3a6cc3a1, 0x56fef170, 0x86c19155, 0xcf7b8a66,
0x551b5e69, 0xb4a8623e, 0xa2bdfa35, 0xc4f068cc,
0x573a6acd, 0x6355e936, 0x03602db9, 0x0edf13c1,
0x2d0bb16d, 0x6980b83c, 0xfeb23763, 0x3dd8a911,
0x01b6bc13, 0xf55579d7, 0xf55c2fa8, 0x19f4196e,
0xe7db5476, 0x8d64a866, 0xc06e16ad, 0xb17fc515,
0xc46feb3c, 0x8bc8a306, 0xad6799d9, 0x571a9133,
0x992466dd, 0x92eb5dcd, 0xac118f50, 0x9fafb226,
0xa1b9cef3, 0x3ab36189, 0x347a19b1, 0x62c73084,
0xc27ded5c, 0x6c8bc58f, 0x1cdde421, 0xed1e47fb,
0xcdcc715e, 0xb9c0ff99, 0x4b122f0f, 0xc4d25184,
0xaf7a5e6c, 0x5bbf18bc, 0x8dd7c6e0, 0x5fb7e420,
0x521f523f, 0x4ad9b8a2, 0xe9da1a6b, 0x97888c02,
0x19d1e354, 0x5aba7d79, 0xa2cc7753, 0x8c2d9655,
0x19829da1, 0x531590a7, 0x19c1c149, 0x3d537f1c,
0x50779b69, 0xed71f2b7, 0x463c58fa, 0x52dc4418,
0xc18c8c76, 0xc120d9f0, 0xafa80d4d, 0x3b74c473,
0xd09410e9, 0x290e4211, 0xc3c8082b, 0x8f6b334a,
0x3bf68ed2, 0xa843cc1b, 0x8d3c0ff3, 0x20e564a0,
0xf8f55a4f, 0x2b40f8e7, 0xfea7f15f, 0xcf00fe21,
0x8a6d37d6, 0xd0d506f1, 0xade00973, 0xefbbde36,
0x84670fa8, 0xfa31ab9e, 0xaedab618, 0xc01f52f5,
0x6558eb4f, 0x71b9e343, 0x4b8d77dd, 0x8cb93da6,
0x740fd52d, 0x425412f8, 0xc5a63360, 0x10e53ad0,
0x5a700f1c, 0x8324ed0b, 0xe53dc1ec, 0x1a366795,
0x6d549d15, 0xc5ce46d7, 0xe17abe76, 0x5f48e0a0,
0xd0f07c02, 0x941249b7, 0xe49ed6ba, 0x37a47f78,
0xe1cfffbd, 0xb007ca84, 0xbb65f4da, 0xb59f35da,
0x33d2aa44, 0x417452ac, 0xc0d674a7, 0x2d61a46a,
0xdc63152a, 0x3e12b7aa, 0x6e615927, 0xa14fb118,
0xa151758d, 0xba81687b, 0xe152f0b3, 0x764254ed,
0x34c77271, 0x0a31acab, 0x54f94aec, 0xb9e994cd,
0x574d9e81, 0x5b623730, 0xce8a21e8, 0x37917f0b,
0xe8a9b5d6, 0x9697adf8, 0xf3d30431, 0x5dcac921,
0x76b35d46, 0xaa430a36, 0xc2194022, 0x22bca65e,
0xdaec70ba, 0xdfaea8cc, 0x777bae8b, 0x242924d5,
0x1f098a5a, 0x4b396b81, 0x55de2522, 0x435c1cb8,
0xaeb8fe1d, 0x9db3c697, 0x5b164f83, 0xe0c16376,
0xa319224c, 0xd0203b35, 0x433ac0fe, 0x1466a19a,
0x45f0b24f, 0x51fda998, 0xc0d52d71, 0xfa0896a8,
0xf9e6053f, 0xa4b0d300, 0xd499cbcc, 0xb95e3d40,
};
#endif /* LTC_SOBER128TAB_C */

View File

@@ -0,0 +1,813 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
/*
* This LTC implementation was adapted from:
* http://www.ecrypt.eu.org/stream/e2-sosemanuk.html
*/
/*
* SOSEMANUK reference implementation.
*
* This code is supposed to run on any conforming C implementation (C90
* or later).
*
* (c) 2005 X-CRYPT project. This software is provided 'as-is', without
* any express or implied warranty. In no event will the authors be held
* liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to no restriction.
*
* Technical remarks and questions can be addressed to
* <thomas.pornin@cryptolog.com>
*/
#include "tomcrypt_private.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#ifdef LTC_SOSEMANUK
/* ======================================================================== */
/*
* We want (and sometimes need) to perform explicit truncations to 32 bits.
*/
#define T32(x) ((x) & (ulong32)0xFFFFFFFF)
/*
* Some of our functions will be tagged as "inline" to help the compiler
* optimize things. We use "inline" only if the compiler is advanced
* enough to understand it; C99 compilers, and pre-C99 versions of gcc,
* understand enough "inline" for our purposes.
*/
/* ======================================================================== */
/*
* Serpent S-boxes, implemented in bitslice mode. These circuits have
* been published by Dag Arne Osvik ("Speeding up Serpent", published in
* the 3rd AES Candidate Conference) and work on five 32-bit registers:
* the four inputs, and a fifth scratch register. There are meant to be
* quite fast on Pentium-class processors. These are not the fastest
* published, but they are "fast enough" and they are unencumbered as
* far as intellectual property is concerned (note: these are rewritten
* from the article itself, and hence are not covered by the GPL on
* Dag's code, which was not used here).
*
* The output bits are permuted. Here is the correspondance:
* S0: 1420
* S1: 2031
* S2: 2314
* S3: 1234
* S4: 1403
* S5: 1302
* S6: 0142
* S7: 4310
* (for instance, the output of S0 is in "r1, r4, r2, r0").
*/
#define S0(r0, r1, r2, r3, r4) do { \
r3 ^= r0; r4 = r1; \
r1 &= r3; r4 ^= r2; \
r1 ^= r0; r0 |= r3; \
r0 ^= r4; r4 ^= r3; \
r3 ^= r2; r2 |= r1; \
r2 ^= r4; r4 = ~r4; \
r4 |= r1; r1 ^= r3; \
r1 ^= r4; r3 |= r0; \
r1 ^= r3; r4 ^= r3; \
} while (0)
#define S1(r0, r1, r2, r3, r4) do { \
r0 = ~r0; r2 = ~r2; \
r4 = r0; r0 &= r1; \
r2 ^= r0; r0 |= r3; \
r3 ^= r2; r1 ^= r0; \
r0 ^= r4; r4 |= r1; \
r1 ^= r3; r2 |= r0; \
r2 &= r4; r0 ^= r1; \
r1 &= r2; \
r1 ^= r0; r0 &= r2; \
r0 ^= r4; \
} while (0)
#define S2(r0, r1, r2, r3, r4) do { \
r4 = r0; r0 &= r2; \
r0 ^= r3; r2 ^= r1; \
r2 ^= r0; r3 |= r4; \
r3 ^= r1; r4 ^= r2; \
r1 = r3; r3 |= r4; \
r3 ^= r0; r0 &= r1; \
r4 ^= r0; r1 ^= r3; \
r1 ^= r4; r4 = ~r4; \
} while (0)
#define S3(r0, r1, r2, r3, r4) do { \
r4 = r0; r0 |= r3; \
r3 ^= r1; r1 &= r4; \
r4 ^= r2; r2 ^= r3; \
r3 &= r0; r4 |= r1; \
r3 ^= r4; r0 ^= r1; \
r4 &= r0; r1 ^= r3; \
r4 ^= r2; r1 |= r0; \
r1 ^= r2; r0 ^= r3; \
r2 = r1; r1 |= r3; \
r1 ^= r0; \
} while (0)
#define S4(r0, r1, r2, r3, r4) do { \
r1 ^= r3; r3 = ~r3; \
r2 ^= r3; r3 ^= r0; \
r4 = r1; r1 &= r3; \
r1 ^= r2; r4 ^= r3; \
r0 ^= r4; r2 &= r4; \
r2 ^= r0; r0 &= r1; \
r3 ^= r0; r4 |= r1; \
r4 ^= r0; r0 |= r3; \
r0 ^= r2; r2 &= r3; \
r0 = ~r0; r4 ^= r2; \
} while (0)
#define S5(r0, r1, r2, r3, r4) do { \
r0 ^= r1; r1 ^= r3; \
r3 = ~r3; r4 = r1; \
r1 &= r0; r2 ^= r3; \
r1 ^= r2; r2 |= r4; \
r4 ^= r3; r3 &= r1; \
r3 ^= r0; r4 ^= r1; \
r4 ^= r2; r2 ^= r0; \
r0 &= r3; r2 = ~r2; \
r0 ^= r4; r4 |= r3; \
r2 ^= r4; \
} while (0)
#define S6(r0, r1, r2, r3, r4) do { \
r2 = ~r2; r4 = r3; \
r3 &= r0; r0 ^= r4; \
r3 ^= r2; r2 |= r4; \
r1 ^= r3; r2 ^= r0; \
r0 |= r1; r2 ^= r1; \
r4 ^= r0; r0 |= r3; \
r0 ^= r2; r4 ^= r3; \
r4 ^= r0; r3 = ~r3; \
r2 &= r4; \
r2 ^= r3; \
} while (0)
#define S7(r0, r1, r2, r3, r4) do { \
r4 = r1; r1 |= r2; \
r1 ^= r3; r4 ^= r2; \
r2 ^= r1; r3 |= r4; \
r3 &= r0; r4 ^= r2; \
r3 ^= r1; r1 |= r4; \
r1 ^= r0; r0 |= r4; \
r0 ^= r2; r1 ^= r4; \
r2 ^= r1; r1 &= r0; \
r1 ^= r4; r2 = ~r2; \
r2 |= r0; \
r4 ^= r2; \
} while (0)
/*
* The Serpent linear transform.
*/
#define SERPENT_LT(x0, x1, x2, x3) do { \
x0 = ROLc(x0, 13); \
x2 = ROLc(x2, 3); \
x1 = x1 ^ x0 ^ x2; \
x3 = x3 ^ x2 ^ T32(x0 << 3); \
x1 = ROLc(x1, 1); \
x3 = ROLc(x3, 7); \
x0 = x0 ^ x1 ^ x3; \
x2 = x2 ^ x3 ^ T32(x1 << 7); \
x0 = ROLc(x0, 5); \
x2 = ROLc(x2, 22); \
} while (0)
/* ======================================================================== */
/*
* Initialize Sosemanuk's state by providing a key. The key is an array of
* 1 to 32 bytes.
* @param st The Sosemanuk state
* @param key Key
* @param keylen Length of key in bytes
* @return CRYPT_OK on success
*/
int sosemanuk_setup(sosemanuk_state *st, const unsigned char *key, unsigned long keylen)
{
/*
* This key schedule is actually a truncated Serpent key schedule.
* The key-derived words (w_i) are computed within the eight
* local variables w0 to w7, which are reused again and again.
*/
#define SKS(S, o0, o1, o2, o3, d0, d1, d2, d3) do { \
ulong32 r0, r1, r2, r3, r4; \
r0 = w ## o0; \
r1 = w ## o1; \
r2 = w ## o2; \
r3 = w ## o3; \
S(r0, r1, r2, r3, r4); \
st->kc[i ++] = r ## d0; \
st->kc[i ++] = r ## d1; \
st->kc[i ++] = r ## d2; \
st->kc[i ++] = r ## d3; \
} while (0)
#define SKS0 SKS(S0, 4, 5, 6, 7, 1, 4, 2, 0)
#define SKS1 SKS(S1, 0, 1, 2, 3, 2, 0, 3, 1)
#define SKS2 SKS(S2, 4, 5, 6, 7, 2, 3, 1, 4)
#define SKS3 SKS(S3, 0, 1, 2, 3, 1, 2, 3, 4)
#define SKS4 SKS(S4, 4, 5, 6, 7, 1, 4, 0, 3)
#define SKS5 SKS(S5, 0, 1, 2, 3, 1, 3, 0, 2)
#define SKS6 SKS(S6, 4, 5, 6, 7, 0, 1, 4, 2)
#define SKS7 SKS(S7, 0, 1, 2, 3, 4, 3, 1, 0)
#define WUP(wi, wi5, wi3, wi1, cc) do { \
ulong32 tt = (wi) ^ (wi5) ^ (wi3) \
^ (wi1) ^ (0x9E3779B9 ^ (ulong32)(cc)); \
(wi) = ROLc(tt, 11); \
} while (0)
#define WUP0(cc) do { \
WUP(w0, w3, w5, w7, cc); \
WUP(w1, w4, w6, w0, cc + 1); \
WUP(w2, w5, w7, w1, cc + 2); \
WUP(w3, w6, w0, w2, cc + 3); \
} while (0)
#define WUP1(cc) do { \
WUP(w4, w7, w1, w3, cc); \
WUP(w5, w0, w2, w4, cc + 1); \
WUP(w6, w1, w3, w5, cc + 2); \
WUP(w7, w2, w4, w6, cc + 3); \
} while (0)
unsigned char wbuf[32];
ulong32 w0, w1, w2, w3, w4, w5, w6, w7;
int i = 0;
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(keylen > 0 && keylen <= 32);
/*
* The key is copied into the wbuf[] buffer and padded to 256 bits
* as described in the Serpent specification.
*/
XMEMCPY(wbuf, key, keylen);
if (keylen < 32) {
wbuf[keylen] = 0x01;
if (keylen < 31) {
XMEMSET(wbuf + keylen + 1, 0, 31 - keylen);
}
}
LOAD32L(w0, wbuf);
LOAD32L(w1, wbuf + 4);
LOAD32L(w2, wbuf + 8);
LOAD32L(w3, wbuf + 12);
LOAD32L(w4, wbuf + 16);
LOAD32L(w5, wbuf + 20);
LOAD32L(w6, wbuf + 24);
LOAD32L(w7, wbuf + 28);
WUP0(0); SKS3;
WUP1(4); SKS2;
WUP0(8); SKS1;
WUP1(12); SKS0;
WUP0(16); SKS7;
WUP1(20); SKS6;
WUP0(24); SKS5;
WUP1(28); SKS4;
WUP0(32); SKS3;
WUP1(36); SKS2;
WUP0(40); SKS1;
WUP1(44); SKS0;
WUP0(48); SKS7;
WUP1(52); SKS6;
WUP0(56); SKS5;
WUP1(60); SKS4;
WUP0(64); SKS3;
WUP1(68); SKS2;
WUP0(72); SKS1;
WUP1(76); SKS0;
WUP0(80); SKS7;
WUP1(84); SKS6;
WUP0(88); SKS5;
WUP1(92); SKS4;
WUP0(96); SKS3;
#undef SKS
#undef SKS0
#undef SKS1
#undef SKS2
#undef SKS3
#undef SKS4
#undef SKS5
#undef SKS6
#undef SKS7
#undef WUP
#undef WUP0
#undef WUP1
return CRYPT_OK;
}
/*
* Initialization continues by setting the IV. The IV length is up to 16 bytes.
* If "ivlen" is 0 (no IV), then the "iv" parameter can be NULL. If multiple
* encryptions/decryptions are to be performed with the same key and
* sosemanuk_done() has not been called, only sosemanuk_setiv() need be called
* to set the state.
* @param st The Sosemanuk state
* @param iv Initialization vector
* @param ivlen Length of iv in bytes
* @return CRYPT_OK on success
*/
int sosemanuk_setiv(sosemanuk_state *st, const unsigned char *iv, unsigned long ivlen)
{
/*
* The Serpent key addition step.
*/
#define KA(zc, x0, x1, x2, x3) do { \
x0 ^= st->kc[(zc)]; \
x1 ^= st->kc[(zc) + 1]; \
x2 ^= st->kc[(zc) + 2]; \
x3 ^= st->kc[(zc) + 3]; \
} while (0)
/*
* One Serpent round.
* zc = current subkey counter
* S = S-box macro for this round
* i0 to i4 = input register numbers (the fifth is a scratch register)
* o0 to o3 = output register numbers
*/
#define FSS(zc, S, i0, i1, i2, i3, i4, o0, o1, o2, o3) do { \
KA(zc, r ## i0, r ## i1, r ## i2, r ## i3); \
S(r ## i0, r ## i1, r ## i2, r ## i3, r ## i4); \
SERPENT_LT(r ## o0, r ## o1, r ## o2, r ## o3); \
} while (0)
/*
* Last Serpent round. Contrary to the "true" Serpent, we keep
* the linear transformation for that last round.
*/
#define FSF(zc, S, i0, i1, i2, i3, i4, o0, o1, o2, o3) do { \
KA(zc, r ## i0, r ## i1, r ## i2, r ## i3); \
S(r ## i0, r ## i1, r ## i2, r ## i3, r ## i4); \
SERPENT_LT(r ## o0, r ## o1, r ## o2, r ## o3); \
KA(zc + 4, r ## o0, r ## o1, r ## o2, r ## o3); \
} while (0)
ulong32 r0, r1, r2, r3, r4;
unsigned char ivtmp[16] = {0};
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(ivlen <= 16);
LTC_ARGCHK(iv != NULL || ivlen == 0);
if (ivlen > 0) XMEMCPY(ivtmp, iv, ivlen);
/*
* Decode IV into four 32-bit words (little-endian).
*/
LOAD32L(r0, ivtmp);
LOAD32L(r1, ivtmp + 4);
LOAD32L(r2, ivtmp + 8);
LOAD32L(r3, ivtmp + 12);
/*
* Encrypt IV with Serpent24. Some values are extracted from the
* output of the twelfth, eighteenth and twenty-fourth rounds.
*/
FSS(0, S0, 0, 1, 2, 3, 4, 1, 4, 2, 0);
FSS(4, S1, 1, 4, 2, 0, 3, 2, 1, 0, 4);
FSS(8, S2, 2, 1, 0, 4, 3, 0, 4, 1, 3);
FSS(12, S3, 0, 4, 1, 3, 2, 4, 1, 3, 2);
FSS(16, S4, 4, 1, 3, 2, 0, 1, 0, 4, 2);
FSS(20, S5, 1, 0, 4, 2, 3, 0, 2, 1, 4);
FSS(24, S6, 0, 2, 1, 4, 3, 0, 2, 3, 1);
FSS(28, S7, 0, 2, 3, 1, 4, 4, 1, 2, 0);
FSS(32, S0, 4, 1, 2, 0, 3, 1, 3, 2, 4);
FSS(36, S1, 1, 3, 2, 4, 0, 2, 1, 4, 3);
FSS(40, S2, 2, 1, 4, 3, 0, 4, 3, 1, 0);
FSS(44, S3, 4, 3, 1, 0, 2, 3, 1, 0, 2);
st->s09 = r3;
st->s08 = r1;
st->s07 = r0;
st->s06 = r2;
FSS(48, S4, 3, 1, 0, 2, 4, 1, 4, 3, 2);
FSS(52, S5, 1, 4, 3, 2, 0, 4, 2, 1, 3);
FSS(56, S6, 4, 2, 1, 3, 0, 4, 2, 0, 1);
FSS(60, S7, 4, 2, 0, 1, 3, 3, 1, 2, 4);
FSS(64, S0, 3, 1, 2, 4, 0, 1, 0, 2, 3);
FSS(68, S1, 1, 0, 2, 3, 4, 2, 1, 3, 0);
st->r1 = r2;
st->s04 = r1;
st->r2 = r3;
st->s05 = r0;
FSS(72, S2, 2, 1, 3, 0, 4, 3, 0, 1, 4);
FSS(76, S3, 3, 0, 1, 4, 2, 0, 1, 4, 2);
FSS(80, S4, 0, 1, 4, 2, 3, 1, 3, 0, 2);
FSS(84, S5, 1, 3, 0, 2, 4, 3, 2, 1, 0);
FSS(88, S6, 3, 2, 1, 0, 4, 3, 2, 4, 1);
FSF(92, S7, 3, 2, 4, 1, 0, 0, 1, 2, 3);
st->s03 = r0;
st->s02 = r1;
st->s01 = r2;
st->s00 = r3;
st->ptr = sizeof(st->buf);
#undef KA
#undef FSS
#undef FSF
return CRYPT_OK;
}
/*
* Multiplication by alpha: alpha * x = T32(x << 8) ^ mul_a[x >> 24]
*/
static const ulong32 mul_a[] = {
0x00000000, 0xE19FCF13, 0x6B973726, 0x8A08F835,
0xD6876E4C, 0x3718A15F, 0xBD10596A, 0x5C8F9679,
0x05A7DC98, 0xE438138B, 0x6E30EBBE, 0x8FAF24AD,
0xD320B2D4, 0x32BF7DC7, 0xB8B785F2, 0x59284AE1,
0x0AE71199, 0xEB78DE8A, 0x617026BF, 0x80EFE9AC,
0xDC607FD5, 0x3DFFB0C6, 0xB7F748F3, 0x566887E0,
0x0F40CD01, 0xEEDF0212, 0x64D7FA27, 0x85483534,
0xD9C7A34D, 0x38586C5E, 0xB250946B, 0x53CF5B78,
0x1467229B, 0xF5F8ED88, 0x7FF015BD, 0x9E6FDAAE,
0xC2E04CD7, 0x237F83C4, 0xA9777BF1, 0x48E8B4E2,
0x11C0FE03, 0xF05F3110, 0x7A57C925, 0x9BC80636,
0xC747904F, 0x26D85F5C, 0xACD0A769, 0x4D4F687A,
0x1E803302, 0xFF1FFC11, 0x75170424, 0x9488CB37,
0xC8075D4E, 0x2998925D, 0xA3906A68, 0x420FA57B,
0x1B27EF9A, 0xFAB82089, 0x70B0D8BC, 0x912F17AF,
0xCDA081D6, 0x2C3F4EC5, 0xA637B6F0, 0x47A879E3,
0x28CE449F, 0xC9518B8C, 0x435973B9, 0xA2C6BCAA,
0xFE492AD3, 0x1FD6E5C0, 0x95DE1DF5, 0x7441D2E6,
0x2D699807, 0xCCF65714, 0x46FEAF21, 0xA7616032,
0xFBEEF64B, 0x1A713958, 0x9079C16D, 0x71E60E7E,
0x22295506, 0xC3B69A15, 0x49BE6220, 0xA821AD33,
0xF4AE3B4A, 0x1531F459, 0x9F390C6C, 0x7EA6C37F,
0x278E899E, 0xC611468D, 0x4C19BEB8, 0xAD8671AB,
0xF109E7D2, 0x109628C1, 0x9A9ED0F4, 0x7B011FE7,
0x3CA96604, 0xDD36A917, 0x573E5122, 0xB6A19E31,
0xEA2E0848, 0x0BB1C75B, 0x81B93F6E, 0x6026F07D,
0x390EBA9C, 0xD891758F, 0x52998DBA, 0xB30642A9,
0xEF89D4D0, 0x0E161BC3, 0x841EE3F6, 0x65812CE5,
0x364E779D, 0xD7D1B88E, 0x5DD940BB, 0xBC468FA8,
0xE0C919D1, 0x0156D6C2, 0x8B5E2EF7, 0x6AC1E1E4,
0x33E9AB05, 0xD2766416, 0x587E9C23, 0xB9E15330,
0xE56EC549, 0x04F10A5A, 0x8EF9F26F, 0x6F663D7C,
0x50358897, 0xB1AA4784, 0x3BA2BFB1, 0xDA3D70A2,
0x86B2E6DB, 0x672D29C8, 0xED25D1FD, 0x0CBA1EEE,
0x5592540F, 0xB40D9B1C, 0x3E056329, 0xDF9AAC3A,
0x83153A43, 0x628AF550, 0xE8820D65, 0x091DC276,
0x5AD2990E, 0xBB4D561D, 0x3145AE28, 0xD0DA613B,
0x8C55F742, 0x6DCA3851, 0xE7C2C064, 0x065D0F77,
0x5F754596, 0xBEEA8A85, 0x34E272B0, 0xD57DBDA3,
0x89F22BDA, 0x686DE4C9, 0xE2651CFC, 0x03FAD3EF,
0x4452AA0C, 0xA5CD651F, 0x2FC59D2A, 0xCE5A5239,
0x92D5C440, 0x734A0B53, 0xF942F366, 0x18DD3C75,
0x41F57694, 0xA06AB987, 0x2A6241B2, 0xCBFD8EA1,
0x977218D8, 0x76EDD7CB, 0xFCE52FFE, 0x1D7AE0ED,
0x4EB5BB95, 0xAF2A7486, 0x25228CB3, 0xC4BD43A0,
0x9832D5D9, 0x79AD1ACA, 0xF3A5E2FF, 0x123A2DEC,
0x4B12670D, 0xAA8DA81E, 0x2085502B, 0xC11A9F38,
0x9D950941, 0x7C0AC652, 0xF6023E67, 0x179DF174,
0x78FBCC08, 0x9964031B, 0x136CFB2E, 0xF2F3343D,
0xAE7CA244, 0x4FE36D57, 0xC5EB9562, 0x24745A71,
0x7D5C1090, 0x9CC3DF83, 0x16CB27B6, 0xF754E8A5,
0xABDB7EDC, 0x4A44B1CF, 0xC04C49FA, 0x21D386E9,
0x721CDD91, 0x93831282, 0x198BEAB7, 0xF81425A4,
0xA49BB3DD, 0x45047CCE, 0xCF0C84FB, 0x2E934BE8,
0x77BB0109, 0x9624CE1A, 0x1C2C362F, 0xFDB3F93C,
0xA13C6F45, 0x40A3A056, 0xCAAB5863, 0x2B349770,
0x6C9CEE93, 0x8D032180, 0x070BD9B5, 0xE69416A6,
0xBA1B80DF, 0x5B844FCC, 0xD18CB7F9, 0x301378EA,
0x693B320B, 0x88A4FD18, 0x02AC052D, 0xE333CA3E,
0xBFBC5C47, 0x5E239354, 0xD42B6B61, 0x35B4A472,
0x667BFF0A, 0x87E43019, 0x0DECC82C, 0xEC73073F,
0xB0FC9146, 0x51635E55, 0xDB6BA660, 0x3AF46973,
0x63DC2392, 0x8243EC81, 0x084B14B4, 0xE9D4DBA7,
0xB55B4DDE, 0x54C482CD, 0xDECC7AF8, 0x3F53B5EB
};
/*
* Multiplication by 1/alpha: 1/alpha * x = (x >> 8) ^ mul_ia[x & 0xFF]
*/
static const ulong32 mul_ia[] = {
0x00000000, 0x180F40CD, 0x301E8033, 0x2811C0FE,
0x603CA966, 0x7833E9AB, 0x50222955, 0x482D6998,
0xC078FBCC, 0xD877BB01, 0xF0667BFF, 0xE8693B32,
0xA04452AA, 0xB84B1267, 0x905AD299, 0x88559254,
0x29F05F31, 0x31FF1FFC, 0x19EEDF02, 0x01E19FCF,
0x49CCF657, 0x51C3B69A, 0x79D27664, 0x61DD36A9,
0xE988A4FD, 0xF187E430, 0xD99624CE, 0xC1996403,
0x89B40D9B, 0x91BB4D56, 0xB9AA8DA8, 0xA1A5CD65,
0x5249BE62, 0x4A46FEAF, 0x62573E51, 0x7A587E9C,
0x32751704, 0x2A7A57C9, 0x026B9737, 0x1A64D7FA,
0x923145AE, 0x8A3E0563, 0xA22FC59D, 0xBA208550,
0xF20DECC8, 0xEA02AC05, 0xC2136CFB, 0xDA1C2C36,
0x7BB9E153, 0x63B6A19E, 0x4BA76160, 0x53A821AD,
0x1B854835, 0x038A08F8, 0x2B9BC806, 0x339488CB,
0xBBC11A9F, 0xA3CE5A52, 0x8BDF9AAC, 0x93D0DA61,
0xDBFDB3F9, 0xC3F2F334, 0xEBE333CA, 0xF3EC7307,
0xA492D5C4, 0xBC9D9509, 0x948C55F7, 0x8C83153A,
0xC4AE7CA2, 0xDCA13C6F, 0xF4B0FC91, 0xECBFBC5C,
0x64EA2E08, 0x7CE56EC5, 0x54F4AE3B, 0x4CFBEEF6,
0x04D6876E, 0x1CD9C7A3, 0x34C8075D, 0x2CC74790,
0x8D628AF5, 0x956DCA38, 0xBD7C0AC6, 0xA5734A0B,
0xED5E2393, 0xF551635E, 0xDD40A3A0, 0xC54FE36D,
0x4D1A7139, 0x551531F4, 0x7D04F10A, 0x650BB1C7,
0x2D26D85F, 0x35299892, 0x1D38586C, 0x053718A1,
0xF6DB6BA6, 0xEED42B6B, 0xC6C5EB95, 0xDECAAB58,
0x96E7C2C0, 0x8EE8820D, 0xA6F942F3, 0xBEF6023E,
0x36A3906A, 0x2EACD0A7, 0x06BD1059, 0x1EB25094,
0x569F390C, 0x4E9079C1, 0x6681B93F, 0x7E8EF9F2,
0xDF2B3497, 0xC724745A, 0xEF35B4A4, 0xF73AF469,
0xBF179DF1, 0xA718DD3C, 0x8F091DC2, 0x97065D0F,
0x1F53CF5B, 0x075C8F96, 0x2F4D4F68, 0x37420FA5,
0x7F6F663D, 0x676026F0, 0x4F71E60E, 0x577EA6C3,
0xE18D0321, 0xF98243EC, 0xD1938312, 0xC99CC3DF,
0x81B1AA47, 0x99BEEA8A, 0xB1AF2A74, 0xA9A06AB9,
0x21F5F8ED, 0x39FAB820, 0x11EB78DE, 0x09E43813,
0x41C9518B, 0x59C61146, 0x71D7D1B8, 0x69D89175,
0xC87D5C10, 0xD0721CDD, 0xF863DC23, 0xE06C9CEE,
0xA841F576, 0xB04EB5BB, 0x985F7545, 0x80503588,
0x0805A7DC, 0x100AE711, 0x381B27EF, 0x20146722,
0x68390EBA, 0x70364E77, 0x58278E89, 0x4028CE44,
0xB3C4BD43, 0xABCBFD8E, 0x83DA3D70, 0x9BD57DBD,
0xD3F81425, 0xCBF754E8, 0xE3E69416, 0xFBE9D4DB,
0x73BC468F, 0x6BB30642, 0x43A2C6BC, 0x5BAD8671,
0x1380EFE9, 0x0B8FAF24, 0x239E6FDA, 0x3B912F17,
0x9A34E272, 0x823BA2BF, 0xAA2A6241, 0xB225228C,
0xFA084B14, 0xE2070BD9, 0xCA16CB27, 0xD2198BEA,
0x5A4C19BE, 0x42435973, 0x6A52998D, 0x725DD940,
0x3A70B0D8, 0x227FF015, 0x0A6E30EB, 0x12617026,
0x451FD6E5, 0x5D109628, 0x750156D6, 0x6D0E161B,
0x25237F83, 0x3D2C3F4E, 0x153DFFB0, 0x0D32BF7D,
0x85672D29, 0x9D686DE4, 0xB579AD1A, 0xAD76EDD7,
0xE55B844F, 0xFD54C482, 0xD545047C, 0xCD4A44B1,
0x6CEF89D4, 0x74E0C919, 0x5CF109E7, 0x44FE492A,
0x0CD320B2, 0x14DC607F, 0x3CCDA081, 0x24C2E04C,
0xAC977218, 0xB49832D5, 0x9C89F22B, 0x8486B2E6,
0xCCABDB7E, 0xD4A49BB3, 0xFCB55B4D, 0xE4BA1B80,
0x17566887, 0x0F59284A, 0x2748E8B4, 0x3F47A879,
0x776AC1E1, 0x6F65812C, 0x477441D2, 0x5F7B011F,
0xD72E934B, 0xCF21D386, 0xE7301378, 0xFF3F53B5,
0xB7123A2D, 0xAF1D7AE0, 0x870CBA1E, 0x9F03FAD3,
0x3EA637B6, 0x26A9777B, 0x0EB8B785, 0x16B7F748,
0x5E9A9ED0, 0x4695DE1D, 0x6E841EE3, 0x768B5E2E,
0xFEDECC7A, 0xE6D18CB7, 0xCEC04C49, 0xD6CF0C84,
0x9EE2651C, 0x86ED25D1, 0xAEFCE52F, 0xB6F3A5E2
};
/*
* Compute the next block of bits of output stream. This is equivalent
* to one full rotation of the shift register.
*/
static LTC_INLINE void s_sosemanuk_internal(sosemanuk_state *st)
{
/*
* MUL_A(x) computes alpha * x (in F_{2^32}).
* MUL_G(x) computes 1/alpha * x (in F_{2^32}).
*/
#define MUL_A(x) (T32((x) << 8) ^ mul_a[(x) >> 24])
#define MUL_G(x) (((x) >> 8) ^ mul_ia[(x) & 0xFF])
/*
* This macro computes the special multiplexer, which chooses
* between "x" and "x xor y", depending on the least significant
* bit of the control word. We use the C "?:" selection operator
* (which most compilers know how to optimise) except for Alpha,
* where the manual sign extension seems to perform equally well
* with DEC/Compaq/HP compiler, and much better with gcc.
*/
#ifdef __alpha
#define XMUX(c, x, y) ((((signed int)((c) << 31) >> 31) & (y)) ^ (x))
#else
#define XMUX(c, x, y) (((c) & 0x1) ? ((x) ^ (y)) : (x))
#endif
/*
* FSM() updates the finite state machine.
*/
#define FSM(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) do { \
ulong32 tt, or1; \
tt = XMUX(r1, s ## x1, s ## x8); \
or1 = r1; \
r1 = T32(r2 + tt); \
tt = T32(or1 * 0x54655307); \
r2 = ROLc(tt, 7); \
} while (0)
/*
* LRU updates the shift register; the dropped value is stored
* in variable "dd".
*/
#define LRU(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, dd) do { \
dd = s ## x0; \
s ## x0 = MUL_A(s ## x0) ^ MUL_G(s ## x3) ^ s ## x9; \
} while (0)
/*
* CC1 stores into variable "ee" the next intermediate word
* (combination of the new states of the LFSR and the FSM).
*/
#define CC1(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, ee) do { \
ee = T32(s ## x9 + r1) ^ r2; \
} while (0)
/*
* STEP computes one internal round. "dd" receives the "s_t"
* value (dropped from the LFSR) and "ee" gets the value computed
* from the LFSR and FSM.
*/
#define STEP(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, dd, ee) do { \
FSM(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9); \
LRU(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, dd); \
CC1(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, ee); \
} while (0)
/*
* Apply one Serpent round (with the provided S-box macro), XOR
* the result with the "v" values, and encode the result into
* the destination buffer, at the provided offset. The "x*"
* arguments encode the output permutation of the "S" macro.
*/
#define SRD(S, x0, x1, x2, x3, ooff) do { \
S(u0, u1, u2, u3, u4); \
STORE32L(u ## x0 ^ v0, st->buf + ooff); \
STORE32L(u ## x1 ^ v1, st->buf + ooff + 4); \
STORE32L(u ## x2 ^ v2, st->buf + ooff + 8); \
STORE32L(u ## x3 ^ v3, st->buf + ooff + 12); \
} while (0)
ulong32 s00 = st->s00;
ulong32 s01 = st->s01;
ulong32 s02 = st->s02;
ulong32 s03 = st->s03;
ulong32 s04 = st->s04;
ulong32 s05 = st->s05;
ulong32 s06 = st->s06;
ulong32 s07 = st->s07;
ulong32 s08 = st->s08;
ulong32 s09 = st->s09;
ulong32 r1 = st->r1;
ulong32 r2 = st->r2;
ulong32 u0, u1, u2, u3, u4;
ulong32 v0, v1, v2, v3;
STEP(00, 01, 02, 03, 04, 05, 06, 07, 08, 09, v0, u0);
STEP(01, 02, 03, 04, 05, 06, 07, 08, 09, 00, v1, u1);
STEP(02, 03, 04, 05, 06, 07, 08, 09, 00, 01, v2, u2);
STEP(03, 04, 05, 06, 07, 08, 09, 00, 01, 02, v3, u3);
SRD(S2, 2, 3, 1, 4, 0);
STEP(04, 05, 06, 07, 08, 09, 00, 01, 02, 03, v0, u0);
STEP(05, 06, 07, 08, 09, 00, 01, 02, 03, 04, v1, u1);
STEP(06, 07, 08, 09, 00, 01, 02, 03, 04, 05, v2, u2);
STEP(07, 08, 09, 00, 01, 02, 03, 04, 05, 06, v3, u3);
SRD(S2, 2, 3, 1, 4, 16);
STEP(08, 09, 00, 01, 02, 03, 04, 05, 06, 07, v0, u0);
STEP(09, 00, 01, 02, 03, 04, 05, 06, 07, 08, v1, u1);
STEP(00, 01, 02, 03, 04, 05, 06, 07, 08, 09, v2, u2);
STEP(01, 02, 03, 04, 05, 06, 07, 08, 09, 00, v3, u3);
SRD(S2, 2, 3, 1, 4, 32);
STEP(02, 03, 04, 05, 06, 07, 08, 09, 00, 01, v0, u0);
STEP(03, 04, 05, 06, 07, 08, 09, 00, 01, 02, v1, u1);
STEP(04, 05, 06, 07, 08, 09, 00, 01, 02, 03, v2, u2);
STEP(05, 06, 07, 08, 09, 00, 01, 02, 03, 04, v3, u3);
SRD(S2, 2, 3, 1, 4, 48);
STEP(06, 07, 08, 09, 00, 01, 02, 03, 04, 05, v0, u0);
STEP(07, 08, 09, 00, 01, 02, 03, 04, 05, 06, v1, u1);
STEP(08, 09, 00, 01, 02, 03, 04, 05, 06, 07, v2, u2);
STEP(09, 00, 01, 02, 03, 04, 05, 06, 07, 08, v3, u3);
SRD(S2, 2, 3, 1, 4, 64);
st->s00 = s00;
st->s01 = s01;
st->s02 = s02;
st->s03 = s03;
st->s04 = s04;
st->s05 = s05;
st->s06 = s06;
st->s07 = s07;
st->s08 = s08;
st->s09 = s09;
st->r1 = r1;
st->r2 = r2;
}
/*
* Combine buffers in1[] and in2[] by XOR, result in out[]. The length
* is "datalen" (in bytes). Partial overlap of out[] with either in1[]
* or in2[] is not allowed. Total overlap (out == in1 and/or out == in2)
* is allowed.
*/
static LTC_INLINE void s_xorbuf(const unsigned char *in1, const unsigned char *in2,
unsigned char *out, unsigned long datalen)
{
while (datalen -- > 0) {
*out ++ = *in1 ++ ^ *in2 ++;
}
}
/*
* Cipher operation, as a stream cipher: data is read from the "in"
* buffer, combined by XOR with the stream, and the result is written
* in the "out" buffer. "in" and "out" must be either equal, or
* reference distinct buffers (no partial overlap is allowed).
* @param st The Sosemanuk state
* @param in Data in
* @param inlen Length of data in bytes
* @param out Data out
* @return CRYPT_OK on success
*/
int sosemanuk_crypt(sosemanuk_state *st,
const unsigned char *in, unsigned long inlen, unsigned char *out)
{
LTC_ARGCHK(st != NULL);
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
if (st->ptr < (sizeof(st->buf))) {
unsigned long rlen = (sizeof(st->buf)) - st->ptr;
if (rlen > inlen) {
rlen = inlen;
}
s_xorbuf(st->buf + st->ptr, in, out, rlen);
in += rlen;
out += rlen;
inlen -= rlen;
st->ptr += rlen;
}
while (inlen > 0) {
s_sosemanuk_internal(st);
if (inlen >= sizeof(st->buf)) {
s_xorbuf(st->buf, in, out, sizeof(st->buf));
in += sizeof(st->buf);
out += sizeof(st->buf);
inlen -= sizeof(st->buf);
} else {
s_xorbuf(st->buf, in, out, inlen);
st->ptr = inlen;
inlen = 0;
}
}
return CRYPT_OK;
}
/*
* Cipher operation, as a PRNG: the provided output buffer is filled with
* pseudo-random bytes as output from the stream cipher.
* @param st The Sosemanuk state
* @param out Data out
* @param outlen Length of output in bytes
* @return CRYPT_OK on success
*/
int sosemanuk_keystream(sosemanuk_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 sosemanuk_crypt(st, out, outlen, out);
}
/*
* Terminate and clear Sosemanuk key context
* @param st The Sosemanuk state
* @return CRYPT_OK on success
*/
int sosemanuk_done(sosemanuk_state *st)
{
LTC_ARGCHK(st != NULL);
zeromem(st, sizeof(sosemanuk_state));
return CRYPT_OK;
}
#endif
#pragma clang diagnostic pop

View File

@@ -0,0 +1,35 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_SOSEMANUK
/**
Encrypt (or decrypt) bytes of ciphertext (or plaintext) with Sosemanuk
@param key The key
@param keylen The key length
@param iv The initial vector
@param ivlen The initial vector length
@param datain The plaintext (or ciphertext)
@param datalen The length of the input and output (octets)
@param dataout [out] The ciphertext (or plaintext)
@return CRYPT_OK if successful
*/
int sosemanuk_memory(const unsigned char *key, unsigned long keylen,
const unsigned char *iv, unsigned long ivlen,
const unsigned char *datain, unsigned long datalen,
unsigned char *dataout)
{
sosemanuk_state st;
int err;
if ((err = sosemanuk_setup(&st, key, keylen)) != CRYPT_OK) goto WIPE_KEY;
if ((err = sosemanuk_setiv(&st, iv, ivlen)) != CRYPT_OK) goto WIPE_KEY;
err = sosemanuk_crypt(&st, datain, datalen, dataout);
WIPE_KEY:
sosemanuk_done(&st);
return err;
}
#endif /* LTC_SOSEMANUK */

View File

@@ -0,0 +1,79 @@
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
/* SPDX-License-Identifier: Unlicense */
#include "tomcrypt_private.h"
#ifdef LTC_SOSEMANUK
int sosemanuk_test(void)
{
#ifndef LTC_TEST
return CRYPT_NOP;
#else
sosemanuk_state st;
int err;
unsigned char out[1000];
{
unsigned char k[] = { 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 };
unsigned char n[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
unsigned char ct[] = { 0x7e, 0xfe, 0x2e, 0x6f, 0x8f, 0x77, 0x15, 0x72, 0x6a, 0x88, 0x14, 0xa6, 0x56, 0x88, 0x29, 0x9a,
0x86, 0x32, 0x7f, 0x14, 0xd6, 0xb1, 0x94, 0x90, 0x25, 0xbc, 0x73, 0xfd, 0x02, 0x6c, 0x6a, 0xb8,
0xda, 0x8e, 0x7f, 0x61, 0x70, 0x81, 0xe3, 0xbb, 0x99, 0xaf, 0x19, 0x9f, 0x20, 0x45 };
char pt[] = "Kilroy was here, and there. ...and everywhere!"; /* len = 46 bytes */
unsigned long len;
len = XSTRLEN(pt);
/* crypt piece by piece */
if ((err = sosemanuk_setup(&st, k, sizeof(k))) != CRYPT_OK) return err;
if ((err = sosemanuk_setiv(&st, n, sizeof(n))) != CRYPT_OK) return err;
if ((err = sosemanuk_crypt(&st, (unsigned char*)pt, 5, out)) != CRYPT_OK) return err;
if ((err = sosemanuk_crypt(&st, (unsigned char*)pt + 5, 25, out + 5)) != CRYPT_OK) return err;
if ((err = sosemanuk_crypt(&st, (unsigned char*)pt + 30, 10, out + 30)) != CRYPT_OK) return err;
if ((err = sosemanuk_crypt(&st, (unsigned char*)pt + 40, len - 40, out + 40)) != CRYPT_OK) return err;
if (compare_testvector(out, len, ct, sizeof(ct), "SOSEMANUK-TV1", 1)) return CRYPT_FAIL_TESTVECTOR;
/* crypt in one go - using sosemanuk_ivctr64() */
if ((err = sosemanuk_setup(&st, k, sizeof(k))) != CRYPT_OK) return err;
if ((err = sosemanuk_setiv(&st, n, sizeof(n))) != CRYPT_OK) return err;
if ((err = sosemanuk_crypt(&st, (unsigned char*)pt, len, out)) != CRYPT_OK) return err;
if (compare_testvector(out, len, ct, sizeof(ct), "SOSEMANUK-TV2", 1)) return CRYPT_FAIL_TESTVECTOR;
/* crypt in a single call */
if ((err = sosemanuk_memory(k, sizeof(k), n, sizeof(n),
(unsigned char*)pt, len, out)) != CRYPT_OK) return err;
if (compare_testvector(out, len, ct, sizeof(ct), "SOSEMANUK-TV3", 1)) return CRYPT_FAIL_TESTVECTOR;
}
{
/* keystream
* http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/sosemanuk/unverified.test-vectors?rev=210&view=auto
* Set 6, vector 0
* key = 0053A6F94C9FF24598EB3E91E4378ADD
* 3083D6297CCF2275C81B6EC11467BA0D
* IV = 0D74DB42A91077DE45AC137AE148AF16
* stream[0..63] = 55EB8D174C2E0351E5A53C90E84740EB
* 0F5A24AAFEC8E0C9F9D2CE48B2ADB0A3
* 4D2E8C4E016102607368FFA43A0F9155
* 0706E3548AD9E5EA15A53EB6F0EDE9DC
*
*/
unsigned char k3[] = { 0x00, 0x53, 0xA6, 0xF9, 0x4C, 0x9F, 0xF2, 0x45, 0x98, 0xEB, 0x3E, 0x91, 0xE4, 0x37, 0x8A, 0xDD,
0x30, 0x83, 0xD6, 0x29, 0x7C, 0xCF, 0x22, 0x75, 0xC8, 0x1B, 0x6E, 0xC1, 0x14, 0x67, 0xBA, 0x0D };
unsigned char n3[] = { 0x0D, 0x74, 0xDB, 0x42, 0xA9, 0x10, 0x77, 0xDE, 0x45, 0xAC, 0x13, 0x7A, 0xE1, 0x48, 0xAF, 0x16 };
unsigned char ct3[] = { 0x55, 0xEB, 0x8D, 0x17, 0x4C, 0x2E, 0x03, 0x51, 0xE5, 0xA5, 0x3C, 0x90, 0xE8, 0x47, 0x40, 0xEB,
0x0F, 0x5A, 0x24, 0xAA, 0xFE, 0xC8, 0xE0, 0xC9, 0xF9, 0xD2, 0xCE, 0x48, 0xB2, 0xAD, 0xB0, 0xA3,
0x4D, 0x2E, 0x8C, 0x4E, 0x01, 0x61, 0x02, 0x60, 0x73, 0x68, 0xFF, 0xA4, 0x3A, 0x0F, 0x91, 0x55,
0x07, 0x06, 0xE3, 0x54, 0x8A, 0xD9, 0xE5, 0xEA, 0x15, 0xA5, 0x3E, 0xB6, 0xF0, 0xED, 0xE9, 0xDC };
if ((err = sosemanuk_setup(&st, k3, sizeof(k3))) != CRYPT_OK) return err;
if ((err = sosemanuk_setiv(&st, n3, sizeof(n3))) != CRYPT_OK) return err;
if ((err = sosemanuk_keystream(&st, out, 64)) != CRYPT_OK) return err;
if ((err = sosemanuk_done(&st)) != CRYPT_OK) return err;
if (compare_testvector(out, 64, ct3, sizeof(ct3), "SOSEMANUK-TV4", 1)) return CRYPT_FAIL_TESTVECTOR;
}
return CRYPT_OK;
#endif
}
#endif