1261287Sdes/* 2261287Sdeschacha-merged.c version 20080118 3261287SdesD. J. Bernstein 4261287SdesPublic domain. 5261287Sdes*/ 6261287Sdes 7261287Sdes#include "includes.h" 8261287Sdes 9261287Sdes#include "chacha.h" 10261287Sdes 11261287Sdes/* $OpenBSD: chacha.c,v 1.1 2013/11/21 00:45:44 djm Exp $ */ 12261287Sdes 13261287Sdestypedef unsigned char u8; 14261287Sdestypedef unsigned int u32; 15261287Sdes 16261287Sdestypedef struct chacha_ctx chacha_ctx; 17261287Sdes 18261287Sdes#define U8C(v) (v##U) 19261287Sdes#define U32C(v) (v##U) 20261287Sdes 21261287Sdes#define U8V(v) ((u8)(v) & U8C(0xFF)) 22261287Sdes#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) 23261287Sdes 24261287Sdes#define ROTL32(v, n) \ 25261287Sdes (U32V((v) << (n)) | ((v) >> (32 - (n)))) 26261287Sdes 27261287Sdes#define U8TO32_LITTLE(p) \ 28261287Sdes (((u32)((p)[0]) ) | \ 29261287Sdes ((u32)((p)[1]) << 8) | \ 30261287Sdes ((u32)((p)[2]) << 16) | \ 31261287Sdes ((u32)((p)[3]) << 24)) 32261287Sdes 33261287Sdes#define U32TO8_LITTLE(p, v) \ 34261287Sdes do { \ 35261287Sdes (p)[0] = U8V((v) ); \ 36261287Sdes (p)[1] = U8V((v) >> 8); \ 37261287Sdes (p)[2] = U8V((v) >> 16); \ 38261287Sdes (p)[3] = U8V((v) >> 24); \ 39261287Sdes } while (0) 40261287Sdes 41261287Sdes#define ROTATE(v,c) (ROTL32(v,c)) 42261287Sdes#define XOR(v,w) ((v) ^ (w)) 43261287Sdes#define PLUS(v,w) (U32V((v) + (w))) 44261287Sdes#define PLUSONE(v) (PLUS((v),1)) 45261287Sdes 46261287Sdes#define QUARTERROUND(a,b,c,d) \ 47261287Sdes a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ 48261287Sdes c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ 49261287Sdes a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ 50261287Sdes c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); 51261287Sdes 52261287Sdesstatic const char sigma[16] = "expand 32-byte k"; 53261287Sdesstatic const char tau[16] = "expand 16-byte k"; 54261287Sdes 55261287Sdesvoid 56261287Sdeschacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) 57261287Sdes{ 58261287Sdes const char *constants; 59261287Sdes 60261287Sdes x->input[4] = U8TO32_LITTLE(k + 0); 61261287Sdes x->input[5] = U8TO32_LITTLE(k + 4); 62261287Sdes x->input[6] = U8TO32_LITTLE(k + 8); 63261287Sdes x->input[7] = U8TO32_LITTLE(k + 12); 64261287Sdes if (kbits == 256) { /* recommended */ 65261287Sdes k += 16; 66261287Sdes constants = sigma; 67261287Sdes } else { /* kbits == 128 */ 68261287Sdes constants = tau; 69261287Sdes } 70261287Sdes x->input[8] = U8TO32_LITTLE(k + 0); 71261287Sdes x->input[9] = U8TO32_LITTLE(k + 4); 72261287Sdes x->input[10] = U8TO32_LITTLE(k + 8); 73261287Sdes x->input[11] = U8TO32_LITTLE(k + 12); 74261287Sdes x->input[0] = U8TO32_LITTLE(constants + 0); 75261287Sdes x->input[1] = U8TO32_LITTLE(constants + 4); 76261287Sdes x->input[2] = U8TO32_LITTLE(constants + 8); 77261287Sdes x->input[3] = U8TO32_LITTLE(constants + 12); 78261287Sdes} 79261287Sdes 80261287Sdesvoid 81261287Sdeschacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) 82261287Sdes{ 83261287Sdes x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); 84261287Sdes x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); 85261287Sdes x->input[14] = U8TO32_LITTLE(iv + 0); 86261287Sdes x->input[15] = U8TO32_LITTLE(iv + 4); 87261287Sdes} 88261287Sdes 89261287Sdesvoid 90261287Sdeschacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) 91261287Sdes{ 92261287Sdes u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; 93261287Sdes u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; 94261287Sdes u8 *ctarget = NULL; 95261287Sdes u8 tmp[64]; 96261287Sdes u_int i; 97261287Sdes 98261287Sdes if (!bytes) return; 99261287Sdes 100261287Sdes j0 = x->input[0]; 101261287Sdes j1 = x->input[1]; 102261287Sdes j2 = x->input[2]; 103261287Sdes j3 = x->input[3]; 104261287Sdes j4 = x->input[4]; 105261287Sdes j5 = x->input[5]; 106261287Sdes j6 = x->input[6]; 107261287Sdes j7 = x->input[7]; 108261287Sdes j8 = x->input[8]; 109261287Sdes j9 = x->input[9]; 110261287Sdes j10 = x->input[10]; 111261287Sdes j11 = x->input[11]; 112261287Sdes j12 = x->input[12]; 113261287Sdes j13 = x->input[13]; 114261287Sdes j14 = x->input[14]; 115261287Sdes j15 = x->input[15]; 116261287Sdes 117261287Sdes for (;;) { 118261287Sdes if (bytes < 64) { 119261287Sdes for (i = 0;i < bytes;++i) tmp[i] = m[i]; 120261287Sdes m = tmp; 121261287Sdes ctarget = c; 122261287Sdes c = tmp; 123261287Sdes } 124261287Sdes x0 = j0; 125261287Sdes x1 = j1; 126261287Sdes x2 = j2; 127261287Sdes x3 = j3; 128261287Sdes x4 = j4; 129261287Sdes x5 = j5; 130261287Sdes x6 = j6; 131261287Sdes x7 = j7; 132261287Sdes x8 = j8; 133261287Sdes x9 = j9; 134261287Sdes x10 = j10; 135261287Sdes x11 = j11; 136261287Sdes x12 = j12; 137261287Sdes x13 = j13; 138261287Sdes x14 = j14; 139261287Sdes x15 = j15; 140261287Sdes for (i = 20;i > 0;i -= 2) { 141261287Sdes QUARTERROUND( x0, x4, x8,x12) 142261287Sdes QUARTERROUND( x1, x5, x9,x13) 143261287Sdes QUARTERROUND( x2, x6,x10,x14) 144261287Sdes QUARTERROUND( x3, x7,x11,x15) 145261287Sdes QUARTERROUND( x0, x5,x10,x15) 146261287Sdes QUARTERROUND( x1, x6,x11,x12) 147261287Sdes QUARTERROUND( x2, x7, x8,x13) 148261287Sdes QUARTERROUND( x3, x4, x9,x14) 149261287Sdes } 150261287Sdes x0 = PLUS(x0,j0); 151261287Sdes x1 = PLUS(x1,j1); 152261287Sdes x2 = PLUS(x2,j2); 153261287Sdes x3 = PLUS(x3,j3); 154261287Sdes x4 = PLUS(x4,j4); 155261287Sdes x5 = PLUS(x5,j5); 156261287Sdes x6 = PLUS(x6,j6); 157261287Sdes x7 = PLUS(x7,j7); 158261287Sdes x8 = PLUS(x8,j8); 159261287Sdes x9 = PLUS(x9,j9); 160261287Sdes x10 = PLUS(x10,j10); 161261287Sdes x11 = PLUS(x11,j11); 162261287Sdes x12 = PLUS(x12,j12); 163261287Sdes x13 = PLUS(x13,j13); 164261287Sdes x14 = PLUS(x14,j14); 165261287Sdes x15 = PLUS(x15,j15); 166261287Sdes 167261287Sdes x0 = XOR(x0,U8TO32_LITTLE(m + 0)); 168261287Sdes x1 = XOR(x1,U8TO32_LITTLE(m + 4)); 169261287Sdes x2 = XOR(x2,U8TO32_LITTLE(m + 8)); 170261287Sdes x3 = XOR(x3,U8TO32_LITTLE(m + 12)); 171261287Sdes x4 = XOR(x4,U8TO32_LITTLE(m + 16)); 172261287Sdes x5 = XOR(x5,U8TO32_LITTLE(m + 20)); 173261287Sdes x6 = XOR(x6,U8TO32_LITTLE(m + 24)); 174261287Sdes x7 = XOR(x7,U8TO32_LITTLE(m + 28)); 175261287Sdes x8 = XOR(x8,U8TO32_LITTLE(m + 32)); 176261287Sdes x9 = XOR(x9,U8TO32_LITTLE(m + 36)); 177261287Sdes x10 = XOR(x10,U8TO32_LITTLE(m + 40)); 178261287Sdes x11 = XOR(x11,U8TO32_LITTLE(m + 44)); 179261287Sdes x12 = XOR(x12,U8TO32_LITTLE(m + 48)); 180261287Sdes x13 = XOR(x13,U8TO32_LITTLE(m + 52)); 181261287Sdes x14 = XOR(x14,U8TO32_LITTLE(m + 56)); 182261287Sdes x15 = XOR(x15,U8TO32_LITTLE(m + 60)); 183261287Sdes 184261287Sdes j12 = PLUSONE(j12); 185261287Sdes if (!j12) { 186261287Sdes j13 = PLUSONE(j13); 187261287Sdes /* stopping at 2^70 bytes per nonce is user's responsibility */ 188261287Sdes } 189261287Sdes 190261287Sdes U32TO8_LITTLE(c + 0,x0); 191261287Sdes U32TO8_LITTLE(c + 4,x1); 192261287Sdes U32TO8_LITTLE(c + 8,x2); 193261287Sdes U32TO8_LITTLE(c + 12,x3); 194261287Sdes U32TO8_LITTLE(c + 16,x4); 195261287Sdes U32TO8_LITTLE(c + 20,x5); 196261287Sdes U32TO8_LITTLE(c + 24,x6); 197261287Sdes U32TO8_LITTLE(c + 28,x7); 198261287Sdes U32TO8_LITTLE(c + 32,x8); 199261287Sdes U32TO8_LITTLE(c + 36,x9); 200261287Sdes U32TO8_LITTLE(c + 40,x10); 201261287Sdes U32TO8_LITTLE(c + 44,x11); 202261287Sdes U32TO8_LITTLE(c + 48,x12); 203261287Sdes U32TO8_LITTLE(c + 52,x13); 204261287Sdes U32TO8_LITTLE(c + 56,x14); 205261287Sdes U32TO8_LITTLE(c + 60,x15); 206261287Sdes 207261287Sdes if (bytes <= 64) { 208261287Sdes if (bytes < 64) { 209261287Sdes for (i = 0;i < bytes;++i) ctarget[i] = c[i]; 210261287Sdes } 211261287Sdes x->input[12] = j12; 212261287Sdes x->input[13] = j13; 213261287Sdes return; 214261287Sdes } 215261287Sdes bytes -= 64; 216261287Sdes c += 64; 217261287Sdes m += 64; 218261287Sdes } 219261287Sdes} 220