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