1276541Sdes/* 2276541Sdeschacha-merged.c version 20080118 3276541SdesD. J. Bernstein 4276541SdesPublic domain. 5276541Sdes*/ 6276541Sdes 7276541Sdes/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */ 8276541Sdes 9276541Sdestypedef unsigned char u8; 10276541Sdestypedef unsigned int u32; 11276541Sdes 12276541Sdestypedef struct 13276541Sdes{ 14276541Sdes u32 input[16]; /* could be compressed */ 15276541Sdes} chacha_ctx; 16276541Sdes 17276541Sdes#define U8C(v) (v##U) 18276541Sdes#define U32C(v) (v##U) 19276541Sdes 20276541Sdes#define U8V(v) ((u8)(v) & U8C(0xFF)) 21276541Sdes#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) 22276541Sdes 23276541Sdes#define ROTL32(v, n) \ 24276541Sdes (U32V((v) << (n)) | ((v) >> (32 - (n)))) 25276541Sdes 26276541Sdes#define U8TO32_LITTLE(p) \ 27276541Sdes (((u32)((p)[0]) ) | \ 28276541Sdes ((u32)((p)[1]) << 8) | \ 29276541Sdes ((u32)((p)[2]) << 16) | \ 30276541Sdes ((u32)((p)[3]) << 24)) 31276541Sdes 32276541Sdes#define U32TO8_LITTLE(p, v) \ 33276541Sdes do { \ 34276541Sdes (p)[0] = U8V((v) ); \ 35276541Sdes (p)[1] = U8V((v) >> 8); \ 36276541Sdes (p)[2] = U8V((v) >> 16); \ 37276541Sdes (p)[3] = U8V((v) >> 24); \ 38276541Sdes } while (0) 39276541Sdes 40276541Sdes#define ROTATE(v,c) (ROTL32(v,c)) 41276541Sdes#define XOR(v,w) ((v) ^ (w)) 42276541Sdes#define PLUS(v,w) (U32V((v) + (w))) 43276541Sdes#define PLUSONE(v) (PLUS((v),1)) 44276541Sdes 45276541Sdes#define QUARTERROUND(a,b,c,d) \ 46276541Sdes a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ 47276541Sdes c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ 48276541Sdes a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ 49276541Sdes c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); 50276541Sdes 51276541Sdesstatic const char sigma[16] = "expand 32-byte k"; 52276541Sdesstatic const char tau[16] = "expand 16-byte k"; 53276541Sdes 54276541Sdesstatic void 55276541Sdeschacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ATTR_UNUSED(ivbits)) 56276541Sdes{ 57276541Sdes const char *constants; 58276541Sdes 59276541Sdes x->input[4] = U8TO32_LITTLE(k + 0); 60276541Sdes x->input[5] = U8TO32_LITTLE(k + 4); 61276541Sdes x->input[6] = U8TO32_LITTLE(k + 8); 62276541Sdes x->input[7] = U8TO32_LITTLE(k + 12); 63276541Sdes if (kbits == 256) { /* recommended */ 64276541Sdes k += 16; 65276541Sdes constants = sigma; 66276541Sdes } else { /* kbits == 128 */ 67276541Sdes constants = tau; 68276541Sdes } 69276541Sdes x->input[8] = U8TO32_LITTLE(k + 0); 70276541Sdes x->input[9] = U8TO32_LITTLE(k + 4); 71276541Sdes x->input[10] = U8TO32_LITTLE(k + 8); 72276541Sdes x->input[11] = U8TO32_LITTLE(k + 12); 73276541Sdes x->input[0] = U8TO32_LITTLE(constants + 0); 74276541Sdes x->input[1] = U8TO32_LITTLE(constants + 4); 75276541Sdes x->input[2] = U8TO32_LITTLE(constants + 8); 76276541Sdes x->input[3] = U8TO32_LITTLE(constants + 12); 77276541Sdes} 78276541Sdes 79276541Sdesstatic void 80276541Sdeschacha_ivsetup(chacha_ctx *x,const u8 *iv) 81276541Sdes{ 82276541Sdes x->input[12] = 0; 83276541Sdes x->input[13] = 0; 84276541Sdes x->input[14] = U8TO32_LITTLE(iv + 0); 85276541Sdes x->input[15] = U8TO32_LITTLE(iv + 4); 86276541Sdes} 87276541Sdes 88276541Sdesstatic void 89276541Sdeschacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) 90276541Sdes{ 91276541Sdes u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; 92276541Sdes u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; 93276541Sdes u8 *ctarget = NULL; 94276541Sdes u8 tmp[64]; 95276541Sdes u_int i; 96276541Sdes 97276541Sdes if (!bytes) return; 98276541Sdes 99276541Sdes j0 = x->input[0]; 100276541Sdes j1 = x->input[1]; 101276541Sdes j2 = x->input[2]; 102276541Sdes j3 = x->input[3]; 103276541Sdes j4 = x->input[4]; 104276541Sdes j5 = x->input[5]; 105276541Sdes j6 = x->input[6]; 106276541Sdes j7 = x->input[7]; 107276541Sdes j8 = x->input[8]; 108276541Sdes j9 = x->input[9]; 109276541Sdes j10 = x->input[10]; 110276541Sdes j11 = x->input[11]; 111276541Sdes j12 = x->input[12]; 112276541Sdes j13 = x->input[13]; 113276541Sdes j14 = x->input[14]; 114276541Sdes j15 = x->input[15]; 115276541Sdes 116276541Sdes for (;;) { 117276541Sdes if (bytes < 64) { 118276541Sdes for (i = 0;i < bytes;++i) tmp[i] = m[i]; 119276541Sdes m = tmp; 120276541Sdes ctarget = c; 121276541Sdes c = tmp; 122276541Sdes } 123276541Sdes x0 = j0; 124276541Sdes x1 = j1; 125276541Sdes x2 = j2; 126276541Sdes x3 = j3; 127276541Sdes x4 = j4; 128276541Sdes x5 = j5; 129276541Sdes x6 = j6; 130276541Sdes x7 = j7; 131276541Sdes x8 = j8; 132276541Sdes x9 = j9; 133276541Sdes x10 = j10; 134276541Sdes x11 = j11; 135276541Sdes x12 = j12; 136276541Sdes x13 = j13; 137276541Sdes x14 = j14; 138276541Sdes x15 = j15; 139276541Sdes for (i = 20;i > 0;i -= 2) { 140276541Sdes QUARTERROUND( x0, x4, x8,x12) 141276541Sdes QUARTERROUND( x1, x5, x9,x13) 142276541Sdes QUARTERROUND( x2, x6,x10,x14) 143276541Sdes QUARTERROUND( x3, x7,x11,x15) 144276541Sdes QUARTERROUND( x0, x5,x10,x15) 145276541Sdes QUARTERROUND( x1, x6,x11,x12) 146276541Sdes QUARTERROUND( x2, x7, x8,x13) 147276541Sdes QUARTERROUND( x3, x4, x9,x14) 148276541Sdes } 149276541Sdes x0 = PLUS(x0,j0); 150276541Sdes x1 = PLUS(x1,j1); 151276541Sdes x2 = PLUS(x2,j2); 152276541Sdes x3 = PLUS(x3,j3); 153276541Sdes x4 = PLUS(x4,j4); 154276541Sdes x5 = PLUS(x5,j5); 155276541Sdes x6 = PLUS(x6,j6); 156276541Sdes x7 = PLUS(x7,j7); 157276541Sdes x8 = PLUS(x8,j8); 158276541Sdes x9 = PLUS(x9,j9); 159276541Sdes x10 = PLUS(x10,j10); 160276541Sdes x11 = PLUS(x11,j11); 161276541Sdes x12 = PLUS(x12,j12); 162276541Sdes x13 = PLUS(x13,j13); 163276541Sdes x14 = PLUS(x14,j14); 164276541Sdes x15 = PLUS(x15,j15); 165276541Sdes 166276541Sdes#ifndef KEYSTREAM_ONLY 167276541Sdes x0 = XOR(x0,U8TO32_LITTLE(m + 0)); 168276541Sdes x1 = XOR(x1,U8TO32_LITTLE(m + 4)); 169276541Sdes x2 = XOR(x2,U8TO32_LITTLE(m + 8)); 170276541Sdes x3 = XOR(x3,U8TO32_LITTLE(m + 12)); 171276541Sdes x4 = XOR(x4,U8TO32_LITTLE(m + 16)); 172276541Sdes x5 = XOR(x5,U8TO32_LITTLE(m + 20)); 173276541Sdes x6 = XOR(x6,U8TO32_LITTLE(m + 24)); 174276541Sdes x7 = XOR(x7,U8TO32_LITTLE(m + 28)); 175276541Sdes x8 = XOR(x8,U8TO32_LITTLE(m + 32)); 176276541Sdes x9 = XOR(x9,U8TO32_LITTLE(m + 36)); 177276541Sdes x10 = XOR(x10,U8TO32_LITTLE(m + 40)); 178276541Sdes x11 = XOR(x11,U8TO32_LITTLE(m + 44)); 179276541Sdes x12 = XOR(x12,U8TO32_LITTLE(m + 48)); 180276541Sdes x13 = XOR(x13,U8TO32_LITTLE(m + 52)); 181276541Sdes x14 = XOR(x14,U8TO32_LITTLE(m + 56)); 182276541Sdes x15 = XOR(x15,U8TO32_LITTLE(m + 60)); 183276541Sdes#endif 184276541Sdes 185276541Sdes j12 = PLUSONE(j12); 186276541Sdes if (!j12) { 187276541Sdes j13 = PLUSONE(j13); 188276541Sdes /* stopping at 2^70 bytes per nonce is user's responsibility */ 189276541Sdes } 190276541Sdes 191276541Sdes U32TO8_LITTLE(c + 0,x0); 192276541Sdes U32TO8_LITTLE(c + 4,x1); 193276541Sdes U32TO8_LITTLE(c + 8,x2); 194276541Sdes U32TO8_LITTLE(c + 12,x3); 195276541Sdes U32TO8_LITTLE(c + 16,x4); 196276541Sdes U32TO8_LITTLE(c + 20,x5); 197276541Sdes U32TO8_LITTLE(c + 24,x6); 198276541Sdes U32TO8_LITTLE(c + 28,x7); 199276541Sdes U32TO8_LITTLE(c + 32,x8); 200276541Sdes U32TO8_LITTLE(c + 36,x9); 201276541Sdes U32TO8_LITTLE(c + 40,x10); 202276541Sdes U32TO8_LITTLE(c + 44,x11); 203276541Sdes U32TO8_LITTLE(c + 48,x12); 204276541Sdes U32TO8_LITTLE(c + 52,x13); 205276541Sdes U32TO8_LITTLE(c + 56,x14); 206276541Sdes U32TO8_LITTLE(c + 60,x15); 207276541Sdes 208276541Sdes if (bytes <= 64) { 209276541Sdes if (bytes < 64) { 210276541Sdes for (i = 0;i < bytes;++i) ctarget[i] = c[i]; 211276541Sdes } 212276541Sdes x->input[12] = j12; 213276541Sdes x->input[13] = j13; 214276541Sdes return; 215276541Sdes } 216276541Sdes bytes -= 64; 217276541Sdes c += 64; 218276541Sdes#ifndef KEYSTREAM_ONLY 219276541Sdes m += 64; 220276541Sdes#endif 221276541Sdes } 222276541Sdes} 223