From 0099a08d5fcb5e031bf3e8e81bf53f936708bc0d Mon Sep 17 00:00:00 2001 From: Peter Barada Date: Fri, 3 Jul 2026 17:45:04 -0400 Subject: [PATCH 1/3] crypto: Support SHA2_224_HMAC Since already have support for SHA2-224, extend cryptodev/cryptosoft to support HMAC version of SHA2-224. Signed-off-by: Peter Barada --- Documentation/components/crypto.rst | 1 + crypto/cryptodev.c | 1 + crypto/cryptosoft.c | 7 +++++++ crypto/xform.c | 9 +++++++++ include/crypto/cryptodev.h | 4 +++- include/crypto/xform.h | 1 + 6 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Documentation/components/crypto.rst b/Documentation/components/crypto.rst index fcc4bb9b1ca0a..aac0fe42fc67d 100644 --- a/Documentation/components/crypto.rst +++ b/Documentation/components/crypto.rst @@ -62,6 +62,7 @@ Authentication and Hashing Algorithms - CRYPTO_SHA1_HMAC - SHA-2 HMAC: + - CRYPTO_SHA2_224_HMAC (224-bit) - CRYPTO_SHA2_256_HMAC (256-bit) - CRYPTO_SHA2_384_HMAC (384-bit) - CRYPTO_SHA2_512_HMAC (512-bit) diff --git a/crypto/cryptodev.c b/crypto/cryptodev.c index a1ff28d63692d..bca32db3687e0 100644 --- a/crypto/cryptodev.c +++ b/crypto/cryptodev.c @@ -250,6 +250,7 @@ static int cryptof_ioctl(FAR struct file *filep, case CRYPTO_MD5_HMAC: case CRYPTO_SHA1_HMAC: case CRYPTO_RIPEMD160_HMAC: + case CRYPTO_SHA2_224_HMAC: case CRYPTO_SHA2_256_HMAC: case CRYPTO_SHA2_384_HMAC: case CRYPTO_SHA2_512_HMAC: diff --git a/crypto/cryptosoft.c b/crypto/cryptosoft.c index 7a22b6ce80f87..9dcbce8b503e2 100644 --- a/crypto/cryptosoft.c +++ b/crypto/cryptosoft.c @@ -1153,6 +1153,7 @@ int swcr_authcompute(FAR struct cryptop *crp, case CRYPTO_MD5_HMAC: case CRYPTO_SHA1_HMAC: case CRYPTO_RIPEMD160_HMAC: + case CRYPTO_SHA2_224_HMAC: case CRYPTO_SHA2_256_HMAC: case CRYPTO_SHA2_384_HMAC: case CRYPTO_SHA2_512_HMAC: @@ -1665,6 +1666,9 @@ int swcr_newsession(FAR uint32_t *sid, FAR struct cryptoini *cri) case CRYPTO_RIPEMD160_HMAC: axf = &auth_hash_hmac_ripemd_160_96; goto authcommon; + case CRYPTO_SHA2_224_HMAC: + axf = &auth_hash_hmac_sha2_224_114; + goto authcommon; case CRYPTO_SHA2_256_HMAC: case CRYPTO_PBKDF2_HMAC_SHA256: axf = &auth_hash_hmac_sha2_256_128; @@ -1894,6 +1898,7 @@ int swcr_freesession(uint64_t tid) case CRYPTO_MD5_HMAC: case CRYPTO_SHA1_HMAC: case CRYPTO_RIPEMD160_HMAC: + case CRYPTO_SHA2_224_HMAC: case CRYPTO_SHA2_256_HMAC: case CRYPTO_SHA2_384_HMAC: case CRYPTO_SHA2_512_HMAC: @@ -2044,6 +2049,7 @@ int swcr_process(struct cryptop *crp) case CRYPTO_MD5_HMAC: case CRYPTO_SHA1_HMAC: case CRYPTO_RIPEMD160_HMAC: + case CRYPTO_SHA2_224_HMAC: case CRYPTO_SHA2_256_HMAC: case CRYPTO_SHA2_384_HMAC: case CRYPTO_SHA2_512_HMAC: @@ -2409,6 +2415,7 @@ void swcr_init(void) algs[CRYPTO_AES_GCM_16] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_AES_GMAC] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_NULL] = CRYPTO_ALG_FLAG_SUPPORTED; + algs[CRYPTO_SHA2_224_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_SHA2_256_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_SHA2_384_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_SHA2_512_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED; diff --git a/crypto/xform.c b/crypto/xform.c index b18982d4f4c00..cc63cd0562bb6 100644 --- a/crypto/xform.c +++ b/crypto/xform.c @@ -357,6 +357,15 @@ const struct auth_hash auth_hash_hmac_ripemd_160_96 = (void (*)(FAR uint8_t *, FAR void *)) rmd160final }; +const struct auth_hash auth_hash_hmac_sha2_224_114 = +{ + CRYPTO_SHA2_256_HMAC, "HMAC-SHA2-224", + HMAC_SHA2_224_BLOCK_LEN, 28, 14, sizeof(SHA2_CTX), HMAC_SHA2_224_BLOCK_LEN, + (void (*)(FAR void *)) sha224init, NULL, NULL, + sha224update_int, + (void (*)(FAR uint8_t *, FAR void *)) sha224final +}; + const struct auth_hash auth_hash_hmac_sha2_256_128 = { CRYPTO_SHA2_256_HMAC, "HMAC-SHA2-256", diff --git a/include/crypto/cryptodev.h b/include/crypto/cryptodev.h index f58f1b38e4386..ad5f62afb5375 100644 --- a/include/crypto/cryptodev.h +++ b/include/crypto/cryptodev.h @@ -73,6 +73,7 @@ #define HMAC_MD5_BLOCK_LEN 64 #define HMAC_SHA1_BLOCK_LEN 64 #define HMAC_RIPEMD160_BLOCK_LEN 64 +#define HMAC_SHA2_224_BLOCK_LEN 64 #define HMAC_SHA2_256_BLOCK_LEN 64 #define HMAC_SHA2_384_BLOCK_LEN 128 #define HMAC_SHA2_512_BLOCK_LEN 128 @@ -138,7 +139,8 @@ #define CRYPTO_PBKDF2_HMAC_SHA1 38 #define CRYPTO_PBKDF2_HMAC_SHA256 39 #define CRYPTO_ESN 40 /* Support for Extended Sequence Numbers */ -#define CRYPTO_ALGORITHM_MAX 40 /* Keep updated */ +#define CRYPTO_SHA2_224_HMAC 41 +#define CRYPTO_ALGORITHM_MAX 41 /* Keep updated */ /* Algorithm flags */ diff --git a/include/crypto/xform.h b/include/crypto/xform.h index f168aa281de1b..6f3bc42ec64c1 100644 --- a/include/crypto/xform.h +++ b/include/crypto/xform.h @@ -118,6 +118,7 @@ extern const struct enc_xform enc_xform_null; extern const struct auth_hash auth_hash_hmac_md5_96; extern const struct auth_hash auth_hash_hmac_sha1_96; extern const struct auth_hash auth_hash_hmac_ripemd_160_96; +extern const struct auth_hash auth_hash_hmac_sha2_224_114; extern const struct auth_hash auth_hash_hmac_sha2_256_128; extern const struct auth_hash auth_hash_hmac_sha2_384_192; extern const struct auth_hash auth_hash_hmac_sha2_512_256; From 32ab64022e6ded7f005e2f027e489e01cdacf407 Mon Sep 17 00:00:00 2001 From: makejian Date: Fri, 10 Jul 2026 14:13:58 +0800 Subject: [PATCH 2/3] crypto: Add ChaCha20/ChaCha20-Poly1305 to /dev/crypto, fix RFC 8439 nonce. Expose the ChaCha20 stream cipher and the ChaCha20-Poly1305 AEAD through the OCF crypto framework (/dev/crypto) so applications such as an SSH server (chacha20-poly1305) can use them directly, and fix the underlying ChaCha nonce/counter layout so both match RFC 8439. RFC 8439 nonce layout fix ------------------------- chacha_ivsetup() previously used the original DJB layout: a 64-bit block counter (input[12..13]) followed by a 64-bit nonce (input[14..15]). RFC 8439 defines a 32-bit block counter (input[12]) and a 96-bit / 12-byte nonce (input[13..15]). With the old layout the existing ChaCha20-Poly1305 AEAD could not reproduce the RFC 8439 test vectors (the last 4 bytes of a 12-byte nonce were consumed as the high half of the counter). This commit switches chacha_ivsetup() to the RFC 8439 layout and updates the ChaCha20-Poly1305 one-shot helpers to pass a 12-byte nonce accordingly. Standalone ChaCha20 on the unified enc path ------------------------------------------- Instead of introducing a separate multi-buffer stream path (parallel encrypt_multi/decrypt_multi callbacks), extend the existing enc_xform encrypt/decrypt callback signature with a length argument: void (*encrypt)(caddr_t, FAR uint8_t *, size_t len); void (*decrypt)(caddr_t, FAR uint8_t *, size_t len); With that single change every cipher, block or stream, flows through the same swcr_encdec path. swcr_encdec already handles a short final block via buflen = MIN(i, blocksize), so arbitrary-length data works without a second code path. This is exactly how the existing stream ciphers (AES-CTR/OFB/CFB) already behave: the cipher keeps its own counter in the context and swcr_encdec feeds it whole blocks (only the last one may be shorter). chacha20_crypt likewise relies on the underlying chacha state block counter (input[12]) to continue the keystream across calls, so no per-call keystream caching is needed. * chacha_private.h: chacha_ivsetup uses a 4-byte counter and a 12-byte nonce (RFC 8439). * chachapoly.c / chachapoly.h: split reinit into chacha20_reinit (raw, counter 0) and chachapoly_reinit (AEAD, counter 1); chacha20_crypt takes a length and encrypts it in one pass, mirroring aes_ctr_crypt; 12-byte nonce for the one-shot AEAD helpers. * xform.h / xform.c: add size_t len to encrypt/decrypt; add enc_xform_chacha20 (blocksize 64, 12-byte IV). * cryptodev.c / cryptosoft.c: register CRYPTO_CHACHA20 as a txform cipher, route new sessions to enc_xform_chacha20, feed the AEAD AAD through crp_aad/crp_aadlen, and handle the short final block in swcr_encdec. * cryptodev.h: add CRYPTO_CHACHA20; bump EALG_MAX_BLOCK_LEN to 64. This keeps all ciphers on one uniform path instead of maintaining two, and any future stream cipher drops in with just an xform table entry. Impact: extends an internal kernel callback signature (enc_xform encrypt/decrypt). All in-tree implementations are updated in the same commit and the user-facing /dev/crypto ABI is unchanged, so this is self-contained and not a breaking change for existing configurations. Testing: Build host: Ubuntu Linux x86_64, GCC (host sim toolchain) Target: sim:crypto (CONFIG_ARCH=sim) Ran the crypto test apps. ChaCha20 uses RFC 8439 2.4.2 vectors (including a 375-byte multi-block vector exercising cross-block counter continuity); ChaCha20-Poly1305 uses the RFC 8439 2.8.2 AEAD vector. A full regression of the other ciphers was run to confirm the extended encrypt/decrypt signature does not change their behaviour: nsh> chacha20 chacha20: 2/2 vectors passed nsh> chachapoly OK test vector 0 chachapoly: 1/1 vectors passed nsh> des3cbc -> all vectors OK nsh> aescbc -> all vectors OK nsh> aesctr -> all vectors OK nsh> aesxts -> 14 vectors OK (encrypt + decrypt) nsh> hmac -> md5 / sha1 / sha256 all success Signed-off-by: makejian --- crypto/chacha_private.h | 6 +-- crypto/chachapoly.c | 36 +++++++++++---- crypto/cryptodev.c | 9 ++++ crypto/cryptosoft.c | 67 +++++++++++++++++++-------- crypto/xform.c | 91 +++++++++++++++++++++---------------- include/crypto/chachapoly.h | 7 +-- include/crypto/cryptodev.h | 5 +- include/crypto/xform.h | 5 +- 8 files changed, 147 insertions(+), 79 deletions(-) diff --git a/crypto/chacha_private.h b/crypto/chacha_private.h index 516b9a115ac46..5829cfbee66bd 100644 --- a/crypto/chacha_private.h +++ b/crypto/chacha_private.h @@ -141,9 +141,9 @@ static void chacha_ivsetup(FAR chacha_ctx *x, FAR const uint8_t *counter) { x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); - x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); - x->input[14] = U8TO32_LITTLE(iv + 0); - x->input[15] = U8TO32_LITTLE(iv + 4); + x->input[13] = U8TO32_LITTLE(iv + 0); + x->input[14] = U8TO32_LITTLE(iv + 4); + x->input[15] = U8TO32_LITTLE(iv + 8); } static void chacha_encrypt_bytes(FAR chacha_ctx *x, diff --git a/crypto/chachapoly.c b/crypto/chachapoly.c index c03bf8fac18dd..885b066ff6e28 100644 --- a/crypto/chachapoly.c +++ b/crypto/chachapoly.c @@ -48,10 +48,7 @@ int chacha20_setkey(FAR void *sched, FAR uint8_t *key, int len) return -1; } - /* initial counter is 1 */ - - ctx->nonce[0] = 1; - memcpy(ctx->nonce + CHACHA20_CTR, key + CHACHA20_KEYSIZE, + memcpy(ctx->nonce, key + CHACHA20_KEYSIZE, CHACHA20_SALT); chacha_keysetup((FAR chacha_ctx *)&ctx->block, key, CHACHA20_KEYSIZE * 8); return 0; @@ -64,12 +61,27 @@ void chacha20_reinit(caddr_t key, FAR uint8_t *iv) chacha_ivsetup((FAR chacha_ctx *)ctx->block, iv, ctx->nonce); } -void chacha20_crypt(caddr_t key, FAR uint8_t *data) +void chacha20_crypt(caddr_t key, FAR uint8_t *data, size_t len) +{ + FAR struct chacha20_ctx *ctx = (FAR struct chacha20_ctx *)key; + + /* The underlying chacha state keeps its own block counter (input[12]), + * so successive calls continue the keystream seamlessly. This mirrors + * how aes_ctr_crypt relies on swcr_encdec feeding whole blocks (only the + * final block may be shorter), keeping every stream cipher on one path. + */ + + chacha_encrypt_bytes((FAR chacha_ctx *)ctx, data, data, len); +} + +void chachapoly_reinit(caddr_t key, FAR uint8_t *iv) { FAR struct chacha20_ctx *ctx = (FAR struct chacha20_ctx *)key; - chacha_encrypt_bytes((FAR chacha_ctx *)ctx->block, data, data, - CHACHA20_BLOCK_LEN); + /* initial counter is 1 */ + + ctx->nonce[0] = 1; + chacha_ivsetup((FAR chacha_ctx *)ctx->block, iv, ctx->nonce); } void chacha20_poly1305_init(FAR void *xctx) @@ -156,9 +168,12 @@ void chacha20poly1305_encrypt( }; uint64_t le_nonce = htole64(nonce); + uint8_t le_nonce_array[12]; + explicit_bzero(le_nonce_array, sizeof(le_nonce_array)); + memcpy(le_nonce_array, &le_nonce, sizeof(uint64_t)); chacha_keysetup(&ctx, key, CHACHA20POLY1305_KEY_SIZE * 8); - chacha_ivsetup(&ctx, (FAR uint8_t *) &le_nonce, NULL); + chacha_ivsetup(&ctx, le_nonce_array, NULL); chacha_encrypt_bytes(&ctx, b.b0, b.b0, sizeof(b.b0)); poly1305_begin(&poly1305_ctx, b.b0); @@ -205,6 +220,9 @@ int chacha20poly1305_decrypt( }; uint64_t le_nonce = htole64(nonce); + uint8_t le_nonce_array[12]; + explicit_bzero(le_nonce_array, sizeof(le_nonce_array)); + memcpy(le_nonce_array, &le_nonce, sizeof(uint64_t)); if (src_len < CHACHA20POLY1305_AUTHTAG_SIZE) { @@ -212,7 +230,7 @@ int chacha20poly1305_decrypt( } chacha_keysetup(&ctx, key, CHACHA20POLY1305_KEY_SIZE * 8); - chacha_ivsetup(&ctx, (FAR uint8_t *) &le_nonce, NULL); + chacha_ivsetup(&ctx, le_nonce_array, NULL); chacha_encrypt_bytes(&ctx, b.b0, b.b0, sizeof(b.b0)); poly1305_begin(&poly1305_ctx, b.b0); diff --git a/crypto/cryptodev.c b/crypto/cryptodev.c index bca32db3687e0..05d380a65c907 100644 --- a/crypto/cryptodev.c +++ b/crypto/cryptodev.c @@ -236,6 +236,8 @@ static int cryptof_ioctl(FAR struct file *filep, case CRYPTO_AES_OFB: case CRYPTO_AES_CFB_8: case CRYPTO_AES_CFB_128: + case CRYPTO_CHACHA20: + case CRYPTO_CHACHA20_POLY1305: case CRYPTO_NULL: txform = true; break; @@ -256,6 +258,7 @@ static int cryptof_ioctl(FAR struct file *filep, case CRYPTO_SHA2_512_HMAC: case CRYPTO_AES_128_GMAC: case CRYPTO_AES_128_CMAC: + case CRYPTO_CHACHA20_POLY1305_MAC: case CRYPTO_MD5: case CRYPTO_POLY1305: case CRYPTO_RIPEMD160: @@ -463,6 +466,12 @@ static int cryptodev_op(FAR struct csession *cse, crp.crp_ivlen = cop->ivlen; } + if (cop->aad) + { + crp.crp_aad = cop->aad; + crp.crp_aadlen = cop->aadlen; + } + if (cop->dst) { crp.crp_dst = cop->dst; diff --git a/crypto/cryptosoft.c b/crypto/cryptosoft.c index 9dcbce8b503e2..de1d87b4e9d3f 100644 --- a/crypto/cryptosoft.c +++ b/crypto/cryptosoft.c @@ -998,6 +998,7 @@ int swcr_encdec(FAR struct cryptop *crp, FAR struct cryptodesc *crd, int j; int blks; int ivlen; + int buflen; exf = sw->sw_exf; blks = exf->blocksize; @@ -1036,7 +1037,7 @@ int swcr_encdec(FAR struct cryptop *crp, FAR struct cryptodesc *crd, * handling themselves. */ - if (exf->reinit) + if (!(crd->crd_flags & CRD_F_UPDATE) && exf->reinit) { exf->reinit((caddr_t)sw->sw_kschedule, iv); } @@ -1047,19 +1048,20 @@ int swcr_encdec(FAR struct cryptop *crp, FAR struct cryptodesc *crd, output = crp->crp_dst; while (i > 0) { - bcopy(buf, blk, exf->blocksize); - buf += exf->blocksize; + buflen = MIN(i, exf->blocksize); + bcopy(buf, blk, buflen); + buf += buflen; if (exf->reinit) { if (crd->crd_flags & CRD_F_ENCRYPT) { exf->encrypt((caddr_t)sw->sw_kschedule, - blk); + blk, buflen); } else { exf->decrypt((caddr_t)sw->sw_kschedule, - blk); + blk, buflen); } } else if (crd->crd_flags & CRD_F_ENCRYPT) @@ -1069,7 +1071,7 @@ int swcr_encdec(FAR struct cryptop *crp, FAR struct cryptodesc *crd, for (j = 0; j < blks; j++) blk[j] ^= ivp[j]; - exf->encrypt((caddr_t)sw->sw_kschedule, blk); + exf->encrypt((caddr_t)sw->sw_kschedule, blk, buflen); /* Keep encrypted block for XOR'ng * with next block @@ -1089,7 +1091,7 @@ int swcr_encdec(FAR struct cryptop *crp, FAR struct cryptodesc *crd, nivp = (ivp == iv) ? iv2 : iv; bcopy(blk, nivp, blks); - exf->decrypt((caddr_t)sw->sw_kschedule, blk); + exf->decrypt((caddr_t)sw->sw_kschedule, blk, buflen); /* XOR with previous block */ @@ -1101,10 +1103,10 @@ int swcr_encdec(FAR struct cryptop *crp, FAR struct cryptodesc *crd, ivp = nivp; } - bcopy(blk, output, exf->blocksize); - output += exf->blocksize; + bcopy(blk, output, buflen); + output += buflen; - i -= blks; + i -= buflen; /* Could be done... */ @@ -1114,7 +1116,10 @@ int swcr_encdec(FAR struct cryptop *crp, FAR struct cryptodesc *crd, } } - bcopy(ivp, crp->crp_iv, ivlen); + if (crp->crp_iv) + { + bcopy(ivp, crp->crp_iv, ivlen); + } return 0; /* Done with encryption/decryption */ } @@ -1279,6 +1284,22 @@ int swcr_authenc(FAR struct cryptop *crp) /* Initialize the IV */ + if (crp->crp_iv) + { + if (!(crde->crd_flags & CRD_F_IV_EXPLICIT)) + { + bcopy(crp->crp_iv, crde->crd_iv, exf->ivsize); + crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; + crde->crd_skip = 0; + } + } + else + { + crde->crd_flags |= CRD_F_IV_PRESENT; + crde->crd_skip = exf->blocksize; + crde->crd_len -= exf->blocksize; + } + if (crde->crd_flags & CRD_F_ENCRYPT) { /* IV explicitly provided ? */ @@ -1317,7 +1338,7 @@ int swcr_authenc(FAR struct cryptop *crp) /* Supply MAC with IV */ - if (axf->reinit) + if (!(crda->crd_flags & CRD_F_UPDATE_AAD) && axf->reinit) { axf->reinit(&ctx, iv, ivlen); } @@ -1326,7 +1347,7 @@ int swcr_authenc(FAR struct cryptop *crp) if (aad) { - aadlen = crda->crd_len; + aadlen = crp->crp_aadlen; /* Section 5 of RFC 4106 specifies that AAD construction consists of * {SPI, ESN, SN} whereas the real packet contains only {SPI, SN}. * Unfortunately it doesn't follow a good example set in the Section @@ -1342,7 +1363,7 @@ int swcr_authenc(FAR struct cryptop *crp) /* SPI */ - bcopy(buf + crda->crd_skip, blk, 4); + bcopy(aad + crda->crd_skip, blk, 4); iskip = 4; /* loop below will start with an offset of 4 */ /* ESN */ @@ -1351,10 +1372,10 @@ int swcr_authenc(FAR struct cryptop *crp) oskip = iskip + 4; /* offset output buffer blk by 8 */ } - for (i = iskip; i < crda->crd_len; i += axf->hashsize) + for (i = iskip; i < aadlen; i += axf->hashsize) { - len = MIN(crda->crd_len - i, axf->hashsize - oskip); - bcopy(buf + crda->crd_skip + i, blk + oskip, len); + len = MIN(aadlen - i, axf->hashsize - oskip); + bcopy(aad + i, blk + oskip, len); bzero(blk + len + oskip, axf->hashsize - len - oskip); axf->update(&ctx, blk, axf->hashsize); oskip = 0; /* reset initial output offset */ @@ -1381,13 +1402,13 @@ int swcr_authenc(FAR struct cryptop *crp) bcopy(buf + i, blk, len); if (crde->crd_flags & CRD_F_ENCRYPT) { - exf->encrypt((caddr_t)swe->sw_kschedule, blk); + exf->encrypt((caddr_t)swe->sw_kschedule, blk, len); axf->update(&ctx, blk, len); } else { axf->update(&ctx, blk, len); - exf->decrypt((caddr_t)swe->sw_kschedule, blk); + exf->decrypt((caddr_t)swe->sw_kschedule, blk, len); } if (crp->crp_dst) @@ -1621,6 +1642,9 @@ int swcr_newsession(FAR uint32_t *sid, FAR struct cryptoini *cri) case CRYPTO_AES_CFB_128: txf = &enc_xform_aes_cfb_128; goto enccommon; + case CRYPTO_CHACHA20: + txf = &enc_xform_chacha20; + goto enccommon; case CRYPTO_CHACHA20_POLY1305: txf = &enc_xform_chacha20_poly1305; goto enccommon; @@ -1883,6 +1907,7 @@ int swcr_freesession(uint64_t tid) case CRYPTO_AES_OFB: case CRYPTO_AES_CFB_8: case CRYPTO_AES_CFB_128: + case CRYPTO_CHACHA20: case CRYPTO_CHACHA20_POLY1305: case CRYPTO_NULL: txf = swd->sw_exf; @@ -1967,7 +1992,7 @@ int swcr_process(struct cryptop *crp) return -EINVAL; } - if (crp->crp_desc == NULL || crp->crp_buf == NULL) + if (crp->crp_desc == NULL) { crp->crp_etype = -EINVAL; goto done; @@ -2021,6 +2046,7 @@ int swcr_process(struct cryptop *crp) case CRYPTO_AES_OFB: case CRYPTO_AES_CFB_8: case CRYPTO_AES_CFB_128: + case CRYPTO_CHACHA20: txf = sw->sw_exf; if (crp->crp_iv) @@ -2425,6 +2451,7 @@ void swcr_init(void) algs[CRYPTO_AES_OFB] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_AES_CFB_8] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_AES_CFB_128] = CRYPTO_ALG_FLAG_SUPPORTED; + algs[CRYPTO_CHACHA20] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_CHACHA20_POLY1305] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_CHACHA20_POLY1305_MAC] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_MD5] = CRYPTO_ALG_FLAG_SUPPORTED; diff --git a/crypto/xform.c b/crypto/xform.c index cc63cd0562bb6..ff9729c22952c 100644 --- a/crypto/xform.c +++ b/crypto/xform.c @@ -112,26 +112,26 @@ 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); -void des3_encrypt(caddr_t, FAR uint8_t *); -void blf_encrypt(caddr_t, FAR uint8_t *); -void cast5_encrypt(caddr_t, FAR uint8_t *); -void aes_encrypt_xform(caddr_t, FAR uint8_t *); -void null_encrypt(caddr_t, FAR uint8_t *); -void aes_xts_encrypt(caddr_t, FAR uint8_t *); -void aes_ofb_encrypt(caddr_t, FAR uint8_t *); -void aes_cfb8_encrypt(caddr_t, FAR uint8_t *); -void aes_cfb128_encrypt(caddr_t, FAR uint8_t *); - -void des3_decrypt(caddr_t, FAR uint8_t *); -void blf_decrypt(caddr_t, FAR uint8_t *); -void cast5_decrypt(caddr_t, FAR uint8_t *); -void aes_decrypt_xform(caddr_t, FAR uint8_t *); -void null_decrypt(caddr_t, FAR uint8_t *); -void aes_xts_decrypt(caddr_t, FAR uint8_t *); -void aes_cfb8_decrypt(caddr_t, FAR uint8_t *); -void aes_cfb128_decrypt(caddr_t, FAR uint8_t *); - -void aes_ctr_crypt(caddr_t, FAR uint8_t *); +void des3_encrypt(caddr_t, FAR uint8_t *, size_t); +void blf_encrypt(caddr_t, FAR uint8_t *, size_t); +void cast5_encrypt(caddr_t, FAR uint8_t *, size_t); +void aes_encrypt_xform(caddr_t, FAR uint8_t *, size_t); +void null_encrypt(caddr_t, FAR uint8_t *, size_t); +void aes_xts_encrypt(caddr_t, FAR uint8_t *, size_t); +void aes_ofb_encrypt(caddr_t, FAR uint8_t *, size_t); +void aes_cfb8_encrypt(caddr_t, FAR uint8_t *, size_t); +void aes_cfb128_encrypt(caddr_t, FAR uint8_t *, size_t); + +void des3_decrypt(caddr_t, FAR uint8_t *, size_t); +void blf_decrypt(caddr_t, FAR uint8_t *, size_t); +void cast5_decrypt(caddr_t, FAR uint8_t *, size_t); +void aes_decrypt_xform(caddr_t, FAR uint8_t *, size_t); +void null_decrypt(caddr_t, FAR uint8_t *, size_t); +void aes_xts_decrypt(caddr_t, FAR uint8_t *, size_t); +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_reinit(caddr_t, FAR uint8_t *); void aes_xts_reinit(caddr_t, FAR uint8_t *); @@ -307,15 +307,26 @@ const struct enc_xform enc_xform_aes_cfb_128 = aes_ofb_reinit }; +const struct enc_xform enc_xform_chacha20 = +{ + CRYPTO_CHACHA20, "CHACHA20", + 64, 12, 32 + 4, 32 + 4, + sizeof(struct chacha20_ctx), + chacha20_crypt, + chacha20_crypt, + chacha20_setkey, + chacha20_reinit +}; + const struct enc_xform enc_xform_chacha20_poly1305 = { CRYPTO_CHACHA20_POLY1305, "CHACHA20-POLY1305", - 1, 8, 32 + 4, 32 + 4, + 64, 12, 32 + 4, 32 + 4, sizeof(struct chacha20_ctx), chacha20_crypt, chacha20_crypt, chacha20_setkey, - chacha20_reinit + chachapoly_reinit }; const struct enc_xform enc_xform_null = @@ -518,12 +529,12 @@ const struct auth_hash auth_hash_crc32 = /* Encryption wrapper routines. */ -void des3_encrypt(caddr_t key, FAR uint8_t *blk) +void des3_encrypt(caddr_t key, FAR uint8_t *blk, size_t len) { des_ecb3_encrypt((caddr_t)blk, (caddr_t)blk, key, key + 128, key + 256, 1); } -void des3_decrypt(caddr_t key, FAR uint8_t *blk) +void des3_decrypt(caddr_t key, FAR uint8_t *blk, size_t len) { des_ecb3_encrypt((caddr_t)blk, (caddr_t)blk, key + 256, key + 128, key, 0); } @@ -539,12 +550,12 @@ int des3_setkey(FAR void *sched, FAR uint8_t *key, int len) return 0; } -void blf_encrypt(caddr_t key, FAR uint8_t *blk) +void blf_encrypt(caddr_t key, FAR uint8_t *blk, size_t len) { blf_ecb_encrypt((FAR blf_ctx *) key, blk, 8); } -void blf_decrypt(caddr_t key, FAR uint8_t *blk) +void blf_decrypt(caddr_t key, FAR uint8_t *blk, size_t len) { blf_ecb_decrypt((FAR blf_ctx *) key, blk, 8); } @@ -561,20 +572,20 @@ int null_setkey(FAR void *sched, FAR uint8_t *key, int len) return 0; } -void null_encrypt(caddr_t key, FAR uint8_t *blk) +void null_encrypt(caddr_t key, FAR uint8_t *blk, size_t len) { } -void null_decrypt(caddr_t key, FAR uint8_t *blk) +void null_decrypt(caddr_t key, FAR uint8_t *blk, size_t len) { } -void cast5_encrypt(caddr_t key, FAR uint8_t *blk) +void cast5_encrypt(caddr_t key, FAR uint8_t *blk, size_t len) { cast_encrypt((FAR cast_key *) key, blk, blk); } -void cast5_decrypt(caddr_t key, FAR uint8_t *blk) +void cast5_decrypt(caddr_t key, FAR uint8_t *blk, size_t len) { cast_decrypt((FAR cast_key *) key, blk, blk); } @@ -586,12 +597,12 @@ int cast5_setkey(FAR void *sched, FAR uint8_t *key, int len) return 0; } -void aes_encrypt_xform(caddr_t key, FAR uint8_t *blk) +void aes_encrypt_xform(caddr_t key, FAR uint8_t *blk, size_t len) { aes_encrypt((FAR AES_CTX *)key, blk, blk); } -void aes_decrypt_xform(caddr_t key, FAR uint8_t *blk) +void aes_decrypt_xform(caddr_t key, FAR uint8_t *blk, size_t len) { aes_decrypt((FAR AES_CTX *)key, blk, blk); } @@ -626,7 +637,7 @@ void aes_gcm_reinit(caddr_t key, FAR uint8_t *iv) ctx->ac_block[AESCTR_BLOCKSIZE - 1] = 1; /* GCM starts with 1 */ } -void aes_ctr_crypt(caddr_t key, FAR uint8_t *data) +void aes_ctr_crypt(caddr_t key, FAR uint8_t *data, size_t len) { FAR struct aes_ctr_ctx *ctx; uint8_t keystream[AESCTR_BLOCKSIZE]; @@ -741,12 +752,12 @@ void aes_xts_crypt(FAR struct aes_xts_ctx *ctx, explicit_bzero(block, sizeof(block)); } -void aes_xts_encrypt(caddr_t key, FAR uint8_t *data) +void aes_xts_encrypt(caddr_t key, FAR uint8_t *data, size_t len) { aes_xts_crypt((FAR struct aes_xts_ctx *)key, data, 1); } -void aes_xts_decrypt(caddr_t key, FAR uint8_t *data) +void aes_xts_decrypt(caddr_t key, FAR uint8_t *data, size_t len) { aes_xts_crypt((FAR struct aes_xts_ctx *)key, data, 0); } @@ -768,7 +779,7 @@ int aes_xts_setkey(FAR void *sched, FAR uint8_t *key, int len) return 0; } -void aes_ofb_encrypt(caddr_t key, FAR uint8_t *data) +void aes_ofb_encrypt(caddr_t key, FAR uint8_t *data, size_t len) { FAR struct aes_ofb_ctx *ctx; int i; @@ -803,7 +814,7 @@ void aes_ofb_reinit(caddr_t key, FAR uint8_t *iv) ctx->iv = iv; } -void aes_cfb8_encrypt(caddr_t key, FAR uint8_t *data) +void aes_cfb8_encrypt(caddr_t key, FAR uint8_t *data, size_t len) { FAR struct aes_ofb_ctx *ctx; uint8_t ov[AESOFB_IVSIZE + 1]; @@ -821,7 +832,7 @@ void aes_cfb8_encrypt(caddr_t key, FAR uint8_t *data) } } -void aes_cfb8_decrypt(caddr_t key, FAR uint8_t *data) +void aes_cfb8_decrypt(caddr_t key, FAR uint8_t *data, size_t len) { FAR struct aes_ofb_ctx *ctx; uint8_t ov[AESOFB_IVSIZE + 1]; @@ -839,7 +850,7 @@ void aes_cfb8_decrypt(caddr_t key, FAR uint8_t *data) } } -void aes_cfb128_encrypt(caddr_t key, FAR uint8_t *data) +void aes_cfb128_encrypt(caddr_t key, FAR uint8_t *data, size_t len) { FAR struct aes_ofb_ctx *ctx; int i; @@ -854,7 +865,7 @@ void aes_cfb128_encrypt(caddr_t key, FAR uint8_t *data) } } -void aes_cfb128_decrypt(caddr_t key, FAR uint8_t *data) +void aes_cfb128_decrypt(caddr_t key, FAR uint8_t *data, size_t len) { FAR struct aes_ofb_ctx *ctx; uint8_t c; diff --git a/include/crypto/chachapoly.h b/include/crypto/chachapoly.h index 49221058daf71..ee5a4607842b2 100644 --- a/include/crypto/chachapoly.h +++ b/include/crypto/chachapoly.h @@ -23,7 +23,7 @@ #define CHACHA20_KEYSIZE 32 #define CHACHA20_CTR 4 #define CHACHA20_SALT 4 -#define CHACHA20_NONCE 8 +#define CHACHA20_NONCE 4 #define CHACHA20_BLOCK_LEN 64 struct chacha20_ctx @@ -34,9 +34,10 @@ struct chacha20_ctx int chacha20_setkey(FAR void *, FAR uint8_t *, int); void chacha20_reinit(caddr_t, FAR uint8_t *); -void chacha20_crypt(caddr_t, FAR uint8_t *); +void chacha20_crypt(caddr_t, FAR uint8_t *, size_t); +void chachapoly_reinit(caddr_t, FAR uint8_t *); -#define POLY1305_KEYLEN 32 +#define POLY1305_KEYLEN 64 #define POLY1305_TAGLEN 16 #define POLY1305_BLOCK_LEN 16 diff --git a/include/crypto/cryptodev.h b/include/crypto/cryptodev.h index ad5f62afb5375..3ee6c4f16cf46 100644 --- a/include/crypto/cryptodev.h +++ b/include/crypto/cryptodev.h @@ -91,7 +91,7 @@ #define BLOWFISH_BLOCK_LEN 8 #define CAST128_BLOCK_LEN 8 #define RIJNDAEL128_BLOCK_LEN 16 -#define EALG_MAX_BLOCK_LEN 16 +#define EALG_MAX_BLOCK_LEN 64 /* Keep this updated */ @@ -140,7 +140,8 @@ #define CRYPTO_PBKDF2_HMAC_SHA256 39 #define CRYPTO_ESN 40 /* Support for Extended Sequence Numbers */ #define CRYPTO_SHA2_224_HMAC 41 -#define CRYPTO_ALGORITHM_MAX 41 /* Keep updated */ +#define CRYPTO_CHACHA20 42 +#define CRYPTO_ALGORITHM_MAX 42 /* Keep updated */ /* Algorithm flags */ diff --git a/include/crypto/xform.h b/include/crypto/xform.h index 6f3bc42ec64c1..2e14495c29fbd 100644 --- a/include/crypto/xform.h +++ b/include/crypto/xform.h @@ -76,8 +76,8 @@ struct enc_xform uint16_t minkey; uint16_t maxkey; uint16_t ctxsize; - CODE void (*encrypt)(caddr_t, FAR uint8_t *); - CODE void (*decrypt)(caddr_t, FAR uint8_t *); + CODE void (*encrypt)(caddr_t, FAR uint8_t *, size_t); + CODE void (*decrypt)(caddr_t, FAR uint8_t *, size_t); CODE int (*setkey)(FAR void *, FAR uint8_t *, int len); CODE void (*reinit)(caddr_t, FAR uint8_t *); }; @@ -112,6 +112,7 @@ extern const struct enc_xform enc_xform_aes_xts; extern const struct enc_xform enc_xform_aes_ofb; extern const struct enc_xform enc_xform_aes_cfb_8; extern const struct enc_xform enc_xform_aes_cfb_128; +extern const struct enc_xform enc_xform_chacha20; extern const struct enc_xform enc_xform_chacha20_poly1305; extern const struct enc_xform enc_xform_null; From 9ef705e0508e6dc6e5a6f2780ce28974c9ff5efb Mon Sep 17 00:00:00 2001 From: Felipe Moura Date: Fri, 10 Jul 2026 18:48:43 -0300 Subject: [PATCH 3/3] crypto: add CRYPTO_CHACHA20_DJB variant (64-bit counter/nonce) CRYPTO_CHACHA20 implements the RFC 8439/IETF parameterization (32-bit counter + 96-bit nonce). SSH's chacha20-poly1305@openssh.com uses the original DJB construction instead: a 64-bit block counter in state words 12..13 and a 64-bit nonce in words 14..15 (libtomcrypt's chacha_ivctr64). The two layouts produce different keystreams for the same key, so an SSH server cannot interoperate with OpenSSH clients through the IETF variant. Signed-off-by: Felipe Moura --- crypto/chachapoly.c | 26 ++++++++++++++++++++++++++ crypto/cryptodev.c | 1 + crypto/cryptosoft.c | 6 ++++++ crypto/xform.c | 11 +++++++++++ include/crypto/chachapoly.h | 2 ++ include/crypto/cryptodev.h | 3 ++- include/crypto/xform.h | 1 + 7 files changed, 49 insertions(+), 1 deletion(-) diff --git a/crypto/chachapoly.c b/crypto/chachapoly.c index 885b066ff6e28..8a0c47a52c801 100644 --- a/crypto/chachapoly.c +++ b/crypto/chachapoly.c @@ -84,6 +84,32 @@ void chachapoly_reinit(caddr_t key, FAR uint8_t *iv) chacha_ivsetup((FAR chacha_ctx *)ctx->block, iv, ctx->nonce); } +int chacha20_djb_setkey(FAR void *sched, FAR uint8_t *key, int len) +{ + FAR struct chacha20_ctx *ctx = (FAR struct chacha20_ctx *)sched; + + if (len != CHACHA20_KEYSIZE) + { + return -1; + } + + chacha_keysetup((FAR chacha_ctx *)ctx->block, key, CHACHA20_KEYSIZE * 8); + return 0; +} + +void chacha20_djb_reinit(caddr_t key, FAR uint8_t *iv) +{ + FAR struct chacha20_ctx *ctx = (FAR struct chacha20_ctx *)key; + + /* Original DJB ChaCha20 layout, as used by chacha20-poly1305@openssh.com + * (libtomcrypt chacha_ivctr64): the 16-byte IV is loaded verbatim into + * state words 12..15 as a 64-bit little-endian block counter followed by + * a 64-bit nonce. + */ + + chacha_ivsetup((FAR chacha_ctx *)ctx->block, iv + 4, iv); +} + void chacha20_poly1305_init(FAR void *xctx) { FAR CHACHA20_POLY1305_CTX *ctx = xctx; diff --git a/crypto/cryptodev.c b/crypto/cryptodev.c index 05d380a65c907..d624e14d330b1 100644 --- a/crypto/cryptodev.c +++ b/crypto/cryptodev.c @@ -237,6 +237,7 @@ static int cryptof_ioctl(FAR struct file *filep, case CRYPTO_AES_CFB_8: case CRYPTO_AES_CFB_128: case CRYPTO_CHACHA20: + case CRYPTO_CHACHA20_DJB: case CRYPTO_CHACHA20_POLY1305: case CRYPTO_NULL: txform = true; diff --git a/crypto/cryptosoft.c b/crypto/cryptosoft.c index de1d87b4e9d3f..c1f4539b060ef 100644 --- a/crypto/cryptosoft.c +++ b/crypto/cryptosoft.c @@ -1645,6 +1645,9 @@ int swcr_newsession(FAR uint32_t *sid, FAR struct cryptoini *cri) case CRYPTO_CHACHA20: txf = &enc_xform_chacha20; goto enccommon; + case CRYPTO_CHACHA20_DJB: + txf = &enc_xform_chacha20_djb; + goto enccommon; case CRYPTO_CHACHA20_POLY1305: txf = &enc_xform_chacha20_poly1305; goto enccommon; @@ -1908,6 +1911,7 @@ int swcr_freesession(uint64_t tid) case CRYPTO_AES_CFB_8: case CRYPTO_AES_CFB_128: case CRYPTO_CHACHA20: + case CRYPTO_CHACHA20_DJB: case CRYPTO_CHACHA20_POLY1305: case CRYPTO_NULL: txf = swd->sw_exf; @@ -2047,6 +2051,7 @@ int swcr_process(struct cryptop *crp) case CRYPTO_AES_CFB_8: case CRYPTO_AES_CFB_128: case CRYPTO_CHACHA20: + case CRYPTO_CHACHA20_DJB: txf = sw->sw_exf; if (crp->crp_iv) @@ -2452,6 +2457,7 @@ void swcr_init(void) algs[CRYPTO_AES_CFB_8] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_AES_CFB_128] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_CHACHA20] = CRYPTO_ALG_FLAG_SUPPORTED; + algs[CRYPTO_CHACHA20_DJB] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_CHACHA20_POLY1305] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_CHACHA20_POLY1305_MAC] = CRYPTO_ALG_FLAG_SUPPORTED; algs[CRYPTO_MD5] = CRYPTO_ALG_FLAG_SUPPORTED; diff --git a/crypto/xform.c b/crypto/xform.c index ff9729c22952c..788a718b08e7b 100644 --- a/crypto/xform.c +++ b/crypto/xform.c @@ -318,6 +318,17 @@ const struct enc_xform enc_xform_chacha20 = chacha20_reinit }; +const struct enc_xform enc_xform_chacha20_djb = +{ + CRYPTO_CHACHA20_DJB, "CHACHA20-DJB", + 64, 16, 32, 32, + sizeof(struct chacha20_ctx), + chacha20_crypt, + chacha20_crypt, + chacha20_djb_setkey, + chacha20_djb_reinit +}; + const struct enc_xform enc_xform_chacha20_poly1305 = { CRYPTO_CHACHA20_POLY1305, "CHACHA20-POLY1305", diff --git a/include/crypto/chachapoly.h b/include/crypto/chachapoly.h index ee5a4607842b2..1886e88af1b4d 100644 --- a/include/crypto/chachapoly.h +++ b/include/crypto/chachapoly.h @@ -36,6 +36,8 @@ int chacha20_setkey(FAR void *, FAR uint8_t *, int); void chacha20_reinit(caddr_t, FAR uint8_t *); void chacha20_crypt(caddr_t, FAR uint8_t *, size_t); void chachapoly_reinit(caddr_t, FAR uint8_t *); +int chacha20_djb_setkey(FAR void *, FAR uint8_t *, int); +void chacha20_djb_reinit(caddr_t, FAR uint8_t *); #define POLY1305_KEYLEN 64 #define POLY1305_TAGLEN 16 diff --git a/include/crypto/cryptodev.h b/include/crypto/cryptodev.h index 3ee6c4f16cf46..824f8fafb125f 100644 --- a/include/crypto/cryptodev.h +++ b/include/crypto/cryptodev.h @@ -141,7 +141,8 @@ #define CRYPTO_ESN 40 /* Support for Extended Sequence Numbers */ #define CRYPTO_SHA2_224_HMAC 41 #define CRYPTO_CHACHA20 42 -#define CRYPTO_ALGORITHM_MAX 42 /* Keep updated */ +#define CRYPTO_CHACHA20_DJB 43 +#define CRYPTO_ALGORITHM_MAX 43 /* Keep updated */ /* Algorithm flags */ diff --git a/include/crypto/xform.h b/include/crypto/xform.h index 2e14495c29fbd..ad6b7ad4086d1 100644 --- a/include/crypto/xform.h +++ b/include/crypto/xform.h @@ -113,6 +113,7 @@ extern const struct enc_xform enc_xform_aes_ofb; extern const struct enc_xform enc_xform_aes_cfb_8; extern const struct enc_xform enc_xform_aes_cfb_128; extern const struct enc_xform enc_xform_chacha20; +extern const struct enc_xform enc_xform_chacha20_djb; extern const struct enc_xform enc_xform_chacha20_poly1305; extern const struct enc_xform enc_xform_null;