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