Commit | Line | Data |
---|---|---|
55d81656 MW |
1 | /* -*-c-*- |
2 | * | |
3 | * ChaCha stream cipher | |
4 | * | |
5 | * (c) 2015 Straylight/Edgeware | |
6 | */ | |
7 | ||
8 | /*----- Licensing notice --------------------------------------------------* | |
9 | * | |
10 | * This file is part of Catacomb. | |
11 | * | |
12 | * Catacomb is free software; you can redistribute it and/or modify | |
13 | * it under the terms of the GNU Library General Public License as | |
14 | * published by the Free Software Foundation; either version 2 of the | |
15 | * License, or (at your option) any later version. | |
16 | * | |
17 | * Catacomb is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | * GNU Library General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU Library General Public | |
23 | * License along with Catacomb; if not, write to the Free | |
24 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |
25 | * MA 02111-1307, USA. | |
26 | */ | |
27 | ||
28 | #ifndef CATACOMB_CHACHA_H | |
29 | #define CATACOMB_CHACHA_H | |
30 | ||
31 | #ifdef __cplusplus | |
32 | extern "C" { | |
33 | #endif | |
34 | ||
35 | /*----- Header files ------------------------------------------------------*/ | |
36 | ||
37 | #include <mLib/bits.h> | |
38 | ||
39 | #ifndef CATACOMB_GCIPHER_H | |
40 | # include "gcipher.h" | |
41 | #endif | |
42 | ||
43 | #ifndef CATACOMB_GRAND_H | |
44 | # include "grand.h" | |
45 | #endif | |
46 | ||
47 | /*----- Constants ---------------------------------------------------------*/ | |
48 | ||
49 | #define CHACHA_NONCESZ 8u | |
1778ca95 | 50 | #define CHACHA_IETF_NONCESZ 12u |
55d81656 MW |
51 | #define CHACHA_KEYSZ 32u |
52 | #define CHACHA_OUTSZ 64u | |
53 | ||
54 | #define HCHACHA_INSZ 16u | |
55 | #define HCHACHA_OUTSZ 32u | |
56 | ||
57 | #define XCHACHA_NONCESZ 24u | |
58 | #define XCHACHA_KEYSZ CHACHA_KEYSZ | |
59 | #define XCHACHA_OUTSZ CHACHA_OUTSZ | |
60 | ||
61 | /*----- Data structures ---------------------------------------------------*/ | |
62 | ||
63 | typedef uint32 chacha_matrix[16]; | |
64 | ||
65 | typedef struct chacha_ctx { | |
66 | chacha_matrix a; | |
0fee61eb MW |
67 | octet b[CHACHA_OUTSZ]; |
68 | unsigned off; | |
55d81656 MW |
69 | } chacha_ctx; |
70 | ||
71 | #define XCHACHA_DEFCTX(name) \ | |
72 | typedef struct name { chacha_ctx s; chacha_matrix k; } name | |
73 | XCHACHA_DEFCTX(xchacha20_ctx); | |
74 | XCHACHA_DEFCTX(xchacha12_ctx); | |
75 | XCHACHA_DEFCTX(xchacha8_ctx); | |
76 | ||
77 | /*----- The ChaCha stream cipher ------------------------------------------*/ | |
78 | ||
79 | /* --- @chacha_init@ --- * | |
80 | * | |
81 | * Arguments: @chacha_ctx *ctx@ = context to fill in | |
82 | * @const void *key@ = pointer to key material | |
83 | * @size_t ksz@ = size of key (either 32 or 16) | |
84 | * @const void *nonce@ = initial nonce, or null | |
85 | * | |
86 | * Returns: --- | |
87 | * | |
88 | * Use: Initializes a ChaCha context ready for use. | |
89 | */ | |
90 | ||
91 | extern void chacha_init(chacha_ctx */*ctx*/, | |
de7f54d2 MW |
92 | const void */*key*/, size_t /*ksz*/, |
93 | const void */*nonce*/); | |
55d81656 | 94 | |
1778ca95 | 95 | /* --- @chacha_setnonce{,_ietf}@ --- * |
55d81656 MW |
96 | * |
97 | * Arguments: @chacha_ctx *ctx@ = pointer to context | |
1778ca95 MW |
98 | * @const void *nonce@ = the nonce (@CHACHA_NONCESZ@ or |
99 | * @CHACHA_IETF_NONCESZ@ bytes) | |
55d81656 MW |
100 | * |
101 | * Returns: --- | |
102 | * | |
103 | * Use: Set a new nonce in the context @ctx@, e.g., for processing a | |
104 | * different message. The stream position is reset to zero (see | |
105 | * @chacha_seek@ etc.). | |
106 | */ | |
107 | ||
108 | extern void chacha_setnonce(chacha_ctx */*ctx*/, const void */*nonce*/); | |
1778ca95 | 109 | extern void chacha_setnonce_ietf(chacha_ctx */*ctx*/, const void */*nonce*/); |
55d81656 | 110 | |
1778ca95 | 111 | /* --- @chacha_seek{,u64,_ietf}@ --- * |
55d81656 MW |
112 | * |
113 | * Arguments: @chacha_ctx *ctx@ = pointer to context | |
1778ca95 | 114 | * @unsigned long i@, @kludge64 i@, @uint32 i@ = new position |
55d81656 MW |
115 | * |
116 | * Returns: --- | |
117 | * | |
1778ca95 | 118 | * Use: Sets a new stream position, in units of Chacha output |
55d81656 | 119 | * blocks, which are @CHACHA_OUTSZ@ bytes each. Byte |
1778ca95 | 120 | * granularity can be achieved by calling @chachaR_encrypt@ |
55d81656 MW |
121 | * appropriately. |
122 | */ | |
123 | ||
124 | extern void chacha_seek(chacha_ctx */*ctx*/, unsigned long /*i*/); | |
125 | extern void chacha_seeku64(chacha_ctx */*ctx*/, kludge64 /*i*/); | |
1778ca95 | 126 | extern void chacha_seek_ietf(chacha_ctx */*ctx*/, uint32 /*i*/); |
55d81656 | 127 | |
1778ca95 | 128 | /* --- @chacha_tell{,u64,_ietf}@ --- * |
55d81656 MW |
129 | * |
130 | * Arguments: @chacha_ctx *ctx@ = pointer to context | |
131 | * | |
132 | * Returns: The current position in the output stream, in blocks, | |
133 | * rounding upwards. | |
134 | */ | |
135 | ||
136 | extern unsigned long chacha_tell(chacha_ctx */*ctx*/); | |
137 | extern kludge64 chacha_tellu64(chacha_ctx */*ctx*/); | |
1778ca95 | 138 | extern uint32 chacha_tell_ietf(chacha_ctx */*ctx*/); |
55d81656 MW |
139 | |
140 | /* --- @chacha{20,12,8}_encrypt@ --- * | |
141 | * | |
142 | * Arguments: @chacha_ctx *ctx@ = pointer to context | |
143 | * @const void *src@ = source buffer (or null) | |
144 | * @void *dest@ = destination buffer (or null) | |
145 | * @size_t sz@ = size of the buffers | |
146 | * | |
147 | * Returns: --- | |
148 | * | |
149 | * Use: Encrypts or decrypts @sz@ bytes of data from @src@ to @dest@. | |
150 | * ChaCha works by XORing plaintext with a keystream, so | |
151 | * encryption and decryption are the same operation. If @dest@ | |
152 | * is null then ignore @src@ and skip @sz@ bytes of the | |
153 | * keystream. If @src@ is null, then just write the keystream | |
154 | * to @dest@. | |
155 | */ | |
156 | ||
157 | extern void chacha20_encrypt(chacha_ctx */*ctx*/, | |
158 | const void */*src*/, void */*dest*/, | |
159 | size_t /*sz*/); | |
160 | extern void chacha12_encrypt(chacha_ctx */*ctx*/, | |
161 | const void */*src*/, void */*dest*/, | |
162 | size_t /*sz*/); | |
163 | extern void chacha8_encrypt(chacha_ctx */*ctx*/, | |
164 | const void */*src*/, void */*dest*/, | |
165 | size_t /*sz*/); | |
166 | ||
167 | /*----- The HChaCha pseudorandom function ---------------------------------*/ | |
168 | ||
169 | /* --- @hchacha{20,12,8}_prf@ --- * | |
170 | * | |
171 | * Arguments: @chacha_ctx *ctx@ = pointer to context | |
172 | * @const void *src@ = the input (@HCHACHA_INSZ@ bytes) | |
173 | * @void *dest@ = the output (@HCHACHA_OUTSZ@ bytes) | |
174 | * | |
175 | * Returns: --- | |
176 | * | |
177 | * Use: Apply the HChaCha/r pseudorandom function to @src@, writing | |
178 | * the result to @out@. | |
179 | */ | |
180 | ||
181 | extern void hchacha20_prf(chacha_ctx */*ctx*/, | |
182 | const void */*src*/, void */*dest*/); | |
183 | extern void hchacha12_prf(chacha_ctx */*ctx*/, | |
184 | const void */*src*/, void */*dest*/); | |
185 | extern void hchacha8_prf(chacha_ctx */*ctx*/, | |
186 | const void */*src*/, void */*dest*/); | |
187 | ||
188 | /*----- The XChaCha stream cipher ----------------------------------------*/ | |
189 | ||
190 | /* --- @xchacha{20,12,8}_init@ --- * | |
191 | * | |
192 | * Arguments: @xchachaR_ctx *ctx@ = the context to fill in | |
193 | * @const void *key@ = pointer to key material | |
194 | * @size_t ksz@ = size of key (either 32 or 16) | |
195 | * @const void *nonce@ = initial nonce, or null | |
196 | * | |
197 | * Returns: --- | |
198 | * | |
199 | * Use: Initializes an XChaCha/r context ready for use. | |
200 | * | |
201 | * There is a different function for each number of rounds, | |
202 | * unlike for plain ChaCha. | |
203 | */ | |
204 | ||
205 | extern void xchacha20_init(xchacha20_ctx */*ctx*/, | |
206 | const void */*key*/, size_t /*ksz*/, | |
207 | const void */*nonce*/); | |
208 | extern void xchacha12_init(xchacha12_ctx */*ctx*/, | |
209 | const void */*key*/, size_t /*ksz*/, | |
210 | const void */*nonce*/); | |
211 | extern void xchacha8_init(xchacha8_ctx */*ctx*/, | |
212 | const void */*key*/, size_t /*ksz*/, | |
213 | const void */*nonce*/); | |
214 | ||
215 | /* --- @xchacha{20,12,8}_setnonce@ --- * | |
216 | * | |
217 | * Arguments: @xchachaR_ctx *ctx@ = pointer to context | |
218 | * @const void *nonce@ = the nonce (@XCHACHA_NONCESZ@ bytes) | |
219 | * | |
220 | * Returns: --- | |
221 | * | |
222 | * Use: Set a new nonce in the context @ctx@, e.g., for processing a | |
223 | * different message. The stream position is reset to zero (see | |
224 | * @chacha_seek@ etc.). | |
225 | * | |
226 | * There is a different function for each number of rounds, | |
227 | * unlike for plain ChaCha. | |
228 | */ | |
229 | ||
230 | extern void xchacha20_setnonce(xchacha20_ctx */*ctx*/, | |
231 | const void */*nonce*/); | |
232 | extern void xchacha12_setnonce(xchacha12_ctx */*ctx*/, | |
233 | const void */*nonce*/); | |
234 | extern void xchacha8_setnonce(xchacha8_ctx */*ctx*/, | |
235 | const void */*nonce*/); | |
236 | ||
d022e630 | 237 | /* --- @xchacha{20,12,8}_seek{,u64}@ --- * |
55d81656 MW |
238 | * |
239 | * Arguments: @xchachaR_ctx *ctx@ = pointer to context | |
240 | * @unsigned long i@, @kludge64 i@ = new position to set | |
241 | * | |
242 | * Returns: --- | |
243 | * | |
244 | * Use: Sets a new stream position, in units of ChaCha output | |
245 | * blocks, which are @XCHACHA_OUTSZ@ bytes each. Byte | |
246 | * granularity can be achieved by calling @xchachaR_encrypt@ | |
247 | * appropriately. | |
248 | * | |
249 | * There is a different function for each number of rounds, | |
250 | * unlike for plain ChaCha, because the context structures are | |
251 | * different. | |
252 | */ | |
253 | ||
254 | extern void xchacha20_seek(xchacha20_ctx */*ctx*/, unsigned long /*i*/); | |
255 | extern void xchacha12_seek(xchacha12_ctx */*ctx*/, unsigned long /*i*/); | |
256 | extern void xchacha8_seek(xchacha8_ctx */*ctx*/, unsigned long /*i*/); | |
257 | extern void xchacha20_seeku64(xchacha20_ctx */*ctx*/, kludge64 /*i*/); | |
258 | extern void xchacha12_seeku64(xchacha12_ctx */*ctx*/, kludge64 /*i*/); | |
259 | extern void xchacha8_seeku64(xchacha8_ctx */*ctx*/, kludge64 /*i*/); | |
260 | ||
d022e630 | 261 | /* --- @xchacha{20,12,8}_tell{,u64}@ --- * |
55d81656 MW |
262 | * |
263 | * Arguments: @chacha_ctx *ctx@ = pointer to context | |
264 | * | |
265 | * Returns: The current position in the output stream, in blocks, | |
266 | * rounding upwards. | |
267 | * | |
268 | * There is a different function for each number of rounds, | |
269 | * unlike for plain ChaCha, because the context structures are | |
270 | * different. | |
271 | */ | |
272 | ||
273 | extern unsigned long xchacha20_tell(xchacha20_ctx */*ctx*/); | |
274 | extern unsigned long xchacha12_tell(xchacha12_ctx */*ctx*/); | |
275 | extern unsigned long xchacha8_tell(xchacha8_ctx */*ctx*/); | |
276 | extern kludge64 xchacha20_tellu64(xchacha20_ctx */*ctx*/); | |
277 | extern kludge64 xchacha12_tellu64(xchacha12_ctx */*ctx*/); | |
278 | extern kludge64 xchacha8_tellu64(xchacha8_ctx */*ctx*/); | |
279 | ||
280 | /* --- @xchacha{20,12,8}_encrypt@ --- * | |
281 | * | |
282 | * Arguments: @xchachaR_ctx *ctx@ = pointer to context | |
283 | * @const void *src@ = source buffer (or null) | |
284 | * @void *dest@ = destination buffer (or null) | |
285 | * @size_t sz@ = size of the buffers | |
286 | * | |
287 | * Returns: --- | |
288 | * | |
289 | * Use: Encrypts or decrypts @sz@ bytes of data from @src@ to @dest@. | |
290 | * XChaCha works by XORing plaintext with a keystream, so | |
291 | * encryption and decryption are the same operation. If @dest@ | |
292 | * is null then ignore @src@ and skip @sz@ bytes of the | |
293 | * keystream. If @src@ is null, then just write the keystream | |
294 | * to @dest@. | |
295 | */ | |
296 | ||
297 | extern void xchacha20_encrypt(xchacha20_ctx */*ctx*/, | |
298 | const void */*src*/, void */*dest*/, | |
299 | size_t /*sz*/); | |
300 | extern void xchacha12_encrypt(xchacha12_ctx */*ctx*/, | |
301 | const void */*src*/, void */*dest*/, | |
302 | size_t /*sz*/); | |
303 | extern void xchacha8_encrypt(xchacha8_ctx */*ctx*/, | |
304 | const void */*src*/, void */*dest*/, | |
305 | size_t /*sz*/); | |
306 | ||
307 | /*----- Generic cipher interface ------------------------------------------*/ | |
308 | ||
309 | extern const octet chacha_keysz[]; | |
310 | #define chacha20_keysz chacha_keysz | |
311 | #define chacha12_keysz chacha_keysz | |
312 | #define chacha8_keysz chacha_keysz | |
1778ca95 MW |
313 | #define chacha_ietf_keysz chacha_keysz |
314 | #define chacha20_ietf_keysz chacha_keysz | |
315 | #define chacha12_ietf_keysz chacha_keysz | |
316 | #define chacha8_ietf_keysz chacha_keysz | |
55d81656 MW |
317 | #define xchacha_keysz chacha_keysz |
318 | #define xchacha20_keysz chacha_keysz | |
319 | #define xchacha12_keysz chacha_keysz | |
320 | #define xchacha8_keysz chacha_keysz | |
321 | ||
6a265416 MW |
322 | extern const gccipher chacha20, chacha12, chacha8; |
323 | extern const gccipher chacha20_ietf, chacha12_ietf, chacha8_ietf; | |
324 | extern const gccipher xchacha20, xchacha12, xchacha8; | |
55d81656 MW |
325 | |
326 | /*----- Generic random number generator interface -------------------------*/ | |
327 | ||
1778ca95 | 328 | /* --- @chacha{20,12,8}{,_ietf}_rand@, @xchacha{20,12,8}_rand@ --- * |
55d81656 MW |
329 | * |
330 | * Arguments: @const void *k@ = pointer to key material | |
331 | * @size_t ksz@ = size of key material | |
332 | * @const void *n@ = pointer to nonce or null | |
1778ca95 MW |
333 | * (@CHACHA_NONCESZ@, @CHACHA_IETF_NONCESZ@, or |
334 | * @XCHACHA_NONCESZ@) | |
55d81656 MW |
335 | * |
336 | * Returns: Pointer to generic random number generator instance. | |
337 | * | |
338 | * Use: Creates a random number interface wrapper around | |
339 | * the ChaCha or XChaCha stream ciphers. | |
340 | */ | |
341 | ||
342 | extern grand *chacha20_rand(const void */*k*/, size_t /*ksz*/, | |
343 | const void */*n*/); | |
344 | extern grand *chacha12_rand(const void */*k*/, size_t /*ksz*/, | |
345 | const void */*n*/); | |
346 | extern grand *chacha8_rand(const void */*k*/, size_t /*ksz*/, | |
347 | const void */*n*/); | |
1778ca95 MW |
348 | extern grand *chacha20_ietf_rand(const void */*k*/, size_t /*ksz*/, |
349 | const void */*n*/); | |
350 | extern grand *chacha12_ietf_rand(const void */*k*/, size_t /*ksz*/, | |
351 | const void */*n*/); | |
352 | extern grand *chacha8_ietf_rand(const void */*k*/, size_t /*ksz*/, | |
353 | const void */*n*/); | |
55d81656 MW |
354 | extern grand *xchacha20_rand(const void */*k*/, size_t /*ksz*/, |
355 | const void */*n*/); | |
356 | extern grand *xchacha12_rand(const void */*k*/, size_t /*ksz*/, | |
357 | const void */*n*/); | |
358 | extern grand *xchacha8_rand(const void */*k*/, size_t /*ksz*/, | |
359 | const void */*n*/); | |
360 | ||
361 | enum { | |
362 | CHACHA_SEEK = GRAND_SPECIFIC('S'), /* @unsigned long pos@ */ | |
363 | CHACHA_SEEKU64, /* @kludge64 pos@ */ | |
364 | CHACHA_TELL, /* @unsigned long *pos@ */ | |
365 | CHACHA_TELLU64 /* @kludge64 *pos@ */ | |
366 | }; | |
367 | ||
368 | /*----- That's all, folks -------------------------------------------------*/ | |
369 | ||
370 | #ifdef __cplusplus | |
371 | } | |
372 | #endif | |
373 | ||
374 | #endif |