This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new ce645060fa3 crypto: add CRYPTO_AES_CTR_SSH variant (128-bit big-endian
counter)
ce645060fa3 is described below
commit ce645060fa301b846d20f0b207d20e42b26010cf
Author: Felipe Moura <[email protected]>
AuthorDate: Tue Jul 14 23:45:04 2026 -0300
crypto: add CRYPTO_AES_CTR_SSH variant (128-bit big-endian counter)
The existing CRYPTO_AES_CTR is the RFC 3686 profile: the last 4 bytes of
the key are a nonce, the IV is 8 bytes and only the low 32 bits of the
counter block are incremented. SSH aes128/192/256-ctr (RFC 4344) instead
uses the key as-is (no embedded nonce) and treats the whole 16-byte IV as
the initial counter block, incremented as a 128-bit big-endian integer,
with the first keystream block being E(IV).
Add CRYPTO_AES_CTR_SSH as a new enc_xform mirroring the CRYPTO_CHACHA20_DJB
addition. It reuses struct aes_ctr_ctx and the AES block; only setkey (full
key, no nonce), reinit (full 16-byte counter) and crypt (encrypt-then-
increment over all 16 bytes) differ from the RFC 3686 variant.
Keystream validated against `openssl enc -aes-128-ctr`, including a counter
that carries across byte boundaries and a non-block-aligned tail.
Signed-off-by: Felipe Moura <[email protected]>
---
crypto/cryptodev.c | 1 +
crypto/cryptosoft.c | 6 ++++
crypto/xform.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++
include/crypto/cryptodev.h | 3 +-
include/crypto/xform.h | 1 +
5 files changed, 78 insertions(+), 1 deletion(-)
diff --git a/crypto/cryptodev.c b/crypto/cryptodev.c
index d624e14d330..7d57202a9c0 100644
--- a/crypto/cryptodev.c
+++ b/crypto/cryptodev.c
@@ -232,6 +232,7 @@ static int cryptof_ioctl(FAR struct file *filep,
case CRYPTO_AES_256_CBC:
case CRYPTO_AES_CMAC:
case CRYPTO_AES_CTR:
+ case CRYPTO_AES_CTR_SSH:
case CRYPTO_AES_XTS:
case CRYPTO_AES_OFB:
case CRYPTO_AES_CFB_8:
diff --git a/crypto/cryptosoft.c b/crypto/cryptosoft.c
index c1f4539b060..a3d10c48765 100644
--- a/crypto/cryptosoft.c
+++ b/crypto/cryptosoft.c
@@ -1619,6 +1619,9 @@ int swcr_newsession(FAR uint32_t *sid, FAR struct
cryptoini *cri)
case CRYPTO_AES_CTR:
txf = &enc_xform_aes_ctr;
goto enccommon;
+ case CRYPTO_AES_CTR_SSH:
+ txf = &enc_xform_aes_ctr_ssh;
+ goto enccommon;
case CRYPTO_AES_XTS:
txf = &enc_xform_aes_xts;
goto enccommon;
@@ -1903,6 +1906,7 @@ int swcr_freesession(uint64_t tid)
case CRYPTO_CAST_CBC:
case CRYPTO_RIJNDAEL128_CBC:
case CRYPTO_AES_CTR:
+ case CRYPTO_AES_CTR_SSH:
case CRYPTO_AES_XTS:
case CRYPTO_AES_GCM_16:
case CRYPTO_AES_GMAC:
@@ -2046,6 +2050,7 @@ int swcr_process(struct cryptop *crp)
case CRYPTO_CAST_CBC:
case CRYPTO_RIJNDAEL128_CBC:
case CRYPTO_AES_CTR:
+ case CRYPTO_AES_CTR_SSH:
case CRYPTO_AES_XTS:
case CRYPTO_AES_OFB:
case CRYPTO_AES_CFB_8:
@@ -2442,6 +2447,7 @@ void swcr_init(void)
algs[CRYPTO_RIPEMD160_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
algs[CRYPTO_RIJNDAEL128_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
algs[CRYPTO_AES_CTR] = CRYPTO_ALG_FLAG_SUPPORTED;
+ algs[CRYPTO_AES_CTR_SSH] = CRYPTO_ALG_FLAG_SUPPORTED;
algs[CRYPTO_AES_XTS] = CRYPTO_ALG_FLAG_SUPPORTED;
algs[CRYPTO_AES_GCM_16] = CRYPTO_ALG_FLAG_SUPPORTED;
algs[CRYPTO_AES_GMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
diff --git a/crypto/xform.c b/crypto/xform.c
index 788a718b08e..b412566ae24 100644
--- a/crypto/xform.c
+++ b/crypto/xform.c
@@ -108,6 +108,7 @@ int blf_setkey(FAR void *, FAR uint8_t *, int);
int cast5_setkey(FAR void *, FAR uint8_t *, int);
int aes_setkey_xform(FAR void *, FAR uint8_t *, int);
int aes_ctr_setkey(FAR void *, FAR uint8_t *, int);
+int aes_ctr_ssh_setkey(FAR void *, FAR uint8_t *, int);
int aes_xts_setkey(FAR void *, FAR uint8_t *, int);
int aes_ofb_setkey(FAR void *, FAR uint8_t *, int);
int null_setkey(FAR void *, FAR uint8_t *, int);
@@ -132,8 +133,10 @@ void aes_cfb8_decrypt(caddr_t, FAR uint8_t *, size_t);
void aes_cfb128_decrypt(caddr_t, FAR uint8_t *, size_t);
void aes_ctr_crypt(caddr_t, FAR uint8_t *, size_t);
+void aes_ctr_ssh_crypt(caddr_t, FAR uint8_t *, size_t);
void aes_ctr_reinit(caddr_t, FAR uint8_t *);
+void aes_ctr_ssh_reinit(caddr_t, FAR uint8_t *);
void aes_xts_reinit(caddr_t, FAR uint8_t *);
void aes_gcm_reinit(caddr_t, FAR uint8_t *);
void aes_ofb_reinit(caddr_t, FAR uint8_t *);
@@ -232,6 +235,17 @@ const struct enc_xform enc_xform_aes_ctr =
aes_ctr_reinit
};
+const struct enc_xform enc_xform_aes_ctr_ssh =
+{
+ CRYPTO_AES_CTR_SSH, "AES-CTR-SSH",
+ 16, 16, 16, 32,
+ sizeof(struct aes_ctr_ctx),
+ aes_ctr_ssh_crypt,
+ aes_ctr_ssh_crypt,
+ aes_ctr_ssh_setkey,
+ aes_ctr_ssh_reinit
+};
+
const struct enc_xform enc_xform_aes_gcm =
{
CRYPTO_AES_GCM_16, "AES-GCM",
@@ -697,6 +711,60 @@ int aes_ctr_setkey(FAR void *sched, FAR uint8_t *key, int
len)
return 0;
}
+/* SSH AES-CTR (RFC 4344). Unlike the RFC 3686 variant above, the key holds
+ * no embedded nonce and the whole 16-byte IV is the initial counter block,
+ * incremented as a 128-bit big-endian integer. The counter is encrypted
+ * before it is incremented so the first block keystream is E(IV).
+ */
+
+void aes_ctr_ssh_crypt(caddr_t key, FAR uint8_t *data, size_t len)
+{
+ FAR struct aes_ctr_ctx *ctx;
+ uint8_t keystream[AESCTR_BLOCKSIZE];
+ int i;
+
+ ctx = (FAR struct aes_ctr_ctx *)key;
+
+ aes_encrypt(&ctx->ac_key, ctx->ac_block, keystream);
+ for (i = 0; i < AESCTR_BLOCKSIZE; i++)
+ {
+ data[i] ^= keystream[i];
+ }
+
+ /* increment the 128-bit big-endian counter */
+
+ for (i = AESCTR_BLOCKSIZE - 1; i >= 0; i--)
+ {
+ if (++ctx->ac_block[i])
+ {
+ break;
+ }
+ }
+
+ explicit_bzero(keystream, sizeof(keystream));
+}
+
+int aes_ctr_ssh_setkey(FAR void *sched, FAR uint8_t *key, int len)
+{
+ FAR struct aes_ctr_ctx *ctx;
+
+ ctx = (FAR struct aes_ctr_ctx *)sched;
+ if (aes_setkey(&ctx->ac_key, key, len) != 0)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+void aes_ctr_ssh_reinit(caddr_t key, FAR uint8_t *iv)
+{
+ FAR struct aes_ctr_ctx *ctx;
+
+ ctx = (FAR struct aes_ctr_ctx *)key;
+ bcopy(iv, ctx->ac_block, AESCTR_BLOCKSIZE);
+}
+
void aes_xts_reinit(caddr_t key, FAR uint8_t *iv)
{
FAR struct aes_xts_ctx *ctx = (FAR struct aes_xts_ctx *)key;
diff --git a/include/crypto/cryptodev.h b/include/crypto/cryptodev.h
index 824f8fafb12..cefe056cedf 100644
--- a/include/crypto/cryptodev.h
+++ b/include/crypto/cryptodev.h
@@ -142,7 +142,8 @@
#define CRYPTO_SHA2_224_HMAC 41
#define CRYPTO_CHACHA20 42
#define CRYPTO_CHACHA20_DJB 43
-#define CRYPTO_ALGORITHM_MAX 43 /* Keep updated */
+#define CRYPTO_AES_CTR_SSH 44
+#define CRYPTO_ALGORITHM_MAX 44 /* Keep updated */
/* Algorithm flags */
diff --git a/include/crypto/xform.h b/include/crypto/xform.h
index ad6b7ad4086..95e7600b558 100644
--- a/include/crypto/xform.h
+++ b/include/crypto/xform.h
@@ -105,6 +105,7 @@ extern const struct enc_xform enc_xform_blf;
extern const struct enc_xform enc_xform_cast5;
extern const struct enc_xform enc_xform_aes;
extern const struct enc_xform enc_xform_aes_ctr;
+extern const struct enc_xform enc_xform_aes_ctr_ssh;
extern const struct enc_xform enc_xform_aes_gcm;
extern const struct enc_xform enc_xform_aes_gmac;
extern const struct enc_xform enc_xform_aes_cmac;