2 * Copyright (C) 2011-2013 Gregor Pintar <grpintar@gmail.com>
4 * Permission is granted to deal in this work without any restriction,
5 * including unlimited rights to use, publicly perform, publish,
6 * reproduce, relicence, modify, merge, and/or distribute in any form,
7 * for any purpose, with or without fee, and by any means.
9 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind,
10 * to the utmost extent permitted by applicable law. In no event
11 * shall a licensor, author or contributor be held liable for any
12 * issues arising in any way out of dealing in the work.
19 #include <kripto/loadstore.h>
20 #include <kripto/rotate.h>
21 #include <kripto/memwipe.h>
22 #include <kripto/stream.h>
23 #include <kripto/desc/stream.h>
25 #include <kripto/stream/chacha.h>
29 const kripto_stream_desc
*desc
;
36 #define QR(A, B, C, D) \
38 A += B; D = ROL32(D ^ A, 16); \
39 C += D; B = ROL32(B ^ C, 12); \
40 A += B; D = ROL32(D ^ A, 8); \
41 C += D; B = ROL32(B ^ C, 7); \
44 static void chacha_core
70 for(i
= 0; i
< r
; i
++)
102 STORE32L(x0
, U8(out
));
103 STORE32L(x1
, U8(out
) + 4);
104 STORE32L(x2
, U8(out
) + 8);
105 STORE32L(x3
, U8(out
) + 12);
106 STORE32L(x4
, U8(out
) + 16);
107 STORE32L(x5
, U8(out
) + 20);
108 STORE32L(x6
, U8(out
) + 24);
109 STORE32L(x7
, U8(out
) + 28);
110 STORE32L(x8
, U8(out
) + 32);
111 STORE32L(x9
, U8(out
) + 36);
112 STORE32L(x10
, U8(out
) + 40);
113 STORE32L(x11
, U8(out
) + 44);
114 STORE32L(x12
, U8(out
) + 48);
115 STORE32L(x13
, U8(out
) + 52);
116 STORE32L(x14
, U8(out
) + 56);
117 STORE32L(x15
, U8(out
) + 60);
120 static void chacha_crypt
130 for(i
= 0; i
< len
; i
++)
134 chacha_core(s
->r
, s
->x
, s
->buf
);
141 U8(out
)[i
] = CU8(in
)[i
] ^ s
->buf
[s
->used
++];
145 static void chacha_prng
154 for(i
= 0; i
< len
; i
++)
158 chacha_core(s
->r
, s
->x
, s
->buf
);
165 U8(out
)[i
] = s
->buf
[s
->used
++];
169 static kripto_stream
*chacha_recreate
174 unsigned int key_len
,
181 uint8_t constant
[16] = "expand 00-byte k";
183 constant
[7] += key_len
/ 10;
184 constant
[8] += key_len
% 10;
186 s
->x
[0] = LOAD32L(constant
);
187 s
->x
[1] = LOAD32L(constant
+ 4);
188 s
->x
[2] = LOAD32L(constant
+ 8);
189 s
->x
[3] = LOAD32L(constant
+ 12);
191 for(i
= 4; i
< 12; i
++)
195 s
->x
[i
] = (s
->x
[i
] >> 8) | (CU8(key
)[j
++] << 24);
196 if(j
== key_len
) j
= 0;
198 s
->x
[i
] = (s
->x
[i
] >> 8) | (CU8(key
)[j
++] << 24);
199 if(j
== key_len
) j
= 0;
201 s
->x
[i
] = (s
->x
[i
] >> 8) | (CU8(key
)[j
++] << 24);
202 if(j
== key_len
) j
= 0;
204 s
->x
[i
] = (s
->x
[i
] >> 8) | (CU8(key
)[j
++] << 24);
205 if(j
== key_len
) j
= 0;
209 s
->x
[12] = s
->x
[13] = s
->x
[14] = s
->x
[15] = 0;
211 if(iv_len
> 8) i
= 48; /* XChaCha */
214 for(; i
< 64 && j
< iv_len
; i
++, j
++)
215 s
->x
[i
>> 2] = (s
->x
[i
>> 2] >> 8) | (CU8(iv
)[j
] << 24);
220 if(iv_len
> 8) /* XChaCha */
222 for(i
= 0; i
< s
->r
; i
++)
224 QR(s
->x
[0], s
->x
[4], s
->x
[8], s
->x
[12]);
225 QR(s
->x
[1], s
->x
[5], s
->x
[9], s
->x
[13]);
226 QR(s
->x
[2], s
->x
[6], s
->x
[10], s
->x
[14]);
227 QR(s
->x
[3], s
->x
[7], s
->x
[11], s
->x
[15]);
229 if(++i
== s
->r
) break;
231 QR(s
->x
[0], s
->x
[5], s
->x
[10], s
->x
[15]);
232 QR(s
->x
[1], s
->x
[6], s
->x
[11], s
->x
[12]);
233 QR(s
->x
[2], s
->x
[7], s
->x
[8], s
->x
[13]);
234 QR(s
->x
[3], s
->x
[4], s
->x
[9], s
->x
[14]);
237 s
->x
[4] = s
->x
[0]; s
->x
[0] = LOAD32L(constant
);
238 s
->x
[5] = s
->x
[1]; s
->x
[1] = LOAD32L(constant
+ 4);
239 s
->x
[6] = s
->x
[2]; s
->x
[2] = LOAD32L(constant
+ 8);
240 s
->x
[7] = s
->x
[3]; s
->x
[3] = LOAD32L(constant
+ 12);
242 s
->x
[8] = s
->x
[12]; s
->x
[12] = 0;
243 s
->x
[9] = s
->x
[13]; s
->x
[13] = 0;
244 s
->x
[10] = s
->x
[14]; s
->x
[14] = 0;
245 s
->x
[11] = s
->x
[15]; s
->x
[15] = 0;
247 for(i
= 56; i
< 64 && j
< iv_len
; i
++, j
++)
248 s
->x
[i
>> 2] = (s
->x
[i
>> 2] >> 8) | (CU8(iv
)[j
] << 24);
256 static kripto_stream
*chacha_create
258 const kripto_stream_desc
*desc
,
261 unsigned int key_len
,
270 s
= malloc(sizeof(kripto_stream
));
273 s
->desc
= kripto_stream_chacha
;
275 (void)chacha_recreate(s
, r
, key
, key_len
, iv
, iv_len
);
280 static void chacha_destroy(kripto_stream
*s
)
282 kripto_memwipe(s
, sizeof(kripto_stream
));
286 static const struct kripto_stream_desc chacha
=
299 const kripto_stream_desc
*const kripto_stream_chacha
= &chacha
;