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 <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2016-12-24 02:17:33 +01:00 committed by Frank Denis
parent db97a35502
commit 6abad20323
2 changed files with 219 additions and 63 deletions

View File

@ -5,9 +5,8 @@
#include <string.h>
#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;
}

View File

@ -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