Index: share/man/man7/crypto.7 =================================================================== --- share/man/man7/crypto.7 +++ share/man/man7/crypto.7 @@ -170,6 +170,9 @@ .It Dv CRYPTO_CHACHA20_POLY1305 Ta 12, 8 Ta 32 Ta 16 Ta ChaCha20-Poly1305 .El +.It Dv CRYPTO_XCHACHA20_POLY1305 Ta 24 Ta 32 Ta 16 Ta +XChaCha20-Poly1305 +.El .Sh SEE ALSO .Xr crypto 4 , .Xr crypto 9 Index: sys/opencrypto/crypto.c =================================================================== --- sys/opencrypto/crypto.c +++ sys/opencrypto/crypto.c @@ -579,6 +579,8 @@ return (&enc_xform_ccm); case CRYPTO_CHACHA20_POLY1305: return (&enc_xform_chacha20_poly1305); + case CRYPTO_XCHACHA20_POLY1305: + return (&enc_xform_xchacha20_poly1305); default: return (NULL); } @@ -671,6 +673,7 @@ [CRYPTO_AES_CCM_CBC_MAC] = ALG_KEYED_DIGEST, [CRYPTO_AES_CCM_16] = ALG_AEAD, [CRYPTO_CHACHA20_POLY1305] = ALG_AEAD, + [CRYPTO_XCHACHA20_POLY1305] = ALG_AEAD, }; static enum alg_type @@ -865,6 +868,12 @@ if (csp->csp_auth_mlen > POLY1305_HASH_LEN) return (false); break; + case CRYPTO_XCHACHA20_POLY1305: + if (csp->csp_ivlen != XCHACHA20_POLY1305_IV_LEN) + return (false); + if (csp->csp_auth_mlen > POLY1305_HASH_LEN) + return (false); + break; } break; case CSP_MODE_ETA: Index: sys/opencrypto/cryptodev.h =================================================================== --- sys/opencrypto/cryptodev.h +++ sys/opencrypto/cryptodev.h @@ -129,6 +129,7 @@ #define AES_XTS_IV_LEN 8 #define AES_XTS_ALPHA 0x87 /* GF(2^128) generator polynomial */ #define CHACHA20_POLY1305_IV_LEN 12 +#define XCHACHA20_POLY1305_IV_LEN 24 /* Min and Max Encryption Key Sizes */ #define NULL_MIN_KEY 0 @@ -142,6 +143,7 @@ #define CAMELLIA_MIN_KEY 16 #define CAMELLIA_MAX_KEY 32 #define CHACHA20_POLY1305_KEY 32 +#define XCHACHA20_POLY1305_KEY 32 /* Maximum hash algorithm result length */ #define AALG_MAX_RESULT_LEN 64 /* Keep this updated */ @@ -191,7 +193,8 @@ #define CRYPTO_AES_CCM_CBC_MAC 39 /* auth side */ #define CRYPTO_AES_CCM_16 40 /* cipher side */ #define CRYPTO_CHACHA20_POLY1305 41 /* combined AEAD cipher per RFC 8439 */ -#define CRYPTO_ALGORITHM_MAX 41 /* Keep updated - see below */ +#define CRYPTO_XCHACHA20_POLY1305 42 +#define CRYPTO_ALGORITHM_MAX 42 /* Keep updated - see below */ #define CRYPTO_ALGO_VALID(x) ((x) >= CRYPTO_ALGORITHM_MIN && \ (x) <= CRYPTO_ALGORITHM_MAX) Index: sys/opencrypto/cryptosoft.c =================================================================== --- sys/opencrypto/cryptosoft.c +++ sys/opencrypto/cryptosoft.c @@ -1330,6 +1330,7 @@ case CRYPTO_AES_NIST_GCM_16: case CRYPTO_AES_CCM_16: case CRYPTO_CHACHA20_POLY1305: + case CRYPTO_XCHACHA20_POLY1305: return (EINVAL); default: if (!swcr_cipher_supported(csp)) @@ -1355,6 +1356,7 @@ } break; case CRYPTO_CHACHA20_POLY1305: + case CRYPTO_XCHACHA20_POLY1305: break; default: return (EINVAL); @@ -1366,6 +1368,7 @@ case CRYPTO_AES_NIST_GCM_16: case CRYPTO_AES_CCM_16: case CRYPTO_CHACHA20_POLY1305: + case CRYPTO_XCHACHA20_POLY1305: return (EINVAL); } switch (csp->csp_auth_alg) { @@ -1422,6 +1425,7 @@ case CRYPTO_AES_NIST_GCM_16: case CRYPTO_AES_CCM_16: case CRYPTO_CHACHA20_POLY1305: + case CRYPTO_XCHACHA20_POLY1305: panic("bad cipher algo"); #endif default: @@ -1446,6 +1450,7 @@ ses->swcr_process = swcr_ccm; break; case CRYPTO_CHACHA20_POLY1305: + case CRYPTO_XCHACHA20_POLY1305: error = swcr_setup_aead(ses, csp); if (error == 0) ses->swcr_process = swcr_chacha20_poly1305; @@ -1462,6 +1467,7 @@ case CRYPTO_AES_NIST_GCM_16: case CRYPTO_AES_CCM_16: case CRYPTO_CHACHA20_POLY1305: + case CRYPTO_XCHACHA20_POLY1305: panic("bad eta cipher algo"); } switch (csp->csp_auth_alg) { Index: sys/opencrypto/xform_chacha20_poly1305.c =================================================================== --- sys/opencrypto/xform_chacha20_poly1305.c +++ sys/opencrypto/xform_chacha20_poly1305.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -39,6 +40,12 @@ char nonce[CHACHA20_POLY1305_IV_LEN]; }; +struct xchacha20_poly1305_ctx { + struct chacha20_poly1305_ctx base_ctx; /* must be first */ + const void *key; + char derived_key[CHACHA20_POLY1305_KEY]; +}; + static int chacha20_poly1305_setkey(void *vctx, const uint8_t *key, int len) { @@ -144,3 +151,58 @@ .update = chacha20_poly1305_update, .final = chacha20_poly1305_final, }; + +static int +xchacha20_poly1305_setkey(void *vctx, const uint8_t *key, int len) +{ + struct xchacha20_poly1305_ctx *ctx = vctx; + + if (len != XCHACHA20_POLY1305_KEY) + return (EINVAL); + + ctx->key = key; + ctx->base_ctx.key = ctx->derived_key; + return (0); +} + +static void +xchacha20_poly1305_reinit(void *vctx, const uint8_t *iv, size_t ivlen) +{ + struct xchacha20_poly1305_ctx *ctx = vctx; + char nonce[CHACHA20_POLY1305_IV_LEN]; + + KASSERT(ivlen == XCHACHA20_POLY1305_IV_LEN, + ("%s: invalid nonce length", __func__)); + + /* + * Use HChaCha20 to derive the internal key used for + * ChaCha20-Poly1305. + */ + crypto_core_hchacha20(ctx->derived_key, iv, ctx->key, NULL); + + memset(nonce, 0, 4); + memcpy(nonce + 4, iv + crypto_core_hchacha20_INPUTBYTES, + sizeof(nonce) - 4); + chacha20_poly1305_reinit(&ctx->base_ctx, nonce, sizeof(nonce)); + explicit_bzero(nonce, sizeof(nonce)); +} + +const struct enc_xform enc_xform_xchacha20_poly1305 = { + .type = CRYPTO_XCHACHA20_POLY1305, + .name = "XChaCha20-Poly1305", + .ctxsize = sizeof(struct xchacha20_poly1305_ctx), + .blocksize = 1, + .native_blocksize = CHACHA20_NATIVE_BLOCK_LEN, + .ivsize = XCHACHA20_POLY1305_IV_LEN, + .minkey = XCHACHA20_POLY1305_KEY, + .maxkey = XCHACHA20_POLY1305_KEY, + .macsize = POLY1305_HASH_LEN, + .encrypt = chacha20_poly1305_crypt, + .decrypt = chacha20_poly1305_crypt, + .setkey = xchacha20_poly1305_setkey, + .reinit = xchacha20_poly1305_reinit, + .encrypt_last = chacha20_poly1305_crypt_last, + .decrypt_last = chacha20_poly1305_crypt_last, + .update = chacha20_poly1305_update, + .final = chacha20_poly1305_final, +}; Index: sys/opencrypto/xform_enc.h =================================================================== --- sys/opencrypto/xform_enc.h +++ sys/opencrypto/xform_enc.h @@ -89,6 +89,7 @@ extern const struct enc_xform enc_xform_camellia; extern const struct enc_xform enc_xform_chacha20; extern const struct enc_xform enc_xform_chacha20_poly1305; +extern const struct enc_xform enc_xform_xchacha20_poly1305; extern const struct enc_xform enc_xform_ccm; struct aes_icm_ctx {