xref: /freebsd/sys/crypto/chacha20/chacha.c (revision 7d93ab5e35d97eb23cb4772be4d431a782a65395)
1150890b0SMark Murray /*
2150890b0SMark Murray chacha-merged.c version 20080118
3150890b0SMark Murray D. J. Bernstein
4150890b0SMark Murray Public domain.
5150890b0SMark Murray */
6150890b0SMark Murray 
7150890b0SMark Murray /* $OpenBSD: chacha.c,v 1.1 2013/11/21 00:45:44 djm Exp $ */
8150890b0SMark Murray 
9150890b0SMark Murray #include <sys/cdefs.h>
10150890b0SMark Murray __FBSDID("$FreeBSD$");
11150890b0SMark Murray 
12150890b0SMark Murray #include <sys/param.h>
13150890b0SMark Murray #include <sys/types.h>
14150890b0SMark Murray 
15150890b0SMark Murray #include <crypto/chacha20/chacha.h>
16150890b0SMark Murray 
17150890b0SMark Murray typedef uint8_t u8;
18150890b0SMark Murray typedef uint32_t u32;
19150890b0SMark Murray 
20150890b0SMark Murray typedef struct chacha_ctx chacha_ctx;
21150890b0SMark Murray 
22150890b0SMark Murray #define U8C(v) (v##U)
23150890b0SMark Murray #define U32C(v) (v##U)
24150890b0SMark Murray 
25150890b0SMark Murray #define U8V(v) ((u8)(v) & U8C(0xFF))
26150890b0SMark Murray #define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
27150890b0SMark Murray 
28150890b0SMark Murray #define ROTL32(v, n) \
29150890b0SMark Murray   (U32V((v) << (n)) | ((v) >> (32 - (n))))
30150890b0SMark Murray 
31150890b0SMark Murray #define U8TO32_LITTLE(p) \
32150890b0SMark Murray   (((u32)((p)[0])      ) | \
33150890b0SMark Murray    ((u32)((p)[1]) <<  8) | \
34150890b0SMark Murray    ((u32)((p)[2]) << 16) | \
35150890b0SMark Murray    ((u32)((p)[3]) << 24))
36150890b0SMark Murray 
37150890b0SMark Murray #define U32TO8_LITTLE(p, v) \
38150890b0SMark Murray   do { \
39150890b0SMark Murray     (p)[0] = U8V((v)      ); \
40150890b0SMark Murray     (p)[1] = U8V((v) >>  8); \
41150890b0SMark Murray     (p)[2] = U8V((v) >> 16); \
42150890b0SMark Murray     (p)[3] = U8V((v) >> 24); \
43150890b0SMark Murray   } while (0)
44150890b0SMark Murray 
45150890b0SMark Murray #define ROTATE(v,c) (ROTL32(v,c))
46150890b0SMark Murray #define XOR(v,w) ((v) ^ (w))
47150890b0SMark Murray #define PLUS(v,w) (U32V((v) + (w)))
48150890b0SMark Murray #define PLUSONE(v) (PLUS((v),1))
49150890b0SMark Murray 
50150890b0SMark Murray #define QUARTERROUND(a,b,c,d) \
51150890b0SMark Murray   a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
52150890b0SMark Murray   c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
53150890b0SMark Murray   a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
54150890b0SMark Murray   c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
55150890b0SMark Murray 
56150890b0SMark Murray static const char sigma[16] = "expand 32-byte k";
57150890b0SMark Murray static const char tau[16] = "expand 16-byte k";
58150890b0SMark Murray 
59c1e80940SXin LI LOCAL void
60150890b0SMark Murray chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits)
61150890b0SMark Murray {
62150890b0SMark Murray   const char *constants;
63150890b0SMark Murray 
64150890b0SMark Murray   x->input[4] = U8TO32_LITTLE(k + 0);
65150890b0SMark Murray   x->input[5] = U8TO32_LITTLE(k + 4);
66150890b0SMark Murray   x->input[6] = U8TO32_LITTLE(k + 8);
67150890b0SMark Murray   x->input[7] = U8TO32_LITTLE(k + 12);
68150890b0SMark Murray   if (kbits == 256) { /* recommended */
69150890b0SMark Murray     k += 16;
70150890b0SMark Murray     constants = sigma;
71150890b0SMark Murray   } else { /* kbits == 128 */
72150890b0SMark Murray     constants = tau;
73150890b0SMark Murray   }
74150890b0SMark Murray   x->input[8] = U8TO32_LITTLE(k + 0);
75150890b0SMark Murray   x->input[9] = U8TO32_LITTLE(k + 4);
76150890b0SMark Murray   x->input[10] = U8TO32_LITTLE(k + 8);
77150890b0SMark Murray   x->input[11] = U8TO32_LITTLE(k + 12);
78150890b0SMark Murray   x->input[0] = U8TO32_LITTLE(constants + 0);
79150890b0SMark Murray   x->input[1] = U8TO32_LITTLE(constants + 4);
80150890b0SMark Murray   x->input[2] = U8TO32_LITTLE(constants + 8);
81150890b0SMark Murray   x->input[3] = U8TO32_LITTLE(constants + 12);
82150890b0SMark Murray }
83150890b0SMark Murray 
84c1e80940SXin LI LOCAL void
85150890b0SMark Murray chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter)
86150890b0SMark Murray {
87*7d93ab5eSConrad Meyer #ifndef CHACHA_NONCE0_CTR128
88150890b0SMark Murray   x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
89150890b0SMark Murray   x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4);
90150890b0SMark Murray   x->input[14] = U8TO32_LITTLE(iv + 0);
91150890b0SMark Murray   x->input[15] = U8TO32_LITTLE(iv + 4);
92*7d93ab5eSConrad Meyer #else
93*7d93ab5eSConrad Meyer   // CHACHA_STATELEN
94*7d93ab5eSConrad Meyer   (void)iv;
95*7d93ab5eSConrad Meyer   x->input[12] = U8TO32_LITTLE(counter + 0);
96*7d93ab5eSConrad Meyer   x->input[13] = U8TO32_LITTLE(counter + 4);
97*7d93ab5eSConrad Meyer   x->input[14] = U8TO32_LITTLE(counter + 8);
98*7d93ab5eSConrad Meyer   x->input[15] = U8TO32_LITTLE(counter + 12);
99*7d93ab5eSConrad Meyer #endif
100150890b0SMark Murray }
101150890b0SMark Murray 
102*7d93ab5eSConrad Meyer #ifdef CHACHA_NONCE0_CTR128
103*7d93ab5eSConrad Meyer LOCAL void
104*7d93ab5eSConrad Meyer chacha_ctrsave(const chacha_ctx *x, u8 *counter)
105*7d93ab5eSConrad Meyer {
106*7d93ab5eSConrad Meyer     U32TO8_LITTLE(counter + 0, x->input[12]);
107*7d93ab5eSConrad Meyer     U32TO8_LITTLE(counter + 4, x->input[13]);
108*7d93ab5eSConrad Meyer     U32TO8_LITTLE(counter + 8, x->input[14]);
109*7d93ab5eSConrad Meyer     U32TO8_LITTLE(counter + 12, x->input[15]);
110*7d93ab5eSConrad Meyer }
111*7d93ab5eSConrad Meyer #endif
112*7d93ab5eSConrad Meyer 
113c1e80940SXin LI LOCAL void
114150890b0SMark Murray chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
115150890b0SMark Murray {
116150890b0SMark Murray   u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
117150890b0SMark Murray   u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
118150890b0SMark Murray   u8 *ctarget = NULL;
119150890b0SMark Murray   u8 tmp[64];
120150890b0SMark Murray   u_int i;
121150890b0SMark Murray 
122150890b0SMark Murray   if (!bytes) return;
123150890b0SMark Murray 
124150890b0SMark Murray   j0 = x->input[0];
125150890b0SMark Murray   j1 = x->input[1];
126150890b0SMark Murray   j2 = x->input[2];
127150890b0SMark Murray   j3 = x->input[3];
128150890b0SMark Murray   j4 = x->input[4];
129150890b0SMark Murray   j5 = x->input[5];
130150890b0SMark Murray   j6 = x->input[6];
131150890b0SMark Murray   j7 = x->input[7];
132150890b0SMark Murray   j8 = x->input[8];
133150890b0SMark Murray   j9 = x->input[9];
134150890b0SMark Murray   j10 = x->input[10];
135150890b0SMark Murray   j11 = x->input[11];
136150890b0SMark Murray   j12 = x->input[12];
137150890b0SMark Murray   j13 = x->input[13];
138150890b0SMark Murray   j14 = x->input[14];
139150890b0SMark Murray   j15 = x->input[15];
140150890b0SMark Murray 
141150890b0SMark Murray   for (;;) {
142150890b0SMark Murray     if (bytes < 64) {
143987733edSConrad Meyer #ifndef KEYSTREAM_ONLY
144150890b0SMark Murray       for (i = 0;i < bytes;++i) tmp[i] = m[i];
145150890b0SMark Murray       m = tmp;
146987733edSConrad Meyer #endif
147150890b0SMark Murray       ctarget = c;
148150890b0SMark Murray       c = tmp;
149150890b0SMark Murray     }
150150890b0SMark Murray     x0 = j0;
151150890b0SMark Murray     x1 = j1;
152150890b0SMark Murray     x2 = j2;
153150890b0SMark Murray     x3 = j3;
154150890b0SMark Murray     x4 = j4;
155150890b0SMark Murray     x5 = j5;
156150890b0SMark Murray     x6 = j6;
157150890b0SMark Murray     x7 = j7;
158150890b0SMark Murray     x8 = j8;
159150890b0SMark Murray     x9 = j9;
160150890b0SMark Murray     x10 = j10;
161150890b0SMark Murray     x11 = j11;
162150890b0SMark Murray     x12 = j12;
163150890b0SMark Murray     x13 = j13;
164150890b0SMark Murray     x14 = j14;
165150890b0SMark Murray     x15 = j15;
166150890b0SMark Murray     for (i = 20;i > 0;i -= 2) {
167150890b0SMark Murray       QUARTERROUND( x0, x4, x8,x12)
168150890b0SMark Murray       QUARTERROUND( x1, x5, x9,x13)
169150890b0SMark Murray       QUARTERROUND( x2, x6,x10,x14)
170150890b0SMark Murray       QUARTERROUND( x3, x7,x11,x15)
171150890b0SMark Murray       QUARTERROUND( x0, x5,x10,x15)
172150890b0SMark Murray       QUARTERROUND( x1, x6,x11,x12)
173150890b0SMark Murray       QUARTERROUND( x2, x7, x8,x13)
174150890b0SMark Murray       QUARTERROUND( x3, x4, x9,x14)
175150890b0SMark Murray     }
176150890b0SMark Murray     x0 = PLUS(x0,j0);
177150890b0SMark Murray     x1 = PLUS(x1,j1);
178150890b0SMark Murray     x2 = PLUS(x2,j2);
179150890b0SMark Murray     x3 = PLUS(x3,j3);
180150890b0SMark Murray     x4 = PLUS(x4,j4);
181150890b0SMark Murray     x5 = PLUS(x5,j5);
182150890b0SMark Murray     x6 = PLUS(x6,j6);
183150890b0SMark Murray     x7 = PLUS(x7,j7);
184150890b0SMark Murray     x8 = PLUS(x8,j8);
185150890b0SMark Murray     x9 = PLUS(x9,j9);
186150890b0SMark Murray     x10 = PLUS(x10,j10);
187150890b0SMark Murray     x11 = PLUS(x11,j11);
188150890b0SMark Murray     x12 = PLUS(x12,j12);
189150890b0SMark Murray     x13 = PLUS(x13,j13);
190150890b0SMark Murray     x14 = PLUS(x14,j14);
191150890b0SMark Murray     x15 = PLUS(x15,j15);
192150890b0SMark Murray 
193c1e80940SXin LI #ifndef KEYSTREAM_ONLY
194150890b0SMark Murray     x0 = XOR(x0,U8TO32_LITTLE(m + 0));
195150890b0SMark Murray     x1 = XOR(x1,U8TO32_LITTLE(m + 4));
196150890b0SMark Murray     x2 = XOR(x2,U8TO32_LITTLE(m + 8));
197150890b0SMark Murray     x3 = XOR(x3,U8TO32_LITTLE(m + 12));
198150890b0SMark Murray     x4 = XOR(x4,U8TO32_LITTLE(m + 16));
199150890b0SMark Murray     x5 = XOR(x5,U8TO32_LITTLE(m + 20));
200150890b0SMark Murray     x6 = XOR(x6,U8TO32_LITTLE(m + 24));
201150890b0SMark Murray     x7 = XOR(x7,U8TO32_LITTLE(m + 28));
202150890b0SMark Murray     x8 = XOR(x8,U8TO32_LITTLE(m + 32));
203150890b0SMark Murray     x9 = XOR(x9,U8TO32_LITTLE(m + 36));
204150890b0SMark Murray     x10 = XOR(x10,U8TO32_LITTLE(m + 40));
205150890b0SMark Murray     x11 = XOR(x11,U8TO32_LITTLE(m + 44));
206150890b0SMark Murray     x12 = XOR(x12,U8TO32_LITTLE(m + 48));
207150890b0SMark Murray     x13 = XOR(x13,U8TO32_LITTLE(m + 52));
208150890b0SMark Murray     x14 = XOR(x14,U8TO32_LITTLE(m + 56));
209150890b0SMark Murray     x15 = XOR(x15,U8TO32_LITTLE(m + 60));
210c1e80940SXin LI #endif
211150890b0SMark Murray 
212150890b0SMark Murray     j12 = PLUSONE(j12);
213150890b0SMark Murray     if (!j12) {
214150890b0SMark Murray       j13 = PLUSONE(j13);
215*7d93ab5eSConrad Meyer #ifndef CHACHA_NONCE0_CTR128
216150890b0SMark Murray       /* stopping at 2^70 bytes per nonce is user's responsibility */
217*7d93ab5eSConrad Meyer #else
218*7d93ab5eSConrad Meyer       if (!j13) {
219*7d93ab5eSConrad Meyer         j14 = PLUSONE(j14);
220*7d93ab5eSConrad Meyer         if (!j14) {
221*7d93ab5eSConrad Meyer           j15 = PLUSONE(j15);
222*7d93ab5eSConrad Meyer         }
223*7d93ab5eSConrad Meyer       }
224*7d93ab5eSConrad Meyer #endif
225150890b0SMark Murray     }
226150890b0SMark Murray 
227150890b0SMark Murray     U32TO8_LITTLE(c + 0,x0);
228150890b0SMark Murray     U32TO8_LITTLE(c + 4,x1);
229150890b0SMark Murray     U32TO8_LITTLE(c + 8,x2);
230150890b0SMark Murray     U32TO8_LITTLE(c + 12,x3);
231150890b0SMark Murray     U32TO8_LITTLE(c + 16,x4);
232150890b0SMark Murray     U32TO8_LITTLE(c + 20,x5);
233150890b0SMark Murray     U32TO8_LITTLE(c + 24,x6);
234150890b0SMark Murray     U32TO8_LITTLE(c + 28,x7);
235150890b0SMark Murray     U32TO8_LITTLE(c + 32,x8);
236150890b0SMark Murray     U32TO8_LITTLE(c + 36,x9);
237150890b0SMark Murray     U32TO8_LITTLE(c + 40,x10);
238150890b0SMark Murray     U32TO8_LITTLE(c + 44,x11);
239150890b0SMark Murray     U32TO8_LITTLE(c + 48,x12);
240150890b0SMark Murray     U32TO8_LITTLE(c + 52,x13);
241150890b0SMark Murray     U32TO8_LITTLE(c + 56,x14);
242150890b0SMark Murray     U32TO8_LITTLE(c + 60,x15);
243150890b0SMark Murray 
244150890b0SMark Murray     if (bytes <= 64) {
245150890b0SMark Murray       if (bytes < 64) {
246150890b0SMark Murray         for (i = 0;i < bytes;++i) ctarget[i] = c[i];
247150890b0SMark Murray       }
248150890b0SMark Murray       x->input[12] = j12;
249150890b0SMark Murray       x->input[13] = j13;
250*7d93ab5eSConrad Meyer #ifdef CHACHA_NONCE0_CTR128
251*7d93ab5eSConrad Meyer       x->input[14] = j14;
252*7d93ab5eSConrad Meyer       x->input[15] = j15;
253*7d93ab5eSConrad Meyer #endif
254150890b0SMark Murray       return;
255150890b0SMark Murray     }
256150890b0SMark Murray     bytes -= 64;
257150890b0SMark Murray     c += 64;
258c1e80940SXin LI #ifndef KEYSTREAM_ONLY
259150890b0SMark Murray     m += 64;
260c1e80940SXin LI #endif
261150890b0SMark Murray   }
262150890b0SMark Murray }
263