xref: /freebsd/sys/crypto/chacha20/chacha.c (revision f7c32ed617858bcd22f8d1b03199099d50125721)
1 /*
2 chacha-merged.c version 20080118
3 D. J. Bernstein
4 Public domain.
5 */
6 
7 /* $OpenBSD: chacha.c,v 1.1 2013/11/21 00:45:44 djm Exp $ */
8 
9 #include <sys/cdefs.h>
10 __FBSDID("$FreeBSD$");
11 
12 #include <sys/param.h>
13 #include <sys/types.h>
14 
15 #include <crypto/chacha20/chacha.h>
16 
17 typedef uint8_t u8;
18 typedef uint32_t u32;
19 
20 typedef struct chacha_ctx chacha_ctx;
21 
22 #define U8C(v) (v##U)
23 #define U32C(v) (v##U)
24 
25 #define U8V(v) ((u8)(v) & U8C(0xFF))
26 #define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
27 
28 #define ROTL32(v, n) \
29   (U32V((v) << (n)) | ((v) >> (32 - (n))))
30 
31 #define U8TO32_LITTLE(p) \
32   (((u32)((p)[0])      ) | \
33    ((u32)((p)[1]) <<  8) | \
34    ((u32)((p)[2]) << 16) | \
35    ((u32)((p)[3]) << 24))
36 
37 #define U32TO8_LITTLE(p, v) \
38   do { \
39     (p)[0] = U8V((v)      ); \
40     (p)[1] = U8V((v) >>  8); \
41     (p)[2] = U8V((v) >> 16); \
42     (p)[3] = U8V((v) >> 24); \
43   } while (0)
44 
45 #define ROTATE(v,c) (ROTL32(v,c))
46 #define XOR(v,w) ((v) ^ (w))
47 #define PLUS(v,w) (U32V((v) + (w)))
48 #define PLUSONE(v) (PLUS((v),1))
49 
50 #define QUARTERROUND(a,b,c,d) \
51   a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
52   c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
53   a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
54   c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
55 
56 static const char sigma[16] = "expand 32-byte k";
57 static const char tau[16] = "expand 16-byte k";
58 
59 LOCAL void
60 chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits)
61 {
62   const char *constants;
63 
64   x->input[4] = U8TO32_LITTLE(k + 0);
65   x->input[5] = U8TO32_LITTLE(k + 4);
66   x->input[6] = U8TO32_LITTLE(k + 8);
67   x->input[7] = U8TO32_LITTLE(k + 12);
68   if (kbits == 256) { /* recommended */
69     k += 16;
70     constants = sigma;
71   } else { /* kbits == 128 */
72     constants = tau;
73   }
74   x->input[8] = U8TO32_LITTLE(k + 0);
75   x->input[9] = U8TO32_LITTLE(k + 4);
76   x->input[10] = U8TO32_LITTLE(k + 8);
77   x->input[11] = U8TO32_LITTLE(k + 12);
78   x->input[0] = U8TO32_LITTLE(constants + 0);
79   x->input[1] = U8TO32_LITTLE(constants + 4);
80   x->input[2] = U8TO32_LITTLE(constants + 8);
81   x->input[3] = U8TO32_LITTLE(constants + 12);
82 }
83 
84 LOCAL void
85 chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter)
86 {
87 #ifndef CHACHA_NONCE0_CTR128
88   x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
89   x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4);
90   x->input[14] = U8TO32_LITTLE(iv + 0);
91   x->input[15] = U8TO32_LITTLE(iv + 4);
92 #else
93   // CHACHA_STATELEN
94   (void)iv;
95   x->input[12] = U8TO32_LITTLE(counter + 0);
96   x->input[13] = U8TO32_LITTLE(counter + 4);
97   x->input[14] = U8TO32_LITTLE(counter + 8);
98   x->input[15] = U8TO32_LITTLE(counter + 12);
99 #endif
100 }
101 
102 #ifdef CHACHA_NONCE0_CTR128
103 LOCAL void
104 chacha_ctrsave(const chacha_ctx *x, u8 *counter)
105 {
106     U32TO8_LITTLE(counter + 0, x->input[12]);
107     U32TO8_LITTLE(counter + 4, x->input[13]);
108     U32TO8_LITTLE(counter + 8, x->input[14]);
109     U32TO8_LITTLE(counter + 12, x->input[15]);
110 }
111 #endif
112 
113 LOCAL void
114 chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
115 {
116   u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
117   u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
118   u8 *ctarget = NULL;
119   u8 tmp[64];
120   u_int i;
121 
122   if (!bytes) return;
123 
124   j0 = x->input[0];
125   j1 = x->input[1];
126   j2 = x->input[2];
127   j3 = x->input[3];
128   j4 = x->input[4];
129   j5 = x->input[5];
130   j6 = x->input[6];
131   j7 = x->input[7];
132   j8 = x->input[8];
133   j9 = x->input[9];
134   j10 = x->input[10];
135   j11 = x->input[11];
136   j12 = x->input[12];
137   j13 = x->input[13];
138   j14 = x->input[14];
139   j15 = x->input[15];
140 
141   for (;;) {
142     if (bytes < 64) {
143 #ifndef KEYSTREAM_ONLY
144       for (i = 0;i < bytes;++i) tmp[i] = m[i];
145       m = tmp;
146 #endif
147       ctarget = c;
148       c = tmp;
149     }
150     x0 = j0;
151     x1 = j1;
152     x2 = j2;
153     x3 = j3;
154     x4 = j4;
155     x5 = j5;
156     x6 = j6;
157     x7 = j7;
158     x8 = j8;
159     x9 = j9;
160     x10 = j10;
161     x11 = j11;
162     x12 = j12;
163     x13 = j13;
164     x14 = j14;
165     x15 = j15;
166     for (i = 20;i > 0;i -= 2) {
167       QUARTERROUND( x0, x4, x8,x12)
168       QUARTERROUND( x1, x5, x9,x13)
169       QUARTERROUND( x2, x6,x10,x14)
170       QUARTERROUND( x3, x7,x11,x15)
171       QUARTERROUND( x0, x5,x10,x15)
172       QUARTERROUND( x1, x6,x11,x12)
173       QUARTERROUND( x2, x7, x8,x13)
174       QUARTERROUND( x3, x4, x9,x14)
175     }
176     x0 = PLUS(x0,j0);
177     x1 = PLUS(x1,j1);
178     x2 = PLUS(x2,j2);
179     x3 = PLUS(x3,j3);
180     x4 = PLUS(x4,j4);
181     x5 = PLUS(x5,j5);
182     x6 = PLUS(x6,j6);
183     x7 = PLUS(x7,j7);
184     x8 = PLUS(x8,j8);
185     x9 = PLUS(x9,j9);
186     x10 = PLUS(x10,j10);
187     x11 = PLUS(x11,j11);
188     x12 = PLUS(x12,j12);
189     x13 = PLUS(x13,j13);
190     x14 = PLUS(x14,j14);
191     x15 = PLUS(x15,j15);
192 
193 #ifndef KEYSTREAM_ONLY
194     x0 = XOR(x0,U8TO32_LITTLE(m + 0));
195     x1 = XOR(x1,U8TO32_LITTLE(m + 4));
196     x2 = XOR(x2,U8TO32_LITTLE(m + 8));
197     x3 = XOR(x3,U8TO32_LITTLE(m + 12));
198     x4 = XOR(x4,U8TO32_LITTLE(m + 16));
199     x5 = XOR(x5,U8TO32_LITTLE(m + 20));
200     x6 = XOR(x6,U8TO32_LITTLE(m + 24));
201     x7 = XOR(x7,U8TO32_LITTLE(m + 28));
202     x8 = XOR(x8,U8TO32_LITTLE(m + 32));
203     x9 = XOR(x9,U8TO32_LITTLE(m + 36));
204     x10 = XOR(x10,U8TO32_LITTLE(m + 40));
205     x11 = XOR(x11,U8TO32_LITTLE(m + 44));
206     x12 = XOR(x12,U8TO32_LITTLE(m + 48));
207     x13 = XOR(x13,U8TO32_LITTLE(m + 52));
208     x14 = XOR(x14,U8TO32_LITTLE(m + 56));
209     x15 = XOR(x15,U8TO32_LITTLE(m + 60));
210 #endif
211 
212     j12 = PLUSONE(j12);
213     if (!j12) {
214       j13 = PLUSONE(j13);
215 #ifndef CHACHA_NONCE0_CTR128
216       /* stopping at 2^70 bytes per nonce is user's responsibility */
217 #else
218       if (!j13) {
219         j14 = PLUSONE(j14);
220         if (!j14) {
221           j15 = PLUSONE(j15);
222         }
223       }
224 #endif
225     }
226 
227     U32TO8_LITTLE(c + 0,x0);
228     U32TO8_LITTLE(c + 4,x1);
229     U32TO8_LITTLE(c + 8,x2);
230     U32TO8_LITTLE(c + 12,x3);
231     U32TO8_LITTLE(c + 16,x4);
232     U32TO8_LITTLE(c + 20,x5);
233     U32TO8_LITTLE(c + 24,x6);
234     U32TO8_LITTLE(c + 28,x7);
235     U32TO8_LITTLE(c + 32,x8);
236     U32TO8_LITTLE(c + 36,x9);
237     U32TO8_LITTLE(c + 40,x10);
238     U32TO8_LITTLE(c + 44,x11);
239     U32TO8_LITTLE(c + 48,x12);
240     U32TO8_LITTLE(c + 52,x13);
241     U32TO8_LITTLE(c + 56,x14);
242     U32TO8_LITTLE(c + 60,x15);
243 
244     if (bytes <= 64) {
245       if (bytes < 64) {
246         for (i = 0;i < bytes;++i) ctarget[i] = c[i];
247       }
248       x->input[12] = j12;
249       x->input[13] = j13;
250 #ifdef CHACHA_NONCE0_CTR128
251       x->input[14] = j14;
252       x->input[15] = j15;
253 #endif
254       return;
255     }
256     bytes -= 64;
257     c += 64;
258 #ifndef KEYSTREAM_ONLY
259     m += 64;
260 #endif
261   }
262 }
263