lantiq: fritz7312: set maximum speed to 100 mbit on 5.4
[openwrt/staging/chunkeey.git] / package / network / services / dropbear / patches / 021-backport-chacha20-poly1305-support.patch
1 From 3cdf9ec918b37c17e12b33e4c244944d1ee836ca Mon Sep 17 00:00:00 2001
2 From: Vladislav Grishenko <themiron@mail.ru>
3 Date: Mon, 6 Apr 2020 23:28:09 +0500
4 Subject: [PATCH] Add Chacha20-Poly1305 authenticated encryption
5
6 * Add general AEAD approach.
7 * Add chacha20-poly1305@openssh.com algo using LibTomCrypt chacha and
8 poly1305 routines.
9
10 Chacha20-Poly1305 is generally faster than AES256 on CPU w/o dedicated
11 AES instructions, having the same key size.
12 Compiling in will add ~5,5kB to binary size on x86-64.
13 ---
14 Makefile.in | 2 +-
15 algo.h | 8 ++
16 chachapoly.c | 148 ++++++++++++++++++++
17 chachapoly.h | 44 ++++++
18 common-algo.c | 11 +-
19 common-kex.c | 44 ++++--
20 default_options.h | 6 +
21 libtomcrypt/src/headers/tomcrypt_dropbear.h | 4 +
22 packet.c | 145 +++++++++++++------
23 session.h | 4 +
24 sysoptions.h | 8 +-
25 11 files changed, 368 insertions(+), 56 deletions(-)
26 create mode 100644 chachapoly.c
27 create mode 100644 chachapoly.h
28
29 diff --git a/Makefile.in b/Makefile.in
30 index aaf7b3b..3437cb2 100644
31 --- a/Makefile.in
32 +++ b/Makefile.in
33 @@ -53,7 +53,7 @@ CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
34 CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
35 common-channel.o common-chansession.o termcodes.o loginrec.o \
36 tcp-accept.o listener.o process-packet.o dh_groups.o \
37 - common-runopts.o circbuffer.o list.o netio.o
38 + common-runopts.o circbuffer.o list.o netio.o chachapoly.o
39
40 KEYOBJS=dropbearkey.o
41
42 diff --git a/algo.h b/algo.h
43 index b12fb94..efd0d73 100644
44 --- a/algo.h
45 +++ b/algo.h
46 @@ -72,6 +72,14 @@ struct dropbear_cipher_mode {
47 unsigned long len, void *cipher_state);
48 int (*decrypt)(const unsigned char *ct, unsigned char *pt,
49 unsigned long len, void *cipher_state);
50 + int (*aead_crypt)(unsigned int seq,
51 + const unsigned char *in, unsigned char *out,
52 + unsigned long len, unsigned long taglen,
53 + void *cipher_state, int direction);
54 + int (*aead_getlength)(unsigned int seq,
55 + const unsigned char *in, unsigned int *outlen,
56 + unsigned long len, void *cipher_state);
57 + const struct dropbear_hash *aead_mac;
58 };
59
60 struct dropbear_hash {
61 diff --git a/chachapoly.c b/chachapoly.c
62 new file mode 100644
63 index 0000000..8fb06c5
64 --- /dev/null
65 +++ b/chachapoly.c
66 @@ -0,0 +1,148 @@
67 +/*
68 + * Dropbear SSH
69 + *
70 + * Copyright (c) 2002,2003 Matt Johnston
71 + * Copyright (c) 2020 by Vladislav Grishenko
72 + * All rights reserved.
73 + *
74 + * Permission is hereby granted, free of charge, to any person obtaining a copy
75 + * of this software and associated documentation files (the "Software"), to deal
76 + * in the Software without restriction, including without limitation the rights
77 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
78 + * copies of the Software, and to permit persons to whom the Software is
79 + * furnished to do so, subject to the following conditions:
80 + *
81 + * The above copyright notice and this permission notice shall be included in
82 + * all copies or substantial portions of the Software.
83 + *
84 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
85 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
86 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
87 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
88 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
89 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
90 + * SOFTWARE. */
91 +
92 +#include "includes.h"
93 +#include "algo.h"
94 +#include "dbutil.h"
95 +#include "chachapoly.h"
96 +
97 +#if DROPBEAR_CHACHA20POLY1305
98 +
99 +#define CHACHA20_KEY_LEN 32
100 +#define CHACHA20_BLOCKSIZE 8
101 +#define POLY1305_KEY_LEN 32
102 +#define POLY1305_TAG_LEN 16
103 +
104 +static const struct ltc_cipher_descriptor dummy = {.name = NULL};
105 +
106 +static const struct dropbear_hash dropbear_chachapoly_mac =
107 + {NULL, POLY1305_KEY_LEN, POLY1305_TAG_LEN};
108 +
109 +const struct dropbear_cipher dropbear_chachapoly =
110 + {&dummy, CHACHA20_KEY_LEN*2, CHACHA20_BLOCKSIZE};
111 +
112 +static int dropbear_chachapoly_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
113 + const unsigned char *key, int keylen,
114 + int UNUSED(num_rounds), dropbear_chachapoly_state *state) {
115 + int err;
116 +
117 + TRACE2(("enter dropbear_chachapoly_start"))
118 +
119 + if (keylen != CHACHA20_KEY_LEN*2) {
120 + return CRYPT_ERROR;
121 + }
122 +
123 + if ((err = chacha_setup(&state->chacha, key,
124 + CHACHA20_KEY_LEN, 20)) != CRYPT_OK) {
125 + return err;
126 + }
127 +
128 + if ((err = chacha_setup(&state->header, key + CHACHA20_KEY_LEN,
129 + CHACHA20_KEY_LEN, 20) != CRYPT_OK)) {
130 + return err;
131 + }
132 +
133 + TRACE2(("leave dropbear_chachapoly_start"))
134 + return CRYPT_OK;
135 +}
136 +
137 +static int dropbear_chachapoly_crypt(unsigned int seq,
138 + const unsigned char *in, unsigned char *out,
139 + unsigned long len, unsigned long taglen,
140 + dropbear_chachapoly_state *state, int direction) {
141 + poly1305_state poly;
142 + unsigned char seqbuf[8], key[POLY1305_KEY_LEN], tag[POLY1305_TAG_LEN];
143 + int err;
144 +
145 + TRACE2(("enter dropbear_chachapoly_crypt"))
146 +
147 + if (len < 4 || taglen != POLY1305_TAG_LEN) {
148 + return CRYPT_ERROR;
149 + }
150 +
151 + STORE64H((uint64_t)seq, seqbuf);
152 + chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 0);
153 + if ((err = chacha_keystream(&state->chacha, key, sizeof(key))) != CRYPT_OK) {
154 + return err;
155 + }
156 +
157 + poly1305_init(&poly, key, sizeof(key));
158 + if (direction == LTC_DECRYPT) {
159 + poly1305_process(&poly, in, len);
160 + poly1305_done(&poly, tag, &taglen);
161 + if (constant_time_memcmp(in + len, tag, taglen) != 0) {
162 + return CRYPT_ERROR;
163 + }
164 + }
165 +
166 + chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0);
167 + if ((err = chacha_crypt(&state->header, in, 4, out)) != CRYPT_OK) {
168 + return err;
169 + }
170 +
171 + chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 1);
172 + if ((err = chacha_crypt(&state->chacha, in + 4, len - 4, out + 4)) != CRYPT_OK) {
173 + return err;
174 + }
175 +
176 + if (direction == LTC_ENCRYPT) {
177 + poly1305_process(&poly, out, len);
178 + poly1305_done(&poly, out + len, &taglen);
179 + }
180 +
181 + TRACE2(("leave dropbear_chachapoly_crypt"))
182 + return CRYPT_OK;
183 +}
184 +
185 +static int dropbear_chachapoly_getlength(unsigned int seq,
186 + const unsigned char *in, unsigned int *outlen,
187 + unsigned long len, dropbear_chachapoly_state *state) {
188 + unsigned char seqbuf[8], buf[4];
189 + int err;
190 +
191 + TRACE2(("enter dropbear_chachapoly_getlength"))
192 +
193 + if (len < sizeof(buf)) {
194 + return CRYPT_ERROR;
195 + }
196 +
197 + STORE64H((uint64_t)seq, seqbuf);
198 + chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0);
199 + if ((err = chacha_crypt(&state->header, in, sizeof(buf), buf)) != CRYPT_OK) {
200 + return err;
201 + }
202 +
203 + LOAD32H(*outlen, buf);
204 +
205 + TRACE2(("leave dropbear_chachapoly_getlength"))
206 + return CRYPT_OK;
207 +}
208 +
209 +const struct dropbear_cipher_mode dropbear_mode_chachapoly =
210 + {(void *)dropbear_chachapoly_start, NULL, NULL,
211 + (void *)dropbear_chachapoly_crypt,
212 + (void *)dropbear_chachapoly_getlength, &dropbear_chachapoly_mac};
213 +
214 +#endif /* DROPBEAR_CHACHA20POLY1305 */
215 diff --git a/chachapoly.h b/chachapoly.h
216 new file mode 100644
217 index 0000000..5a7c5b2
218 --- /dev/null
219 +++ b/chachapoly.h
220 @@ -0,0 +1,44 @@
221 +/*
222 + * Dropbear SSH
223 + *
224 + * Copyright (c) 2002,2003 Matt Johnston
225 + * Copyright (c) 2020 by Vladislav Grishenko
226 + * All rights reserved.
227 + *
228 + * Permission is hereby granted, free of charge, to any person obtaining a copy
229 + * of this software and associated documentation files (the "Software"), to deal
230 + * in the Software without restriction, including without limitation the rights
231 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
232 + * copies of the Software, and to permit persons to whom the Software is
233 + * furnished to do so, subject to the following conditions:
234 + *
235 + * The above copyright notice and this permission notice shall be included in
236 + * all copies or substantial portions of the Software.
237 + *
238 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
239 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
240 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
241 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
242 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
243 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
244 + * SOFTWARE. */
245 +
246 +#ifndef DROPBEAR_DROPBEAR_CHACHAPOLY_H_
247 +#define DROPBEAR_DROPBEAR_CHACHAPOLY_H_
248 +
249 +#include "includes.h"
250 +#include "algo.h"
251 +
252 +#if DROPBEAR_CHACHA20POLY1305
253 +
254 +typedef struct {
255 + chacha_state chacha;
256 + chacha_state header;
257 +} dropbear_chachapoly_state;
258 +
259 +extern const struct dropbear_cipher dropbear_chachapoly;
260 +extern const struct dropbear_cipher_mode dropbear_mode_chachapoly;
261 +
262 +#endif /* DROPBEAR_CHACHA20POLY1305 */
263 +
264 +#endif /* DROPBEAR_DROPBEAR_CHACHAPOLY_H_ */
265 diff --git a/common-algo.c b/common-algo.c
266 index 558aad2..1436456 100644
267 --- a/common-algo.c
268 +++ b/common-algo.c
269 @@ -30,6 +30,7 @@
270 #include "dh_groups.h"
271 #include "ltc_prng.h"
272 #include "ecc.h"
273 +#include "chachapoly.h"
274
275 /* This file (algo.c) organises the ciphers which can be used, and is used to
276 * decide which ciphers/hashes/compression/signing to use during key exchange*/
277 @@ -86,11 +87,11 @@ const struct dropbear_cipher dropbear_nocipher =
278 * about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
279 #if DROPBEAR_ENABLE_CBC_MODE
280 const struct dropbear_cipher_mode dropbear_mode_cbc =
281 - {(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
282 + {(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt, NULL, NULL, NULL};
283 #endif /* DROPBEAR_ENABLE_CBC_MODE */
284
285 const struct dropbear_cipher_mode dropbear_mode_none =
286 - {void_start, void_cipher, void_cipher};
287 + {void_start, void_cipher, void_cipher, NULL, NULL, NULL};
288
289 #if DROPBEAR_ENABLE_CTR_MODE
290 /* a wrapper to make ctr_start and cbc_start look the same */
291 @@ -101,7 +102,7 @@ static int dropbear_big_endian_ctr_start(int cipher,
292 return ctr_start(cipher, IV, key, keylen, num_rounds, CTR_COUNTER_BIG_ENDIAN, ctr);
293 }
294 const struct dropbear_cipher_mode dropbear_mode_ctr =
295 - {(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
296 + {(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt, NULL, NULL, NULL};
297 #endif /* DROPBEAR_ENABLE_CTR_MODE */
298
299 /* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
300 @@ -137,6 +138,10 @@ const struct dropbear_hash dropbear_nohash =
301 * that is also supported by the server will get used. */
302
303 algo_type sshciphers[] = {
304 +#if DROPBEAR_CHACHA20POLY1305
305 + {"chacha20-poly1305@openssh.com", 0, &dropbear_chachapoly, 1, &dropbear_mode_chachapoly},
306 +#endif
307 +
308 #if DROPBEAR_ENABLE_CTR_MODE
309 #if DROPBEAR_AES128
310 {"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
311 diff --git a/common-kex.c b/common-kex.c
312 index 16b7e27..5e2923f 100644
313 --- a/common-kex.c
314 +++ b/common-kex.c
315 @@ -329,9 +329,12 @@ static void gen_new_keys() {
316 hashkeys(S2C_key, sizeof(S2C_key), &hs, 'D');
317
318 if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) {
319 - int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
320 - if (recv_cipher < 0)
321 - dropbear_exit("Crypto error");
322 + int recv_cipher = -1;
323 + if (ses.newkeys->recv.algo_crypt->cipherdesc->name != NULL) {
324 + recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
325 + if (recv_cipher < 0)
326 + dropbear_exit("Crypto error");
327 + }
328 if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
329 recv_IV, recv_key,
330 ses.newkeys->recv.algo_crypt->keysize, 0,
331 @@ -341,9 +344,12 @@ static void gen_new_keys() {
332 }
333
334 if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) {
335 - int trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
336 - if (trans_cipher < 0)
337 - dropbear_exit("Crypto error");
338 + int trans_cipher = -1;
339 + if (ses.newkeys->trans.algo_crypt->cipherdesc->name != NULL) {
340 + trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
341 + if (trans_cipher < 0)
342 + dropbear_exit("Crypto error");
343 + }
344 if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
345 trans_IV, trans_key,
346 ses.newkeys->trans.algo_crypt->keysize, 0,
347 @@ -868,19 +874,29 @@ static void read_kex_algos() {
348
349 /* mac_algorithms_client_to_server */
350 c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
351 +#if DROPBEAR_AEAD_MODE
352 + if (((struct dropbear_cipher_mode*)c2s_cipher_algo->mode)->aead_crypt != NULL) {
353 + c2s_hash_algo = NULL;
354 + } else
355 +#endif
356 if (c2s_hash_algo == NULL) {
357 erralgo = "mac c->s";
358 goto error;
359 }
360 - TRACE(("hash c2s is %s", c2s_hash_algo->name))
361 + TRACE(("hash c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "<implicit>"))
362
363 /* mac_algorithms_server_to_client */
364 s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
365 +#if DROPBEAR_AEAD_MODE
366 + if (((struct dropbear_cipher_mode*)s2c_cipher_algo->mode)->aead_crypt != NULL) {
367 + s2c_hash_algo = NULL;
368 + } else
369 +#endif
370 if (s2c_hash_algo == NULL) {
371 erralgo = "mac s->c";
372 goto error;
373 }
374 - TRACE(("hash s2c is %s", s2c_hash_algo->name))
375 + TRACE(("hash s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "<implicit>"))
376
377 /* compression_algorithms_client_to_server */
378 c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
379 @@ -925,8 +941,14 @@ static void read_kex_algos() {
380 ses.newkeys->trans.crypt_mode =
381 (struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
382 ses.newkeys->recv.algo_mac =
383 +#if DROPBEAR_AEAD_MODE
384 + s2c_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac :
385 +#endif
386 (struct dropbear_hash*)s2c_hash_algo->data;
387 ses.newkeys->trans.algo_mac =
388 +#if DROPBEAR_AEAD_MODE
389 + c2s_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac :
390 +#endif
391 (struct dropbear_hash*)c2s_hash_algo->data;
392 ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
393 ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
394 @@ -941,8 +963,14 @@ static void read_kex_algos() {
395 ses.newkeys->trans.crypt_mode =
396 (struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
397 ses.newkeys->recv.algo_mac =
398 +#if DROPBEAR_AEAD_MODE
399 + c2s_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac :
400 +#endif
401 (struct dropbear_hash*)c2s_hash_algo->data;
402 ses.newkeys->trans.algo_mac =
403 +#if DROPBEAR_AEAD_MODE
404 + s2c_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac :
405 +#endif
406 (struct dropbear_hash*)s2c_hash_algo->data;
407 ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
408 ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
409 diff --git a/default_options.h b/default_options.h
410 index bafbb07..1a2ab10 100644
411 --- a/default_options.h
412 +++ b/default_options.h
413 @@ -99,6 +99,12 @@ IMPORTANT: Some options will require "make clean" after changes */
414 * and forwards compatibility */
415 #define DROPBEAR_ENABLE_CTR_MODE 1
416
417 +/* Enable Chacha20-Poly1305 authenticated encryption mode. This is
418 + * generally faster than AES256 on CPU w/o dedicated AES instructions,
419 + * having the same key size.
420 + * Compiling in will add ~5,5kB to binary size on x86-64 */
421 +#define DROPBEAR_CHACHA20POLY1305 1
422 +
423 /* Message integrity. sha2-256 is recommended as a default,
424 sha1 for compatibility */
425 #define DROPBEAR_SHA1_HMAC 1
426 diff --git a/libtomcrypt/src/headers/tomcrypt_dropbear.h b/libtomcrypt/src/headers/tomcrypt_dropbear.h
427 index b0ce45b..59960e5 100644
428 --- a/libtomcrypt/src/headers/tomcrypt_dropbear.h
429 +++ b/libtomcrypt/src/headers/tomcrypt_dropbear.h
430 @@ -35,6 +35,10 @@
431 #define LTC_CTR_MODE
432 #endif
433
434 +#if DROPBEAR_CHACHA20POLY1305
435 +#define LTC_CHACHA
436 +#define LTC_POLY1305
437 +#endif
438
439 #if DROPBEAR_SHA512
440 #define LTC_SHA512
441 diff --git a/packet.c b/packet.c
442 index 9fda0d6..0454726 100644
443 --- a/packet.c
444 +++ b/packet.c
445 @@ -215,7 +215,7 @@ static int read_packet_init() {
446
447 unsigned int maxlen;
448 int slen;
449 - unsigned int len;
450 + unsigned int len, plen;
451 unsigned int blocksize;
452 unsigned int macsize;
453
454 @@ -254,21 +254,35 @@ static int read_packet_init() {
455 /* now we have the first block, need to get packet length, so we decrypt
456 * the first block (only need first 4 bytes) */
457 buf_setpos(ses.readbuf, 0);
458 - if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize),
459 - buf_getwriteptr(ses.readbuf, blocksize),
460 - blocksize,
461 - &ses.keys->recv.cipher_state) != CRYPT_OK) {
462 - dropbear_exit("Error decrypting");
463 +#if DROPBEAR_AEAD_MODE
464 + if (ses.keys->recv.crypt_mode->aead_crypt) {
465 + if (ses.keys->recv.crypt_mode->aead_getlength(ses.recvseq,
466 + buf_getptr(ses.readbuf, blocksize), &plen,
467 + blocksize,
468 + &ses.keys->recv.cipher_state) != CRYPT_OK) {
469 + dropbear_exit("Error decrypting");
470 + }
471 + len = plen + 4 + macsize;
472 + } else
473 +#endif
474 + {
475 + if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize),
476 + buf_getwriteptr(ses.readbuf, blocksize),
477 + blocksize,
478 + &ses.keys->recv.cipher_state) != CRYPT_OK) {
479 + dropbear_exit("Error decrypting");
480 + }
481 + plen = buf_getint(ses.readbuf) + 4;
482 + len = plen + macsize;
483 }
484 - len = buf_getint(ses.readbuf) + 4 + macsize;
485
486 TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize))
487
488
489 /* check packet length */
490 if ((len > RECV_MAX_PACKET_LEN) ||
491 - (len < MIN_PACKET_LEN + macsize) ||
492 - ((len - macsize) % blocksize != 0)) {
493 + (plen < blocksize) ||
494 + (plen % blocksize != 0)) {
495 dropbear_exit("Integrity error (bad packet size %u)", len);
496 }
497
498 @@ -294,23 +308,42 @@ void decrypt_packet() {
499
500 ses.kexstate.datarecv += ses.readbuf->len;
501
502 - /* we've already decrypted the first blocksize in read_packet_init */
503 - buf_setpos(ses.readbuf, blocksize);
504 -
505 - /* decrypt it in-place */
506 - len = ses.readbuf->len - macsize - ses.readbuf->pos;
507 - if (ses.keys->recv.crypt_mode->decrypt(
508 - buf_getptr(ses.readbuf, len),
509 - buf_getwriteptr(ses.readbuf, len),
510 - len,
511 - &ses.keys->recv.cipher_state) != CRYPT_OK) {
512 - dropbear_exit("Error decrypting");
513 - }
514 - buf_incrpos(ses.readbuf, len);
515 +#if DROPBEAR_AEAD_MODE
516 + if (ses.keys->recv.crypt_mode->aead_crypt) {
517 + /* first blocksize is not decrypted yet */
518 + buf_setpos(ses.readbuf, 0);
519 +
520 + /* decrypt it in-place */
521 + len = ses.readbuf->len - macsize - ses.readbuf->pos;
522 + if (ses.keys->recv.crypt_mode->aead_crypt(ses.recvseq,
523 + buf_getptr(ses.readbuf, len + macsize),
524 + buf_getwriteptr(ses.readbuf, len),
525 + len, macsize,
526 + &ses.keys->recv.cipher_state, LTC_DECRYPT) != CRYPT_OK) {
527 + dropbear_exit("Error decrypting");
528 + }
529 + buf_incrpos(ses.readbuf, len);
530 + } else
531 +#endif
532 + {
533 + /* we've already decrypted the first blocksize in read_packet_init */
534 + buf_setpos(ses.readbuf, blocksize);
535 +
536 + /* decrypt it in-place */
537 + len = ses.readbuf->len - macsize - ses.readbuf->pos;
538 + if (ses.keys->recv.crypt_mode->decrypt(
539 + buf_getptr(ses.readbuf, len),
540 + buf_getwriteptr(ses.readbuf, len),
541 + len,
542 + &ses.keys->recv.cipher_state) != CRYPT_OK) {
543 + dropbear_exit("Error decrypting");
544 + }
545 + buf_incrpos(ses.readbuf, len);
546
547 - /* check the hmac */
548 - if (checkmac() != DROPBEAR_SUCCESS) {
549 - dropbear_exit("Integrity error");
550 + /* check the hmac */
551 + if (checkmac() != DROPBEAR_SUCCESS) {
552 + dropbear_exit("Integrity error");
553 + }
554 }
555
556 /* get padding length */
557 @@ -557,9 +590,16 @@ void encrypt_packet() {
558 buf_setpos(ses.writepayload, 0);
559 buf_setlen(ses.writepayload, 0);
560
561 - /* length of padding - packet length must be a multiple of blocksize,
562 - * with a minimum of 4 bytes of padding */
563 - padlen = blocksize - (writebuf->len) % blocksize;
564 + /* length of padding - packet length excluding the packetlength uint32
565 + * field in aead mode must be a multiple of blocksize, with a minimum of
566 + * 4 bytes of padding */
567 + len = writebuf->len;
568 +#if DROPBEAR_AEAD_MODE
569 + if (ses.keys->trans.crypt_mode->aead_crypt) {
570 + len -= 4;
571 + }
572 +#endif
573 + padlen = blocksize - len % blocksize;
574 if (padlen < 4) {
575 padlen += blocksize;
576 }
577 @@ -579,23 +619,42 @@ void encrypt_packet() {
578 buf_incrlen(writebuf, padlen);
579 genrandom(buf_getptr(writebuf, padlen), padlen);
580
581 - make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes);
582 +#if DROPBEAR_AEAD_MODE
583 + if (ses.keys->trans.crypt_mode->aead_crypt) {
584 + /* do the actual encryption, in-place */
585 + buf_setpos(writebuf, 0);
586 + /* encrypt it in-place*/
587 + len = writebuf->len;
588 + buf_incrlen(writebuf, mac_size);
589 + if (ses.keys->trans.crypt_mode->aead_crypt(ses.transseq,
590 + buf_getptr(writebuf, len),
591 + buf_getwriteptr(writebuf, len + mac_size),
592 + len, mac_size,
593 + &ses.keys->trans.cipher_state, LTC_ENCRYPT) != CRYPT_OK) {
594 + dropbear_exit("Error encrypting");
595 + }
596 + buf_incrpos(writebuf, len + mac_size);
597 + } else
598 +#endif
599 + {
600 + make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes);
601 +
602 + /* do the actual encryption, in-place */
603 + buf_setpos(writebuf, 0);
604 + /* encrypt it in-place*/
605 + len = writebuf->len;
606 + if (ses.keys->trans.crypt_mode->encrypt(
607 + buf_getptr(writebuf, len),
608 + buf_getwriteptr(writebuf, len),
609 + len,
610 + &ses.keys->trans.cipher_state) != CRYPT_OK) {
611 + dropbear_exit("Error encrypting");
612 + }
613 + buf_incrpos(writebuf, len);
614
615 - /* do the actual encryption, in-place */
616 - buf_setpos(writebuf, 0);
617 - /* encrypt it in-place*/
618 - len = writebuf->len;
619 - if (ses.keys->trans.crypt_mode->encrypt(
620 - buf_getptr(writebuf, len),
621 - buf_getwriteptr(writebuf, len),
622 - len,
623 - &ses.keys->trans.cipher_state) != CRYPT_OK) {
624 - dropbear_exit("Error encrypting");
625 + /* stick the MAC on it */
626 + buf_putbytes(writebuf, mac_bytes, mac_size);
627 }
628 - buf_incrpos(writebuf, len);
629 -
630 - /* stick the MAC on it */
631 - buf_putbytes(writebuf, mac_bytes, mac_size);
632
633 /* Update counts */
634 ses.kexstate.datatrans += writebuf->len;
635 diff --git a/session.h b/session.h
636 index e436882..a8f8914 100644
637 --- a/session.h
638 +++ b/session.h
639 @@ -41,6 +41,7 @@
640 #include "chansession.h"
641 #include "dbutil.h"
642 #include "netio.h"
643 +#include "chachapoly.h"
644
645 void common_session_init(int sock_in, int sock_out);
646 void session_loop(void(*loophandler)(void)) ATTRIB_NORETURN;
647 @@ -80,6 +81,9 @@ struct key_context_directional {
648 symmetric_CBC cbc;
649 #if DROPBEAR_ENABLE_CTR_MODE
650 symmetric_CTR ctr;
651 +#endif
652 +#if DROPBEAR_CHACHA20POLY1305
653 + dropbear_chachapoly_state chachapoly;
654 #endif
655 } cipher_state;
656 unsigned char mackey[MAX_MAC_LEN];
657 diff --git a/sysoptions.h b/sysoptions.h
658 index 2c27caf..2432779 100644
659 --- a/sysoptions.h
660 +++ b/sysoptions.h
661 @@ -92,7 +92,11 @@
662 #define MD5_HASH_SIZE 16
663 #define MAX_HASH_SIZE 64 /* sha512 */
664
665 +#if DROPBEAR_CHACHA20POLY1305
666 +#define MAX_KEY_LEN 64 /* 2 x 256 bits for chacha20 */
667 +#else
668 #define MAX_KEY_LEN 32 /* 256 bits for aes256 etc */
669 +#endif
670 #define MAX_IV_LEN 20 /* must be same as max blocksize, */
671
672 #if DROPBEAR_SHA2_512_HMAC
673 @@ -207,6 +211,8 @@ If you test it please contact the Dropbear author */
674
675 #define DROPBEAR_TWOFISH ((DROPBEAR_TWOFISH256) || (DROPBEAR_TWOFISH128))
676
677 +#define DROPBEAR_AEAD_MODE ((DROPBEAR_CHACHA20POLY1305))
678 +
679 #define DROPBEAR_CLI_ANYTCPFWD ((DROPBEAR_CLI_REMOTETCPFWD) || (DROPBEAR_CLI_LOCALTCPFWD))
680
681 #define DROPBEAR_TCP_ACCEPT ((DROPBEAR_CLI_LOCALTCPFWD) || (DROPBEAR_SVR_REMOTETCPFWD))
682 @@ -249,7 +255,7 @@ If you test it please contact the Dropbear author */
683 #endif
684
685 #if !(DROPBEAR_AES128 || DROPBEAR_3DES || DROPBEAR_AES256 || DROPBEAR_BLOWFISH \
686 - || DROPBEAR_TWOFISH256 || DROPBEAR_TWOFISH128)
687 + || DROPBEAR_TWOFISH256 || DROPBEAR_TWOFISH128 || DROPBEAR_CHACHA20POLY1305)
688 #error "At least one encryption algorithm must be enabled. AES128 is recommended."
689 #endif
690
691 --
692 2.17.1
693