chacha.c revision 261287
146432Sphk/*
246432Sphkchacha-merged.c version 20080118
346432SphkD. J. Bernstein
446432SphkPublic domain.
546432Sphk*/
646432Sphk
746432Sphk#include "includes.h"
846432Sphk
946432Sphk#include "chacha.h"
10117280Scharnier
11117280Scharnier/* $OpenBSD: chacha.c,v 1.1 2013/11/21 00:45:44 djm Exp $ */
12117280Scharnier
13112705Smaximtypedef unsigned char u8;
1446155Sphktypedef unsigned int u32;
15158428Smatteo
1678723Sddtypedef struct chacha_ctx chacha_ctx;
1746155Sphk
1878723Sdd#define U8C(v) (v##U)
1946155Sphk#define U32C(v) (v##U)
2078723Sdd
21129848Smaxim#define U8V(v) ((u8)(v) & U8C(0xFF))
22112705Smaxim#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
23112705Smaxim
24133743Smaxim#define ROTL32(v, n) \
25112705Smaxim  (U32V((v) << (n)) | ((v) >> (32 - (n))))
2678723Sdd
2778723Sdd#define U8TO32_LITTLE(p) \
2878723Sdd  (((u32)((p)[0])      ) | \
2978723Sdd   ((u32)((p)[1]) <<  8) | \
3078723Sdd   ((u32)((p)[2]) << 16) | \
31112705Smaxim   ((u32)((p)[3]) << 24))
32158428Smatteo
33133743Smaxim#define U32TO8_LITTLE(p, v) \
34112705Smaxim  do { \
35129848Smaxim    (p)[0] = U8V((v)      ); \
36129848Smaxim    (p)[1] = U8V((v) >>  8); \
37129848Smaxim    (p)[2] = U8V((v) >> 16); \
38129848Smaxim    (p)[3] = U8V((v) >> 24); \
39129848Smaxim  } while (0)
40129848Smaxim
41129848Smaxim#define ROTATE(v,c) (ROTL32(v,c))
42129848Smaxim#define XOR(v,w) ((v) ^ (w))
43129848Smaxim#define PLUS(v,w) (U32V((v) + (w)))
44129848Smaxim#define PLUSONE(v) (PLUS((v),1))
45129848Smaxim
46129848Smaxim#define QUARTERROUND(a,b,c,d) \
47129848Smaxim  a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
48129848Smaxim  c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
49129848Smaxim  a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
50129848Smaxim  c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
5146155Sphk
5246155Sphkstatic const char sigma[16] = "expand 32-byte k";
5346155Sphkstatic const char tau[16] = "expand 16-byte k";
54137808Sdelphij
5546155Sphkvoid
56137808Sdelphijchacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits)
5746155Sphk{
58136051Sstefanf  const char *constants;
59153056Sphilip
60153056Sphilip  x->input[4] = U8TO32_LITTLE(k + 0);
61133743Smaxim  x->input[5] = U8TO32_LITTLE(k + 4);
62137807Sdelphij  x->input[6] = U8TO32_LITTLE(k + 8);
63158428Smatteo  x->input[7] = U8TO32_LITTLE(k + 12);
64153056Sphilip  if (kbits == 256) { /* recommended */
6546155Sphk    k += 16;
66153056Sphilip    constants = sigma;
67153056Sphilip  } else { /* kbits == 128 */
68153056Sphilip    constants = tau;
69112705Smaxim  }
70158428Smatteo  x->input[8] = U8TO32_LITTLE(k + 0);
71112705Smaxim  x->input[9] = U8TO32_LITTLE(k + 4);
72113277Smike  x->input[10] = U8TO32_LITTLE(k + 8);
73113277Smike  x->input[11] = U8TO32_LITTLE(k + 12);
74113277Smike  x->input[0] = U8TO32_LITTLE(constants + 0);
75153056Sphilip  x->input[1] = U8TO32_LITTLE(constants + 4);
76153056Sphilip  x->input[2] = U8TO32_LITTLE(constants + 8);
77153056Sphilip  x->input[3] = U8TO32_LITTLE(constants + 12);
78153056Sphilip}
79158428Smatteo
80158428Smatteovoid
81158428Smatteochacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter)
82112705Smaxim{
83112705Smaxim  x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
84129848Smaxim  x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4);
85112705Smaxim  x->input[14] = U8TO32_LITTLE(iv + 0);
86129848Smaxim  x->input[15] = U8TO32_LITTLE(iv + 4);
87129848Smaxim}
88129848Smaxim
89129848Smaximvoid
90133743Smaximchacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
91133743Smaxim{
92133743Smaxim  u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
93112705Smaxim  u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
94112705Smaxim  u8 *ctarget = NULL;
95112705Smaxim  u8 tmp[64];
96113277Smike  u_int i;
97112705Smaxim
98112705Smaxim  if (!bytes) return;
99112705Smaxim
100112705Smaxim  j0 = x->input[0];
101129848Smaxim  j1 = x->input[1];
102129848Smaxim  j2 = x->input[2];
103133743Smaxim  j3 = x->input[3];
104133743Smaxim  j4 = x->input[4];
105129848Smaxim  j5 = x->input[5];
106129848Smaxim  j6 = x->input[6];
107131182Spjd  j7 = x->input[7];
108131182Spjd  j8 = x->input[8];
109131182Spjd  j9 = x->input[9];
110131182Spjd  j10 = x->input[10];
11151399Sphk  j11 = x->input[11];
11251399Sphk  j12 = x->input[12];
113131182Spjd  j13 = x->input[13];
114112705Smaxim  j14 = x->input[14];
115112972Smaxim  j15 = x->input[15];
116112972Smaxim
11746432Sphk  for (;;) {
118153056Sphilip    if (bytes < 64) {
119153056Sphilip      for (i = 0;i < bytes;++i) tmp[i] = m[i];
120153056Sphilip      m = tmp;
121153056Sphilip      ctarget = c;
122153056Sphilip      c = tmp;
123113277Smike    }
124113277Smike    x0 = j0;
125112972Smaxim    x1 = j1;
126113804Smike    x2 = j2;
127113277Smike    x3 = j3;
128113804Smike    x4 = j4;
129113804Smike    x5 = j5;
130153056Sphilip    x6 = j6;
131153056Sphilip    x7 = j7;
132153056Sphilip    x8 = j8;
133153056Sphilip    x9 = j9;
134153056Sphilip    x10 = j10;
135153056Sphilip    x11 = j11;
136153056Sphilip    x12 = j12;
137153056Sphilip    x13 = j13;
138153056Sphilip    x14 = j14;
139158428Smatteo    x15 = j15;
140158428Smatteo    for (i = 20;i > 0;i -= 2) {
141112705Smaxim      QUARTERROUND( x0, x4, x8,x12)
142129848Smaxim      QUARTERROUND( x1, x5, x9,x13)
143129848Smaxim      QUARTERROUND( x2, x6,x10,x14)
144133743Smaxim      QUARTERROUND( x3, x7,x11,x15)
145133743Smaxim      QUARTERROUND( x0, x5,x10,x15)
146133743Smaxim      QUARTERROUND( x1, x6,x11,x12)
147133743Smaxim      QUARTERROUND( x2, x7, x8,x13)
148112972Smaxim      QUARTERROUND( x3, x4, x9,x14)
149112972Smaxim    }
150112972Smaxim    x0 = PLUS(x0,j0);
151112972Smaxim    x1 = PLUS(x1,j1);
152112972Smaxim    x2 = PLUS(x2,j2);
153157790Smaxim    x3 = PLUS(x3,j3);
154112972Smaxim    x4 = PLUS(x4,j4);
155113206Smaxim    x5 = PLUS(x5,j5);
156112705Smaxim    x6 = PLUS(x6,j6);
157133743Smaxim    x7 = PLUS(x7,j7);
158133743Smaxim    x8 = PLUS(x8,j8);
159133743Smaxim    x9 = PLUS(x9,j9);
160133743Smaxim    x10 = PLUS(x10,j10);
161133743Smaxim    x11 = PLUS(x11,j11);
162133743Smaxim    x12 = PLUS(x12,j12);
163133743Smaxim    x13 = PLUS(x13,j13);
164133743Smaxim    x14 = PLUS(x14,j14);
165133743Smaxim    x15 = PLUS(x15,j15);
166133743Smaxim
167133743Smaxim    x0 = XOR(x0,U8TO32_LITTLE(m + 0));
168133743Smaxim    x1 = XOR(x1,U8TO32_LITTLE(m + 4));
169133743Smaxim    x2 = XOR(x2,U8TO32_LITTLE(m + 8));
170112972Smaxim    x3 = XOR(x3,U8TO32_LITTLE(m + 12));
171112972Smaxim    x4 = XOR(x4,U8TO32_LITTLE(m + 16));
172113277Smike    x5 = XOR(x5,U8TO32_LITTLE(m + 20));
17346155Sphk    x6 = XOR(x6,U8TO32_LITTLE(m + 24));
174112705Smaxim    x7 = XOR(x7,U8TO32_LITTLE(m + 28));
175112705Smaxim    x8 = XOR(x8,U8TO32_LITTLE(m + 32));
176112705Smaxim    x9 = XOR(x9,U8TO32_LITTLE(m + 36));
177112705Smaxim    x10 = XOR(x10,U8TO32_LITTLE(m + 40));
178112705Smaxim    x11 = XOR(x11,U8TO32_LITTLE(m + 44));
179158428Smatteo    x12 = XOR(x12,U8TO32_LITTLE(m + 48));
180158428Smatteo    x13 = XOR(x13,U8TO32_LITTLE(m + 52));
181158428Smatteo    x14 = XOR(x14,U8TO32_LITTLE(m + 56));
182129848Smaxim    x15 = XOR(x15,U8TO32_LITTLE(m + 60));
183112972Smaxim
184112705Smaxim    j12 = PLUSONE(j12);
185158428Smatteo    if (!j12) {
186158428Smatteo      j13 = PLUSONE(j13);
187158428Smatteo      /* stopping at 2^70 bytes per nonce is user's responsibility */
188158428Smatteo    }
189158428Smatteo
190158428Smatteo    U32TO8_LITTLE(c + 0,x0);
191158428Smatteo    U32TO8_LITTLE(c + 4,x1);
192158428Smatteo    U32TO8_LITTLE(c + 8,x2);
193    U32TO8_LITTLE(c + 12,x3);
194    U32TO8_LITTLE(c + 16,x4);
195    U32TO8_LITTLE(c + 20,x5);
196    U32TO8_LITTLE(c + 24,x6);
197    U32TO8_LITTLE(c + 28,x7);
198    U32TO8_LITTLE(c + 32,x8);
199    U32TO8_LITTLE(c + 36,x9);
200    U32TO8_LITTLE(c + 40,x10);
201    U32TO8_LITTLE(c + 44,x11);
202    U32TO8_LITTLE(c + 48,x12);
203    U32TO8_LITTLE(c + 52,x13);
204    U32TO8_LITTLE(c + 56,x14);
205    U32TO8_LITTLE(c + 60,x15);
206
207    if (bytes <= 64) {
208      if (bytes < 64) {
209        for (i = 0;i < bytes;++i) ctarget[i] = c[i];
210      }
211      x->input[12] = j12;
212      x->input[13] = j13;
213      return;
214    }
215    bytes -= 64;
216    c += 64;
217    m += 64;
218  }
219}
220