aboutsummaryrefslogtreecommitdiffstats
path: root/package/network/services/dropbear/patches/021-backport-chacha20-poly1305-support.patch
diff options
context:
space:
mode:
authorVladislav Grishenko <themiron@mail.ru>2020-04-13 03:24:28 +0500
committerHans Dedecker <dedeckeh@gmail.com>2020-05-30 21:27:10 +0200
commitf166cf9ca07ceb023db356532cf4154ef433322a (patch)
treedbc22710b222fb4e437a3d581fa085c8e423033d /package/network/services/dropbear/patches/021-backport-chacha20-poly1305-support.patch
parent02f08056bcbc5f014894b7edcea43f2ff822fd90 (diff)
downloadupstream-f166cf9ca07ceb023db356532cf4154ef433322a.tar.gz
upstream-f166cf9ca07ceb023db356532cf4154ef433322a.tar.bz2
upstream-f166cf9ca07ceb023db356532cf4154ef433322a.zip
dropbear: add ed25519 and chacha20-poly1305
- add Ed25519 support (backport): * DROPBEAR_ED25519 option for ssh-ed25519, * disabled by default - add Chacha20-Poly1305 support (backport): * DROPBEAR_CHACHA20POLY1305 for chacha20-poly1305@openssh.com, * enabled by default - update feature costs in binary size Signed-off-by: Vladislav Grishenko <themiron@mail.ru>
Diffstat (limited to 'package/network/services/dropbear/patches/021-backport-chacha20-poly1305-support.patch')
-rw-r--r--package/network/services/dropbear/patches/021-backport-chacha20-poly1305-support.patch693
1 files changed, 693 insertions, 0 deletions
diff --git a/package/network/services/dropbear/patches/021-backport-chacha20-poly1305-support.patch b/package/network/services/dropbear/patches/021-backport-chacha20-poly1305-support.patch
new file mode 100644
index 0000000000..2120b4593e
--- /dev/null
+++ b/package/network/services/dropbear/patches/021-backport-chacha20-poly1305-support.patch
@@ -0,0 +1,693 @@
+From 3cdf9ec918b37c17e12b33e4c244944d1ee836ca Mon Sep 17 00:00:00 2001
+From: Vladislav Grishenko <themiron@mail.ru>
+Date: Mon, 6 Apr 2020 23:28:09 +0500
+Subject: [PATCH] Add Chacha20-Poly1305 authenticated encryption
+
+* Add general AEAD approach.
+* Add chacha20-poly1305@openssh.com algo using LibTomCrypt chacha and
+ poly1305 routines.
+
+Chacha20-Poly1305 is generally faster than AES256 on CPU w/o dedicated
+AES instructions, having the same key size.
+Compiling in will add ~5,5kB to binary size on x86-64.
+---
+ Makefile.in | 2 +-
+ algo.h | 8 ++
+ chachapoly.c | 148 ++++++++++++++++++++
+ chachapoly.h | 44 ++++++
+ common-algo.c | 11 +-
+ common-kex.c | 44 ++++--
+ default_options.h | 6 +
+ libtomcrypt/src/headers/tomcrypt_dropbear.h | 4 +
+ packet.c | 145 +++++++++++++------
+ session.h | 4 +
+ sysoptions.h | 8 +-
+ 11 files changed, 368 insertions(+), 56 deletions(-)
+ create mode 100644 chachapoly.c
+ create mode 100644 chachapoly.h
+
+diff --git a/Makefile.in b/Makefile.in
+index aaf7b3b..3437cb2 100644
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -53,7 +53,7 @@ CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
+ CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
+ common-channel.o common-chansession.o termcodes.o loginrec.o \
+ tcp-accept.o listener.o process-packet.o dh_groups.o \
+- common-runopts.o circbuffer.o list.o netio.o
++ common-runopts.o circbuffer.o list.o netio.o chachapoly.o
+
+ KEYOBJS=dropbearkey.o
+
+diff --git a/algo.h b/algo.h
+index b12fb94..efd0d73 100644
+--- a/algo.h
++++ b/algo.h
+@@ -72,6 +72,14 @@ struct dropbear_cipher_mode {
+ unsigned long len, void *cipher_state);
+ int (*decrypt)(const unsigned char *ct, unsigned char *pt,
+ unsigned long len, void *cipher_state);
++ int (*aead_crypt)(unsigned int seq,
++ const unsigned char *in, unsigned char *out,
++ unsigned long len, unsigned long taglen,
++ void *cipher_state, int direction);
++ int (*aead_getlength)(unsigned int seq,
++ const unsigned char *in, unsigned int *outlen,
++ unsigned long len, void *cipher_state);
++ const struct dropbear_hash *aead_mac;
+ };
+
+ struct dropbear_hash {
+diff --git a/chachapoly.c b/chachapoly.c
+new file mode 100644
+index 0000000..8fb06c5
+--- /dev/null
++++ b/chachapoly.c
+@@ -0,0 +1,148 @@
++/*
++ * Dropbear SSH
++ *
++ * Copyright (c) 2002,2003 Matt Johnston
++ * Copyright (c) 2020 by Vladislav Grishenko
++ * All rights reserved.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE. */
++
++#include "includes.h"
++#include "algo.h"
++#include "dbutil.h"
++#include "chachapoly.h"
++
++#if DROPBEAR_CHACHA20POLY1305
++
++#define CHACHA20_KEY_LEN 32
++#define CHACHA20_BLOCKSIZE 8
++#define POLY1305_KEY_LEN 32
++#define POLY1305_TAG_LEN 16
++
++static const struct ltc_cipher_descriptor dummy = {.name = NULL};
++
++static const struct dropbear_hash dropbear_chachapoly_mac =
++ {NULL, POLY1305_KEY_LEN, POLY1305_TAG_LEN};
++
++const struct dropbear_cipher dropbear_chachapoly =
++ {&dummy, CHACHA20_KEY_LEN*2, CHACHA20_BLOCKSIZE};
++
++static int dropbear_chachapoly_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
++ const unsigned char *key, int keylen,
++ int UNUSED(num_rounds), dropbear_chachapoly_state *state) {
++ int err;
++
++ TRACE2(("enter dropbear_chachapoly_start"))
++
++ if (keylen != CHACHA20_KEY_LEN*2) {
++ return CRYPT_ERROR;
++ }
++
++ if ((err = chacha_setup(&state->chacha, key,
++ CHACHA20_KEY_LEN, 20)) != CRYPT_OK) {
++ return err;
++ }
++
++ if ((err = chacha_setup(&state->header, key + CHACHA20_KEY_LEN,
++ CHACHA20_KEY_LEN, 20) != CRYPT_OK)) {
++ return err;
++ }
++
++ TRACE2(("leave dropbear_chachapoly_start"))
++ return CRYPT_OK;
++}
++
++static int dropbear_chachapoly_crypt(unsigned int seq,
++ const unsigned char *in, unsigned char *out,
++ unsigned long len, unsigned long taglen,
++ dropbear_chachapoly_state *state, int direction) {
++ poly1305_state poly;
++ unsigned char seqbuf[8], key[POLY1305_KEY_LEN], tag[POLY1305_TAG_LEN];
++ int err;
++
++ TRACE2(("enter dropbear_chachapoly_crypt"))
++
++ if (len < 4 || taglen != POLY1305_TAG_LEN) {
++ return CRYPT_ERROR;
++ }
++
++ STORE64H((uint64_t)seq, seqbuf);
++ chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 0);
++ if ((err = chacha_keystream(&state->chacha, key, sizeof(key))) != CRYPT_OK) {
++ return err;
++ }
++
++ poly1305_init(&poly, key, sizeof(key));
++ if (direction == LTC_DECRYPT) {
++ poly1305_process(&poly, in, len);
++ poly1305_done(&poly, tag, &taglen);
++ if (constant_time_memcmp(in + len, tag, taglen) != 0) {
++ return CRYPT_ERROR;
++ }
++ }
++
++ chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0);
++ if ((err = chacha_crypt(&state->header, in, 4, out)) != CRYPT_OK) {
++ return err;
++ }
++
++ chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 1);
++ if ((err = chacha_crypt(&state->chacha, in + 4, len - 4, out + 4)) != CRYPT_OK) {
++ return err;
++ }
++
++ if (direction == LTC_ENCRYPT) {
++ poly1305_process(&poly, out, len);
++ poly1305_done(&poly, out + len, &taglen);
++ }
++
++ TRACE2(("leave dropbear_chachapoly_crypt"))
++ return CRYPT_OK;
++}
++
++static int dropbear_chachapoly_getlength(unsigned int seq,
++ const unsigned char *in, unsigned int *outlen,
++ unsigned long len, dropbear_chachapoly_state *state) {
++ unsigned char seqbuf[8], buf[4];
++ int err;
++
++ TRACE2(("enter dropbear_chachapoly_getlength"))
++
++ if (len < sizeof(buf)) {
++ return CRYPT_ERROR;
++ }
++
++ STORE64H((uint64_t)seq, seqbuf);
++ chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0);
++ if ((err = chacha_crypt(&state->header, in, sizeof(buf), buf)) != CRYPT_OK) {
++ return err;
++ }
++
++ LOAD32H(*outlen, buf);
++
++ TRACE2(("leave dropbear_chachapoly_getlength"))
++ return CRYPT_OK;
++}
++
++const struct dropbear_cipher_mode dropbear_mode_chachapoly =
++ {(void *)dropbear_chachapoly_start, NULL, NULL,
++ (void *)dropbear_chachapoly_crypt,
++ (void *)dropbear_chachapoly_getlength, &dropbear_chachapoly_mac};
++
++#endif /* DROPBEAR_CHACHA20POLY1305 */
+diff --git a/chachapoly.h b/chachapoly.h
+new file mode 100644
+index 0000000..5a7c5b2
+--- /dev/null
++++ b/chachapoly.h
+@@ -0,0 +1,44 @@
++/*
++ * Dropbear SSH
++ *
++ * Copyright (c) 2002,2003 Matt Johnston
++ * Copyright (c) 2020 by Vladislav Grishenko
++ * All rights reserved.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE. */
++
++#ifndef DROPBEAR_DROPBEAR_CHACHAPOLY_H_
++#define DROPBEAR_DROPBEAR_CHACHAPOLY_H_
++
++#include "includes.h"
++#include "algo.h"
++
++#if DROPBEAR_CHACHA20POLY1305
++
++typedef struct {
++ chacha_state chacha;
++ chacha_state header;
++} dropbear_chachapoly_state;
++
++extern const struct dropbear_cipher dropbear_chachapoly;
++extern const struct dropbear_cipher_mode dropbear_mode_chachapoly;
++
++#endif /* DROPBEAR_CHACHA20POLY1305 */
++
++#endif /* DROPBEAR_DROPBEAR_CHACHAPOLY_H_ */
+diff --git a/common-algo.c b/common-algo.c
+index 558aad2..1436456 100644
+--- a/common-algo.c
++++ b/common-algo.c
+@@ -30,6 +30,7 @@
+ #include "dh_groups.h"
+ #include "ltc_prng.h"
+ #include "ecc.h"
++#include "chachapoly.h"
+
+ /* This file (algo.c) organises the ciphers which can be used, and is used to
+ * decide which ciphers/hashes/compression/signing to use during key exchange*/
+@@ -86,11 +87,11 @@ const struct dropbear_cipher dropbear_nocipher =
+ * about the symmetric_CBC vs symmetric_CTR cipher_state pointer */
+ #if DROPBEAR_ENABLE_CBC_MODE
+ const struct dropbear_cipher_mode dropbear_mode_cbc =
+- {(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt};
++ {(void*)cbc_start, (void*)cbc_encrypt, (void*)cbc_decrypt, NULL, NULL, NULL};
+ #endif /* DROPBEAR_ENABLE_CBC_MODE */
+
+ const struct dropbear_cipher_mode dropbear_mode_none =
+- {void_start, void_cipher, void_cipher};
++ {void_start, void_cipher, void_cipher, NULL, NULL, NULL};
+
+ #if DROPBEAR_ENABLE_CTR_MODE
+ /* a wrapper to make ctr_start and cbc_start look the same */
+@@ -101,7 +102,7 @@ static int dropbear_big_endian_ctr_start(int cipher,
+ return ctr_start(cipher, IV, key, keylen, num_rounds, CTR_COUNTER_BIG_ENDIAN, ctr);
+ }
+ const struct dropbear_cipher_mode dropbear_mode_ctr =
+- {(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt};
++ {(void*)dropbear_big_endian_ctr_start, (void*)ctr_encrypt, (void*)ctr_decrypt, NULL, NULL, NULL};
+ #endif /* DROPBEAR_ENABLE_CTR_MODE */
+
+ /* Mapping of ssh hashes to libtomcrypt hashes, including keysize etc.
+@@ -137,6 +138,10 @@ const struct dropbear_hash dropbear_nohash =
+ * that is also supported by the server will get used. */
+
+ algo_type sshciphers[] = {
++#if DROPBEAR_CHACHA20POLY1305
++ {"chacha20-poly1305@openssh.com", 0, &dropbear_chachapoly, 1, &dropbear_mode_chachapoly},
++#endif
++
+ #if DROPBEAR_ENABLE_CTR_MODE
+ #if DROPBEAR_AES128
+ {"aes128-ctr", 0, &dropbear_aes128, 1, &dropbear_mode_ctr},
+diff --git a/common-kex.c b/common-kex.c
+index 16b7e27..5e2923f 100644
+--- a/common-kex.c
++++ b/common-kex.c
+@@ -329,9 +329,12 @@ static void gen_new_keys() {
+ hashkeys(S2C_key, sizeof(S2C_key), &hs, 'D');
+
+ if (ses.newkeys->recv.algo_crypt->cipherdesc != NULL) {
+- int recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
+- if (recv_cipher < 0)
+- dropbear_exit("Crypto error");
++ int recv_cipher = -1;
++ if (ses.newkeys->recv.algo_crypt->cipherdesc->name != NULL) {
++ recv_cipher = find_cipher(ses.newkeys->recv.algo_crypt->cipherdesc->name);
++ if (recv_cipher < 0)
++ dropbear_exit("Crypto error");
++ }
+ if (ses.newkeys->recv.crypt_mode->start(recv_cipher,
+ recv_IV, recv_key,
+ ses.newkeys->recv.algo_crypt->keysize, 0,
+@@ -341,9 +344,12 @@ static void gen_new_keys() {
+ }
+
+ if (ses.newkeys->trans.algo_crypt->cipherdesc != NULL) {
+- int trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
+- if (trans_cipher < 0)
+- dropbear_exit("Crypto error");
++ int trans_cipher = -1;
++ if (ses.newkeys->trans.algo_crypt->cipherdesc->name != NULL) {
++ trans_cipher = find_cipher(ses.newkeys->trans.algo_crypt->cipherdesc->name);
++ if (trans_cipher < 0)
++ dropbear_exit("Crypto error");
++ }
+ if (ses.newkeys->trans.crypt_mode->start(trans_cipher,
+ trans_IV, trans_key,
+ ses.newkeys->trans.algo_crypt->keysize, 0,
+@@ -868,19 +874,29 @@ static void read_kex_algos() {
+
+ /* mac_algorithms_client_to_server */
+ c2s_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
++#if DROPBEAR_AEAD_MODE
++ if (((struct dropbear_cipher_mode*)c2s_cipher_algo->mode)->aead_crypt != NULL) {
++ c2s_hash_algo = NULL;
++ } else
++#endif
+ if (c2s_hash_algo == NULL) {
+ erralgo = "mac c->s";
+ goto error;
+ }
+- TRACE(("hash c2s is %s", c2s_hash_algo->name))
++ TRACE(("hash c2s is %s", c2s_hash_algo ? c2s_hash_algo->name : "<implicit>"))
+
+ /* mac_algorithms_server_to_client */
+ s2c_hash_algo = buf_match_algo(ses.payload, sshhashes, NULL, NULL);
++#if DROPBEAR_AEAD_MODE
++ if (((struct dropbear_cipher_mode*)s2c_cipher_algo->mode)->aead_crypt != NULL) {
++ s2c_hash_algo = NULL;
++ } else
++#endif
+ if (s2c_hash_algo == NULL) {
+ erralgo = "mac s->c";
+ goto error;
+ }
+- TRACE(("hash s2c is %s", s2c_hash_algo->name))
++ TRACE(("hash s2c is %s", s2c_hash_algo ? s2c_hash_algo->name : "<implicit>"))
+
+ /* compression_algorithms_client_to_server */
+ c2s_comp_algo = buf_match_algo(ses.payload, ses.compress_algos, NULL, NULL);
+@@ -925,8 +941,14 @@ static void read_kex_algos() {
+ ses.newkeys->trans.crypt_mode =
+ (struct dropbear_cipher_mode*)c2s_cipher_algo->mode;
+ ses.newkeys->recv.algo_mac =
++#if DROPBEAR_AEAD_MODE
++ s2c_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac :
++#endif
+ (struct dropbear_hash*)s2c_hash_algo->data;
+ ses.newkeys->trans.algo_mac =
++#if DROPBEAR_AEAD_MODE
++ c2s_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac :
++#endif
+ (struct dropbear_hash*)c2s_hash_algo->data;
+ ses.newkeys->recv.algo_comp = s2c_comp_algo->val;
+ ses.newkeys->trans.algo_comp = c2s_comp_algo->val;
+@@ -941,8 +963,14 @@ static void read_kex_algos() {
+ ses.newkeys->trans.crypt_mode =
+ (struct dropbear_cipher_mode*)s2c_cipher_algo->mode;
+ ses.newkeys->recv.algo_mac =
++#if DROPBEAR_AEAD_MODE
++ c2s_hash_algo == NULL ? ses.newkeys->recv.crypt_mode->aead_mac :
++#endif
+ (struct dropbear_hash*)c2s_hash_algo->data;
+ ses.newkeys->trans.algo_mac =
++#if DROPBEAR_AEAD_MODE
++ s2c_hash_algo == NULL ? ses.newkeys->trans.crypt_mode->aead_mac :
++#endif
+ (struct dropbear_hash*)s2c_hash_algo->data;
+ ses.newkeys->recv.algo_comp = c2s_comp_algo->val;
+ ses.newkeys->trans.algo_comp = s2c_comp_algo->val;
+diff --git a/default_options.h b/default_options.h
+index bafbb07..1a2ab10 100644
+--- a/default_options.h
++++ b/default_options.h
+@@ -99,6 +99,12 @@ IMPORTANT: Some options will require "make clean" after changes */
+ * and forwards compatibility */
+ #define DROPBEAR_ENABLE_CTR_MODE 1
+
++/* Enable Chacha20-Poly1305 authenticated encryption mode. This is
++ * generally faster than AES256 on CPU w/o dedicated AES instructions,
++ * having the same key size.
++ * Compiling in will add ~5,5kB to binary size on x86-64 */
++#define DROPBEAR_CHACHA20POLY1305 1
++
+ /* Message integrity. sha2-256 is recommended as a default,
+ sha1 for compatibility */
+ #define DROPBEAR_SHA1_HMAC 1
+diff --git a/libtomcrypt/src/headers/tomcrypt_dropbear.h b/libtomcrypt/src/headers/tomcrypt_dropbear.h
+index b0ce45b..59960e5 100644
+--- a/libtomcrypt/src/headers/tomcrypt_dropbear.h
++++ b/libtomcrypt/src/headers/tomcrypt_dropbear.h
+@@ -35,6 +35,10 @@
+ #define LTC_CTR_MODE
+ #endif
+
++#if DROPBEAR_CHACHA20POLY1305
++#define LTC_CHACHA
++#define LTC_POLY1305
++#endif
+
+ #if DROPBEAR_SHA512
+ #define LTC_SHA512
+diff --git a/packet.c b/packet.c
+index 9fda0d6..0454726 100644
+--- a/packet.c
++++ b/packet.c
+@@ -215,7 +215,7 @@ static int read_packet_init() {
+
+ unsigned int maxlen;
+ int slen;
+- unsigned int len;
++ unsigned int len, plen;
+ unsigned int blocksize;
+ unsigned int macsize;
+
+@@ -254,21 +254,35 @@ static int read_packet_init() {
+ /* now we have the first block, need to get packet length, so we decrypt
+ * the first block (only need first 4 bytes) */
+ buf_setpos(ses.readbuf, 0);
+- if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize),
+- buf_getwriteptr(ses.readbuf, blocksize),
+- blocksize,
+- &ses.keys->recv.cipher_state) != CRYPT_OK) {
+- dropbear_exit("Error decrypting");
++#if DROPBEAR_AEAD_MODE
++ if (ses.keys->recv.crypt_mode->aead_crypt) {
++ if (ses.keys->recv.crypt_mode->aead_getlength(ses.recvseq,
++ buf_getptr(ses.readbuf, blocksize), &plen,
++ blocksize,
++ &ses.keys->recv.cipher_state) != CRYPT_OK) {
++ dropbear_exit("Error decrypting");
++ }
++ len = plen + 4 + macsize;
++ } else
++#endif
++ {
++ if (ses.keys->recv.crypt_mode->decrypt(buf_getptr(ses.readbuf, blocksize),
++ buf_getwriteptr(ses.readbuf, blocksize),
++ blocksize,
++ &ses.keys->recv.cipher_state) != CRYPT_OK) {
++ dropbear_exit("Error decrypting");
++ }
++ plen = buf_getint(ses.readbuf) + 4;
++ len = plen + macsize;
+ }
+- len = buf_getint(ses.readbuf) + 4 + macsize;
+
+ TRACE2(("packet size is %u, block %u mac %u", len, blocksize, macsize))
+
+
+ /* check packet length */
+ if ((len > RECV_MAX_PACKET_LEN) ||
+- (len < MIN_PACKET_LEN + macsize) ||
+- ((len - macsize) % blocksize != 0)) {
++ (plen < blocksize) ||
++ (plen % blocksize != 0)) {
+ dropbear_exit("Integrity error (bad packet size %u)", len);
+ }
+
+@@ -294,23 +308,42 @@ void decrypt_packet() {
+
+ ses.kexstate.datarecv += ses.readbuf->len;
+
+- /* we've already decrypted the first blocksize in read_packet_init */
+- buf_setpos(ses.readbuf, blocksize);
+-
+- /* decrypt it in-place */
+- len = ses.readbuf->len - macsize - ses.readbuf->pos;
+- if (ses.keys->recv.crypt_mode->decrypt(
+- buf_getptr(ses.readbuf, len),
+- buf_getwriteptr(ses.readbuf, len),
+- len,
+- &ses.keys->recv.cipher_state) != CRYPT_OK) {
+- dropbear_exit("Error decrypting");
+- }
+- buf_incrpos(ses.readbuf, len);
++#if DROPBEAR_AEAD_MODE
++ if (ses.keys->recv.crypt_mode->aead_crypt) {
++ /* first blocksize is not decrypted yet */
++ buf_setpos(ses.readbuf, 0);
++
++ /* decrypt it in-place */
++ len = ses.readbuf->len - macsize - ses.readbuf->pos;
++ if (ses.keys->recv.crypt_mode->aead_crypt(ses.recvseq,
++ buf_getptr(ses.readbuf, len + macsize),
++ buf_getwriteptr(ses.readbuf, len),
++ len, macsize,
++ &ses.keys->recv.cipher_state, LTC_DECRYPT) != CRYPT_OK) {
++ dropbear_exit("Error decrypting");
++ }
++ buf_incrpos(ses.readbuf, len);
++ } else
++#endif
++ {
++ /* we've already decrypted the first blocksize in read_packet_init */
++ buf_setpos(ses.readbuf, blocksize);
++
++ /* decrypt it in-place */
++ len = ses.readbuf->len - macsize - ses.readbuf->pos;
++ if (ses.keys->recv.crypt_mode->decrypt(
++ buf_getptr(ses.readbuf, len),
++ buf_getwriteptr(ses.readbuf, len),
++ len,
++ &ses.keys->recv.cipher_state) != CRYPT_OK) {
++ dropbear_exit("Error decrypting");
++ }
++ buf_incrpos(ses.readbuf, len);
+
+- /* check the hmac */
+- if (checkmac() != DROPBEAR_SUCCESS) {
+- dropbear_exit("Integrity error");
++ /* check the hmac */
++ if (checkmac() != DROPBEAR_SUCCESS) {
++ dropbear_exit("Integrity error");
++ }
+ }
+
+ /* get padding length */
+@@ -557,9 +590,16 @@ void encrypt_packet() {
+ buf_setpos(ses.writepayload, 0);
+ buf_setlen(ses.writepayload, 0);
+
+- /* length of padding - packet length must be a multiple of blocksize,
+- * with a minimum of 4 bytes of padding */
+- padlen = blocksize - (writebuf->len) % blocksize;
++ /* length of padding - packet length excluding the packetlength uint32
++ * field in aead mode must be a multiple of blocksize, with a minimum of
++ * 4 bytes of padding */
++ len = writebuf->len;
++#if DROPBEAR_AEAD_MODE
++ if (ses.keys->trans.crypt_mode->aead_crypt) {
++ len -= 4;
++ }
++#endif
++ padlen = blocksize - len % blocksize;
+ if (padlen < 4) {
+ padlen += blocksize;
+ }
+@@ -579,23 +619,42 @@ void encrypt_packet() {
+ buf_incrlen(writebuf, padlen);
+ genrandom(buf_getptr(writebuf, padlen), padlen);
+
+- make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes);
++#if DROPBEAR_AEAD_MODE
++ if (ses.keys->trans.crypt_mode->aead_crypt) {
++ /* do the actual encryption, in-place */
++ buf_setpos(writebuf, 0);
++ /* encrypt it in-place*/
++ len = writebuf->len;
++ buf_incrlen(writebuf, mac_size);
++ if (ses.keys->trans.crypt_mode->aead_crypt(ses.transseq,
++ buf_getptr(writebuf, len),
++ buf_getwriteptr(writebuf, len + mac_size),
++ len, mac_size,
++ &ses.keys->trans.cipher_state, LTC_ENCRYPT) != CRYPT_OK) {
++ dropbear_exit("Error encrypting");
++ }
++ buf_incrpos(writebuf, len + mac_size);
++ } else
++#endif
++ {
++ make_mac(ses.transseq, &ses.keys->trans, writebuf, writebuf->len, mac_bytes);
++
++ /* do the actual encryption, in-place */
++ buf_setpos(writebuf, 0);
++ /* encrypt it in-place*/
++ len = writebuf->len;
++ if (ses.keys->trans.crypt_mode->encrypt(
++ buf_getptr(writebuf, len),
++ buf_getwriteptr(writebuf, len),
++ len,
++ &ses.keys->trans.cipher_state) != CRYPT_OK) {
++ dropbear_exit("Error encrypting");
++ }
++ buf_incrpos(writebuf, len);
+
+- /* do the actual encryption, in-place */
+- buf_setpos(writebuf, 0);
+- /* encrypt it in-place*/
+- len = writebuf->len;
+- if (ses.keys->trans.crypt_mode->encrypt(
+- buf_getptr(writebuf, len),
+- buf_getwriteptr(writebuf, len),
+- len,
+- &ses.keys->trans.cipher_state) != CRYPT_OK) {
+- dropbear_exit("Error encrypting");
++ /* stick the MAC on it */
++ buf_putbytes(writebuf, mac_bytes, mac_size);
+ }
+- buf_incrpos(writebuf, len);
+-
+- /* stick the MAC on it */
+- buf_putbytes(writebuf, mac_bytes, mac_size);
+
+ /* Update counts */
+ ses.kexstate.datatrans += writebuf->len;
+diff --git a/session.h b/session.h
+index e436882..a8f8914 100644
+--- a/session.h
++++ b/session.h
+@@ -41,6 +41,7 @@
+ #include "chansession.h"
+ #include "dbutil.h"
+ #include "netio.h"
++#include "chachapoly.h"
+
+ void common_session_init(int sock_in, int sock_out);
+ void session_loop(void(*loophandler)(void)) ATTRIB_NORETURN;
+@@ -80,6 +81,9 @@ struct key_context_directional {
+ symmetric_CBC cbc;
+ #if DROPBEAR_ENABLE_CTR_MODE
+ symmetric_CTR ctr;
++#endif
++#if DROPBEAR_CHACHA20POLY1305
++ dropbear_chachapoly_state chachapoly;
+ #endif
+ } cipher_state;
+ unsigned char mackey[MAX_MAC_LEN];
+diff --git a/sysoptions.h b/sysoptions.h
+index 2c27caf..2432779 100644
+--- a/sysoptions.h
++++ b/sysoptions.h
+@@ -92,7 +92,11 @@
+ #define MD5_HASH_SIZE 16
+ #define MAX_HASH_SIZE 64 /* sha512 */
+
++#if DROPBEAR_CHACHA20POLY1305
++#define MAX_KEY_LEN 64 /* 2 x 256 bits for chacha20 */
++#else
+ #define MAX_KEY_LEN 32 /* 256 bits for aes256 etc */
++#endif
+ #define MAX_IV_LEN 20 /* must be same as max blocksize, */
+
+ #if DROPBEAR_SHA2_512_HMAC
+@@ -207,6 +211,8 @@ If you test it please contact the Dropbear author */
+
+ #define DROPBEAR_TWOFISH ((DROPBEAR_TWOFISH256) || (DROPBEAR_TWOFISH128))
+
++#define DROPBEAR_AEAD_MODE ((DROPBEAR_CHACHA20POLY1305))
++
+ #define DROPBEAR_CLI_ANYTCPFWD ((DROPBEAR_CLI_REMOTETCPFWD) || (DROPBEAR_CLI_LOCALTCPFWD))
+
+ #define DROPBEAR_TCP_ACCEPT ((DROPBEAR_CLI_LOCALTCPFWD) || (DROPBEAR_SVR_REMOTETCPFWD))
+@@ -249,7 +255,7 @@ If you test it please contact the Dropbear author */
+ #endif
+
+ #if !(DROPBEAR_AES128 || DROPBEAR_3DES || DROPBEAR_AES256 || DROPBEAR_BLOWFISH \
+- || DROPBEAR_TWOFISH256 || DROPBEAR_TWOFISH128)
++ || DROPBEAR_TWOFISH256 || DROPBEAR_TWOFISH128 || DROPBEAR_CHACHA20POLY1305)
+ #error "At least one encryption algorithm must be enabled. AES128 is recommended."
+ #endif
+
+--
+2.17.1
+