netutils/dropbear: use NuttX /dev/crypto for chacha20-poly1305

Replace the bundled libtomcrypt chacha20-poly1305@openssh.com with an
adapter backed by the NuttX crypto framework: CRYPTO_CHACHA20 for the
two keystreams (payload and packet-length) and CRYPTO_POLY1305 for the
per-packet MAC, both routed through /dev/crypto ioctls. Gated behind
CONFIG_NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY (default y when
NETUTILS_DROPBEAR_NUTTX_CRYPTO is enabled).

Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
This commit is contained in:
Felipe Moura 2026-07-09 18:37:06 -03:00
parent 81b2a1be26
commit 7840ea5bdb
5 changed files with 406 additions and 0 deletions

View file

@ -68,6 +68,11 @@ if(CONFIG_NETUTILS_DROPBEAR)
patch -s -N -l -p1 -d "${DROPBEAR_UNPACKNAME}" -i
"${CMAKE_CURRENT_SOURCE_DIR}/patch/0005-use-nuttx-sha256-hmac.patch"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
execute_process(
COMMAND
patch -s -N -l -p1 -d "${DROPBEAR_UNPACKNAME}" -i
"${CMAKE_CURRENT_SOURCE_DIR}/patch/0006-use-nuttx-chachapoly-cryptodev.patch"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
message(STATUS "Generating default_options_guard.h")
execute_process(
COMMAND
@ -151,6 +156,12 @@ if(CONFIG_NETUTILS_DROPBEAR)
port/dropbear_ltc_hmac_sha256.c)
endif()
if(CONFIG_NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY)
# Replace the bundled chacha20-poly1305 with the /dev/crypto adapter.
list(REMOVE_ITEM DROPBEAR_SRCS dropbear/src/chachapoly.c)
list(APPEND DROPBEAR_SRCS port/dropbear_chachapoly.c)
endif()
list(APPEND DROPBEAR_SRCS ${LIBTOMCRYPT_SRCS})
if(CONFIG_NETUTILS_DROPBEAR_SCP)
@ -216,6 +227,10 @@ if(CONFIG_NETUTILS_DROPBEAR)
DROPBEAR_NUTTX_HMAC_SHA256=1)
endif()
if(CONFIG_NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY)
target_compile_definitions(${PROGNAME} PRIVATE DROPBEAR_NUTTX_CHACHAPOLY=1)
endif()
if(CONFIG_NETUTILS_DROPBEAR_SCP)
target_compile_definitions(
scp PRIVATE LOCALOPTIONS_H_EXISTS=1 DROPBEAR_NUTTX=1
@ -246,6 +261,17 @@ if(CONFIG_NETUTILS_DROPBEAR)
set_source_files_properties(${LIBTOMCRYPT_SRCS} PROPERTIES COMPILE_DEFINITIONS
LTC_SOURCE=1)
if(CONFIG_NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY)
# The NuttX crypto backend pulled in by /dev/crypto also exports
# ecc_make_key. Dropbear only uses libtomcrypt's ecc_make_key_ex, so rename
# the unused plain wrapper to avoid a multiple definition. Append so the
# LTC_SOURCE define set above is preserved.
set_property(
SOURCE dropbear/libtomcrypt/src/pk/ecc/ecc_make_key.c
APPEND
PROPERTY COMPILE_DEFINITIONS ecc_make_key=dropbear_ltc_ecc_make_key)
endif()
target_compile_options(${PROGNAME} PRIVATE -Wno-pointer-sign -Wno-format)
if(CONFIG_NETUTILS_DROPBEAR_SCP)

View file

@ -100,6 +100,19 @@ config NETUTILS_DROPBEAR_NUTTX_CRYPTO
modules, reducing flash usage. This requires a flat build because
Dropbear calls the kernel crypto functions directly.
config NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY
bool "Use NuttX /dev/crypto for chacha20-poly1305"
default y
depends on NETUTILS_DROPBEAR_NUTTX_CRYPTO
select CRYPTO_CRYPTODEV
select CRYPTO_SW_AES
select CRYPTO_CRYPTODEV_SOFTWARE_CRYPTO
---help---
Implement the chacha20-poly1305@openssh.com cipher through the NuttX
crypto device (/dev/crypto) using the CRYPTO_CHACHA20 and
CRYPTO_POLY1305 algorithms instead of the bundled libtomcrypt
implementation.
config NETUTILS_DROPBEAR_PORT
int "Dropbear listen port"
default 2222

View file

@ -68,6 +68,10 @@ CFLAGS += ${DEFINE_PREFIX}DROPBEAR_NUTTX_SHA256=1
CFLAGS += ${DEFINE_PREFIX}DROPBEAR_NUTTX_HMAC_SHA256=1
endif
ifneq ($(CONFIG_NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY),)
CFLAGS += ${DEFINE_PREFIX}DROPBEAR_NUTTX_CHACHAPOLY=1
endif
dropbear_nshsession.c_CFLAGS += ${DEFINE_PREFIX}Channel=dropbear_channel
dropbear_nshsession.c_CFLAGS += ${DEFINE_PREFIX}ChanType=dropbear_chantype
@ -138,6 +142,13 @@ CSRCS += port/dropbear_ltc_sha256.c
CSRCS += port/dropbear_ltc_hmac_sha256.c
endif
ifneq ($(CONFIG_NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY),)
# Replace the bundled chacha20-poly1305 with the /dev/crypto adapter.
CSRCS := $(filter-out dropbear/src/chachapoly.c,$(CSRCS))
CSRCS += port/dropbear_chachapoly.c
endif
CSRCS += $(TOMMATH_SRCS)
CSRCS += $(TOMCRYPT_SRCS)
@ -149,6 +160,13 @@ endif
# Match the ESP-IDF port behavior: LTC_SOURCE is only for libtomcrypt sources.
$(foreach src,$(TOMCRYPT_SRCS),$(eval $(src)_CFLAGS += ${DEFINE_PREFIX}LTC_SOURCE=1))
ifneq ($(CONFIG_NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY),)
# The NuttX crypto backend pulled in by /dev/crypto also exports ecc_make_key.
# Dropbear only uses libtomcrypt's ecc_make_key_ex, so rename the unused plain
# wrapper to avoid a link-time multiple definition.
dropbear/libtomcrypt/src/pk/ecc/ecc_make_key.c_CFLAGS += ${DEFINE_PREFIX}ecc_make_key=dropbear_ltc_ecc_make_key
endif
MAINSRC = dropbear_main.c
ifneq ($(CONFIG_NETUTILS_DROPBEAR_SCP),)
@ -181,6 +199,7 @@ $(DROPBEAR_UNPACKNAME): $(DROPBEAR_ZIP)
$(Q) $(PATCH) -s -N -l -p1 -d $(DROPBEAR_UNPACKNAME) -i $(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)patch$(DELIM)0003-allow-localoptions-to-override-tracking-malloc.patch; true
$(Q) $(PATCH) -s -N -l -p1 -d $(DROPBEAR_UNPACKNAME) -i $(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)patch$(DELIM)0004-use-nuttx-unused-macro.patch; true
$(Q) $(PATCH) -s -N -l -p1 -d $(DROPBEAR_UNPACKNAME) -i $(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)patch$(DELIM)0005-use-nuttx-sha256-hmac.patch; true
$(Q) $(PATCH) -s -N -l -p1 -d $(DROPBEAR_UNPACKNAME) -i $(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)patch$(DELIM)0006-use-nuttx-chachapoly-cryptodev.patch; true
@echo "Generating default_options_guard.h"
$(Q) sh $(DROPBEAR_UNPACKNAME)$(DELIM)src$(DELIM)ifndef_wrapper.sh \
< $(DROPBEAR_UNPACKNAME)$(DELIM)src$(DELIM)default_options.h \

View file

@ -0,0 +1,20 @@
--- a/src/chachapoly.h
+++ b/src/chachapoly.h
@@ -31,10 +31,17 @@
#if DROPBEAR_CHACHA20POLY1305
+#ifdef DROPBEAR_NUTTX_CHACHAPOLY
+typedef struct {
+ unsigned char key_main[32];
+ unsigned char key_header[32];
+} dropbear_chachapoly_state;
+#else
typedef struct {
chacha_state chacha;
chacha_state header;
} dropbear_chachapoly_state;
+#endif
extern const struct dropbear_cipher dropbear_chachapoly;
extern const struct dropbear_cipher_mode dropbear_mode_chachapoly;

View file

@ -0,0 +1,328 @@
/****************************************************************************
* apps/netutils/dropbear/port/dropbear_chachapoly.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "includes.h"
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <crypto/cryptodev.h>
#include "algo.h"
#include "dbutil.h"
#include "chachapoly.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define CHACHA20_KEY_LEN 32
#define CHACHA20_BLOCKSIZE 8
#define CHACHA20_IV_LEN 16
#define POLY1305_KEY_LEN 32
#define POLY1305_TAG_LEN 16
/****************************************************************************
* Private Data
****************************************************************************/
static const struct ltc_cipher_descriptor g_dropbear_chachapoly_dummy =
{
.name = NULL
};
static const struct dropbear_hash g_dropbear_chachapoly_mac =
{
NULL,
POLY1305_KEY_LEN,
POLY1305_TAG_LEN
};
static int g_dropbear_cryptofd = -1;
/****************************************************************************
* Public Data
****************************************************************************/
const struct dropbear_cipher dropbear_chachapoly =
{
&g_dropbear_chachapoly_dummy,
CHACHA20_KEY_LEN * 2,
CHACHA20_BLOCKSIZE
};
/****************************************************************************
* Private Functions
****************************************************************************/
static int dropbear_cryptodev_fd(void)
{
int fd;
int cfd;
if (g_dropbear_cryptofd >= 0)
{
return g_dropbear_cryptofd;
}
fd = open("/dev/crypto", O_RDWR);
if (fd < 0)
{
return -1;
}
if (ioctl(fd, CRIOGET, &cfd) < 0)
{
close(fd);
return -1;
}
close(fd);
g_dropbear_cryptofd = cfd;
return g_dropbear_cryptofd;
}
static int dropbear_chacha(FAR const unsigned char *key, unsigned int seq,
uint64_t counter, FAR const unsigned char *in,
FAR unsigned char *out, size_t len)
{
struct session_op session;
struct crypt_op cryp;
unsigned char iv[CHACHA20_IV_LEN];
int cfd;
int ret = CRYPT_ERROR;
int i;
cfd = dropbear_cryptodev_fd();
if (cfd < 0)
{
return CRYPT_ERROR;
}
memset(iv, 0, sizeof(iv));
for (i = 0; i < 8; i++)
{
iv[i] = (unsigned char)(counter >> (8 * i));
}
STORE64H((uint64_t)seq, iv + 8);
memset(&session, 0, sizeof(session));
session.cipher = CRYPTO_CHACHA20;
session.key = (caddr_t)key;
session.keylen = CHACHA20_KEY_LEN;
if (ioctl(cfd, CIOCGSESSION, &session) < 0)
{
return CRYPT_ERROR;
}
memset(&cryp, 0, sizeof(cryp));
cryp.ses = session.ses;
cryp.op = COP_ENCRYPT;
cryp.len = len;
cryp.src = (caddr_t)in;
cryp.dst = (caddr_t)out;
cryp.iv = (caddr_t)iv;
cryp.ivlen = sizeof(iv);
if (ioctl(cfd, CIOCCRYPT, &cryp) == 0)
{
ret = CRYPT_OK;
}
ioctl(cfd, CIOCFSESSION, &session.ses);
return ret;
}
static int dropbear_poly1305(FAR const unsigned char *key,
FAR const unsigned char *in, size_t len,
FAR unsigned char *tag)
{
struct session_op session;
struct crypt_op cryp;
int cfd;
int ret = CRYPT_ERROR;
cfd = dropbear_cryptodev_fd();
if (cfd < 0)
{
return CRYPT_ERROR;
}
memset(&session, 0, sizeof(session));
session.mac = CRYPTO_POLY1305;
session.mackey = (caddr_t)key;
session.mackeylen = POLY1305_KEY_LEN;
if (ioctl(cfd, CIOCGSESSION, &session) < 0)
{
return CRYPT_ERROR;
}
memset(&cryp, 0, sizeof(cryp));
cryp.ses = session.ses;
cryp.op = COP_ENCRYPT;
cryp.flags = COP_FLAG_UPDATE;
cryp.len = len;
cryp.src = (caddr_t)in;
if (ioctl(cfd, CIOCCRYPT, &cryp) == 0)
{
cryp.flags = 0;
cryp.len = 0;
cryp.mac = (caddr_t)tag;
if (ioctl(cfd, CIOCCRYPT, &cryp) == 0)
{
ret = CRYPT_OK;
}
}
ioctl(cfd, CIOCFSESSION, &session.ses);
return ret;
}
static int dropbear_chachapoly_start(int cipher,
FAR const unsigned char *iv,
FAR const unsigned char *key,
int keylen, int num_rounds,
FAR dropbear_chachapoly_state *state)
{
UNUSED(cipher);
UNUSED(iv);
if (keylen != CHACHA20_KEY_LEN * 2 || num_rounds != 0)
{
return CRYPT_ERROR;
}
if (dropbear_cryptodev_fd() < 0)
{
return CRYPT_ERROR;
}
memcpy(state->key_main, key, CHACHA20_KEY_LEN);
memcpy(state->key_header, key + CHACHA20_KEY_LEN, CHACHA20_KEY_LEN);
return CRYPT_OK;
}
static int dropbear_chachapoly_crypt(unsigned int seq,
FAR const unsigned char *in,
FAR unsigned char *out,
unsigned long len, unsigned long taglen,
FAR dropbear_chachapoly_state *state,
int direction)
{
unsigned char key[POLY1305_KEY_LEN];
unsigned char tag[POLY1305_TAG_LEN];
unsigned char zero[POLY1305_KEY_LEN];
int ret = CRYPT_ERROR;
if (len < 4 || taglen != POLY1305_TAG_LEN)
{
return CRYPT_ERROR;
}
memset(zero, 0, sizeof(zero));
if (dropbear_chacha(state->key_main, seq, 0, zero, key,
sizeof(key)) != CRYPT_OK)
{
goto out;
}
if (direction == LTC_DECRYPT)
{
if (dropbear_poly1305(key, in, len, tag) != CRYPT_OK)
{
goto out;
}
if (constant_time_memcmp(in + len, tag, sizeof(tag)) != 0)
{
goto out;
}
}
if (dropbear_chacha(state->key_header, seq, 0, in, out, 4) != CRYPT_OK)
{
goto out;
}
if (dropbear_chacha(state->key_main, seq, 1, in + 4, out + 4,
len - 4) != CRYPT_OK)
{
goto out;
}
if (direction == LTC_ENCRYPT)
{
if (dropbear_poly1305(key, out, len, out + len) != CRYPT_OK)
{
goto out;
}
}
ret = CRYPT_OK;
out:
zeromem(key, sizeof(key));
zeromem(tag, sizeof(tag));
return ret;
}
static int
dropbear_chachapoly_getlength(unsigned int seq, FAR const unsigned char *in,
FAR unsigned int *outlen, unsigned long len,
FAR dropbear_chachapoly_state *state)
{
unsigned char buf[4];
if (len < sizeof(buf))
{
return CRYPT_ERROR;
}
if (dropbear_chacha(state->key_header, seq, 0, in, buf,
sizeof(buf)) != CRYPT_OK)
{
return CRYPT_ERROR;
}
LOAD32H(*outlen, buf);
return CRYPT_OK;
}
/****************************************************************************
* Public Data
****************************************************************************/
const struct dropbear_cipher_mode dropbear_mode_chachapoly =
{
(void *)dropbear_chachapoly_start,
NULL,
NULL,
(void *)dropbear_chachapoly_crypt,
(void *)dropbear_chachapoly_getlength,
&g_dropbear_chachapoly_mac
};