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
This commit is contained in:
parent
7df4c50643
commit
8f35841f1f
@ -31,7 +31,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd October 6, 2021
|
.Dd January 11, 2022
|
||||||
.Dt CRYPTO 7
|
.Dt CRYPTO 7
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -170,6 +170,9 @@ AES Counter with CBC-MAC
|
|||||||
.It Dv CRYPTO_CHACHA20_POLY1305 Ta 12, 8 Ta 32 Ta 16 Ta
|
.It Dv CRYPTO_CHACHA20_POLY1305 Ta 12, 8 Ta 32 Ta 16 Ta
|
||||||
ChaCha20-Poly1305
|
ChaCha20-Poly1305
|
||||||
.El
|
.El
|
||||||
|
.It Dv CRYPTO_XCHACHA20_POLY1305 Ta 24 Ta 32 Ta 16 Ta
|
||||||
|
XChaCha20-Poly1305
|
||||||
|
.El
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr crypto 4 ,
|
.Xr crypto 4 ,
|
||||||
.Xr crypto 9
|
.Xr crypto 9
|
||||||
|
@ -579,6 +579,8 @@ crypto_cipher(const struct crypto_session_params *csp)
|
|||||||
return (&enc_xform_ccm);
|
return (&enc_xform_ccm);
|
||||||
case CRYPTO_CHACHA20_POLY1305:
|
case CRYPTO_CHACHA20_POLY1305:
|
||||||
return (&enc_xform_chacha20_poly1305);
|
return (&enc_xform_chacha20_poly1305);
|
||||||
|
case CRYPTO_XCHACHA20_POLY1305:
|
||||||
|
return (&enc_xform_xchacha20_poly1305);
|
||||||
default:
|
default:
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
@ -671,6 +673,7 @@ static enum alg_type {
|
|||||||
[CRYPTO_AES_CCM_CBC_MAC] = ALG_KEYED_DIGEST,
|
[CRYPTO_AES_CCM_CBC_MAC] = ALG_KEYED_DIGEST,
|
||||||
[CRYPTO_AES_CCM_16] = ALG_AEAD,
|
[CRYPTO_AES_CCM_16] = ALG_AEAD,
|
||||||
[CRYPTO_CHACHA20_POLY1305] = ALG_AEAD,
|
[CRYPTO_CHACHA20_POLY1305] = ALG_AEAD,
|
||||||
|
[CRYPTO_XCHACHA20_POLY1305] = ALG_AEAD,
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum alg_type
|
static enum alg_type
|
||||||
@ -865,6 +868,12 @@ check_csp(const struct crypto_session_params *csp)
|
|||||||
if (csp->csp_auth_mlen > POLY1305_HASH_LEN)
|
if (csp->csp_auth_mlen > POLY1305_HASH_LEN)
|
||||||
return (false);
|
return (false);
|
||||||
break;
|
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;
|
break;
|
||||||
case CSP_MODE_ETA:
|
case CSP_MODE_ETA:
|
||||||
|
@ -129,6 +129,7 @@
|
|||||||
#define AES_XTS_IV_LEN 8
|
#define AES_XTS_IV_LEN 8
|
||||||
#define AES_XTS_ALPHA 0x87 /* GF(2^128) generator polynomial */
|
#define AES_XTS_ALPHA 0x87 /* GF(2^128) generator polynomial */
|
||||||
#define CHACHA20_POLY1305_IV_LEN 12
|
#define CHACHA20_POLY1305_IV_LEN 12
|
||||||
|
#define XCHACHA20_POLY1305_IV_LEN 24
|
||||||
|
|
||||||
/* Min and Max Encryption Key Sizes */
|
/* Min and Max Encryption Key Sizes */
|
||||||
#define NULL_MIN_KEY 0
|
#define NULL_MIN_KEY 0
|
||||||
@ -142,6 +143,7 @@
|
|||||||
#define CAMELLIA_MIN_KEY 16
|
#define CAMELLIA_MIN_KEY 16
|
||||||
#define CAMELLIA_MAX_KEY 32
|
#define CAMELLIA_MAX_KEY 32
|
||||||
#define CHACHA20_POLY1305_KEY 32
|
#define CHACHA20_POLY1305_KEY 32
|
||||||
|
#define XCHACHA20_POLY1305_KEY 32
|
||||||
|
|
||||||
/* Maximum hash algorithm result length */
|
/* Maximum hash algorithm result length */
|
||||||
#define AALG_MAX_RESULT_LEN 64 /* Keep this updated */
|
#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_CBC_MAC 39 /* auth side */
|
||||||
#define CRYPTO_AES_CCM_16 40 /* cipher side */
|
#define CRYPTO_AES_CCM_16 40 /* cipher side */
|
||||||
#define CRYPTO_CHACHA20_POLY1305 41 /* combined AEAD cipher per RFC 8439 */
|
#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 && \
|
#define CRYPTO_ALGO_VALID(x) ((x) >= CRYPTO_ALGORITHM_MIN && \
|
||||||
(x) <= CRYPTO_ALGORITHM_MAX)
|
(x) <= CRYPTO_ALGORITHM_MAX)
|
||||||
|
@ -1330,6 +1330,7 @@ swcr_probesession(device_t dev, const struct crypto_session_params *csp)
|
|||||||
case CRYPTO_AES_NIST_GCM_16:
|
case CRYPTO_AES_NIST_GCM_16:
|
||||||
case CRYPTO_AES_CCM_16:
|
case CRYPTO_AES_CCM_16:
|
||||||
case CRYPTO_CHACHA20_POLY1305:
|
case CRYPTO_CHACHA20_POLY1305:
|
||||||
|
case CRYPTO_XCHACHA20_POLY1305:
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
default:
|
default:
|
||||||
if (!swcr_cipher_supported(csp))
|
if (!swcr_cipher_supported(csp))
|
||||||
@ -1355,6 +1356,7 @@ swcr_probesession(device_t dev, const struct crypto_session_params *csp)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CRYPTO_CHACHA20_POLY1305:
|
case CRYPTO_CHACHA20_POLY1305:
|
||||||
|
case CRYPTO_XCHACHA20_POLY1305:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return (EINVAL);
|
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_NIST_GCM_16:
|
||||||
case CRYPTO_AES_CCM_16:
|
case CRYPTO_AES_CCM_16:
|
||||||
case CRYPTO_CHACHA20_POLY1305:
|
case CRYPTO_CHACHA20_POLY1305:
|
||||||
|
case CRYPTO_XCHACHA20_POLY1305:
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
switch (csp->csp_auth_alg) {
|
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_NIST_GCM_16:
|
||||||
case CRYPTO_AES_CCM_16:
|
case CRYPTO_AES_CCM_16:
|
||||||
case CRYPTO_CHACHA20_POLY1305:
|
case CRYPTO_CHACHA20_POLY1305:
|
||||||
|
case CRYPTO_XCHACHA20_POLY1305:
|
||||||
panic("bad cipher algo");
|
panic("bad cipher algo");
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
@ -1446,6 +1450,7 @@ swcr_newsession(device_t dev, crypto_session_t cses,
|
|||||||
ses->swcr_process = swcr_ccm;
|
ses->swcr_process = swcr_ccm;
|
||||||
break;
|
break;
|
||||||
case CRYPTO_CHACHA20_POLY1305:
|
case CRYPTO_CHACHA20_POLY1305:
|
||||||
|
case CRYPTO_XCHACHA20_POLY1305:
|
||||||
error = swcr_setup_aead(ses, csp);
|
error = swcr_setup_aead(ses, csp);
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
ses->swcr_process = swcr_chacha20_poly1305;
|
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_NIST_GCM_16:
|
||||||
case CRYPTO_AES_CCM_16:
|
case CRYPTO_AES_CCM_16:
|
||||||
case CRYPTO_CHACHA20_POLY1305:
|
case CRYPTO_CHACHA20_POLY1305:
|
||||||
|
case CRYPTO_XCHACHA20_POLY1305:
|
||||||
panic("bad eta cipher algo");
|
panic("bad eta cipher algo");
|
||||||
}
|
}
|
||||||
switch (csp->csp_auth_alg) {
|
switch (csp->csp_auth_alg) {
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <opencrypto/xform_auth.h>
|
#include <opencrypto/xform_auth.h>
|
||||||
#include <opencrypto/xform_enc.h>
|
#include <opencrypto/xform_enc.h>
|
||||||
|
|
||||||
|
#include <sodium/crypto_core_hchacha20.h>
|
||||||
#include <sodium/crypto_onetimeauth_poly1305.h>
|
#include <sodium/crypto_onetimeauth_poly1305.h>
|
||||||
#include <sodium/crypto_stream_chacha20.h>
|
#include <sodium/crypto_stream_chacha20.h>
|
||||||
|
|
||||||
@ -39,6 +40,12 @@ struct chacha20_poly1305_ctx {
|
|||||||
char nonce[CHACHA20_POLY1305_IV_LEN];
|
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
|
static int
|
||||||
chacha20_poly1305_setkey(void *vctx, const uint8_t *key, int len)
|
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,
|
.update = chacha20_poly1305_update,
|
||||||
.final = chacha20_poly1305_final,
|
.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,
|
||||||
|
};
|
||||||
|
@ -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_camellia;
|
||||||
extern const struct enc_xform enc_xform_chacha20;
|
extern const struct enc_xform enc_xform_chacha20;
|
||||||
extern const struct enc_xform enc_xform_chacha20_poly1305;
|
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;
|
extern const struct enc_xform enc_xform_ccm;
|
||||||
|
|
||||||
struct aes_icm_ctx {
|
struct aes_icm_ctx {
|
||||||
|
Loading…
Reference in New Issue
Block a user