xref: /netbsd-src/crypto/external/bsd/openssh/dist/chacha.c (revision a629fefc36f2e87b36355a611e948fafe62680b4)
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