1 /* ===================================================================
2 *
3 * Copyright (c) 2014, Legrandin <helderijs@gmail.com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 * ===================================================================
30 */
31
32 #include "common.h"
33 #include "endianess.h"
34
35 FAKE_INIT(chacha20)
36
37 #define KEY_SIZE 32
38
39 typedef struct {
40 /** Initial state for the next iteration **/
41 uint32_t h[16];
42 size_t nonceSize; /** in bytes **/
43
44 /** How many bytes at the beginning of the key stream
45 * have already been used.
46 */
47 unsigned usedKeyStream;
48
49 uint8_t keyStream[sizeof(uint32_t)*16];
50 } stream_state;
51
52 #define ROTL(q, n) (((q) << (n)) | ((q) >> (32 - (n))))
53
54 #define QR(a, b, c, d) {\
55 a+=b; d^=a; d=ROTL(d,16); \
56 c+=d; b^=c; b=ROTL(b,12); \
57 a+=b; d^=a; d=ROTL(d,8); \
58 c+=d; b^=c; b=ROTL(b,7); \
59 }
60
chacha20_init(stream_state ** pState,const uint8_t * key,size_t keySize,const uint8_t * nonce,size_t nonceSize)61 EXPORT_SYM int chacha20_init(stream_state **pState,
62 const uint8_t *key,
63 size_t keySize,
64 const uint8_t *nonce,
65 size_t nonceSize)
66 {
67 stream_state *hs;
68 unsigned i;
69
70 if (NULL == pState || NULL == nonce)
71 return ERR_NULL;
72
73 if (NULL == key || keySize != KEY_SIZE)
74 return ERR_KEY_SIZE;
75
76 if (nonceSize != 8 && nonceSize != 12 && nonceSize != 16)
77 return ERR_NONCE_SIZE;
78
79 *pState = hs = (stream_state*) calloc(1, sizeof(stream_state));
80 if (NULL == hs)
81 return ERR_MEMORY;
82
83 hs->h[0] = 0x61707865;
84 hs->h[1] = 0x3320646e;
85 hs->h[2] = 0x79622d32;
86 hs->h[3] = 0x6b206574;
87
88 /** Move 256-bit/32-byte key into h[4..11] **/
89 for (i=0; i<32/4; i++) {
90 hs->h[4+i] = LOAD_U32_LITTLE(key + 4*i);
91 }
92
93 switch (nonceSize) {
94 case 8: {
95 /*
96 cccccccc cccccccc cccccccc cccccccc
97 kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
98 kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
99 bbbbbbbb BBBBBBBB nnnnnnnn nnnnnnnn
100
101 c=constant k=key b=blockcount(low) B=blockcount(high) n=nonce
102 */
103
104 /** h[12] remains 0 (offset) **/
105 /** h[13] remains 0 (offset) **/
106 hs->h[14] = LOAD_U32_LITTLE(nonce + 0);
107 hs->h[15] = LOAD_U32_LITTLE(nonce + 4);
108 break;
109 }
110 case 12: {
111 /*
112 cccccccc cccccccc cccccccc cccccccc
113 kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
114 kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
115 bbbbbbbb nnnnnnnn nnnnnnnn nnnnnnnn
116
117 c=constant k=key b=blockcount n=nonce
118 */
119
120 /** h[12] remains 0 (offset) **/
121 hs->h[13] = LOAD_U32_LITTLE(nonce + 0);
122 hs->h[14] = LOAD_U32_LITTLE(nonce + 4);
123 hs->h[15] = LOAD_U32_LITTLE(nonce + 8);
124 break;
125 }
126 case 16: {
127 /*
128 cccccccc cccccccc cccccccc cccccccc
129 kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
130 kkkkkkkk kkkkkkkk kkkkkkkk kkkkkkkk
131 nnnnnnnn nnnnnnnn nnnnnnnn nnnnnnnn
132
133 c=constant k=key n=nonce
134 */
135
136 hs->h[12] = LOAD_U32_LITTLE(nonce + 0);
137 hs->h[13] = LOAD_U32_LITTLE(nonce + 4);
138 hs->h[14] = LOAD_U32_LITTLE(nonce + 8);
139 hs->h[15] = LOAD_U32_LITTLE(nonce + 12);
140 break;
141 }
142 default:
143 return ERR_NONCE_SIZE;
144 }
145
146 hs->nonceSize = nonceSize;
147 hs->usedKeyStream = sizeof hs->keyStream;
148
149 return 0;
150 }
151
chacha20_destroy(stream_state * state)152 EXPORT_SYM int chacha20_destroy(stream_state *state)
153 {
154 if (NULL == state)
155 return ERR_NULL;
156 free(state);
157 return 0;
158 }
159
chacha20_core(stream_state * state,uint32_t h[16])160 static int chacha20_core(stream_state *state, uint32_t h[16])
161 {
162 unsigned i;
163
164 memcpy(h, state->h, sizeof state->h);
165
166 for (i=0; i<10; i++) {
167 /** Column round **/
168 QR(h[0], h[4], h[ 8], h[12]);
169 QR(h[1], h[5], h[ 9], h[13]);
170 QR(h[2], h[6], h[10], h[14]);
171 QR(h[3], h[7], h[11], h[15]);
172 /** Diagonal round **/
173 QR(h[0], h[5], h[10], h[15]);
174 QR(h[1], h[6], h[11], h[12]);
175 QR(h[2], h[7], h[ 8], h[13]);
176 QR(h[3], h[4], h[ 9], h[14]);
177 }
178
179 for (i=0; i<16; i++) {
180 uint32_t sum;
181
182 sum = h[i] + state->h[i];
183 STORE_U32_LITTLE(state->keyStream + 4*i, sum);
184 }
185
186 state->usedKeyStream = 0;
187
188 switch (state->nonceSize) {
189 case 8: {
190 /** Nonce is 64 bits, counter is two words **/
191 if (++state->h[12] == 0) {
192 if (++state->h[13] == 0) {
193 return ERR_MAX_DATA;
194 }
195 }
196 break;
197 }
198 case 12: {
199 /** Nonce is 96 bits, counter is one word **/
200 if (++state->h[12] == 0) {
201 return ERR_MAX_DATA;
202 }
203 break;
204 }
205 case 16: {
206 /** Nonce is 192 bits, there is no counter as this is intended
207 * to be run once only (HChaCha20) **/
208 break;
209 }
210 }
211
212 return 0;
213 }
214
chacha20_encrypt(stream_state * state,const uint8_t in[],uint8_t out[],size_t len)215 EXPORT_SYM int chacha20_encrypt(stream_state *state,
216 const uint8_t in[],
217 uint8_t out[],
218 size_t len)
219 {
220 if (NULL == state || NULL == in || NULL == out)
221 return ERR_NULL;
222
223 if ((state->nonceSize != 8) && (state->nonceSize != 12))
224 return ERR_NONCE_SIZE;
225
226 while (len>0) {
227 unsigned keyStreamToUse;
228 unsigned i;
229 uint32_t h[16];
230
231 if (state->usedKeyStream == sizeof state->keyStream) {
232 int result;
233
234 result = chacha20_core(state, h);
235 if (result)
236 return result;
237 }
238
239 keyStreamToUse = (unsigned)MIN(len, sizeof state->keyStream - state->usedKeyStream);
240 for (i=0; i<keyStreamToUse; i++)
241 *out++ = *in++ ^ state->keyStream[i + state->usedKeyStream];
242
243 len -= keyStreamToUse;
244 state->usedKeyStream += keyStreamToUse;
245 }
246
247 return 0;
248 }
249
chacha20_seek(stream_state * state,unsigned long block_high,unsigned long block_low,unsigned offset)250 EXPORT_SYM int chacha20_seek(stream_state *state,
251 unsigned long block_high,
252 unsigned long block_low,
253 unsigned offset)
254 {
255 int result;
256 uint32_t h[16];
257
258 if (NULL == state)
259 return ERR_NULL;
260
261 if ((state->nonceSize != 8) && (state->nonceSize != 12))
262 return ERR_NONCE_SIZE;
263
264 if (offset >= sizeof state->keyStream)
265 return ERR_MAX_OFFSET;
266
267 if (state->nonceSize == 8) {
268 /** Nonce is 64 bits, counter is two words **/
269 state->h[12] = (uint32_t)block_low;
270 state->h[13] = (uint32_t)block_high;
271 } else {
272 /** Nonce is 96 bits, counter is one word **/
273 if (block_high > 0) {
274 return ERR_MAX_OFFSET;
275 }
276 state->h[12] = (uint32_t)block_low;
277 }
278
279 result = chacha20_core(state, h);
280 if (result)
281 return result;
282
283 state->usedKeyStream = offset;
284
285 return 0;
286 }
287
288 /*
289 * Based on https://tools.ietf.org/html/draft-arciszewski-xchacha-03
290 */
hchacha20(const uint8_t key[KEY_SIZE],const uint8_t nonce16[16],uint8_t subkey[KEY_SIZE])291 EXPORT_SYM int hchacha20(const uint8_t key[KEY_SIZE],
292 const uint8_t nonce16[16], /* First 16 bytes of the 24 byte nonce */
293 uint8_t subkey[KEY_SIZE])
294 {
295 stream_state *pState;
296 uint32_t h[16];
297
298 if (NULL == key || NULL == nonce16 || NULL == subkey) {
299 return ERR_NULL;
300 }
301
302 chacha20_init(&pState, key, KEY_SIZE, nonce16, 16);
303 if (NULL == pState)
304 return ERR_MEMORY;
305
306 chacha20_core(pState, h);
307 /* We only keep first and last row from the new state */
308 STORE_U32_LITTLE(subkey + 0, h[0]);
309 STORE_U32_LITTLE(subkey + 4, h[1]);
310 STORE_U32_LITTLE(subkey + 8, h[2]);
311 STORE_U32_LITTLE(subkey + 12, h[3]);
312 STORE_U32_LITTLE(subkey + 16, h[12]);
313 STORE_U32_LITTLE(subkey + 20, h[13]);
314 STORE_U32_LITTLE(subkey + 24, h[14]);
315 STORE_U32_LITTLE(subkey + 28, h[15]);
316 chacha20_destroy(pState);
317
318 return 0;
319 }
320
321 #ifdef PROFILE
main(void)322 int main(void)
323 {
324 const unsigned data_size = 1024*1024;
325 const uint8_t key[32] = "12345678901234561234567890123456";
326 const uint8_t nonce[8] = "12345678";
327 stream_state *state;
328 uint8_t *data;
329
330 data = malloc(data_size);
331 for (int i=0; i<data_size; i++) {
332 data[i] = (uint8_t) i;
333 }
334
335 chacha20_init(&state, key, 32, nonce, 8);
336
337 for (int i=0; i<1024; i++)
338 chacha20_encrypt(state, data, data, data_size);
339
340 chacha20_destroy(state);
341 free(data);
342 }
343 #endif
344