1261287Sdes/*
2261287Sdeschacha-merged.c version 20080118
3261287SdesD. J. Bernstein
4261287SdesPublic domain.
5261287Sdes*/
6261287Sdes
7261287Sdes#include "includes.h"
8261287Sdes
9261287Sdes#include "chacha.h"
10261287Sdes
11261287Sdes/* $OpenBSD: chacha.c,v 1.1 2013/11/21 00:45:44 djm Exp $ */
12261287Sdes
13261287Sdestypedef unsigned char u8;
14261287Sdestypedef unsigned int u32;
15261287Sdes
16261287Sdestypedef struct chacha_ctx chacha_ctx;
17261287Sdes
18261287Sdes#define U8C(v) (v##U)
19261287Sdes#define U32C(v) (v##U)
20261287Sdes
21261287Sdes#define U8V(v) ((u8)(v) & U8C(0xFF))
22261287Sdes#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
23261287Sdes
24261287Sdes#define ROTL32(v, n) \
25261287Sdes  (U32V((v) << (n)) | ((v) >> (32 - (n))))
26261287Sdes
27261287Sdes#define U8TO32_LITTLE(p) \
28261287Sdes  (((u32)((p)[0])      ) | \
29261287Sdes   ((u32)((p)[1]) <<  8) | \
30261287Sdes   ((u32)((p)[2]) << 16) | \
31261287Sdes   ((u32)((p)[3]) << 24))
32261287Sdes
33261287Sdes#define U32TO8_LITTLE(p, v) \
34261287Sdes  do { \
35261287Sdes    (p)[0] = U8V((v)      ); \
36261287Sdes    (p)[1] = U8V((v) >>  8); \
37261287Sdes    (p)[2] = U8V((v) >> 16); \
38261287Sdes    (p)[3] = U8V((v) >> 24); \
39261287Sdes  } while (0)
40261287Sdes
41261287Sdes#define ROTATE(v,c) (ROTL32(v,c))
42261287Sdes#define XOR(v,w) ((v) ^ (w))
43261287Sdes#define PLUS(v,w) (U32V((v) + (w)))
44261287Sdes#define PLUSONE(v) (PLUS((v),1))
45261287Sdes
46261287Sdes#define QUARTERROUND(a,b,c,d) \
47261287Sdes  a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
48261287Sdes  c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
49261287Sdes  a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
50261287Sdes  c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
51261287Sdes
52261287Sdesstatic const char sigma[16] = "expand 32-byte k";
53261287Sdesstatic const char tau[16] = "expand 16-byte k";
54261287Sdes
55261287Sdesvoid
56261287Sdeschacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits)
57261287Sdes{
58261287Sdes  const char *constants;
59261287Sdes
60261287Sdes  x->input[4] = U8TO32_LITTLE(k + 0);
61261287Sdes  x->input[5] = U8TO32_LITTLE(k + 4);
62261287Sdes  x->input[6] = U8TO32_LITTLE(k + 8);
63261287Sdes  x->input[7] = U8TO32_LITTLE(k + 12);
64261287Sdes  if (kbits == 256) { /* recommended */
65261287Sdes    k += 16;
66261287Sdes    constants = sigma;
67261287Sdes  } else { /* kbits == 128 */
68261287Sdes    constants = tau;
69261287Sdes  }
70261287Sdes  x->input[8] = U8TO32_LITTLE(k + 0);
71261287Sdes  x->input[9] = U8TO32_LITTLE(k + 4);
72261287Sdes  x->input[10] = U8TO32_LITTLE(k + 8);
73261287Sdes  x->input[11] = U8TO32_LITTLE(k + 12);
74261287Sdes  x->input[0] = U8TO32_LITTLE(constants + 0);
75261287Sdes  x->input[1] = U8TO32_LITTLE(constants + 4);
76261287Sdes  x->input[2] = U8TO32_LITTLE(constants + 8);
77261287Sdes  x->input[3] = U8TO32_LITTLE(constants + 12);
78261287Sdes}
79261287Sdes
80261287Sdesvoid
81261287Sdeschacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter)
82261287Sdes{
83261287Sdes  x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
84261287Sdes  x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4);
85261287Sdes  x->input[14] = U8TO32_LITTLE(iv + 0);
86261287Sdes  x->input[15] = U8TO32_LITTLE(iv + 4);
87261287Sdes}
88261287Sdes
89261287Sdesvoid
90261287Sdeschacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
91261287Sdes{
92261287Sdes  u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
93261287Sdes  u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
94261287Sdes  u8 *ctarget = NULL;
95261287Sdes  u8 tmp[64];
96261287Sdes  u_int i;
97261287Sdes
98261287Sdes  if (!bytes) return;
99261287Sdes
100261287Sdes  j0 = x->input[0];
101261287Sdes  j1 = x->input[1];
102261287Sdes  j2 = x->input[2];
103261287Sdes  j3 = x->input[3];
104261287Sdes  j4 = x->input[4];
105261287Sdes  j5 = x->input[5];
106261287Sdes  j6 = x->input[6];
107261287Sdes  j7 = x->input[7];
108261287Sdes  j8 = x->input[8];
109261287Sdes  j9 = x->input[9];
110261287Sdes  j10 = x->input[10];
111261287Sdes  j11 = x->input[11];
112261287Sdes  j12 = x->input[12];
113261287Sdes  j13 = x->input[13];
114261287Sdes  j14 = x->input[14];
115261287Sdes  j15 = x->input[15];
116261287Sdes
117261287Sdes  for (;;) {
118261287Sdes    if (bytes < 64) {
119261287Sdes      for (i = 0;i < bytes;++i) tmp[i] = m[i];
120261287Sdes      m = tmp;
121261287Sdes      ctarget = c;
122261287Sdes      c = tmp;
123261287Sdes    }
124261287Sdes    x0 = j0;
125261287Sdes    x1 = j1;
126261287Sdes    x2 = j2;
127261287Sdes    x3 = j3;
128261287Sdes    x4 = j4;
129261287Sdes    x5 = j5;
130261287Sdes    x6 = j6;
131261287Sdes    x7 = j7;
132261287Sdes    x8 = j8;
133261287Sdes    x9 = j9;
134261287Sdes    x10 = j10;
135261287Sdes    x11 = j11;
136261287Sdes    x12 = j12;
137261287Sdes    x13 = j13;
138261287Sdes    x14 = j14;
139261287Sdes    x15 = j15;
140261287Sdes    for (i = 20;i > 0;i -= 2) {
141261287Sdes      QUARTERROUND( x0, x4, x8,x12)
142261287Sdes      QUARTERROUND( x1, x5, x9,x13)
143261287Sdes      QUARTERROUND( x2, x6,x10,x14)
144261287Sdes      QUARTERROUND( x3, x7,x11,x15)
145261287Sdes      QUARTERROUND( x0, x5,x10,x15)
146261287Sdes      QUARTERROUND( x1, x6,x11,x12)
147261287Sdes      QUARTERROUND( x2, x7, x8,x13)
148261287Sdes      QUARTERROUND( x3, x4, x9,x14)
149261287Sdes    }
150261287Sdes    x0 = PLUS(x0,j0);
151261287Sdes    x1 = PLUS(x1,j1);
152261287Sdes    x2 = PLUS(x2,j2);
153261287Sdes    x3 = PLUS(x3,j3);
154261287Sdes    x4 = PLUS(x4,j4);
155261287Sdes    x5 = PLUS(x5,j5);
156261287Sdes    x6 = PLUS(x6,j6);
157261287Sdes    x7 = PLUS(x7,j7);
158261287Sdes    x8 = PLUS(x8,j8);
159261287Sdes    x9 = PLUS(x9,j9);
160261287Sdes    x10 = PLUS(x10,j10);
161261287Sdes    x11 = PLUS(x11,j11);
162261287Sdes    x12 = PLUS(x12,j12);
163261287Sdes    x13 = PLUS(x13,j13);
164261287Sdes    x14 = PLUS(x14,j14);
165261287Sdes    x15 = PLUS(x15,j15);
166261287Sdes
167261287Sdes    x0 = XOR(x0,U8TO32_LITTLE(m + 0));
168261287Sdes    x1 = XOR(x1,U8TO32_LITTLE(m + 4));
169261287Sdes    x2 = XOR(x2,U8TO32_LITTLE(m + 8));
170261287Sdes    x3 = XOR(x3,U8TO32_LITTLE(m + 12));
171261287Sdes    x4 = XOR(x4,U8TO32_LITTLE(m + 16));
172261287Sdes    x5 = XOR(x5,U8TO32_LITTLE(m + 20));
173261287Sdes    x6 = XOR(x6,U8TO32_LITTLE(m + 24));
174261287Sdes    x7 = XOR(x7,U8TO32_LITTLE(m + 28));
175261287Sdes    x8 = XOR(x8,U8TO32_LITTLE(m + 32));
176261287Sdes    x9 = XOR(x9,U8TO32_LITTLE(m + 36));
177261287Sdes    x10 = XOR(x10,U8TO32_LITTLE(m + 40));
178261287Sdes    x11 = XOR(x11,U8TO32_LITTLE(m + 44));
179261287Sdes    x12 = XOR(x12,U8TO32_LITTLE(m + 48));
180261287Sdes    x13 = XOR(x13,U8TO32_LITTLE(m + 52));
181261287Sdes    x14 = XOR(x14,U8TO32_LITTLE(m + 56));
182261287Sdes    x15 = XOR(x15,U8TO32_LITTLE(m + 60));
183261287Sdes
184261287Sdes    j12 = PLUSONE(j12);
185261287Sdes    if (!j12) {
186261287Sdes      j13 = PLUSONE(j13);
187261287Sdes      /* stopping at 2^70 bytes per nonce is user's responsibility */
188261287Sdes    }
189261287Sdes
190261287Sdes    U32TO8_LITTLE(c + 0,x0);
191261287Sdes    U32TO8_LITTLE(c + 4,x1);
192261287Sdes    U32TO8_LITTLE(c + 8,x2);
193261287Sdes    U32TO8_LITTLE(c + 12,x3);
194261287Sdes    U32TO8_LITTLE(c + 16,x4);
195261287Sdes    U32TO8_LITTLE(c + 20,x5);
196261287Sdes    U32TO8_LITTLE(c + 24,x6);
197261287Sdes    U32TO8_LITTLE(c + 28,x7);
198261287Sdes    U32TO8_LITTLE(c + 32,x8);
199261287Sdes    U32TO8_LITTLE(c + 36,x9);
200261287Sdes    U32TO8_LITTLE(c + 40,x10);
201261287Sdes    U32TO8_LITTLE(c + 44,x11);
202261287Sdes    U32TO8_LITTLE(c + 48,x12);
203261287Sdes    U32TO8_LITTLE(c + 52,x13);
204261287Sdes    U32TO8_LITTLE(c + 56,x14);
205261287Sdes    U32TO8_LITTLE(c + 60,x15);
206261287Sdes
207261287Sdes    if (bytes <= 64) {
208261287Sdes      if (bytes < 64) {
209261287Sdes        for (i = 0;i < bytes;++i) ctarget[i] = c[i];
210261287Sdes      }
211261287Sdes      x->input[12] = j12;
212261287Sdes      x->input[13] = j13;
213261287Sdes      return;
214261287Sdes    }
215261287Sdes    bytes -= 64;
216261287Sdes    c += 64;
217261287Sdes    m += 64;
218261287Sdes  }
219261287Sdes}
220