diff --git a/share/man/man7/crypto.7 b/share/man/man7/crypto.7 --- a/share/man/man7/crypto.7 +++ b/share/man/man7/crypto.7 @@ -167,7 +167,7 @@ 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 diff --git a/sys/crypto/openssl/ossl_chacha20.c b/sys/crypto/openssl/ossl_chacha20.c --- a/sys/crypto/openssl/ossl_chacha20.c +++ b/sys/crypto/openssl/ossl_chacha20.c @@ -161,7 +161,8 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ /* 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 @@ 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) { diff --git a/sys/opencrypto/crypto.c b/sys/opencrypto/crypto.c --- a/sys/opencrypto/crypto.c +++ b/sys/opencrypto/crypto.c @@ -852,10 +852,15 @@ 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: diff --git a/sys/opencrypto/cryptosoft.c b/sys/opencrypto/cryptosoft.c --- a/sys/opencrypto/cryptosoft.c +++ b/sys/opencrypto/cryptosoft.c @@ -1393,9 +1393,6 @@ struct swcr_auth *swa; const 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; diff --git a/sys/opencrypto/xform_chacha20_poly1305.c b/sys/opencrypto/xform_chacha20_poly1305.c --- a/sys/opencrypto/xform_chacha20_poly1305.c +++ b/sys/opencrypto/xform_chacha20_poly1305.c @@ -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 @@ ("%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 @@ 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 @@ 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 @@ 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)); } diff --git a/tools/tools/crypto/cryptocheck.c b/tools/tools/crypto/cryptocheck.c --- a/tools/tools/crypto/cryptocheck.c +++ b/tools/tools/crypto/cryptocheck.c @@ -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 @@ -233,7 +233,7 @@ .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 }, };