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;

Reply via email to