10468feb28696751efcddada8de69a622afffdba8Elliott Hughes/* 20468feb28696751efcddada8de69a622afffdba8Elliott Hugheschacha-merged.c version 20080118 30468feb28696751efcddada8de69a622afffdba8Elliott HughesD. J. Bernstein 40468feb28696751efcddada8de69a622afffdba8Elliott HughesPublic domain. 50468feb28696751efcddada8de69a622afffdba8Elliott Hughes*/ 60468feb28696751efcddada8de69a622afffdba8Elliott Hughes 70468feb28696751efcddada8de69a622afffdba8Elliott Hughes/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */ 80468feb28696751efcddada8de69a622afffdba8Elliott Hughes 90468feb28696751efcddada8de69a622afffdba8Elliott Hughestypedef unsigned char u8; 100468feb28696751efcddada8de69a622afffdba8Elliott Hughestypedef unsigned int u32; 110468feb28696751efcddada8de69a622afffdba8Elliott Hughes 120468feb28696751efcddada8de69a622afffdba8Elliott Hughestypedef struct 130468feb28696751efcddada8de69a622afffdba8Elliott Hughes{ 140468feb28696751efcddada8de69a622afffdba8Elliott Hughes u32 input[16]; /* could be compressed */ 150468feb28696751efcddada8de69a622afffdba8Elliott Hughes} chacha_ctx; 160468feb28696751efcddada8de69a622afffdba8Elliott Hughes 170468feb28696751efcddada8de69a622afffdba8Elliott Hughes#define U8C(v) (v##U) 180468feb28696751efcddada8de69a622afffdba8Elliott Hughes#define U32C(v) (v##U) 190468feb28696751efcddada8de69a622afffdba8Elliott Hughes 200468feb28696751efcddada8de69a622afffdba8Elliott Hughes#define U8V(v) ((u8)(v) & U8C(0xFF)) 210468feb28696751efcddada8de69a622afffdba8Elliott Hughes#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) 220468feb28696751efcddada8de69a622afffdba8Elliott Hughes 230468feb28696751efcddada8de69a622afffdba8Elliott Hughes#define ROTL32(v, n) \ 240468feb28696751efcddada8de69a622afffdba8Elliott Hughes (U32V((v) << (n)) | ((v) >> (32 - (n)))) 250468feb28696751efcddada8de69a622afffdba8Elliott Hughes 260468feb28696751efcddada8de69a622afffdba8Elliott Hughes#define U8TO32_LITTLE(p) \ 270468feb28696751efcddada8de69a622afffdba8Elliott Hughes (((u32)((p)[0]) ) | \ 280468feb28696751efcddada8de69a622afffdba8Elliott Hughes ((u32)((p)[1]) << 8) | \ 290468feb28696751efcddada8de69a622afffdba8Elliott Hughes ((u32)((p)[2]) << 16) | \ 300468feb28696751efcddada8de69a622afffdba8Elliott Hughes ((u32)((p)[3]) << 24)) 310468feb28696751efcddada8de69a622afffdba8Elliott Hughes 320468feb28696751efcddada8de69a622afffdba8Elliott Hughes#define U32TO8_LITTLE(p, v) \ 330468feb28696751efcddada8de69a622afffdba8Elliott Hughes do { \ 340468feb28696751efcddada8de69a622afffdba8Elliott Hughes (p)[0] = U8V((v) ); \ 350468feb28696751efcddada8de69a622afffdba8Elliott Hughes (p)[1] = U8V((v) >> 8); \ 360468feb28696751efcddada8de69a622afffdba8Elliott Hughes (p)[2] = U8V((v) >> 16); \ 370468feb28696751efcddada8de69a622afffdba8Elliott Hughes (p)[3] = U8V((v) >> 24); \ 380468feb28696751efcddada8de69a622afffdba8Elliott Hughes } while (0) 390468feb28696751efcddada8de69a622afffdba8Elliott Hughes 400468feb28696751efcddada8de69a622afffdba8Elliott Hughes#define ROTATE(v,c) (ROTL32(v,c)) 410468feb28696751efcddada8de69a622afffdba8Elliott Hughes#define XOR(v,w) ((v) ^ (w)) 420468feb28696751efcddada8de69a622afffdba8Elliott Hughes#define PLUS(v,w) (U32V((v) + (w))) 430468feb28696751efcddada8de69a622afffdba8Elliott Hughes#define PLUSONE(v) (PLUS((v),1)) 440468feb28696751efcddada8de69a622afffdba8Elliott Hughes 450468feb28696751efcddada8de69a622afffdba8Elliott Hughes#define QUARTERROUND(a,b,c,d) \ 460468feb28696751efcddada8de69a622afffdba8Elliott Hughes a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ 470468feb28696751efcddada8de69a622afffdba8Elliott Hughes c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ 480468feb28696751efcddada8de69a622afffdba8Elliott Hughes a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ 490468feb28696751efcddada8de69a622afffdba8Elliott Hughes c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); 500468feb28696751efcddada8de69a622afffdba8Elliott Hughes 510468feb28696751efcddada8de69a622afffdba8Elliott Hughesstatic const char sigma[16] = "expand 32-byte k"; 520468feb28696751efcddada8de69a622afffdba8Elliott Hughesstatic const char tau[16] = "expand 16-byte k"; 530468feb28696751efcddada8de69a622afffdba8Elliott Hughes 540468feb28696751efcddada8de69a622afffdba8Elliott Hughesstatic void 550468feb28696751efcddada8de69a622afffdba8Elliott Hugheschacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits) 560468feb28696751efcddada8de69a622afffdba8Elliott Hughes{ 570468feb28696751efcddada8de69a622afffdba8Elliott Hughes const char *constants; 580468feb28696751efcddada8de69a622afffdba8Elliott Hughes 590468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[4] = U8TO32_LITTLE(k + 0); 600468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[5] = U8TO32_LITTLE(k + 4); 610468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[6] = U8TO32_LITTLE(k + 8); 620468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[7] = U8TO32_LITTLE(k + 12); 630468feb28696751efcddada8de69a622afffdba8Elliott Hughes if (kbits == 256) { /* recommended */ 640468feb28696751efcddada8de69a622afffdba8Elliott Hughes k += 16; 650468feb28696751efcddada8de69a622afffdba8Elliott Hughes constants = sigma; 660468feb28696751efcddada8de69a622afffdba8Elliott Hughes } else { /* kbits == 128 */ 670468feb28696751efcddada8de69a622afffdba8Elliott Hughes constants = tau; 680468feb28696751efcddada8de69a622afffdba8Elliott Hughes } 690468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[8] = U8TO32_LITTLE(k + 0); 700468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[9] = U8TO32_LITTLE(k + 4); 710468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[10] = U8TO32_LITTLE(k + 8); 720468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[11] = U8TO32_LITTLE(k + 12); 730468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[0] = U8TO32_LITTLE(constants + 0); 740468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[1] = U8TO32_LITTLE(constants + 4); 750468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[2] = U8TO32_LITTLE(constants + 8); 760468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[3] = U8TO32_LITTLE(constants + 12); 770468feb28696751efcddada8de69a622afffdba8Elliott Hughes} 780468feb28696751efcddada8de69a622afffdba8Elliott Hughes 790468feb28696751efcddada8de69a622afffdba8Elliott Hughesstatic void 800468feb28696751efcddada8de69a622afffdba8Elliott Hugheschacha_ivsetup(chacha_ctx *x,const u8 *iv) 810468feb28696751efcddada8de69a622afffdba8Elliott Hughes{ 820468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[12] = 0; 830468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[13] = 0; 840468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[14] = U8TO32_LITTLE(iv + 0); 850468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[15] = U8TO32_LITTLE(iv + 4); 860468feb28696751efcddada8de69a622afffdba8Elliott Hughes} 870468feb28696751efcddada8de69a622afffdba8Elliott Hughes 880468feb28696751efcddada8de69a622afffdba8Elliott Hughesstatic void 890468feb28696751efcddada8de69a622afffdba8Elliott Hugheschacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) 900468feb28696751efcddada8de69a622afffdba8Elliott Hughes{ 910468feb28696751efcddada8de69a622afffdba8Elliott Hughes u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; 920468feb28696751efcddada8de69a622afffdba8Elliott Hughes u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; 930468feb28696751efcddada8de69a622afffdba8Elliott Hughes u8 *ctarget = NULL; 940468feb28696751efcddada8de69a622afffdba8Elliott Hughes u8 tmp[64]; 950468feb28696751efcddada8de69a622afffdba8Elliott Hughes u_int i; 960468feb28696751efcddada8de69a622afffdba8Elliott Hughes 970468feb28696751efcddada8de69a622afffdba8Elliott Hughes if (!bytes) return; 980468feb28696751efcddada8de69a622afffdba8Elliott Hughes 990468feb28696751efcddada8de69a622afffdba8Elliott Hughes j0 = x->input[0]; 1000468feb28696751efcddada8de69a622afffdba8Elliott Hughes j1 = x->input[1]; 1010468feb28696751efcddada8de69a622afffdba8Elliott Hughes j2 = x->input[2]; 1020468feb28696751efcddada8de69a622afffdba8Elliott Hughes j3 = x->input[3]; 1030468feb28696751efcddada8de69a622afffdba8Elliott Hughes j4 = x->input[4]; 1040468feb28696751efcddada8de69a622afffdba8Elliott Hughes j5 = x->input[5]; 1050468feb28696751efcddada8de69a622afffdba8Elliott Hughes j6 = x->input[6]; 1060468feb28696751efcddada8de69a622afffdba8Elliott Hughes j7 = x->input[7]; 1070468feb28696751efcddada8de69a622afffdba8Elliott Hughes j8 = x->input[8]; 1080468feb28696751efcddada8de69a622afffdba8Elliott Hughes j9 = x->input[9]; 1090468feb28696751efcddada8de69a622afffdba8Elliott Hughes j10 = x->input[10]; 1100468feb28696751efcddada8de69a622afffdba8Elliott Hughes j11 = x->input[11]; 1110468feb28696751efcddada8de69a622afffdba8Elliott Hughes j12 = x->input[12]; 1120468feb28696751efcddada8de69a622afffdba8Elliott Hughes j13 = x->input[13]; 1130468feb28696751efcddada8de69a622afffdba8Elliott Hughes j14 = x->input[14]; 1140468feb28696751efcddada8de69a622afffdba8Elliott Hughes j15 = x->input[15]; 1150468feb28696751efcddada8de69a622afffdba8Elliott Hughes 1160468feb28696751efcddada8de69a622afffdba8Elliott Hughes for (;;) { 1170468feb28696751efcddada8de69a622afffdba8Elliott Hughes if (bytes < 64) { 1180468feb28696751efcddada8de69a622afffdba8Elliott Hughes for (i = 0;i < bytes;++i) tmp[i] = m[i]; 1190468feb28696751efcddada8de69a622afffdba8Elliott Hughes m = tmp; 1200468feb28696751efcddada8de69a622afffdba8Elliott Hughes ctarget = c; 1210468feb28696751efcddada8de69a622afffdba8Elliott Hughes c = tmp; 1220468feb28696751efcddada8de69a622afffdba8Elliott Hughes } 1230468feb28696751efcddada8de69a622afffdba8Elliott Hughes x0 = j0; 1240468feb28696751efcddada8de69a622afffdba8Elliott Hughes x1 = j1; 1250468feb28696751efcddada8de69a622afffdba8Elliott Hughes x2 = j2; 1260468feb28696751efcddada8de69a622afffdba8Elliott Hughes x3 = j3; 1270468feb28696751efcddada8de69a622afffdba8Elliott Hughes x4 = j4; 1280468feb28696751efcddada8de69a622afffdba8Elliott Hughes x5 = j5; 1290468feb28696751efcddada8de69a622afffdba8Elliott Hughes x6 = j6; 1300468feb28696751efcddada8de69a622afffdba8Elliott Hughes x7 = j7; 1310468feb28696751efcddada8de69a622afffdba8Elliott Hughes x8 = j8; 1320468feb28696751efcddada8de69a622afffdba8Elliott Hughes x9 = j9; 1330468feb28696751efcddada8de69a622afffdba8Elliott Hughes x10 = j10; 1340468feb28696751efcddada8de69a622afffdba8Elliott Hughes x11 = j11; 1350468feb28696751efcddada8de69a622afffdba8Elliott Hughes x12 = j12; 1360468feb28696751efcddada8de69a622afffdba8Elliott Hughes x13 = j13; 1370468feb28696751efcddada8de69a622afffdba8Elliott Hughes x14 = j14; 1380468feb28696751efcddada8de69a622afffdba8Elliott Hughes x15 = j15; 1390468feb28696751efcddada8de69a622afffdba8Elliott Hughes for (i = 20;i > 0;i -= 2) { 1400468feb28696751efcddada8de69a622afffdba8Elliott Hughes QUARTERROUND( x0, x4, x8,x12) 1410468feb28696751efcddada8de69a622afffdba8Elliott Hughes QUARTERROUND( x1, x5, x9,x13) 1420468feb28696751efcddada8de69a622afffdba8Elliott Hughes QUARTERROUND( x2, x6,x10,x14) 1430468feb28696751efcddada8de69a622afffdba8Elliott Hughes QUARTERROUND( x3, x7,x11,x15) 1440468feb28696751efcddada8de69a622afffdba8Elliott Hughes QUARTERROUND( x0, x5,x10,x15) 1450468feb28696751efcddada8de69a622afffdba8Elliott Hughes QUARTERROUND( x1, x6,x11,x12) 1460468feb28696751efcddada8de69a622afffdba8Elliott Hughes QUARTERROUND( x2, x7, x8,x13) 1470468feb28696751efcddada8de69a622afffdba8Elliott Hughes QUARTERROUND( x3, x4, x9,x14) 1480468feb28696751efcddada8de69a622afffdba8Elliott Hughes } 1490468feb28696751efcddada8de69a622afffdba8Elliott Hughes x0 = PLUS(x0,j0); 1500468feb28696751efcddada8de69a622afffdba8Elliott Hughes x1 = PLUS(x1,j1); 1510468feb28696751efcddada8de69a622afffdba8Elliott Hughes x2 = PLUS(x2,j2); 1520468feb28696751efcddada8de69a622afffdba8Elliott Hughes x3 = PLUS(x3,j3); 1530468feb28696751efcddada8de69a622afffdba8Elliott Hughes x4 = PLUS(x4,j4); 1540468feb28696751efcddada8de69a622afffdba8Elliott Hughes x5 = PLUS(x5,j5); 1550468feb28696751efcddada8de69a622afffdba8Elliott Hughes x6 = PLUS(x6,j6); 1560468feb28696751efcddada8de69a622afffdba8Elliott Hughes x7 = PLUS(x7,j7); 1570468feb28696751efcddada8de69a622afffdba8Elliott Hughes x8 = PLUS(x8,j8); 1580468feb28696751efcddada8de69a622afffdba8Elliott Hughes x9 = PLUS(x9,j9); 1590468feb28696751efcddada8de69a622afffdba8Elliott Hughes x10 = PLUS(x10,j10); 1600468feb28696751efcddada8de69a622afffdba8Elliott Hughes x11 = PLUS(x11,j11); 1610468feb28696751efcddada8de69a622afffdba8Elliott Hughes x12 = PLUS(x12,j12); 1620468feb28696751efcddada8de69a622afffdba8Elliott Hughes x13 = PLUS(x13,j13); 1630468feb28696751efcddada8de69a622afffdba8Elliott Hughes x14 = PLUS(x14,j14); 1640468feb28696751efcddada8de69a622afffdba8Elliott Hughes x15 = PLUS(x15,j15); 1650468feb28696751efcddada8de69a622afffdba8Elliott Hughes 1660468feb28696751efcddada8de69a622afffdba8Elliott Hughes#ifndef KEYSTREAM_ONLY 1670468feb28696751efcddada8de69a622afffdba8Elliott Hughes x0 = XOR(x0,U8TO32_LITTLE(m + 0)); 1680468feb28696751efcddada8de69a622afffdba8Elliott Hughes x1 = XOR(x1,U8TO32_LITTLE(m + 4)); 1690468feb28696751efcddada8de69a622afffdba8Elliott Hughes x2 = XOR(x2,U8TO32_LITTLE(m + 8)); 1700468feb28696751efcddada8de69a622afffdba8Elliott Hughes x3 = XOR(x3,U8TO32_LITTLE(m + 12)); 1710468feb28696751efcddada8de69a622afffdba8Elliott Hughes x4 = XOR(x4,U8TO32_LITTLE(m + 16)); 1720468feb28696751efcddada8de69a622afffdba8Elliott Hughes x5 = XOR(x5,U8TO32_LITTLE(m + 20)); 1730468feb28696751efcddada8de69a622afffdba8Elliott Hughes x6 = XOR(x6,U8TO32_LITTLE(m + 24)); 1740468feb28696751efcddada8de69a622afffdba8Elliott Hughes x7 = XOR(x7,U8TO32_LITTLE(m + 28)); 1750468feb28696751efcddada8de69a622afffdba8Elliott Hughes x8 = XOR(x8,U8TO32_LITTLE(m + 32)); 1760468feb28696751efcddada8de69a622afffdba8Elliott Hughes x9 = XOR(x9,U8TO32_LITTLE(m + 36)); 1770468feb28696751efcddada8de69a622afffdba8Elliott Hughes x10 = XOR(x10,U8TO32_LITTLE(m + 40)); 1780468feb28696751efcddada8de69a622afffdba8Elliott Hughes x11 = XOR(x11,U8TO32_LITTLE(m + 44)); 1790468feb28696751efcddada8de69a622afffdba8Elliott Hughes x12 = XOR(x12,U8TO32_LITTLE(m + 48)); 1800468feb28696751efcddada8de69a622afffdba8Elliott Hughes x13 = XOR(x13,U8TO32_LITTLE(m + 52)); 1810468feb28696751efcddada8de69a622afffdba8Elliott Hughes x14 = XOR(x14,U8TO32_LITTLE(m + 56)); 1820468feb28696751efcddada8de69a622afffdba8Elliott Hughes x15 = XOR(x15,U8TO32_LITTLE(m + 60)); 1830468feb28696751efcddada8de69a622afffdba8Elliott Hughes#endif 1840468feb28696751efcddada8de69a622afffdba8Elliott Hughes 1850468feb28696751efcddada8de69a622afffdba8Elliott Hughes j12 = PLUSONE(j12); 1860468feb28696751efcddada8de69a622afffdba8Elliott Hughes if (!j12) { 1870468feb28696751efcddada8de69a622afffdba8Elliott Hughes j13 = PLUSONE(j13); 1880468feb28696751efcddada8de69a622afffdba8Elliott Hughes /* stopping at 2^70 bytes per nonce is user's responsibility */ 1890468feb28696751efcddada8de69a622afffdba8Elliott Hughes } 1900468feb28696751efcddada8de69a622afffdba8Elliott Hughes 1910468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 0,x0); 1920468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 4,x1); 1930468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 8,x2); 1940468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 12,x3); 1950468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 16,x4); 1960468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 20,x5); 1970468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 24,x6); 1980468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 28,x7); 1990468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 32,x8); 2000468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 36,x9); 2010468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 40,x10); 2020468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 44,x11); 2030468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 48,x12); 2040468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 52,x13); 2050468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 56,x14); 2060468feb28696751efcddada8de69a622afffdba8Elliott Hughes U32TO8_LITTLE(c + 60,x15); 2070468feb28696751efcddada8de69a622afffdba8Elliott Hughes 2080468feb28696751efcddada8de69a622afffdba8Elliott Hughes if (bytes <= 64) { 2090468feb28696751efcddada8de69a622afffdba8Elliott Hughes if (bytes < 64) { 2100468feb28696751efcddada8de69a622afffdba8Elliott Hughes for (i = 0;i < bytes;++i) ctarget[i] = c[i]; 2110468feb28696751efcddada8de69a622afffdba8Elliott Hughes } 2120468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[12] = j12; 2130468feb28696751efcddada8de69a622afffdba8Elliott Hughes x->input[13] = j13; 2140468feb28696751efcddada8de69a622afffdba8Elliott Hughes return; 2150468feb28696751efcddada8de69a622afffdba8Elliott Hughes } 2160468feb28696751efcddada8de69a622afffdba8Elliott Hughes bytes -= 64; 2170468feb28696751efcddada8de69a622afffdba8Elliott Hughes c += 64; 2180468feb28696751efcddada8de69a622afffdba8Elliott Hughes#ifndef KEYSTREAM_ONLY 2190468feb28696751efcddada8de69a622afffdba8Elliott Hughes m += 64; 2200468feb28696751efcddada8de69a622afffdba8Elliott Hughes#endif 2210468feb28696751efcddada8de69a622afffdba8Elliott Hughes } 2220468feb28696751efcddada8de69a622afffdba8Elliott Hughes} 223