1*ba1276acSMatthew Dillon /* $OpenBSD: chacha.c,v 1.2 2023/07/17 05:26:38 djm Exp $ */
236e94dc5SPeter Avalos /*
336e94dc5SPeter Avalos chacha-merged.c version 20080118
436e94dc5SPeter Avalos D. J. Bernstein
536e94dc5SPeter Avalos Public domain.
636e94dc5SPeter Avalos */
736e94dc5SPeter Avalos
836e94dc5SPeter Avalos #include "includes.h"
936e94dc5SPeter Avalos
1036e94dc5SPeter Avalos #include "chacha.h"
1136e94dc5SPeter Avalos
1236e94dc5SPeter Avalos typedef unsigned char u8;
1336e94dc5SPeter Avalos typedef unsigned int u32;
1436e94dc5SPeter Avalos
1536e94dc5SPeter Avalos typedef struct chacha_ctx chacha_ctx;
1636e94dc5SPeter Avalos
1736e94dc5SPeter Avalos #define U8C(v) (v##U)
1836e94dc5SPeter Avalos #define U32C(v) (v##U)
1936e94dc5SPeter Avalos
2036e94dc5SPeter Avalos #define U8V(v) ((u8)(v) & U8C(0xFF))
2136e94dc5SPeter Avalos #define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
2236e94dc5SPeter Avalos
2336e94dc5SPeter Avalos #define ROTL32(v, n) \
2436e94dc5SPeter Avalos (U32V((v) << (n)) | ((v) >> (32 - (n))))
2536e94dc5SPeter Avalos
2636e94dc5SPeter Avalos #define U8TO32_LITTLE(p) \
2736e94dc5SPeter Avalos (((u32)((p)[0]) ) | \
2836e94dc5SPeter Avalos ((u32)((p)[1]) << 8) | \
2936e94dc5SPeter Avalos ((u32)((p)[2]) << 16) | \
3036e94dc5SPeter Avalos ((u32)((p)[3]) << 24))
3136e94dc5SPeter Avalos
3236e94dc5SPeter Avalos #define U32TO8_LITTLE(p, v) \
3336e94dc5SPeter Avalos do { \
3436e94dc5SPeter Avalos (p)[0] = U8V((v) ); \
3536e94dc5SPeter Avalos (p)[1] = U8V((v) >> 8); \
3636e94dc5SPeter Avalos (p)[2] = U8V((v) >> 16); \
3736e94dc5SPeter Avalos (p)[3] = U8V((v) >> 24); \
3836e94dc5SPeter Avalos } while (0)
3936e94dc5SPeter Avalos
4036e94dc5SPeter Avalos #define ROTATE(v,c) (ROTL32(v,c))
4136e94dc5SPeter Avalos #define XOR(v,w) ((v) ^ (w))
4236e94dc5SPeter Avalos #define PLUS(v,w) (U32V((v) + (w)))
4336e94dc5SPeter Avalos #define PLUSONE(v) (PLUS((v),1))
4436e94dc5SPeter Avalos
4536e94dc5SPeter Avalos #define QUARTERROUND(a,b,c,d) \
4636e94dc5SPeter Avalos a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
4736e94dc5SPeter Avalos c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
4836e94dc5SPeter Avalos a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
4936e94dc5SPeter Avalos c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
5036e94dc5SPeter Avalos
5136e94dc5SPeter Avalos static const char sigma[16] = "expand 32-byte k";
5236e94dc5SPeter Avalos static const char tau[16] = "expand 16-byte k";
5336e94dc5SPeter Avalos
5436e94dc5SPeter Avalos void
chacha_keysetup(chacha_ctx * x,const u8 * k,u32 kbits)5536e94dc5SPeter Avalos chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits)
5636e94dc5SPeter Avalos {
5736e94dc5SPeter Avalos const char *constants;
5836e94dc5SPeter Avalos
5936e94dc5SPeter Avalos x->input[4] = U8TO32_LITTLE(k + 0);
6036e94dc5SPeter Avalos x->input[5] = U8TO32_LITTLE(k + 4);
6136e94dc5SPeter Avalos x->input[6] = U8TO32_LITTLE(k + 8);
6236e94dc5SPeter Avalos x->input[7] = U8TO32_LITTLE(k + 12);
6336e94dc5SPeter Avalos if (kbits == 256) { /* recommended */
6436e94dc5SPeter Avalos k += 16;
6536e94dc5SPeter Avalos constants = sigma;
6636e94dc5SPeter Avalos } else { /* kbits == 128 */
6736e94dc5SPeter Avalos constants = tau;
6836e94dc5SPeter Avalos }
6936e94dc5SPeter Avalos x->input[8] = U8TO32_LITTLE(k + 0);
7036e94dc5SPeter Avalos x->input[9] = U8TO32_LITTLE(k + 4);
7136e94dc5SPeter Avalos x->input[10] = U8TO32_LITTLE(k + 8);
7236e94dc5SPeter Avalos x->input[11] = U8TO32_LITTLE(k + 12);
7336e94dc5SPeter Avalos x->input[0] = U8TO32_LITTLE(constants + 0);
7436e94dc5SPeter Avalos x->input[1] = U8TO32_LITTLE(constants + 4);
7536e94dc5SPeter Avalos x->input[2] = U8TO32_LITTLE(constants + 8);
7636e94dc5SPeter Avalos x->input[3] = U8TO32_LITTLE(constants + 12);
7736e94dc5SPeter Avalos }
7836e94dc5SPeter Avalos
7936e94dc5SPeter Avalos void
chacha_ivsetup(chacha_ctx * x,const u8 * iv,const u8 * counter)8036e94dc5SPeter Avalos chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter)
8136e94dc5SPeter Avalos {
8236e94dc5SPeter Avalos x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
8336e94dc5SPeter Avalos x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4);
8436e94dc5SPeter Avalos x->input[14] = U8TO32_LITTLE(iv + 0);
8536e94dc5SPeter Avalos x->input[15] = U8TO32_LITTLE(iv + 4);
8636e94dc5SPeter Avalos }
8736e94dc5SPeter Avalos
8836e94dc5SPeter Avalos void
chacha_encrypt_bytes(chacha_ctx * x,const u8 * m,u8 * c,u32 bytes)8936e94dc5SPeter Avalos chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
9036e94dc5SPeter Avalos {
9136e94dc5SPeter Avalos u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
9236e94dc5SPeter Avalos u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
9336e94dc5SPeter Avalos u8 *ctarget = NULL;
9436e94dc5SPeter Avalos u8 tmp[64];
9536e94dc5SPeter Avalos u_int i;
9636e94dc5SPeter Avalos
9736e94dc5SPeter Avalos if (!bytes) return;
9836e94dc5SPeter Avalos
9936e94dc5SPeter Avalos j0 = x->input[0];
10036e94dc5SPeter Avalos j1 = x->input[1];
10136e94dc5SPeter Avalos j2 = x->input[2];
10236e94dc5SPeter Avalos j3 = x->input[3];
10336e94dc5SPeter Avalos j4 = x->input[4];
10436e94dc5SPeter Avalos j5 = x->input[5];
10536e94dc5SPeter Avalos j6 = x->input[6];
10636e94dc5SPeter Avalos j7 = x->input[7];
10736e94dc5SPeter Avalos j8 = x->input[8];
10836e94dc5SPeter Avalos j9 = x->input[9];
10936e94dc5SPeter Avalos j10 = x->input[10];
11036e94dc5SPeter Avalos j11 = x->input[11];
11136e94dc5SPeter Avalos j12 = x->input[12];
11236e94dc5SPeter Avalos j13 = x->input[13];
11336e94dc5SPeter Avalos j14 = x->input[14];
11436e94dc5SPeter Avalos j15 = x->input[15];
11536e94dc5SPeter Avalos
11636e94dc5SPeter Avalos for (;;) {
11736e94dc5SPeter Avalos if (bytes < 64) {
11836e94dc5SPeter Avalos for (i = 0;i < bytes;++i) tmp[i] = m[i];
11936e94dc5SPeter Avalos m = tmp;
12036e94dc5SPeter Avalos ctarget = c;
12136e94dc5SPeter Avalos c = tmp;
12236e94dc5SPeter Avalos }
12336e94dc5SPeter Avalos x0 = j0;
12436e94dc5SPeter Avalos x1 = j1;
12536e94dc5SPeter Avalos x2 = j2;
12636e94dc5SPeter Avalos x3 = j3;
12736e94dc5SPeter Avalos x4 = j4;
12836e94dc5SPeter Avalos x5 = j5;
12936e94dc5SPeter Avalos x6 = j6;
13036e94dc5SPeter Avalos x7 = j7;
13136e94dc5SPeter Avalos x8 = j8;
13236e94dc5SPeter Avalos x9 = j9;
13336e94dc5SPeter Avalos x10 = j10;
13436e94dc5SPeter Avalos x11 = j11;
13536e94dc5SPeter Avalos x12 = j12;
13636e94dc5SPeter Avalos x13 = j13;
13736e94dc5SPeter Avalos x14 = j14;
13836e94dc5SPeter Avalos x15 = j15;
13936e94dc5SPeter Avalos for (i = 20;i > 0;i -= 2) {
14036e94dc5SPeter Avalos QUARTERROUND( x0, x4, x8,x12)
14136e94dc5SPeter Avalos QUARTERROUND( x1, x5, x9,x13)
14236e94dc5SPeter Avalos QUARTERROUND( x2, x6,x10,x14)
14336e94dc5SPeter Avalos QUARTERROUND( x3, x7,x11,x15)
14436e94dc5SPeter Avalos QUARTERROUND( x0, x5,x10,x15)
14536e94dc5SPeter Avalos QUARTERROUND( x1, x6,x11,x12)
14636e94dc5SPeter Avalos QUARTERROUND( x2, x7, x8,x13)
14736e94dc5SPeter Avalos QUARTERROUND( x3, x4, x9,x14)
14836e94dc5SPeter Avalos }
14936e94dc5SPeter Avalos x0 = PLUS(x0,j0);
15036e94dc5SPeter Avalos x1 = PLUS(x1,j1);
15136e94dc5SPeter Avalos x2 = PLUS(x2,j2);
15236e94dc5SPeter Avalos x3 = PLUS(x3,j3);
15336e94dc5SPeter Avalos x4 = PLUS(x4,j4);
15436e94dc5SPeter Avalos x5 = PLUS(x5,j5);
15536e94dc5SPeter Avalos x6 = PLUS(x6,j6);
15636e94dc5SPeter Avalos x7 = PLUS(x7,j7);
15736e94dc5SPeter Avalos x8 = PLUS(x8,j8);
15836e94dc5SPeter Avalos x9 = PLUS(x9,j9);
15936e94dc5SPeter Avalos x10 = PLUS(x10,j10);
16036e94dc5SPeter Avalos x11 = PLUS(x11,j11);
16136e94dc5SPeter Avalos x12 = PLUS(x12,j12);
16236e94dc5SPeter Avalos x13 = PLUS(x13,j13);
16336e94dc5SPeter Avalos x14 = PLUS(x14,j14);
16436e94dc5SPeter Avalos x15 = PLUS(x15,j15);
16536e94dc5SPeter Avalos
16636e94dc5SPeter Avalos x0 = XOR(x0,U8TO32_LITTLE(m + 0));
16736e94dc5SPeter Avalos x1 = XOR(x1,U8TO32_LITTLE(m + 4));
16836e94dc5SPeter Avalos x2 = XOR(x2,U8TO32_LITTLE(m + 8));
16936e94dc5SPeter Avalos x3 = XOR(x3,U8TO32_LITTLE(m + 12));
17036e94dc5SPeter Avalos x4 = XOR(x4,U8TO32_LITTLE(m + 16));
17136e94dc5SPeter Avalos x5 = XOR(x5,U8TO32_LITTLE(m + 20));
17236e94dc5SPeter Avalos x6 = XOR(x6,U8TO32_LITTLE(m + 24));
17336e94dc5SPeter Avalos x7 = XOR(x7,U8TO32_LITTLE(m + 28));
17436e94dc5SPeter Avalos x8 = XOR(x8,U8TO32_LITTLE(m + 32));
17536e94dc5SPeter Avalos x9 = XOR(x9,U8TO32_LITTLE(m + 36));
17636e94dc5SPeter Avalos x10 = XOR(x10,U8TO32_LITTLE(m + 40));
17736e94dc5SPeter Avalos x11 = XOR(x11,U8TO32_LITTLE(m + 44));
17836e94dc5SPeter Avalos x12 = XOR(x12,U8TO32_LITTLE(m + 48));
17936e94dc5SPeter Avalos x13 = XOR(x13,U8TO32_LITTLE(m + 52));
18036e94dc5SPeter Avalos x14 = XOR(x14,U8TO32_LITTLE(m + 56));
18136e94dc5SPeter Avalos x15 = XOR(x15,U8TO32_LITTLE(m + 60));
18236e94dc5SPeter Avalos
18336e94dc5SPeter Avalos j12 = PLUSONE(j12);
18436e94dc5SPeter Avalos if (!j12) {
18536e94dc5SPeter Avalos j13 = PLUSONE(j13);
18636e94dc5SPeter Avalos /* stopping at 2^70 bytes per nonce is user's responsibility */
18736e94dc5SPeter Avalos }
18836e94dc5SPeter Avalos
18936e94dc5SPeter Avalos U32TO8_LITTLE(c + 0,x0);
19036e94dc5SPeter Avalos U32TO8_LITTLE(c + 4,x1);
19136e94dc5SPeter Avalos U32TO8_LITTLE(c + 8,x2);
19236e94dc5SPeter Avalos U32TO8_LITTLE(c + 12,x3);
19336e94dc5SPeter Avalos U32TO8_LITTLE(c + 16,x4);
19436e94dc5SPeter Avalos U32TO8_LITTLE(c + 20,x5);
19536e94dc5SPeter Avalos U32TO8_LITTLE(c + 24,x6);
19636e94dc5SPeter Avalos U32TO8_LITTLE(c + 28,x7);
19736e94dc5SPeter Avalos U32TO8_LITTLE(c + 32,x8);
19836e94dc5SPeter Avalos U32TO8_LITTLE(c + 36,x9);
19936e94dc5SPeter Avalos U32TO8_LITTLE(c + 40,x10);
20036e94dc5SPeter Avalos U32TO8_LITTLE(c + 44,x11);
20136e94dc5SPeter Avalos U32TO8_LITTLE(c + 48,x12);
20236e94dc5SPeter Avalos U32TO8_LITTLE(c + 52,x13);
20336e94dc5SPeter Avalos U32TO8_LITTLE(c + 56,x14);
20436e94dc5SPeter Avalos U32TO8_LITTLE(c + 60,x15);
20536e94dc5SPeter Avalos
20636e94dc5SPeter Avalos if (bytes <= 64) {
20736e94dc5SPeter Avalos if (bytes < 64) {
20836e94dc5SPeter Avalos for (i = 0;i < bytes;++i) ctarget[i] = c[i];
20936e94dc5SPeter Avalos }
21036e94dc5SPeter Avalos x->input[12] = j12;
21136e94dc5SPeter Avalos x->input[13] = j13;
21236e94dc5SPeter Avalos return;
21336e94dc5SPeter Avalos }
21436e94dc5SPeter Avalos bytes -= 64;
21536e94dc5SPeter Avalos c += 64;
21636e94dc5SPeter Avalos m += 64;
21736e94dc5SPeter Avalos }
21836e94dc5SPeter Avalos }
219