1*a629fefcSchristos /* $OpenBSD: chacha.c,v 1.2 2023/07/17 05:26:38 djm Exp $ */
25484a5efSchristos /*
35484a5efSchristos chacha-merged.c version 20080118
45484a5efSchristos D. J. Bernstein
55484a5efSchristos Public domain.
65484a5efSchristos */
75484a5efSchristos
88a4530f9Schristos #include "includes.h"
9*a629fefcSchristos __RCSID("$NetBSD: chacha.c,v 1.6 2023/10/25 20:19:57 christos Exp $");
108a4530f9Schristos
118a4530f9Schristos #include <stdio.h> /* for NULL */
125484a5efSchristos #include "chacha.h"
135484a5efSchristos
145484a5efSchristos typedef unsigned char u8;
155484a5efSchristos typedef unsigned int u32;
165484a5efSchristos
175484a5efSchristos typedef struct chacha_ctx chacha_ctx;
185484a5efSchristos
195484a5efSchristos #define U8C(v) (v##U)
205484a5efSchristos #define U32C(v) (v##U)
215484a5efSchristos
225484a5efSchristos #define U8V(v) ((u8)(v) & U8C(0xFF))
235484a5efSchristos #define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
245484a5efSchristos
255484a5efSchristos #define ROTL32(v, n) \
265484a5efSchristos (U32V((v) << (n)) | ((v) >> (32 - (n))))
275484a5efSchristos
285484a5efSchristos #define U8TO32_LITTLE(p) \
295484a5efSchristos (((u32)((p)[0]) ) | \
305484a5efSchristos ((u32)((p)[1]) << 8) | \
315484a5efSchristos ((u32)((p)[2]) << 16) | \
325484a5efSchristos ((u32)((p)[3]) << 24))
335484a5efSchristos
345484a5efSchristos #define U32TO8_LITTLE(p, v) \
355484a5efSchristos do { \
365484a5efSchristos (p)[0] = U8V((v) ); \
375484a5efSchristos (p)[1] = U8V((v) >> 8); \
385484a5efSchristos (p)[2] = U8V((v) >> 16); \
395484a5efSchristos (p)[3] = U8V((v) >> 24); \
405484a5efSchristos } while (0)
415484a5efSchristos
425484a5efSchristos #define ROTATE(v,c) (ROTL32(v,c))
435484a5efSchristos #define XOR(v,w) ((v) ^ (w))
445484a5efSchristos #define PLUS(v,w) (U32V((v) + (w)))
455484a5efSchristos #define PLUSONE(v) (PLUS((v),1))
465484a5efSchristos
475484a5efSchristos #define QUARTERROUND(a,b,c,d) \
485484a5efSchristos a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
495484a5efSchristos c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
505484a5efSchristos a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
515484a5efSchristos c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
525484a5efSchristos
535484a5efSchristos static const char sigma[16] = "expand 32-byte k";
545484a5efSchristos static const char tau[16] = "expand 16-byte k";
555484a5efSchristos
565484a5efSchristos void
chacha_keysetup(chacha_ctx * x,const u8 * k,u32 kbits)575484a5efSchristos chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits)
585484a5efSchristos {
595484a5efSchristos const char *constants;
605484a5efSchristos
615484a5efSchristos x->input[4] = U8TO32_LITTLE(k + 0);
625484a5efSchristos x->input[5] = U8TO32_LITTLE(k + 4);
635484a5efSchristos x->input[6] = U8TO32_LITTLE(k + 8);
645484a5efSchristos x->input[7] = U8TO32_LITTLE(k + 12);
655484a5efSchristos if (kbits == 256) { /* recommended */
665484a5efSchristos k += 16;
675484a5efSchristos constants = sigma;
685484a5efSchristos } else { /* kbits == 128 */
695484a5efSchristos constants = tau;
705484a5efSchristos }
715484a5efSchristos x->input[8] = U8TO32_LITTLE(k + 0);
725484a5efSchristos x->input[9] = U8TO32_LITTLE(k + 4);
735484a5efSchristos x->input[10] = U8TO32_LITTLE(k + 8);
745484a5efSchristos x->input[11] = U8TO32_LITTLE(k + 12);
755484a5efSchristos x->input[0] = U8TO32_LITTLE(constants + 0);
765484a5efSchristos x->input[1] = U8TO32_LITTLE(constants + 4);
775484a5efSchristos x->input[2] = U8TO32_LITTLE(constants + 8);
785484a5efSchristos x->input[3] = U8TO32_LITTLE(constants + 12);
795484a5efSchristos }
805484a5efSchristos
815484a5efSchristos void
chacha_ivsetup(chacha_ctx * x,const u8 * iv,const u8 * counter)825484a5efSchristos chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter)
835484a5efSchristos {
845484a5efSchristos x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
855484a5efSchristos x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4);
865484a5efSchristos x->input[14] = U8TO32_LITTLE(iv + 0);
875484a5efSchristos x->input[15] = U8TO32_LITTLE(iv + 4);
885484a5efSchristos }
895484a5efSchristos
905484a5efSchristos void
chacha_encrypt_bytes(chacha_ctx * x,const u8 * m,u8 * c,u32 bytes)915484a5efSchristos chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
925484a5efSchristos {
935484a5efSchristos u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
945484a5efSchristos u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
955484a5efSchristos u8 *ctarget = NULL;
965484a5efSchristos u8 tmp[64];
975484a5efSchristos u_int i;
985484a5efSchristos
995484a5efSchristos if (!bytes) return;
1005484a5efSchristos
1015484a5efSchristos j0 = x->input[0];
1025484a5efSchristos j1 = x->input[1];
1035484a5efSchristos j2 = x->input[2];
1045484a5efSchristos j3 = x->input[3];
1055484a5efSchristos j4 = x->input[4];
1065484a5efSchristos j5 = x->input[5];
1075484a5efSchristos j6 = x->input[6];
1085484a5efSchristos j7 = x->input[7];
1095484a5efSchristos j8 = x->input[8];
1105484a5efSchristos j9 = x->input[9];
1115484a5efSchristos j10 = x->input[10];
1125484a5efSchristos j11 = x->input[11];
1135484a5efSchristos j12 = x->input[12];
1145484a5efSchristos j13 = x->input[13];
1155484a5efSchristos j14 = x->input[14];
1165484a5efSchristos j15 = x->input[15];
1175484a5efSchristos
1185484a5efSchristos for (;;) {
1195484a5efSchristos if (bytes < 64) {
1205484a5efSchristos for (i = 0;i < bytes;++i) tmp[i] = m[i];
1215484a5efSchristos m = tmp;
1225484a5efSchristos ctarget = c;
1235484a5efSchristos c = tmp;
1245484a5efSchristos }
1255484a5efSchristos x0 = j0;
1265484a5efSchristos x1 = j1;
1275484a5efSchristos x2 = j2;
1285484a5efSchristos x3 = j3;
1295484a5efSchristos x4 = j4;
1305484a5efSchristos x5 = j5;
1315484a5efSchristos x6 = j6;
1325484a5efSchristos x7 = j7;
1335484a5efSchristos x8 = j8;
1345484a5efSchristos x9 = j9;
1355484a5efSchristos x10 = j10;
1365484a5efSchristos x11 = j11;
1375484a5efSchristos x12 = j12;
1385484a5efSchristos x13 = j13;
1395484a5efSchristos x14 = j14;
1405484a5efSchristos x15 = j15;
1415484a5efSchristos for (i = 20;i > 0;i -= 2) {
1425484a5efSchristos QUARTERROUND( x0, x4, x8,x12)
1435484a5efSchristos QUARTERROUND( x1, x5, x9,x13)
1445484a5efSchristos QUARTERROUND( x2, x6,x10,x14)
1455484a5efSchristos QUARTERROUND( x3, x7,x11,x15)
1465484a5efSchristos QUARTERROUND( x0, x5,x10,x15)
1475484a5efSchristos QUARTERROUND( x1, x6,x11,x12)
1485484a5efSchristos QUARTERROUND( x2, x7, x8,x13)
1495484a5efSchristos QUARTERROUND( x3, x4, x9,x14)
1505484a5efSchristos }
1515484a5efSchristos x0 = PLUS(x0,j0);
1525484a5efSchristos x1 = PLUS(x1,j1);
1535484a5efSchristos x2 = PLUS(x2,j2);
1545484a5efSchristos x3 = PLUS(x3,j3);
1555484a5efSchristos x4 = PLUS(x4,j4);
1565484a5efSchristos x5 = PLUS(x5,j5);
1575484a5efSchristos x6 = PLUS(x6,j6);
1585484a5efSchristos x7 = PLUS(x7,j7);
1595484a5efSchristos x8 = PLUS(x8,j8);
1605484a5efSchristos x9 = PLUS(x9,j9);
1615484a5efSchristos x10 = PLUS(x10,j10);
1625484a5efSchristos x11 = PLUS(x11,j11);
1635484a5efSchristos x12 = PLUS(x12,j12);
1645484a5efSchristos x13 = PLUS(x13,j13);
1655484a5efSchristos x14 = PLUS(x14,j14);
1665484a5efSchristos x15 = PLUS(x15,j15);
1675484a5efSchristos
1685484a5efSchristos x0 = XOR(x0,U8TO32_LITTLE(m + 0));
1695484a5efSchristos x1 = XOR(x1,U8TO32_LITTLE(m + 4));
1705484a5efSchristos x2 = XOR(x2,U8TO32_LITTLE(m + 8));
1715484a5efSchristos x3 = XOR(x3,U8TO32_LITTLE(m + 12));
1725484a5efSchristos x4 = XOR(x4,U8TO32_LITTLE(m + 16));
1735484a5efSchristos x5 = XOR(x5,U8TO32_LITTLE(m + 20));
1745484a5efSchristos x6 = XOR(x6,U8TO32_LITTLE(m + 24));
1755484a5efSchristos x7 = XOR(x7,U8TO32_LITTLE(m + 28));
1765484a5efSchristos x8 = XOR(x8,U8TO32_LITTLE(m + 32));
1775484a5efSchristos x9 = XOR(x9,U8TO32_LITTLE(m + 36));
1785484a5efSchristos x10 = XOR(x10,U8TO32_LITTLE(m + 40));
1795484a5efSchristos x11 = XOR(x11,U8TO32_LITTLE(m + 44));
1805484a5efSchristos x12 = XOR(x12,U8TO32_LITTLE(m + 48));
1815484a5efSchristos x13 = XOR(x13,U8TO32_LITTLE(m + 52));
1825484a5efSchristos x14 = XOR(x14,U8TO32_LITTLE(m + 56));
1835484a5efSchristos x15 = XOR(x15,U8TO32_LITTLE(m + 60));
1845484a5efSchristos
1855484a5efSchristos j12 = PLUSONE(j12);
1865484a5efSchristos if (!j12) {
1875484a5efSchristos j13 = PLUSONE(j13);
1885484a5efSchristos /* stopping at 2^70 bytes per nonce is user's responsibility */
1895484a5efSchristos }
1905484a5efSchristos
1915484a5efSchristos U32TO8_LITTLE(c + 0,x0);
1925484a5efSchristos U32TO8_LITTLE(c + 4,x1);
1935484a5efSchristos U32TO8_LITTLE(c + 8,x2);
1945484a5efSchristos U32TO8_LITTLE(c + 12,x3);
1955484a5efSchristos U32TO8_LITTLE(c + 16,x4);
1965484a5efSchristos U32TO8_LITTLE(c + 20,x5);
1975484a5efSchristos U32TO8_LITTLE(c + 24,x6);
1985484a5efSchristos U32TO8_LITTLE(c + 28,x7);
1995484a5efSchristos U32TO8_LITTLE(c + 32,x8);
2005484a5efSchristos U32TO8_LITTLE(c + 36,x9);
2015484a5efSchristos U32TO8_LITTLE(c + 40,x10);
2025484a5efSchristos U32TO8_LITTLE(c + 44,x11);
2035484a5efSchristos U32TO8_LITTLE(c + 48,x12);
2045484a5efSchristos U32TO8_LITTLE(c + 52,x13);
2055484a5efSchristos U32TO8_LITTLE(c + 56,x14);
2065484a5efSchristos U32TO8_LITTLE(c + 60,x15);
2075484a5efSchristos
2085484a5efSchristos if (bytes <= 64) {
2095484a5efSchristos if (bytes < 64) {
2105484a5efSchristos for (i = 0;i < bytes;++i) ctarget[i] = c[i];
2115484a5efSchristos }
2125484a5efSchristos x->input[12] = j12;
2135484a5efSchristos x->input[13] = j13;
2145484a5efSchristos return;
2155484a5efSchristos }
2165484a5efSchristos bytes -= 64;
2175484a5efSchristos c += 64;
2185484a5efSchristos m += 64;
2195484a5efSchristos }
2205484a5efSchristos }
221