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 | |
50 | #define CHACHA_KEYSZ 32u | |
51 | #define CHACHA_OUTSZ 64u | |
52 | ||
53 | #define HCHACHA_INSZ 16u | |
54 | #define HCHACHA_OUTSZ 32u | |
55 | ||
56 | #define XCHACHA_NONCESZ 24u | |
57 | #define XCHACHA_KEYSZ CHACHA_KEYSZ | |
58 | #define XCHACHA_OUTSZ CHACHA_OUTSZ | |
59 | ||
60 | /*----- Data structures ---------------------------------------------------*/ | |
61 | ||
62 | typedef uint32 chacha_matrix[16]; | |
63 | ||
64 | typedef struct chacha_ctx { | |
65 | chacha_matrix a; | |
66 | octet buf[CHACHA_OUTSZ]; | |
67 | size_t bufi; | |
68 | } chacha_ctx; | |
69 | ||
70 | #define XCHACHA_DEFCTX(name) \ | |
71 | typedef struct name { chacha_ctx s; chacha_matrix k; } name | |
72 | XCHACHA_DEFCTX(xchacha20_ctx); | |
73 | XCHACHA_DEFCTX(xchacha12_ctx); | |
74 | XCHACHA_DEFCTX(xchacha8_ctx); | |
75 | ||
76 | /*----- The ChaCha stream cipher ------------------------------------------*/ | |
77 | ||
78 | /* --- @chacha_init@ --- * | |
79 | * | |
80 | * Arguments: @chacha_ctx *ctx@ = context to fill in | |
81 | * @const void *key@ = pointer to key material | |
82 | * @size_t ksz@ = size of key (either 32 or 16) | |
83 | * @const void *nonce@ = initial nonce, or null | |
84 | * | |
85 | * Returns: --- | |
86 | * | |
87 | * Use: Initializes a ChaCha context ready for use. | |
88 | */ | |
89 | ||
90 | extern void chacha_init(chacha_ctx */*ctx*/, | |
91 | const void */*key*/, size_t /*ksz*/, | |
92 | const void */*nonce*/); | |
93 | ||
94 | /* --- @chacha_setnonce@ --- * | |
95 | * | |
96 | * Arguments: @chacha_ctx *ctx@ = pointer to context | |
97 | * @const void *nonce@ = the nonce (@CHACHA_NONCESZ@ bytes) | |
98 | * | |
99 | * Returns: --- | |
100 | * | |
101 | * Use: Set a new nonce in the context @ctx@, e.g., for processing a | |
102 | * different message. The stream position is reset to zero (see | |
103 | * @chacha_seek@ etc.). | |
104 | */ | |
105 | ||
106 | extern void chacha_setnonce(chacha_ctx */*ctx*/, const void */*nonce*/); | |
107 | ||
108 | /* --- @chacha_seek@, @chacha_seeku64@ --- * | |
109 | * | |
110 | * Arguments: @chacha_ctx *ctx@ = pointer to context | |
111 | * @unsigned long i@, @kludge64 i@ = new position to set | |
112 | * | |
113 | * Returns: --- | |
114 | * | |
115 | * Use: Sets a new stream position, in units of ChaCha output | |
116 | * blocks, which are @CHACHA_OUTSZ@ bytes each. Byte | |
117 | * granularity can be achieved by calling @chacha_encrypt@ | |
118 | * appropriately. | |
119 | */ | |
120 | ||
121 | extern void chacha_seek(chacha_ctx */*ctx*/, unsigned long /*i*/); | |
122 | extern void chacha_seeku64(chacha_ctx */*ctx*/, kludge64 /*i*/); | |
123 | ||
124 | /* --- @chacha_tell@, @chacha_tellu64@ --- * | |
125 | * | |
126 | * Arguments: @chacha_ctx *ctx@ = pointer to context | |
127 | * | |
128 | * Returns: The current position in the output stream, in blocks, | |
129 | * rounding upwards. | |
130 | */ | |
131 | ||
132 | extern unsigned long chacha_tell(chacha_ctx */*ctx*/); | |
133 | extern kludge64 chacha_tellu64(chacha_ctx */*ctx*/); | |
134 | ||
135 | /* --- @chacha{20,12,8}_encrypt@ --- * | |
136 | * | |
137 | * Arguments: @chacha_ctx *ctx@ = pointer to context | |
138 | * @const void *src@ = source buffer (or null) | |
139 | * @void *dest@ = destination buffer (or null) | |
140 | * @size_t sz@ = size of the buffers | |
141 | * | |
142 | * Returns: --- | |
143 | * | |
144 | * Use: Encrypts or decrypts @sz@ bytes of data from @src@ to @dest@. | |
145 | * ChaCha works by XORing plaintext with a keystream, so | |
146 | * encryption and decryption are the same operation. If @dest@ | |
147 | * is null then ignore @src@ and skip @sz@ bytes of the | |
148 | * keystream. If @src@ is null, then just write the keystream | |
149 | * to @dest@. | |
150 | */ | |
151 | ||
152 | extern void chacha20_encrypt(chacha_ctx */*ctx*/, | |
153 | const void */*src*/, void */*dest*/, | |
154 | size_t /*sz*/); | |
155 | extern void chacha12_encrypt(chacha_ctx */*ctx*/, | |
156 | const void */*src*/, void */*dest*/, | |
157 | size_t /*sz*/); | |
158 | extern void chacha8_encrypt(chacha_ctx */*ctx*/, | |
159 | const void */*src*/, void */*dest*/, | |
160 | size_t /*sz*/); | |
161 | ||
162 | /*----- The HChaCha pseudorandom function ---------------------------------*/ | |
163 | ||
164 | /* --- @hchacha{20,12,8}_prf@ --- * | |
165 | * | |
166 | * Arguments: @chacha_ctx *ctx@ = pointer to context | |
167 | * @const void *src@ = the input (@HCHACHA_INSZ@ bytes) | |
168 | * @void *dest@ = the output (@HCHACHA_OUTSZ@ bytes) | |
169 | * | |
170 | * Returns: --- | |
171 | * | |
172 | * Use: Apply the HChaCha/r pseudorandom function to @src@, writing | |
173 | * the result to @out@. | |
174 | */ | |
175 | ||
176 | extern void hchacha20_prf(chacha_ctx */*ctx*/, | |
177 | const void */*src*/, void */*dest*/); | |
178 | extern void hchacha12_prf(chacha_ctx */*ctx*/, | |
179 | const void */*src*/, void */*dest*/); | |
180 | extern void hchacha8_prf(chacha_ctx */*ctx*/, | |
181 | const void */*src*/, void */*dest*/); | |
182 | ||
183 | /*----- The XChaCha stream cipher ----------------------------------------*/ | |
184 | ||
185 | /* --- @xchacha{20,12,8}_init@ --- * | |
186 | * | |
187 | * Arguments: @xchachaR_ctx *ctx@ = the context to fill in | |
188 | * @const void *key@ = pointer to key material | |
189 | * @size_t ksz@ = size of key (either 32 or 16) | |
190 | * @const void *nonce@ = initial nonce, or null | |
191 | * | |
192 | * Returns: --- | |
193 | * | |
194 | * Use: Initializes an XChaCha/r context ready for use. | |
195 | * | |
196 | * There is a different function for each number of rounds, | |
197 | * unlike for plain ChaCha. | |
198 | */ | |
199 | ||
200 | extern void xchacha20_init(xchacha20_ctx */*ctx*/, | |
201 | const void */*key*/, size_t /*ksz*/, | |
202 | const void */*nonce*/); | |
203 | extern void xchacha12_init(xchacha12_ctx */*ctx*/, | |
204 | const void */*key*/, size_t /*ksz*/, | |
205 | const void */*nonce*/); | |
206 | extern void xchacha8_init(xchacha8_ctx */*ctx*/, | |
207 | const void */*key*/, size_t /*ksz*/, | |
208 | const void */*nonce*/); | |
209 | ||
210 | /* --- @xchacha{20,12,8}_setnonce@ --- * | |
211 | * | |
212 | * Arguments: @xchachaR_ctx *ctx@ = pointer to context | |
213 | * @const void *nonce@ = the nonce (@XCHACHA_NONCESZ@ bytes) | |
214 | * | |
215 | * Returns: --- | |
216 | * | |
217 | * Use: Set a new nonce in the context @ctx@, e.g., for processing a | |
218 | * different message. The stream position is reset to zero (see | |
219 | * @chacha_seek@ etc.). | |
220 | * | |
221 | * There is a different function for each number of rounds, | |
222 | * unlike for plain ChaCha. | |
223 | */ | |
224 | ||
225 | extern void xchacha20_setnonce(xchacha20_ctx */*ctx*/, | |
226 | const void */*nonce*/); | |
227 | extern void xchacha12_setnonce(xchacha12_ctx */*ctx*/, | |
228 | const void */*nonce*/); | |
229 | extern void xchacha8_setnonce(xchacha8_ctx */*ctx*/, | |
230 | const void */*nonce*/); | |
231 | ||
232 | /* --- @xchacha{20,12,8}_seek@, @xchacha{20,12,8}_seeku64@ --- * | |
233 | * | |
234 | * Arguments: @xchachaR_ctx *ctx@ = pointer to context | |
235 | * @unsigned long i@, @kludge64 i@ = new position to set | |
236 | * | |
237 | * Returns: --- | |
238 | * | |
239 | * Use: Sets a new stream position, in units of ChaCha output | |
240 | * blocks, which are @XCHACHA_OUTSZ@ bytes each. Byte | |
241 | * granularity can be achieved by calling @xchachaR_encrypt@ | |
242 | * appropriately. | |
243 | * | |
244 | * There is a different function for each number of rounds, | |
245 | * unlike for plain ChaCha, because the context structures are | |
246 | * different. | |
247 | */ | |
248 | ||
249 | extern void xchacha20_seek(xchacha20_ctx */*ctx*/, unsigned long /*i*/); | |
250 | extern void xchacha12_seek(xchacha12_ctx */*ctx*/, unsigned long /*i*/); | |
251 | extern void xchacha8_seek(xchacha8_ctx */*ctx*/, unsigned long /*i*/); | |
252 | extern void xchacha20_seeku64(xchacha20_ctx */*ctx*/, kludge64 /*i*/); | |
253 | extern void xchacha12_seeku64(xchacha12_ctx */*ctx*/, kludge64 /*i*/); | |
254 | extern void xchacha8_seeku64(xchacha8_ctx */*ctx*/, kludge64 /*i*/); | |
255 | ||
256 | /* --- @xchacha{20,12,8}_tell@, @xchacha{20,12,8}_tellu64@ --- * | |
257 | * | |
258 | * Arguments: @chacha_ctx *ctx@ = pointer to context | |
259 | * | |
260 | * Returns: The current position in the output stream, in blocks, | |
261 | * rounding upwards. | |
262 | * | |
263 | * There is a different function for each number of rounds, | |
264 | * unlike for plain ChaCha, because the context structures are | |
265 | * different. | |
266 | */ | |
267 | ||
268 | extern unsigned long xchacha20_tell(xchacha20_ctx */*ctx*/); | |
269 | extern unsigned long xchacha12_tell(xchacha12_ctx */*ctx*/); | |
270 | extern unsigned long xchacha8_tell(xchacha8_ctx */*ctx*/); | |
271 | extern kludge64 xchacha20_tellu64(xchacha20_ctx */*ctx*/); | |
272 | extern kludge64 xchacha12_tellu64(xchacha12_ctx */*ctx*/); | |
273 | extern kludge64 xchacha8_tellu64(xchacha8_ctx */*ctx*/); | |
274 | ||
275 | /* --- @xchacha{20,12,8}_encrypt@ --- * | |
276 | * | |
277 | * Arguments: @xchachaR_ctx *ctx@ = pointer to context | |
278 | * @const void *src@ = source buffer (or null) | |
279 | * @void *dest@ = destination buffer (or null) | |
280 | * @size_t sz@ = size of the buffers | |
281 | * | |
282 | * Returns: --- | |
283 | * | |
284 | * Use: Encrypts or decrypts @sz@ bytes of data from @src@ to @dest@. | |
285 | * XChaCha works by XORing plaintext with a keystream, so | |
286 | * encryption and decryption are the same operation. If @dest@ | |
287 | * is null then ignore @src@ and skip @sz@ bytes of the | |
288 | * keystream. If @src@ is null, then just write the keystream | |
289 | * to @dest@. | |
290 | */ | |
291 | ||
292 | extern void xchacha20_encrypt(xchacha20_ctx */*ctx*/, | |
293 | const void */*src*/, void */*dest*/, | |
294 | size_t /*sz*/); | |
295 | extern void xchacha12_encrypt(xchacha12_ctx */*ctx*/, | |
296 | const void */*src*/, void */*dest*/, | |
297 | size_t /*sz*/); | |
298 | extern void xchacha8_encrypt(xchacha8_ctx */*ctx*/, | |
299 | const void */*src*/, void */*dest*/, | |
300 | size_t /*sz*/); | |
301 | ||
302 | /*----- Generic cipher interface ------------------------------------------*/ | |
303 | ||
304 | extern const octet chacha_keysz[]; | |
305 | #define chacha20_keysz chacha_keysz | |
306 | #define chacha12_keysz chacha_keysz | |
307 | #define chacha8_keysz chacha_keysz | |
308 | #define xchacha_keysz chacha_keysz | |
309 | #define xchacha20_keysz chacha_keysz | |
310 | #define xchacha12_keysz chacha_keysz | |
311 | #define xchacha8_keysz chacha_keysz | |
312 | ||
313 | const gccipher chacha20, chacha12, chacha8; | |
314 | const gccipher xchacha20, xchacha12, xchacha8; | |
315 | ||
316 | /*----- Generic random number generator interface -------------------------*/ | |
317 | ||
318 | /* --- @chacha{,12,8}_rand@, @xchacha{,12,8}_rand@ --- * | |
319 | * | |
320 | * Arguments: @const void *k@ = pointer to key material | |
321 | * @size_t ksz@ = size of key material | |
322 | * @const void *n@ = pointer to nonce or null | |
323 | * (@CHACHA_NONCESZ@ or @XCHACHA_NONCESZ@) | |
324 | * | |
325 | * Returns: Pointer to generic random number generator instance. | |
326 | * | |
327 | * Use: Creates a random number interface wrapper around | |
328 | * the ChaCha or XChaCha stream ciphers. | |
329 | */ | |
330 | ||
331 | extern grand *chacha20_rand(const void */*k*/, size_t /*ksz*/, | |
332 | const void */*n*/); | |
333 | extern grand *chacha12_rand(const void */*k*/, size_t /*ksz*/, | |
334 | const void */*n*/); | |
335 | extern grand *chacha8_rand(const void */*k*/, size_t /*ksz*/, | |
336 | const void */*n*/); | |
337 | extern grand *xchacha20_rand(const void */*k*/, size_t /*ksz*/, | |
338 | const void */*n*/); | |
339 | extern grand *xchacha12_rand(const void */*k*/, size_t /*ksz*/, | |
340 | const void */*n*/); | |
341 | extern grand *xchacha8_rand(const void */*k*/, size_t /*ksz*/, | |
342 | const void */*n*/); | |
343 | ||
344 | enum { | |
345 | CHACHA_SEEK = GRAND_SPECIFIC('S'), /* @unsigned long pos@ */ | |
346 | CHACHA_SEEKU64, /* @kludge64 pos@ */ | |
347 | CHACHA_TELL, /* @unsigned long *pos@ */ | |
348 | CHACHA_TELLU64 /* @kludge64 *pos@ */ | |
349 | }; | |
350 | ||
351 | /*----- That's all, folks -------------------------------------------------*/ | |
352 | ||
353 | #ifdef __cplusplus | |
354 | } | |
355 | #endif | |
356 | ||
357 | #endif |