blob: 781f48fda44851057954731a6e6c49f43657fee4 [file] [log] [blame]
/******************************************************************************
* Filename: sw_chacha.c
* Revised: 2016-10-05 12:42:03 +0200 (Wed, 05 Oct 2016)
* Revision: 47308
******************************************************************************/
/*
chacha-ref.c version 20080118
D. J. Bernstein
Public domain.
*/
#define ECRYPT_LITTLE_ENDIAN
#include "sw_ecrypt-sync.h"
#define ROTATE(v,c) (ROTL32(v,c))
#define XOR(v,w) ((v) ^ (w))
#define PLUS(v,w) (U32V((v) + (w)))
#define PLUSONE(v) (PLUS((v),1))
#define QUARTERROUND(a,b,c,d) \
x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);
static void salsa20_wordtobyte(u8 output[64],const u32 input[16])
{
u32 x[16];
int i;
for (i = 0;i < 16;++i) x[i] = input[i];
for (i = 8;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] = PLUS(x[i],input[i]);
for (i = 0;i < 16;++i) U32TO8_LITTLE(output + 4 * i,x[i]);
}
void ECRYPT_init(void)
{
return;
}
static const char sigma[16] = "expand 32-byte k";
static const char tau[16] = "expand 16-byte k";
void ECRYPT_keysetup(ECRYPT_ctx *x,const u8 *k,u32 kbits,u32 ivbits)
{
const char *constants;
x->input[4] = U8TO32_LITTLE(k + 0);
x->input[5] = U8TO32_LITTLE(k + 4);
x->input[6] = U8TO32_LITTLE(k + 8);
x->input[7] = U8TO32_LITTLE(k + 12);
if (kbits == 256) { /* recommended */
k += 16;
constants = sigma;
} else { /* kbits == 128 */
constants = tau;
}
x->input[8] = U8TO32_LITTLE(k + 0);
x->input[9] = U8TO32_LITTLE(k + 4);
x->input[10] = U8TO32_LITTLE(k + 8);
x->input[11] = U8TO32_LITTLE(k + 12);
x->input[0] = U8TO32_LITTLE(constants + 0);
x->input[1] = U8TO32_LITTLE(constants + 4);
x->input[2] = U8TO32_LITTLE(constants + 8);
x->input[3] = U8TO32_LITTLE(constants + 12);
}
void ECRYPT_ivsetup(ECRYPT_ctx *x,const u8 *iv)
{
x->input[12] = 0;
x->input[13] = 0;
x->input[14] = U8TO32_LITTLE(iv + 0);
x->input[15] = U8TO32_LITTLE(iv + 4);
}
void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes)
{
u8 output[64];
int i;
if (!bytes) return;
for (;;) {
salsa20_wordtobyte(output,x->input);
x->input[12] = PLUSONE(x->input[12]);
if (!x->input[12]) {
x->input[13] = PLUSONE(x->input[13]);
/* stopping at 2^70 bytes per nonce is user's responsibility */
}
if (bytes <= 64) {
for (i = 0;i < bytes;++i) c[i] = m[i] ^ output[i];
return;
}
for (i = 0;i < 64;++i) c[i] = m[i] ^ output[i];
bytes -= 64;
c += 64;
m += 64;
}
}
void ECRYPT_decrypt_bytes(ECRYPT_ctx *x,const u8 *c,u8 *m,u32 bytes)
{
ECRYPT_encrypt_bytes(x,c,m,bytes);
}
void ECRYPT_keystream_bytes(ECRYPT_ctx *x,u8 *stream,u32 bytes)
{
u32 i;
for (i = 0;i < bytes;++i) stream[i] = 0;
ECRYPT_encrypt_bytes(x,stream,stream,bytes);
}