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