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