mirror of
https://git.FreeBSD.org/src.git
synced 2024-10-19 02:29:40 +00:00
crypto: Support Chacha20-Poly1305 with a nonce size of 8 bytes.
This is useful for WireGuard which uses a nonce of 8 bytes rather
than the 12 bytes used for IPsec and TLS.
Note that this also fixes a (should be) harmless bug in ossl(4) where
the counter was incorrectly treated as a 64-bit counter instead of a
32-bit counter in terms of wrapping when using a 12 byte nonce.
However, this required a single message (TLS record) longer than 64 *
(2^32 - 1) bytes (about 256 GB) to trigger.
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D32122
(cherry picked from commit 42dcd39528
)
This commit is contained in:
parent
dffa7f13db
commit
64c043d2d2
@ -167,7 +167,7 @@ The following AEAD algorithms are supported:
|
||||
AES Galois/Counter Mode
|
||||
.It Dv CRYPTO_AES_CCM_16 Ta 12, 7-13 Ta 16, 24, 32 Ta 16 Ta
|
||||
AES Counter with CBC-MAC
|
||||
.It Dv CRYPTO_CHACHA20_POLY1305 Ta 12 Ta 32 Ta 16 Ta
|
||||
.It Dv CRYPTO_CHACHA20_POLY1305 Ta 12, 8 Ta 32 Ta 16 Ta
|
||||
ChaCha20-Poly1305
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
|
@ -161,7 +161,8 @@ ossl_chacha20_poly1305_encrypt(struct cryptop *crp,
|
||||
for (i = 0; i < nitems(key); i++)
|
||||
key[i] = CHACHA_U8TOU32(cipher_key + i * 4);
|
||||
|
||||
crypto_read_iv(crp, counter + 1);
|
||||
memset(counter, 0, sizeof(counter));
|
||||
crypto_read_iv(crp, counter + (CHACHA_CTR_SIZE - csp->csp_ivlen) / 4);
|
||||
for (i = 1; i < nitems(counter); i++)
|
||||
counter[i] = le32toh(counter[i]);
|
||||
|
||||
@ -223,7 +224,7 @@ ossl_chacha20_poly1305_encrypt(struct cryptop *crp,
|
||||
|
||||
/* Truncate if the 32-bit counter would roll over. */
|
||||
next_counter = counter[0] + todo / CHACHA_BLK_SIZE;
|
||||
if (next_counter < counter[0]) {
|
||||
if (csp->csp_ivlen == 8 && next_counter < counter[0]) {
|
||||
todo -= next_counter * CHACHA_BLK_SIZE;
|
||||
next_counter = 0;
|
||||
}
|
||||
@ -232,7 +233,7 @@ ossl_chacha20_poly1305_encrypt(struct cryptop *crp,
|
||||
Poly1305_Update(&auth_ctx, out, todo);
|
||||
|
||||
counter[0] = next_counter;
|
||||
if (counter[0] == 0)
|
||||
if (csp->csp_ivlen == 8 && counter[0] == 0)
|
||||
counter[1]++;
|
||||
|
||||
if (out == block) {
|
||||
@ -307,7 +308,8 @@ ossl_chacha20_poly1305_decrypt(struct cryptop *crp,
|
||||
for (i = 0; i < nitems(key); i++)
|
||||
key[i] = CHACHA_U8TOU32(cipher_key + i * 4);
|
||||
|
||||
crypto_read_iv(crp, counter + 1);
|
||||
memset(counter, 0, sizeof(counter));
|
||||
crypto_read_iv(crp, counter + (CHACHA_CTR_SIZE - csp->csp_ivlen) / 4);
|
||||
for (i = 1; i < nitems(counter); i++)
|
||||
counter[i] = le32toh(counter[i]);
|
||||
|
||||
@ -391,7 +393,7 @@ ossl_chacha20_poly1305_decrypt(struct cryptop *crp,
|
||||
|
||||
/* Truncate if the 32-bit counter would roll over. */
|
||||
next_counter = counter[0] + todo / CHACHA_BLK_SIZE;
|
||||
if (next_counter < counter[0]) {
|
||||
if (csp->csp_ivlen == 8 && next_counter < counter[0]) {
|
||||
todo -= next_counter * CHACHA_BLK_SIZE;
|
||||
next_counter = 0;
|
||||
}
|
||||
@ -399,7 +401,7 @@ ossl_chacha20_poly1305_decrypt(struct cryptop *crp,
|
||||
ChaCha20_ctr32(out, in, todo, key, counter);
|
||||
|
||||
counter[0] = next_counter;
|
||||
if (counter[0] == 0)
|
||||
if (csp->csp_ivlen == 8 && counter[0] == 0)
|
||||
counter[1]++;
|
||||
|
||||
if (out == block) {
|
||||
|
@ -882,10 +882,15 @@ check_csp(const struct crypto_session_params *csp)
|
||||
return (false);
|
||||
break;
|
||||
case CRYPTO_AES_NIST_GCM_16:
|
||||
case CRYPTO_CHACHA20_POLY1305:
|
||||
if (csp->csp_auth_mlen > 16)
|
||||
return (false);
|
||||
break;
|
||||
case CRYPTO_CHACHA20_POLY1305:
|
||||
if (csp->csp_ivlen != 8 && csp->csp_ivlen != 12)
|
||||
return (false);
|
||||
if (csp->csp_auth_mlen > POLY1305_HASH_LEN)
|
||||
return (false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CSP_MODE_ETA:
|
||||
|
@ -1393,9 +1393,6 @@ swcr_setup_chacha20_poly1305(struct swcr_session *ses,
|
||||
struct swcr_auth *swa;
|
||||
struct auth_hash *axf;
|
||||
|
||||
if (csp->csp_ivlen != CHACHA20_POLY1305_IV_LEN)
|
||||
return (EINVAL);
|
||||
|
||||
/* First, setup the auth side. */
|
||||
swa = &ses->swcr_auth;
|
||||
axf = &auth_hash_chacha20_poly1305;
|
||||
|
@ -34,6 +34,7 @@
|
||||
struct chacha20_poly1305_cipher_ctx {
|
||||
const void *key;
|
||||
uint32_t ic;
|
||||
bool ietf;
|
||||
char nonce[CHACHA20_POLY1305_IV_LEN];
|
||||
};
|
||||
|
||||
@ -58,7 +59,8 @@ chacha20_poly1305_reinit(void *vctx, const uint8_t *iv, size_t ivlen)
|
||||
("%s: invalid nonce length", __func__));
|
||||
|
||||
/* Block 0 is used for the poly1305 key. */
|
||||
memcpy(ctx->nonce, iv, sizeof(ctx->nonce));
|
||||
memcpy(ctx->nonce, iv, ivlen);
|
||||
ctx->ietf = (ivlen == CHACHA20_POLY1305_IV_LEN);
|
||||
ctx->ic = 1;
|
||||
}
|
||||
|
||||
@ -68,8 +70,12 @@ chacha20_poly1305_crypt(void *vctx, const uint8_t *in, uint8_t *out)
|
||||
struct chacha20_poly1305_cipher_ctx *ctx = vctx;
|
||||
int error;
|
||||
|
||||
error = crypto_stream_chacha20_ietf_xor_ic(out, in,
|
||||
CHACHA20_NATIVE_BLOCK_LEN, ctx->nonce, ctx->ic, ctx->key);
|
||||
if (ctx->ietf)
|
||||
error = crypto_stream_chacha20_ietf_xor_ic(out, in,
|
||||
CHACHA20_NATIVE_BLOCK_LEN, ctx->nonce, ctx->ic, ctx->key);
|
||||
else
|
||||
error = crypto_stream_chacha20_xor_ic(out, in,
|
||||
CHACHA20_NATIVE_BLOCK_LEN, ctx->nonce, ctx->ic, ctx->key);
|
||||
KASSERT(error == 0, ("%s failed: %d", __func__, error));
|
||||
ctx->ic++;
|
||||
}
|
||||
@ -82,8 +88,12 @@ chacha20_poly1305_crypt_last(void *vctx, const uint8_t *in, uint8_t *out,
|
||||
|
||||
int error;
|
||||
|
||||
error = crypto_stream_chacha20_ietf_xor_ic(out, in, len, ctx->nonce,
|
||||
ctx->ic, ctx->key);
|
||||
if (ctx->ietf)
|
||||
error = crypto_stream_chacha20_ietf_xor_ic(out, in, len,
|
||||
ctx->nonce, ctx->ic, ctx->key);
|
||||
else
|
||||
error = crypto_stream_chacha20_xor_ic(out, in, len, ctx->nonce,
|
||||
ctx->ic, ctx->key);
|
||||
KASSERT(error == 0, ("%s failed: %d", __func__, error));
|
||||
}
|
||||
|
||||
@ -129,7 +139,16 @@ chacha20_poly1305_Reinit(void *vctx, const uint8_t *nonce, u_int noncelen)
|
||||
struct chacha20_poly1305_auth_ctx *ctx = vctx;
|
||||
char block[CHACHA20_NATIVE_BLOCK_LEN];
|
||||
|
||||
crypto_stream_chacha20_ietf(block, sizeof(block), nonce, ctx->key);
|
||||
switch (noncelen) {
|
||||
case 8:
|
||||
crypto_stream_chacha20(block, sizeof(block), nonce, ctx->key);
|
||||
break;
|
||||
case CHACHA20_POLY1305_IV_LEN:
|
||||
crypto_stream_chacha20_ietf(block, sizeof(block), nonce, ctx->key);
|
||||
break;
|
||||
default:
|
||||
__assert_unreachable();
|
||||
}
|
||||
crypto_onetimeauth_poly1305_init(&ctx->state, block);
|
||||
explicit_bzero(block, sizeof(block));
|
||||
}
|
||||
|
@ -126,7 +126,7 @@
|
||||
* aes-ccm 128-bit AES-CCM
|
||||
* aes-ccm192 192-bit AES-CCM
|
||||
* aes-ccm256 256-bit AES-CCM
|
||||
* chacha20-poly1305 Chacha20 (96 bit nonce) with Poly1305 per RFC 8439
|
||||
* chacha20-poly1305 Chacha20 with Poly1305 per RFC 8439
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
@ -233,7 +233,7 @@ static const struct alg {
|
||||
.evp_cipher = EVP_aes_256_ccm },
|
||||
{ .name = "chacha20-poly1305", .cipher = CRYPTO_CHACHA20_POLY1305,
|
||||
.type = T_AEAD, .tag_len = POLY1305_HASH_LEN,
|
||||
.iv_sizes = { CHACHA20_POLY1305_IV_LEN },
|
||||
.iv_sizes = { CHACHA20_POLY1305_IV_LEN, 8 },
|
||||
.evp_cipher = EVP_chacha20_poly1305 },
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user