| /****************************************************************************** |
| * 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); |
| } |