19d12795fSRobert Mustacchi /*
29d12795fSRobert Mustacchi chacha-merged.c version 20080118
39d12795fSRobert Mustacchi D. J. Bernstein
49d12795fSRobert Mustacchi Public domain.
59d12795fSRobert Mustacchi */
69d12795fSRobert Mustacchi 
79d12795fSRobert Mustacchi /* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */
89d12795fSRobert Mustacchi 
99d12795fSRobert Mustacchi #include <chacha.h>
109d12795fSRobert Mustacchi #include <stddef.h>
119d12795fSRobert Mustacchi 
129d12795fSRobert Mustacchi typedef unsigned char u8;
139d12795fSRobert Mustacchi typedef unsigned int u32;
149d12795fSRobert Mustacchi typedef unsigned int u_int;
159d12795fSRobert Mustacchi 
169d12795fSRobert Mustacchi #define U8C(v) (v##U)
179d12795fSRobert Mustacchi #define U32C(v) (v##U)
189d12795fSRobert Mustacchi 
199d12795fSRobert Mustacchi #define U8V(v) ((u8)(v) & U8C(0xFF))
209d12795fSRobert Mustacchi #define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
219d12795fSRobert Mustacchi 
229d12795fSRobert Mustacchi #define ROTL32(v, n) \
239d12795fSRobert Mustacchi   (U32V((v) << (n)) | ((v) >> (32 - (n))))
249d12795fSRobert Mustacchi 
259d12795fSRobert Mustacchi #define U8TO32_LITTLE(p) \
269d12795fSRobert Mustacchi   (((u32)((p)[0])      ) | \
279d12795fSRobert Mustacchi    ((u32)((p)[1]) <<  8) | \
289d12795fSRobert Mustacchi    ((u32)((p)[2]) << 16) | \
299d12795fSRobert Mustacchi    ((u32)((p)[3]) << 24))
309d12795fSRobert Mustacchi 
319d12795fSRobert Mustacchi #define U32TO8_LITTLE(p, v) \
329d12795fSRobert Mustacchi   do { \
339d12795fSRobert Mustacchi     (p)[0] = U8V((v)      ); \
349d12795fSRobert Mustacchi     (p)[1] = U8V((v) >>  8); \
359d12795fSRobert Mustacchi     (p)[2] = U8V((v) >> 16); \
369d12795fSRobert Mustacchi     (p)[3] = U8V((v) >> 24); \
379d12795fSRobert Mustacchi   } while (0)
389d12795fSRobert Mustacchi 
399d12795fSRobert Mustacchi #define ROTATE(v,c) (ROTL32(v,c))
409d12795fSRobert Mustacchi #define XOR(v,w) ((v) ^ (w))
419d12795fSRobert Mustacchi #define PLUS(v,w) (U32V((v) + (w)))
429d12795fSRobert Mustacchi #define PLUSONE(v) (PLUS((v),1))
439d12795fSRobert Mustacchi 
449d12795fSRobert Mustacchi #define QUARTERROUND(a,b,c,d) \
459d12795fSRobert Mustacchi   a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
469d12795fSRobert Mustacchi   c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
479d12795fSRobert Mustacchi   a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
489d12795fSRobert Mustacchi   c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
499d12795fSRobert Mustacchi 
509d12795fSRobert Mustacchi static const char sigma[16] = "expand 32-byte k";
519d12795fSRobert Mustacchi static const char tau[16] = "expand 16-byte k";
529d12795fSRobert Mustacchi 
539d12795fSRobert Mustacchi void
chacha_keysetup(chacha_ctx_t * x,const u8 * k,u32 kbits,u32 ivbits __unused)54*4a38094cSToomas Soome chacha_keysetup(chacha_ctx_t *x, const u8 *k, u32 kbits, u32 ivbits __unused)
559d12795fSRobert Mustacchi {
569d12795fSRobert Mustacchi   const char *constants;
579d12795fSRobert Mustacchi 
589d12795fSRobert Mustacchi   x->chacha_input[4] = U8TO32_LITTLE(k + 0);
599d12795fSRobert Mustacchi   x->chacha_input[5] = U8TO32_LITTLE(k + 4);
609d12795fSRobert Mustacchi   x->chacha_input[6] = U8TO32_LITTLE(k + 8);
619d12795fSRobert Mustacchi   x->chacha_input[7] = U8TO32_LITTLE(k + 12);
629d12795fSRobert Mustacchi   if (kbits == 256) { /* recommended */
639d12795fSRobert Mustacchi     k += 16;
649d12795fSRobert Mustacchi     constants = sigma;
659d12795fSRobert Mustacchi   } else { /* kbits == 128 */
669d12795fSRobert Mustacchi     constants = tau;
679d12795fSRobert Mustacchi   }
689d12795fSRobert Mustacchi   x->chacha_input[8] = U8TO32_LITTLE(k + 0);
699d12795fSRobert Mustacchi   x->chacha_input[9] = U8TO32_LITTLE(k + 4);
709d12795fSRobert Mustacchi   x->chacha_input[10] = U8TO32_LITTLE(k + 8);
719d12795fSRobert Mustacchi   x->chacha_input[11] = U8TO32_LITTLE(k + 12);
729d12795fSRobert Mustacchi   x->chacha_input[0] = U8TO32_LITTLE(constants + 0);
739d12795fSRobert Mustacchi   x->chacha_input[1] = U8TO32_LITTLE(constants + 4);
749d12795fSRobert Mustacchi   x->chacha_input[2] = U8TO32_LITTLE(constants + 8);
759d12795fSRobert Mustacchi   x->chacha_input[3] = U8TO32_LITTLE(constants + 12);
769d12795fSRobert Mustacchi }
779d12795fSRobert Mustacchi 
789d12795fSRobert Mustacchi void
chacha_ivsetup(chacha_ctx_t * x,const u8 * iv)79*4a38094cSToomas Soome chacha_ivsetup(chacha_ctx_t *x, const u8 *iv)
809d12795fSRobert Mustacchi {
819d12795fSRobert Mustacchi   x->chacha_input[12] = 0;
829d12795fSRobert Mustacchi   x->chacha_input[13] = 0;
839d12795fSRobert Mustacchi   x->chacha_input[14] = U8TO32_LITTLE(iv + 0);
849d12795fSRobert Mustacchi   x->chacha_input[15] = U8TO32_LITTLE(iv + 4);
859d12795fSRobert Mustacchi }
869d12795fSRobert Mustacchi 
879d12795fSRobert Mustacchi void
chacha_encrypt_bytes(chacha_ctx_t * x,const u8 * m,u8 * c,u32 bytes)88*4a38094cSToomas Soome chacha_encrypt_bytes(chacha_ctx_t *x, const u8 *m, u8 *c, u32 bytes)
899d12795fSRobert Mustacchi {
909d12795fSRobert Mustacchi   u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
919d12795fSRobert Mustacchi   u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
929d12795fSRobert Mustacchi   u8 *ctarget = NULL;
939d12795fSRobert Mustacchi   u8 tmp[64];
949d12795fSRobert Mustacchi   u_int i;
959d12795fSRobert Mustacchi 
969d12795fSRobert Mustacchi   if (!bytes) return;
979d12795fSRobert Mustacchi 
989d12795fSRobert Mustacchi   j0 = x->chacha_input[0];
999d12795fSRobert Mustacchi   j1 = x->chacha_input[1];
1009d12795fSRobert Mustacchi   j2 = x->chacha_input[2];
1019d12795fSRobert Mustacchi   j3 = x->chacha_input[3];
1029d12795fSRobert Mustacchi   j4 = x->chacha_input[4];
1039d12795fSRobert Mustacchi   j5 = x->chacha_input[5];
1049d12795fSRobert Mustacchi   j6 = x->chacha_input[6];
1059d12795fSRobert Mustacchi   j7 = x->chacha_input[7];
1069d12795fSRobert Mustacchi   j8 = x->chacha_input[8];
1079d12795fSRobert Mustacchi   j9 = x->chacha_input[9];
1089d12795fSRobert Mustacchi   j10 = x->chacha_input[10];
1099d12795fSRobert Mustacchi   j11 = x->chacha_input[11];
1109d12795fSRobert Mustacchi   j12 = x->chacha_input[12];
1119d12795fSRobert Mustacchi   j13 = x->chacha_input[13];
1129d12795fSRobert Mustacchi   j14 = x->chacha_input[14];
1139d12795fSRobert Mustacchi   j15 = x->chacha_input[15];
1149d12795fSRobert Mustacchi 
1159d12795fSRobert Mustacchi   for (;;) {
1169d12795fSRobert Mustacchi     if (bytes < 64) {
1179d12795fSRobert Mustacchi       for (i = 0;i < bytes;++i) tmp[i] = m[i];
1189d12795fSRobert Mustacchi       m = tmp;
1199d12795fSRobert Mustacchi       ctarget = c;
1209d12795fSRobert Mustacchi       c = tmp;
1219d12795fSRobert Mustacchi     }
1229d12795fSRobert Mustacchi     x0 = j0;
1239d12795fSRobert Mustacchi     x1 = j1;
1249d12795fSRobert Mustacchi     x2 = j2;
1259d12795fSRobert Mustacchi     x3 = j3;
1269d12795fSRobert Mustacchi     x4 = j4;
1279d12795fSRobert Mustacchi     x5 = j5;
1289d12795fSRobert Mustacchi     x6 = j6;
1299d12795fSRobert Mustacchi     x7 = j7;
1309d12795fSRobert Mustacchi     x8 = j8;
1319d12795fSRobert Mustacchi     x9 = j9;
1329d12795fSRobert Mustacchi     x10 = j10;
1339d12795fSRobert Mustacchi     x11 = j11;
1349d12795fSRobert Mustacchi     x12 = j12;
1359d12795fSRobert Mustacchi     x13 = j13;
1369d12795fSRobert Mustacchi     x14 = j14;
1379d12795fSRobert Mustacchi     x15 = j15;
1389d12795fSRobert Mustacchi     for (i = 20;i > 0;i -= 2) {
1399d12795fSRobert Mustacchi       QUARTERROUND( x0, x4, x8,x12)
1409d12795fSRobert Mustacchi       QUARTERROUND( x1, x5, x9,x13)
1419d12795fSRobert Mustacchi       QUARTERROUND( x2, x6,x10,x14)
1429d12795fSRobert Mustacchi       QUARTERROUND( x3, x7,x11,x15)
1439d12795fSRobert Mustacchi       QUARTERROUND( x0, x5,x10,x15)
1449d12795fSRobert Mustacchi       QUARTERROUND( x1, x6,x11,x12)
1459d12795fSRobert Mustacchi       QUARTERROUND( x2, x7, x8,x13)
1469d12795fSRobert Mustacchi       QUARTERROUND( x3, x4, x9,x14)
1479d12795fSRobert Mustacchi     }
1489d12795fSRobert Mustacchi     x0 = PLUS(x0,j0);
1499d12795fSRobert Mustacchi     x1 = PLUS(x1,j1);
1509d12795fSRobert Mustacchi     x2 = PLUS(x2,j2);
1519d12795fSRobert Mustacchi     x3 = PLUS(x3,j3);
1529d12795fSRobert Mustacchi     x4 = PLUS(x4,j4);
1539d12795fSRobert Mustacchi     x5 = PLUS(x5,j5);
1549d12795fSRobert Mustacchi     x6 = PLUS(x6,j6);
1559d12795fSRobert Mustacchi     x7 = PLUS(x7,j7);
1569d12795fSRobert Mustacchi     x8 = PLUS(x8,j8);
1579d12795fSRobert Mustacchi     x9 = PLUS(x9,j9);
1589d12795fSRobert Mustacchi     x10 = PLUS(x10,j10);
1599d12795fSRobert Mustacchi     x11 = PLUS(x11,j11);
1609d12795fSRobert Mustacchi     x12 = PLUS(x12,j12);
1619d12795fSRobert Mustacchi     x13 = PLUS(x13,j13);
1629d12795fSRobert Mustacchi     x14 = PLUS(x14,j14);
1639d12795fSRobert Mustacchi     x15 = PLUS(x15,j15);
1649d12795fSRobert Mustacchi 
1659d12795fSRobert Mustacchi #ifndef KEYSTREAM_ONLY
1669d12795fSRobert Mustacchi     x0 = XOR(x0,U8TO32_LITTLE(m + 0));
1679d12795fSRobert Mustacchi     x1 = XOR(x1,U8TO32_LITTLE(m + 4));
1689d12795fSRobert Mustacchi     x2 = XOR(x2,U8TO32_LITTLE(m + 8));
1699d12795fSRobert Mustacchi     x3 = XOR(x3,U8TO32_LITTLE(m + 12));
1709d12795fSRobert Mustacchi     x4 = XOR(x4,U8TO32_LITTLE(m + 16));
1719d12795fSRobert Mustacchi     x5 = XOR(x5,U8TO32_LITTLE(m + 20));
1729d12795fSRobert Mustacchi     x6 = XOR(x6,U8TO32_LITTLE(m + 24));
1739d12795fSRobert Mustacchi     x7 = XOR(x7,U8TO32_LITTLE(m + 28));
1749d12795fSRobert Mustacchi     x8 = XOR(x8,U8TO32_LITTLE(m + 32));
1759d12795fSRobert Mustacchi     x9 = XOR(x9,U8TO32_LITTLE(m + 36));
1769d12795fSRobert Mustacchi     x10 = XOR(x10,U8TO32_LITTLE(m + 40));
1779d12795fSRobert Mustacchi     x11 = XOR(x11,U8TO32_LITTLE(m + 44));
1789d12795fSRobert Mustacchi     x12 = XOR(x12,U8TO32_LITTLE(m + 48));
1799d12795fSRobert Mustacchi     x13 = XOR(x13,U8TO32_LITTLE(m + 52));
1809d12795fSRobert Mustacchi     x14 = XOR(x14,U8TO32_LITTLE(m + 56));
1819d12795fSRobert Mustacchi     x15 = XOR(x15,U8TO32_LITTLE(m + 60));
1829d12795fSRobert Mustacchi #endif
1839d12795fSRobert Mustacchi 
1849d12795fSRobert Mustacchi     j12 = PLUSONE(j12);
1859d12795fSRobert Mustacchi     if (!j12) {
1869d12795fSRobert Mustacchi       j13 = PLUSONE(j13);
1879d12795fSRobert Mustacchi       /* stopping at 2^70 bytes per nonce is user's responsibility */
1889d12795fSRobert Mustacchi     }
1899d12795fSRobert Mustacchi 
1909d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 0,x0);
1919d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 4,x1);
1929d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 8,x2);
1939d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 12,x3);
1949d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 16,x4);
1959d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 20,x5);
1969d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 24,x6);
1979d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 28,x7);
1989d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 32,x8);
1999d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 36,x9);
2009d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 40,x10);
2019d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 44,x11);
2029d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 48,x12);
2039d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 52,x13);
2049d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 56,x14);
2059d12795fSRobert Mustacchi     U32TO8_LITTLE(c + 60,x15);
2069d12795fSRobert Mustacchi 
2079d12795fSRobert Mustacchi     if (bytes <= 64) {
2089d12795fSRobert Mustacchi       if (bytes < 64) {
2099d12795fSRobert Mustacchi         for (i = 0;i < bytes;++i) ctarget[i] = c[i];
2109d12795fSRobert Mustacchi       }
2119d12795fSRobert Mustacchi       x->chacha_input[12] = j12;
2129d12795fSRobert Mustacchi       x->chacha_input[13] = j13;
2139d12795fSRobert Mustacchi       return;
2149d12795fSRobert Mustacchi     }
2159d12795fSRobert Mustacchi     bytes -= 64;
2169d12795fSRobert Mustacchi     c += 64;
2179d12795fSRobert Mustacchi #ifndef KEYSTREAM_ONLY
2189d12795fSRobert Mustacchi     m += 64;
2199d12795fSRobert Mustacchi #endif
2209d12795fSRobert Mustacchi   }
2219d12795fSRobert Mustacchi }
222