aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2022-01-11 22:16:05 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2022-01-11 22:16:41 +0000
commit8f35841f1f35cce332e94f0a3a69f51e2eb5e762 (patch)
treee38257607a5dd172c4b2826b07943de1ea68ebad
parent7df4c50643cfeecdd42b8e55c38709bf84b1b002 (diff)
downloadsrc-8f35841f1f35cce332e94f0a3a69f51e2eb5e762.tar.gz
src-8f35841f1f35cce332e94f0a3a69f51e2eb5e762.zip
crypto: Add support for the XChaCha20-Poly1305 AEAD cipher.
This cipher is a wrapper around the ChaCha20-Poly1305 AEAD cipher which accepts a larger nonce. Part of the nonce is used along with the key as an input to HChaCha20 to generate a derived key used for ChaCha20-Poly1305. This cipher is used by WireGuard. Reviewed by: markj Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D33523
-rw-r--r--share/man/man7/crypto.75
-rw-r--r--sys/opencrypto/crypto.c9
-rw-r--r--sys/opencrypto/cryptodev.h5
-rw-r--r--sys/opencrypto/cryptosoft.c6
-rw-r--r--sys/opencrypto/xform_chacha20_poly1305.c62
-rw-r--r--sys/opencrypto/xform_enc.h1
6 files changed, 86 insertions, 2 deletions
diff --git a/share/man/man7/crypto.7 b/share/man/man7/crypto.7
index c7af22af4deb..01ff339fa31f 100644
--- a/share/man/man7/crypto.7
+++ b/share/man/man7/crypto.7
@@ -31,7 +31,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 6, 2021
+.Dd January 11, 2022
.Dt CRYPTO 7
.Os
.Sh NAME
@@ -170,6 +170,9 @@ AES Counter with CBC-MAC
.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
diff --git a/sys/opencrypto/crypto.c b/sys/opencrypto/crypto.c
index acc7b8d2ecb8..0b2c250a7af2 100644
--- a/sys/opencrypto/crypto.c
+++ b/sys/opencrypto/crypto.c
@@ -579,6 +579,8 @@ crypto_cipher(const struct crypto_session_params *csp)
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 @@ static enum alg_type {
[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 @@ check_csp(const struct crypto_session_params *csp)
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:
diff --git a/sys/opencrypto/cryptodev.h b/sys/opencrypto/cryptodev.h
index ed396ed86912..b2eb01566f4f 100644
--- a/sys/opencrypto/cryptodev.h
+++ b/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)
diff --git a/sys/opencrypto/cryptosoft.c b/sys/opencrypto/cryptosoft.c
index 43fefae99c40..65eb29bdfd91 100644
--- a/sys/opencrypto/cryptosoft.c
+++ b/sys/opencrypto/cryptosoft.c
@@ -1330,6 +1330,7 @@ swcr_probesession(device_t dev, const struct crypto_session_params *csp)
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 @@ swcr_probesession(device_t dev, const struct crypto_session_params *csp)
}
break;
case CRYPTO_CHACHA20_POLY1305:
+ case CRYPTO_XCHACHA20_POLY1305:
break;
default:
return (EINVAL);
@@ -1366,6 +1368,7 @@ swcr_probesession(device_t dev, const struct crypto_session_params *csp)
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 @@ swcr_newsession(device_t dev, crypto_session_t cses,
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 @@ swcr_newsession(device_t dev, crypto_session_t cses,
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 @@ swcr_newsession(device_t dev, crypto_session_t cses,
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) {
diff --git a/sys/opencrypto/xform_chacha20_poly1305.c b/sys/opencrypto/xform_chacha20_poly1305.c
index cb1fc4cea88d..eec82681bd2c 100644
--- a/sys/opencrypto/xform_chacha20_poly1305.c
+++ b/sys/opencrypto/xform_chacha20_poly1305.c
@@ -28,6 +28,7 @@
#include <opencrypto/xform_auth.h>
#include <opencrypto/xform_enc.h>
+#include <sodium/crypto_core_hchacha20.h>
#include <sodium/crypto_onetimeauth_poly1305.h>
#include <sodium/crypto_stream_chacha20.h>
@@ -39,6 +40,12 @@ struct chacha20_poly1305_ctx {
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 @@ const struct enc_xform enc_xform_chacha20_poly1305 = {
.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,
+};
diff --git a/sys/opencrypto/xform_enc.h b/sys/opencrypto/xform_enc.h
index c998e06d4944..9364ff36431c 100644
--- a/sys/opencrypto/xform_enc.h
+++ b/sys/opencrypto/xform_enc.h
@@ -89,6 +89,7 @@ extern const struct enc_xform enc_xform_aes_xts;
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 {