From 6abad20323fef37594b6c6832eea3c57f59d03c4 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sat, 24 Dec 2016 02:17:33 +0100 Subject: [PATCH] xchacha20poly1305: optimize and be compatible with ietf chacha20poly1305 (#461) Due to SSL, the IETF version of chacha20poly1305 is going to be the one that's in libraries places. While the 12-byte nonce thing is a little weird, it has other benefits, like adding padding to the auth tag, which might help fend off certain attacks. But more importantly, since chacha20poly1305 in the IETF construction is lots of places, it would be useful to be able to build xchacha20poly1305 out of it. Fortunately it's very easy to make hchacha20 (either stand-alone, or out of the normal chacha20 block function), and then that can be composed with an existing library's chacha20poly1305. It looks a bit like this: xchacha20poly1305(input, key, nonce) { new_key = hchacha20(key, nonce) return chacha20poly1305(input, new_key, nonce + 16) } This is also an efficient way to do it, since it means hchacha20 must only be computed once. Unfortuantely, non-IETF xchacha20poly1305 means that you deprive virtually all other libraries that only support the more common IETF construction the ability the ability to interoperate with libsodium, through the simple construction. Rather, it forces everyone to reimplement the AEAD part. So, this commit adds a xchacha20poly1305 that uses the IETF construction with the padding. While we're at it, we redefine xchacha20poly1305 in terms of chacha20poly1305, which gives the same output, but computes one less hchacha20 and is generally a lot cleaner and simpler to understand. Signed-off-by: Jason A. Donenfeld --- .../sodium/aead_xchacha20poly1305.c | 212 ++++++++++++------ .../sodium/crypto_aead_xchacha20poly1305.h | 70 ++++++ 2 files changed, 219 insertions(+), 63 deletions(-) diff --git a/src/libsodium/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c b/src/libsodium/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c index 3a40995c..716b9064 100644 --- a/src/libsodium/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c +++ b/src/libsodium/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c @@ -5,9 +5,8 @@ #include #include "crypto_aead_xchacha20poly1305.h" -#include "crypto_onetimeauth_poly1305.h" -#include "crypto_stream_xchacha20.h" -#include "crypto_verify_16.h" +#include "crypto_aead_chacha20poly1305.h" +#include "crypto_core_hchacha20.h" #include "utils.h" #include "private/common.h" @@ -24,32 +23,15 @@ crypto_aead_xchacha20poly1305_encrypt_detached(unsigned char *c, const unsigned char *npub, const unsigned char *k) { - crypto_onetimeauth_poly1305_state state; - unsigned char block0[64U]; - unsigned char slen[8U]; + int ret; + unsigned char k2[crypto_core_hchacha20_OUTPUTBYTES]; - (void) nsec; - crypto_stream_xchacha20(block0, sizeof block0, npub, k); - crypto_onetimeauth_poly1305_init(&state, block0); - sodium_memzero(block0, sizeof block0); - - crypto_onetimeauth_poly1305_update(&state, ad, adlen); - STORE64_LE(slen, (uint64_t) adlen); - crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); - - crypto_stream_xchacha20_xor_ic(c, m, mlen, npub, 1U, k); - - crypto_onetimeauth_poly1305_update(&state, c, mlen); - STORE64_LE(slen, (uint64_t) mlen); - crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); - - crypto_onetimeauth_poly1305_final(&state, mac); - sodium_memzero(&state, sizeof state); - - if (maclen_p != NULL) { - *maclen_p = crypto_aead_xchacha20poly1305_ABYTES; - } - return 0; + crypto_core_hchacha20(k2, npub, k, NULL); + ret = crypto_aead_chacha20poly1305_encrypt_detached(c, + mac, maclen_p, m, mlen, ad, adlen, nsec, + npub + crypto_core_hchacha20_INPUTBYTES, k2); + sodium_memzero(k2, crypto_core_hchacha20_OUTPUTBYTES); + return ret; } int @@ -94,43 +76,16 @@ crypto_aead_xchacha20poly1305_decrypt_detached(unsigned char *m, const unsigned char *npub, const unsigned char *k) { - crypto_onetimeauth_poly1305_state state; - unsigned char block0[64U]; - unsigned char slen[8U]; - unsigned char computed_mac[crypto_aead_xchacha20poly1305_ABYTES]; - unsigned long long mlen; - int ret; + int ret; + unsigned char k2[crypto_core_hchacha20_OUTPUTBYTES]; - (void) nsec; - crypto_stream_xchacha20(block0, sizeof block0, npub, k); - crypto_onetimeauth_poly1305_init(&state, block0); - sodium_memzero(block0, sizeof block0); + crypto_core_hchacha20(k2, npub, k, NULL); + ret = crypto_aead_chacha20poly1305_decrypt_detached(m, + nsec, c, clen, mac, ad, adlen, + npub + crypto_core_hchacha20_INPUTBYTES, k2); + sodium_memzero(k2, crypto_core_hchacha20_OUTPUTBYTES); + return ret; - crypto_onetimeauth_poly1305_update(&state, ad, adlen); - STORE64_LE(slen, (uint64_t) adlen); - crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); - - mlen = clen; - crypto_onetimeauth_poly1305_update(&state, c, mlen); - STORE64_LE(slen, (uint64_t) mlen); - crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); - - crypto_onetimeauth_poly1305_final(&state, computed_mac); - sodium_memzero(&state, sizeof state); - - (void) sizeof(int[sizeof computed_mac == 16U ? 1 : -1]); - ret = crypto_verify_16(computed_mac, mac); - sodium_memzero(computed_mac, sizeof computed_mac); - if (m == NULL) { - return ret; - } - if (ret != 0) { - memset(m, 0, mlen); - return -1; - } - crypto_stream_xchacha20_xor_ic(m, c, mlen, npub, 1U, k); - - return 0; } int @@ -163,6 +118,117 @@ crypto_aead_xchacha20poly1305_decrypt(unsigned char *m, return ret; } +int +crypto_aead_xchacha20poly1305_ietf_encrypt_detached(unsigned char *c, + unsigned char *mac, + unsigned long long *maclen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + int ret; + unsigned char k2[crypto_core_hchacha20_OUTPUTBYTES]; + unsigned char npub2[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] = { 0 }; + + crypto_core_hchacha20(k2, npub, k, NULL); + memcpy(npub2 + 4, npub + crypto_core_hchacha20_INPUTBYTES, crypto_aead_chacha20poly1305_ietf_NPUBBYTES - 4); + ret = crypto_aead_chacha20poly1305_ietf_encrypt_detached(c, + mac, maclen_p, m, mlen, ad, adlen, nsec, + npub2, k2); + sodium_memzero(k2, crypto_core_hchacha20_OUTPUTBYTES); + return ret; +} + +int +crypto_aead_xchacha20poly1305_ietf_encrypt(unsigned char *c, + unsigned long long *clen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned long long clen = 0ULL; + int ret; + + if (mlen > UINT64_MAX - crypto_aead_xchacha20poly1305_ietf_ABYTES) { + abort(); /* LCOV_EXCL_LINE */ + } + ret = crypto_aead_xchacha20poly1305_ietf_encrypt_detached(c, + c + mlen, NULL, + m, mlen, + ad, adlen, + nsec, npub, k); + if (clen_p != NULL) { + if (ret == 0) { + clen = mlen + crypto_aead_xchacha20poly1305_ietf_ABYTES; + } + *clen_p = clen; + } + return ret; +} + +int +crypto_aead_xchacha20poly1305_ietf_decrypt_detached(unsigned char *m, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *mac, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + int ret; + unsigned char k2[crypto_core_hchacha20_OUTPUTBYTES]; + unsigned char npub2[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] = { 0 }; + + crypto_core_hchacha20(k2, npub, k, NULL); + memcpy(npub2 + 4, npub + crypto_core_hchacha20_INPUTBYTES, crypto_aead_chacha20poly1305_ietf_NPUBBYTES - 4); + ret = crypto_aead_chacha20poly1305_ietf_decrypt_detached(m, + nsec, c, clen, mac, ad, adlen, + npub2, k2); + sodium_memzero(k2, crypto_core_hchacha20_OUTPUTBYTES); + return ret; + +} + +int +crypto_aead_xchacha20poly1305_ietf_decrypt(unsigned char *m, + unsigned long long *mlen_p, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned long long mlen = 0ULL; + int ret = -1; + + if (clen >= crypto_aead_xchacha20poly1305_ietf_ABYTES) { + ret = crypto_aead_xchacha20poly1305_ietf_decrypt_detached + (m, nsec, + c, clen - crypto_aead_xchacha20poly1305_ietf_ABYTES, + c + clen - crypto_aead_xchacha20poly1305_ietf_ABYTES, + ad, adlen, npub, k); + } + if (mlen_p != NULL) { + if (ret == 0) { + mlen = clen - crypto_aead_xchacha20poly1305_ietf_ABYTES; + } + *mlen_p = mlen; + } + return ret; +} + size_t crypto_aead_xchacha20poly1305_keybytes(void) { return crypto_aead_xchacha20poly1305_KEYBYTES; @@ -182,3 +248,23 @@ size_t crypto_aead_xchacha20poly1305_abytes(void) { return crypto_aead_xchacha20poly1305_ABYTES; } + +size_t +crypto_aead_xchacha20poly1305_ietf_keybytes(void) { + return crypto_aead_xchacha20poly1305_ietf_KEYBYTES; +} + +size_t +crypto_aead_xchacha20poly1305_ietf_npubbytes(void) { + return crypto_aead_xchacha20poly1305_ietf_NPUBBYTES; +} + +size_t +crypto_aead_xchacha20poly1305_ietf_nsecbytes(void) { + return crypto_aead_xchacha20poly1305_ietf_NSECBYTES; +} + +size_t +crypto_aead_xchacha20poly1305_ietf_abytes(void) { + return crypto_aead_xchacha20poly1305_ietf_ABYTES; +} diff --git a/src/libsodium/include/sodium/crypto_aead_xchacha20poly1305.h b/src/libsodium/include/sodium/crypto_aead_xchacha20poly1305.h index f1460750..a12f4bf9 100644 --- a/src/libsodium/include/sodium/crypto_aead_xchacha20poly1305.h +++ b/src/libsodium/include/sodium/crypto_aead_xchacha20poly1305.h @@ -27,6 +27,22 @@ size_t crypto_aead_xchacha20poly1305_npubbytes(void); SODIUM_EXPORT size_t crypto_aead_xchacha20poly1305_abytes(void); +#define crypto_aead_xchacha20poly1305_ietf_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_aead_xchacha20poly1305_ietf_keybytes(void); + +#define crypto_aead_xchacha20poly1305_ietf_NSECBYTES 0U +SODIUM_EXPORT +size_t crypto_aead_xchacha20poly1305_ietf_nsecbytes(void); + +#define crypto_aead_xchacha20poly1305_ietf_NPUBBYTES 24U +SODIUM_EXPORT +size_t crypto_aead_xchacha20poly1305_ietf_npubbytes(void); + +#define crypto_aead_xchacha20poly1305_ietf_ABYTES 16U +SODIUM_EXPORT +size_t crypto_aead_xchacha20poly1305_ietf_abytes(void); + SODIUM_EXPORT int crypto_aead_xchacha20poly1305_encrypt(unsigned char *c, unsigned long long *clen_p, @@ -74,6 +90,60 @@ int crypto_aead_xchacha20poly1305_decrypt_detached(unsigned char *m, const unsigned char *k) __attribute__ ((warn_unused_result)); +SODIUM_EXPORT +int crypto_aead_xchacha20poly1305_ietf_encrypt(unsigned char *c, + unsigned long long *clen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_aead_xchacha20poly1305_ietf_decrypt(unsigned char *m, + unsigned long long *mlen_p, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_aead_xchacha20poly1305_ietf_encrypt_detached(unsigned char *c, + unsigned char *mac, + unsigned long long *maclen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_aead_xchacha20poly1305_ietf_decrypt_detached(unsigned char *m, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *mac, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +/* Aliases */ + +#define crypto_aead_xchacha20poly1305_IETF_KEYBYTES crypto_aead_xchacha20poly1305_ietf_KEYBYTES +#define crypto_aead_xchacha20poly1305_IETF_NSECBYTES crypto_aead_xchacha20poly1305_ietf_NSECBYTES +#define crypto_aead_xchacha20poly1305_IETF_NPUBBYTES crypto_aead_xchacha20poly1305_ietf_NPUBBYTES +#define crypto_aead_xchacha20poly1305_IETF_ABYTES crypto_aead_xchacha20poly1305_ietf_ABYTES + #ifdef __cplusplus } #endif