1150890b0SMark Murray /* 2150890b0SMark Murray chacha-merged.c version 20080118 3150890b0SMark Murray D. J. Bernstein 4150890b0SMark Murray Public domain. 5150890b0SMark Murray */ 6150890b0SMark Murray 7150890b0SMark Murray /* $OpenBSD: chacha.c,v 1.1 2013/11/21 00:45:44 djm Exp $ */ 8150890b0SMark Murray 9150890b0SMark Murray #include <sys/cdefs.h> 10150890b0SMark Murray __FBSDID("$FreeBSD$"); 11150890b0SMark Murray 12150890b0SMark Murray #include <sys/param.h> 13150890b0SMark Murray #include <sys/types.h> 14150890b0SMark Murray 15150890b0SMark Murray #include <crypto/chacha20/chacha.h> 16150890b0SMark Murray 17150890b0SMark Murray typedef uint8_t u8; 18150890b0SMark Murray typedef uint32_t u32; 19150890b0SMark Murray 20150890b0SMark Murray typedef struct chacha_ctx chacha_ctx; 21150890b0SMark Murray 22150890b0SMark Murray #define U8C(v) (v##U) 23150890b0SMark Murray #define U32C(v) (v##U) 24150890b0SMark Murray 25150890b0SMark Murray #define U8V(v) ((u8)(v) & U8C(0xFF)) 26150890b0SMark Murray #define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) 27150890b0SMark Murray 28150890b0SMark Murray #define ROTL32(v, n) \ 29150890b0SMark Murray (U32V((v) << (n)) | ((v) >> (32 - (n)))) 30150890b0SMark Murray 31150890b0SMark Murray #define U8TO32_LITTLE(p) \ 32150890b0SMark Murray (((u32)((p)[0]) ) | \ 33150890b0SMark Murray ((u32)((p)[1]) << 8) | \ 34150890b0SMark Murray ((u32)((p)[2]) << 16) | \ 35150890b0SMark Murray ((u32)((p)[3]) << 24)) 36150890b0SMark Murray 37150890b0SMark Murray #define U32TO8_LITTLE(p, v) \ 38150890b0SMark Murray do { \ 39150890b0SMark Murray (p)[0] = U8V((v) ); \ 40150890b0SMark Murray (p)[1] = U8V((v) >> 8); \ 41150890b0SMark Murray (p)[2] = U8V((v) >> 16); \ 42150890b0SMark Murray (p)[3] = U8V((v) >> 24); \ 43150890b0SMark Murray } while (0) 44150890b0SMark Murray 45150890b0SMark Murray #define ROTATE(v,c) (ROTL32(v,c)) 46150890b0SMark Murray #define XOR(v,w) ((v) ^ (w)) 47150890b0SMark Murray #define PLUS(v,w) (U32V((v) + (w))) 48150890b0SMark Murray #define PLUSONE(v) (PLUS((v),1)) 49150890b0SMark Murray 50150890b0SMark Murray #define QUARTERROUND(a,b,c,d) \ 51150890b0SMark Murray a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ 52150890b0SMark Murray c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ 53150890b0SMark Murray a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ 54150890b0SMark Murray c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); 55150890b0SMark Murray 56150890b0SMark Murray static const char sigma[16] = "expand 32-byte k"; 57150890b0SMark Murray static const char tau[16] = "expand 16-byte k"; 58150890b0SMark Murray 59c1e80940SXin LI LOCAL void 60150890b0SMark Murray chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) 61150890b0SMark Murray { 62150890b0SMark Murray const char *constants; 63150890b0SMark Murray 64150890b0SMark Murray x->input[4] = U8TO32_LITTLE(k + 0); 65150890b0SMark Murray x->input[5] = U8TO32_LITTLE(k + 4); 66150890b0SMark Murray x->input[6] = U8TO32_LITTLE(k + 8); 67150890b0SMark Murray x->input[7] = U8TO32_LITTLE(k + 12); 68150890b0SMark Murray if (kbits == 256) { /* recommended */ 69150890b0SMark Murray k += 16; 70150890b0SMark Murray constants = sigma; 71150890b0SMark Murray } else { /* kbits == 128 */ 72150890b0SMark Murray constants = tau; 73150890b0SMark Murray } 74150890b0SMark Murray x->input[8] = U8TO32_LITTLE(k + 0); 75150890b0SMark Murray x->input[9] = U8TO32_LITTLE(k + 4); 76150890b0SMark Murray x->input[10] = U8TO32_LITTLE(k + 8); 77150890b0SMark Murray x->input[11] = U8TO32_LITTLE(k + 12); 78150890b0SMark Murray x->input[0] = U8TO32_LITTLE(constants + 0); 79150890b0SMark Murray x->input[1] = U8TO32_LITTLE(constants + 4); 80150890b0SMark Murray x->input[2] = U8TO32_LITTLE(constants + 8); 81150890b0SMark Murray x->input[3] = U8TO32_LITTLE(constants + 12); 82150890b0SMark Murray } 83150890b0SMark Murray 84c1e80940SXin LI LOCAL void 85150890b0SMark Murray chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) 86150890b0SMark Murray { 87150890b0SMark Murray x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); 88150890b0SMark Murray x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); 89150890b0SMark Murray x->input[14] = U8TO32_LITTLE(iv + 0); 90150890b0SMark Murray x->input[15] = U8TO32_LITTLE(iv + 4); 91150890b0SMark Murray } 92150890b0SMark Murray 93c1e80940SXin LI LOCAL void 94150890b0SMark Murray chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) 95150890b0SMark Murray { 96150890b0SMark Murray u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; 97150890b0SMark Murray u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; 98150890b0SMark Murray u8 *ctarget = NULL; 99150890b0SMark Murray u8 tmp[64]; 100150890b0SMark Murray u_int i; 101150890b0SMark Murray 102150890b0SMark Murray if (!bytes) return; 103150890b0SMark Murray 104150890b0SMark Murray j0 = x->input[0]; 105150890b0SMark Murray j1 = x->input[1]; 106150890b0SMark Murray j2 = x->input[2]; 107150890b0SMark Murray j3 = x->input[3]; 108150890b0SMark Murray j4 = x->input[4]; 109150890b0SMark Murray j5 = x->input[5]; 110150890b0SMark Murray j6 = x->input[6]; 111150890b0SMark Murray j7 = x->input[7]; 112150890b0SMark Murray j8 = x->input[8]; 113150890b0SMark Murray j9 = x->input[9]; 114150890b0SMark Murray j10 = x->input[10]; 115150890b0SMark Murray j11 = x->input[11]; 116150890b0SMark Murray j12 = x->input[12]; 117150890b0SMark Murray j13 = x->input[13]; 118150890b0SMark Murray j14 = x->input[14]; 119150890b0SMark Murray j15 = x->input[15]; 120150890b0SMark Murray 121150890b0SMark Murray for (;;) { 122150890b0SMark Murray if (bytes < 64) { 123*987733edSConrad Meyer #ifndef KEYSTREAM_ONLY 124150890b0SMark Murray for (i = 0;i < bytes;++i) tmp[i] = m[i]; 125150890b0SMark Murray m = tmp; 126*987733edSConrad Meyer #endif 127150890b0SMark Murray ctarget = c; 128150890b0SMark Murray c = tmp; 129150890b0SMark Murray } 130150890b0SMark Murray x0 = j0; 131150890b0SMark Murray x1 = j1; 132150890b0SMark Murray x2 = j2; 133150890b0SMark Murray x3 = j3; 134150890b0SMark Murray x4 = j4; 135150890b0SMark Murray x5 = j5; 136150890b0SMark Murray x6 = j6; 137150890b0SMark Murray x7 = j7; 138150890b0SMark Murray x8 = j8; 139150890b0SMark Murray x9 = j9; 140150890b0SMark Murray x10 = j10; 141150890b0SMark Murray x11 = j11; 142150890b0SMark Murray x12 = j12; 143150890b0SMark Murray x13 = j13; 144150890b0SMark Murray x14 = j14; 145150890b0SMark Murray x15 = j15; 146150890b0SMark Murray for (i = 20;i > 0;i -= 2) { 147150890b0SMark Murray QUARTERROUND( x0, x4, x8,x12) 148150890b0SMark Murray QUARTERROUND( x1, x5, x9,x13) 149150890b0SMark Murray QUARTERROUND( x2, x6,x10,x14) 150150890b0SMark Murray QUARTERROUND( x3, x7,x11,x15) 151150890b0SMark Murray QUARTERROUND( x0, x5,x10,x15) 152150890b0SMark Murray QUARTERROUND( x1, x6,x11,x12) 153150890b0SMark Murray QUARTERROUND( x2, x7, x8,x13) 154150890b0SMark Murray QUARTERROUND( x3, x4, x9,x14) 155150890b0SMark Murray } 156150890b0SMark Murray x0 = PLUS(x0,j0); 157150890b0SMark Murray x1 = PLUS(x1,j1); 158150890b0SMark Murray x2 = PLUS(x2,j2); 159150890b0SMark Murray x3 = PLUS(x3,j3); 160150890b0SMark Murray x4 = PLUS(x4,j4); 161150890b0SMark Murray x5 = PLUS(x5,j5); 162150890b0SMark Murray x6 = PLUS(x6,j6); 163150890b0SMark Murray x7 = PLUS(x7,j7); 164150890b0SMark Murray x8 = PLUS(x8,j8); 165150890b0SMark Murray x9 = PLUS(x9,j9); 166150890b0SMark Murray x10 = PLUS(x10,j10); 167150890b0SMark Murray x11 = PLUS(x11,j11); 168150890b0SMark Murray x12 = PLUS(x12,j12); 169150890b0SMark Murray x13 = PLUS(x13,j13); 170150890b0SMark Murray x14 = PLUS(x14,j14); 171150890b0SMark Murray x15 = PLUS(x15,j15); 172150890b0SMark Murray 173c1e80940SXin LI #ifndef KEYSTREAM_ONLY 174150890b0SMark Murray x0 = XOR(x0,U8TO32_LITTLE(m + 0)); 175150890b0SMark Murray x1 = XOR(x1,U8TO32_LITTLE(m + 4)); 176150890b0SMark Murray x2 = XOR(x2,U8TO32_LITTLE(m + 8)); 177150890b0SMark Murray x3 = XOR(x3,U8TO32_LITTLE(m + 12)); 178150890b0SMark Murray x4 = XOR(x4,U8TO32_LITTLE(m + 16)); 179150890b0SMark Murray x5 = XOR(x5,U8TO32_LITTLE(m + 20)); 180150890b0SMark Murray x6 = XOR(x6,U8TO32_LITTLE(m + 24)); 181150890b0SMark Murray x7 = XOR(x7,U8TO32_LITTLE(m + 28)); 182150890b0SMark Murray x8 = XOR(x8,U8TO32_LITTLE(m + 32)); 183150890b0SMark Murray x9 = XOR(x9,U8TO32_LITTLE(m + 36)); 184150890b0SMark Murray x10 = XOR(x10,U8TO32_LITTLE(m + 40)); 185150890b0SMark Murray x11 = XOR(x11,U8TO32_LITTLE(m + 44)); 186150890b0SMark Murray x12 = XOR(x12,U8TO32_LITTLE(m + 48)); 187150890b0SMark Murray x13 = XOR(x13,U8TO32_LITTLE(m + 52)); 188150890b0SMark Murray x14 = XOR(x14,U8TO32_LITTLE(m + 56)); 189150890b0SMark Murray x15 = XOR(x15,U8TO32_LITTLE(m + 60)); 190c1e80940SXin LI #endif 191150890b0SMark Murray 192150890b0SMark Murray j12 = PLUSONE(j12); 193150890b0SMark Murray if (!j12) { 194150890b0SMark Murray j13 = PLUSONE(j13); 195150890b0SMark Murray /* stopping at 2^70 bytes per nonce is user's responsibility */ 196150890b0SMark Murray } 197150890b0SMark Murray 198150890b0SMark Murray U32TO8_LITTLE(c + 0,x0); 199150890b0SMark Murray U32TO8_LITTLE(c + 4,x1); 200150890b0SMark Murray U32TO8_LITTLE(c + 8,x2); 201150890b0SMark Murray U32TO8_LITTLE(c + 12,x3); 202150890b0SMark Murray U32TO8_LITTLE(c + 16,x4); 203150890b0SMark Murray U32TO8_LITTLE(c + 20,x5); 204150890b0SMark Murray U32TO8_LITTLE(c + 24,x6); 205150890b0SMark Murray U32TO8_LITTLE(c + 28,x7); 206150890b0SMark Murray U32TO8_LITTLE(c + 32,x8); 207150890b0SMark Murray U32TO8_LITTLE(c + 36,x9); 208150890b0SMark Murray U32TO8_LITTLE(c + 40,x10); 209150890b0SMark Murray U32TO8_LITTLE(c + 44,x11); 210150890b0SMark Murray U32TO8_LITTLE(c + 48,x12); 211150890b0SMark Murray U32TO8_LITTLE(c + 52,x13); 212150890b0SMark Murray U32TO8_LITTLE(c + 56,x14); 213150890b0SMark Murray U32TO8_LITTLE(c + 60,x15); 214150890b0SMark Murray 215150890b0SMark Murray if (bytes <= 64) { 216150890b0SMark Murray if (bytes < 64) { 217150890b0SMark Murray for (i = 0;i < bytes;++i) ctarget[i] = c[i]; 218150890b0SMark Murray } 219150890b0SMark Murray x->input[12] = j12; 220150890b0SMark Murray x->input[13] = j13; 221150890b0SMark Murray return; 222150890b0SMark Murray } 223150890b0SMark Murray bytes -= 64; 224150890b0SMark Murray c += 64; 225c1e80940SXin LI #ifndef KEYSTREAM_ONLY 226150890b0SMark Murray m += 64; 227c1e80940SXin LI #endif 228150890b0SMark Murray } 229150890b0SMark Murray } 230