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