git: 8fbc0cc23a60 - stable/13 - <crypto/chacha20_poly1305>: Fix operations with 8 byte nonce.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 15 Nov 2022 01:42:45 UTC
The branch stable/13 has been updated by jhb: URL: https://cgit.FreeBSD.org/src/commit/?id=8fbc0cc23a607bb1a5ef13e18d9e19b5ee54a90d commit 8fbc0cc23a607bb1a5ef13e18d9e19b5ee54a90d Author: John Baldwin <jhb@FreeBSD.org> AuthorDate: 2022-11-15 01:24:56 +0000 Commit: John Baldwin <jhb@FreeBSD.org> CommitDate: 2022-11-15 01:39:54 +0000 <crypto/chacha20_poly1305>: Fix operations with 8 byte nonce. In head, the inline ChaCha20+Poly1305 API is implemented using the software implementation backing OCF, but that requires API changes that can't be MFC'd. As a result, this API in stable/13 uses libsodium directly. However, libsodium's version of ChaCha20+Poly1305 with an 8 byte nonce uses a different construction for the Poly1305 hash than is used for the standard IETF AEAD cipher used for TLS and IPsec. WireGuard's use of an 8 byte nonce also uses the more standard construction. Since the verison in stable/13 was using libsodium directly for the 8 byte nonce case, it was generating incorrect MACs for if_wg(4). As a workaround, change the direct API to always use the IETF API from libsodium which uses 12 byte nonces. This can be done by zero-extending the provided 8 byte nonce to 12 bytes so long as the passed in buffers are sufficiently small to not overflow a 4 byte counter. This fixes key negotiation for if_wg(4) on stable/13. This is also a direct commit to stable/13. Reported by: Marek Zarychta <mzar@bpine64.dom.potoki.eu> --- sys/crypto/chacha20_poly1305.c | 46 +++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/sys/crypto/chacha20_poly1305.c b/sys/crypto/chacha20_poly1305.c index 9aaa570ccca4..516fc333f949 100644 --- a/sys/crypto/chacha20_poly1305.c +++ b/sys/crypto/chacha20_poly1305.c @@ -34,17 +34,38 @@ #include <sodium/crypto_aead_chacha20poly1305.h> #include <sodium/crypto_aead_xchacha20poly1305.h> +/* + * libsodium's chacha20poly1305 AEAD cipher does not construct the + * Poly1305 digest in the same method as the IETF AEAD construct. + * Specifically, libsodium does not pad the AAD and cipher text with + * zeroes to a 16 byte boundary, and libsodium inserts the AAD and + * cipher text lengths as inputs into the digest after each data + * segment rather than appending both data lengths after the padded + * cipher text. + * + * Instead, always use libsodium's chacha20poly1305 IETF AEAD cipher. + * This cipher uses a 96-bit nonce with a 32-bit counter. The data + * encrypted here should never be large enough to overflow the counter + * to the second word, so just pass zeros as the first word of the + * nonce to mimic a 64-bit nonce and 64-bit counter. + */ void chacha20_poly1305_encrypt(uint8_t *dst, const uint8_t *src, const size_t src_len, const uint8_t *aad, const size_t aad_len, const uint8_t *nonce, const size_t nonce_len, const uint8_t *key) { + char local_nonce[12]; + + MPASS(aad_len + src_len <= + crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX); if (nonce_len == crypto_aead_chacha20poly1305_ietf_NPUBBYTES) - crypto_aead_chacha20poly1305_ietf_encrypt(dst, NULL, src, - src_len, aad, aad_len, NULL, nonce, key); - else - crypto_aead_chacha20poly1305_encrypt(dst, NULL, src, - src_len, aad, aad_len, NULL, nonce, key); + memcpy(local_nonce, nonce, sizeof(local_nonce)); + else { + memset(local_nonce, 0, 4); + memcpy(local_nonce + 4, nonce, 8); + } + crypto_aead_chacha20poly1305_ietf_encrypt(dst, NULL, src, src_len, + aad, aad_len, NULL, local_nonce, key); } bool @@ -52,14 +73,19 @@ chacha20_poly1305_decrypt(uint8_t *dst, const uint8_t *src, const size_t src_len, const uint8_t *aad, const size_t aad_len, const uint8_t *nonce, const size_t nonce_len, const uint8_t *key) { + char local_nonce[12]; int ret; + MPASS(aad_len + src_len <= + crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX); if (nonce_len == crypto_aead_chacha20poly1305_ietf_NPUBBYTES) - ret = crypto_aead_chacha20poly1305_ietf_decrypt(dst, NULL, - NULL, src, src_len, aad, aad_len, nonce, key); - else - ret = crypto_aead_chacha20poly1305_decrypt(dst, NULL, - NULL, src, src_len, aad, aad_len, nonce, key); + memcpy(local_nonce, nonce, sizeof(local_nonce)); + else { + memset(local_nonce, 0, 4); + memcpy(local_nonce + 4, nonce, 8); + } + ret = crypto_aead_chacha20poly1305_ietf_decrypt(dst, NULL, NULL, + src, src_len, aad, aad_len, local_nonce, key); return (ret == 0); }