From df7ad2632875a8a298959e1785564dff0725de97 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 16 Aug 2017 13:23:17 +0200 Subject: [PATCH] Introduce a new crypto_secretstream_*() API No high-level API yet, since there is no high-level AEAD API. --- src/libsodium/Makefile.am | 1 + .../secretstream_xchacha20poly1305.c | 235 ++++++++++++++++++ src/libsodium/include/Makefile.am | 1 + src/libsodium/include/sodium.h | 1 + .../crypto_secretstream_xchacha20poly1305.h | 84 +++++++ 5 files changed, 322 insertions(+) create mode 100644 src/libsodium/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c create mode 100644 src/libsodium/include/sodium/crypto_secretstream_xchacha20poly1305.h diff --git a/src/libsodium/Makefile.am b/src/libsodium/Makefile.am index 3320f636..8186b806 100644 --- a/src/libsodium/Makefile.am +++ b/src/libsodium/Makefile.am @@ -62,6 +62,7 @@ libsodium_la_SOURCES = \ crypto_secretbox/crypto_secretbox.c \ crypto_secretbox/crypto_secretbox_easy.c \ crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305.c \ + crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c \ crypto_shorthash/crypto_shorthash.c \ crypto_shorthash/siphash24/shorthash_siphash24.c \ crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c \ diff --git a/src/libsodium/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c b/src/libsodium/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c new file mode 100644 index 00000000..cba8601b --- /dev/null +++ b/src/libsodium/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c @@ -0,0 +1,235 @@ + +#include +#include +#include +#include + +#include "core.h" +#include "crypto_aead_xchacha20poly1305.h" +#include "crypto_aead_chacha20poly1305.h" +#include "crypto_core_hchacha20.h" +#include "crypto_onetimeauth_poly1305.h" +#include "crypto_secretstream_xchacha20poly1305.h" +#include "randombytes.h" +#include "utils.h" + +#include "private/common.h" + +#define crypto_secretstream_xchacha20poly1305_COUNTERBYTES 4U +#define crypto_secretstream_xchacha20poly1305_INONCEBYTES 8U + +static const unsigned char _pad0[16] = { 0 }; + +void +crypto_secretstream_xchacha20poly1305_keygen + (unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]) +{ + randombytes_buf(k, crypto_secretstream_xchacha20poly1305_KEYBYTES); +} + +int +crypto_secretstream_xchacha20poly1305_init_push + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char out[crypto_secretstream_xchacha20poly1305_INITBYTES], + const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]) +{ + randombytes_buf(out, crypto_core_hchacha20_INPUTBYTES + + crypto_secretstream_xchacha20poly1305_INONCEBYTES); + crypto_core_hchacha20(state->k, out, k, NULL); + memcpy(state->nonce, out + crypto_core_hchacha20_INPUTBYTES, + crypto_secretstream_xchacha20poly1305_INONCEBYTES); + memset(state->nonce + crypto_secretstream_xchacha20poly1305_INONCEBYTES, 0, + crypto_secretstream_xchacha20poly1305_COUNTERBYTES); + memset(state->_pad, 0, sizeof state->_pad); + + return 0; +} + +int +crypto_secretstream_xchacha20poly1305_init_pull + (crypto_secretstream_xchacha20poly1305_state *state, + const unsigned char in[crypto_secretstream_xchacha20poly1305_INITBYTES], + const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]) +{ + crypto_core_hchacha20(state->k, in, k, NULL); + memcpy(state->nonce, in + crypto_core_hchacha20_INPUTBYTES, + crypto_secretstream_xchacha20poly1305_INONCEBYTES); + memset(state->nonce + crypto_secretstream_xchacha20poly1305_INONCEBYTES, 0, + crypto_secretstream_xchacha20poly1305_COUNTERBYTES); + memset(state->_pad, 0, sizeof state->_pad); + + return 0; +} + +void +crypto_secretstream_xchacha20poly1305_rekey + (crypto_secretstream_xchacha20poly1305_state *state) +{ + unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + + crypto_secretstream_xchacha20poly1305_INONCEBYTES]; + + crypto_stream_chacha20_ietf(new_key_and_inonce, sizeof new_key_and_inonce, + state->nonce, state->k); + memcpy(state->k, new_key_and_inonce, sizeof state->k); + memcpy(state->nonce, new_key_and_inonce + sizeof state->k, + crypto_secretstream_xchacha20poly1305_INONCEBYTES); + memset(state->nonce + crypto_secretstream_xchacha20poly1305_INONCEBYTES, 0, + crypto_secretstream_xchacha20poly1305_COUNTERBYTES); +} + +int +crypto_secretstream_xchacha20poly1305_push + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *out, unsigned long long *outlen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, unsigned char tag) +{ + crypto_onetimeauth_poly1305_state poly1305_state; + unsigned char block[64U]; + unsigned char slen[8U]; + unsigned char *c; + unsigned char *mac; + unsigned int i; + + if (outlen_p != NULL) { + *outlen_p = 0U; + } + if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGESBYTES_MAX) { + return -1; + } + crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); + crypto_onetimeauth_poly1305_init(&poly1305_state, block); + sodium_memzero(block, sizeof block); + + crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, + (0x10 - adlen) & 0xf); + memset(block, 0, sizeof block); + block[0] = tag; + + crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, + state->nonce, 1U, state->k); + crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); + out[0] = block[0]; + + c = out + (sizeof tag); + crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k); + crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); + crypto_onetimeauth_poly1305_update + (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); + + STORE64_LE(slen, (uint64_t) adlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + STORE64_LE(slen, (sizeof block) + mlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + + mac = c + mlen; + crypto_onetimeauth_poly1305_final(&poly1305_state, mac); + sodium_memzero(&poly1305_state, sizeof poly1305_state); + + for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { + state->nonce[i] ^= mac[i]; + } + sodium_increment(&state->nonce[crypto_secretstream_xchacha20poly1305_INONCEBYTES], + crypto_secretstream_xchacha20poly1305_COUNTERBYTES); + if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || + sodium_is_zero(&state->nonce[crypto_secretstream_xchacha20poly1305_INONCEBYTES], + crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { + crypto_secretstream_xchacha20poly1305_rekey(state); + } + if (outlen_p != NULL) { + *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen; + } + return 0; +} + +int +crypto_secretstream_xchacha20poly1305_pull + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p, + const unsigned char *in, unsigned long long inlen, + const unsigned char *ad, unsigned long long adlen) +{ + crypto_onetimeauth_poly1305_state poly1305_state; + unsigned char block[64U]; + unsigned char slen[8U]; + unsigned char mac[crypto_onetimeauth_poly1305_BYTES]; + const unsigned char *c; + const unsigned char *stored_mac; + unsigned long long mlen; + unsigned int i; + unsigned char tag; + + if (mlen_p != NULL) { + *mlen_p = 0U; + } + if (tag_p != NULL) { + *tag_p = 0xff; + } + if (inlen < crypto_secretstream_xchacha20poly1305_ABYTES) { + return -1; + } + mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES; + if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGESBYTES_MAX) { + return -1; + } + crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); + crypto_onetimeauth_poly1305_init(&poly1305_state, block); + sodium_memzero(block, sizeof block); + + crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, + (0x10 - adlen) & 0xf); + + memset(block, 0, sizeof block); + block[0] = in[0]; + crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, + state->nonce, 1U, state->k); + tag = block[0]; + block[0] = in[0]; + crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); + + c = in + (sizeof tag); + crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); + crypto_onetimeauth_poly1305_update + (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); + + STORE64_LE(slen, (uint64_t) adlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + STORE64_LE(slen, (sizeof block) + mlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + + crypto_onetimeauth_poly1305_final(&poly1305_state, mac); + sodium_memzero(&poly1305_state, sizeof poly1305_state); + + stored_mac = c + mlen; + if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) { + sodium_memzero(mac, sizeof mac); + return -1; + } + + crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k); + for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { + state->nonce[i] ^= mac[i]; + } + sodium_increment(&state->nonce[crypto_secretstream_xchacha20poly1305_INONCEBYTES], + crypto_secretstream_xchacha20poly1305_COUNTERBYTES); + if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || + sodium_is_zero(&state->nonce[crypto_secretstream_xchacha20poly1305_INONCEBYTES], + crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { + crypto_secretstream_xchacha20poly1305_rekey(state); + } + if (mlen_p != NULL) { + *mlen_p = mlen; + } + if (tag_p != NULL) { + *tag_p = tag; + } + return 0; +} + +size_t +crypto_secretstream_xchacha20poly1305_statebytes(void) +{ + return sizeof(crypto_secretstream_xchacha20poly1305_state); +} diff --git a/src/libsodium/include/Makefile.am b/src/libsodium/include/Makefile.am index a63d127a..06f3f4a4 100644 --- a/src/libsodium/include/Makefile.am +++ b/src/libsodium/include/Makefile.am @@ -36,6 +36,7 @@ SODIUM_EXPORT = \ sodium/crypto_secretbox.h \ sodium/crypto_secretbox_xchacha20poly1305.h \ sodium/crypto_secretbox_xsalsa20poly1305.h \ + sodium/crypto_secretstream_xchacha20poly1305.h \ sodium/crypto_shorthash.h \ sodium/crypto_shorthash_siphash24.h \ sodium/crypto_sign.h \ diff --git a/src/libsodium/include/sodium.h b/src/libsodium/include/sodium.h index 1f79e87b..8c3e8bc7 100644 --- a/src/libsodium/include/sodium.h +++ b/src/libsodium/include/sodium.h @@ -35,6 +35,7 @@ #include "sodium/crypto_scalarmult_curve25519.h" #include "sodium/crypto_secretbox.h" #include "sodium/crypto_secretbox_xsalsa20poly1305.h" +#include "sodium/crypto_secretstream_xchacha20poly1305.h" #include "sodium/crypto_shorthash.h" #include "sodium/crypto_shorthash_siphash24.h" #include "sodium/crypto_sign.h" diff --git a/src/libsodium/include/sodium/crypto_secretstream_xchacha20poly1305.h b/src/libsodium/include/sodium/crypto_secretstream_xchacha20poly1305.h new file mode 100644 index 00000000..9b782d3c --- /dev/null +++ b/src/libsodium/include/sodium/crypto_secretstream_xchacha20poly1305.h @@ -0,0 +1,84 @@ +#ifndef crypto_secretstream_xchacha20poly1305_H +#define crypto_secretstream_xchacha20poly1305_H + +#include + +#include "crypto_aead_xchacha20poly1305.h" +#include "crypto_stream_chacha20.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_secretstream_xchacha20poly1305_ABYTES \ + (1U + crypto_aead_xchacha20poly1305_ietf_ABYTES) + +#define crypto_secretstream_xchacha20poly1305_INITBYTES \ + crypto_aead_xchacha20poly1305_ietf_NPUBBYTES + +#define crypto_secretstream_xchacha20poly1305_KEYBYTES \ + crypto_aead_xchacha20poly1305_ietf_KEYBYTES + +#define crypto_secretstream_xchacha20poly1305_MESSAGESBYTES_MAX \ + ((1ULL << 32) - 2ULL * 64ULL) + +#define crypto_secretstream_xchacha20poly1305_TAG_MESSAGE 0x00 +#define crypto_secretstream_xchacha20poly1305_TAG_PUSH 0x01 +#define crypto_secretstream_xchacha20poly1305_TAG_REKEY 0x02 + +#define crypto_secretstream_xchacha20poly1305_TAG_FINAL \ + (crypto_secretstream_xchacha20poly1305_TAG_PUSH | \ + crypto_secretstream_xchacha20poly1305_TAG_REKEY) + +typedef struct crypto_secretstream_xchacha20poly1305_state { + unsigned char k[crypto_stream_chacha20_ietf_KEYBYTES]; + unsigned char nonce[crypto_stream_chacha20_ietf_NONCEBYTES]; + unsigned char _pad[8]; +} crypto_secretstream_xchacha20poly1305_state; + +SODIUM_EXPORT +size_t crypto_secretstream_xchacha20poly1305_statebytes(void); + +SODIUM_EXPORT +void crypto_secretstream_xchacha20poly1305_keygen + (unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]); + +SODIUM_EXPORT +int crypto_secretstream_xchacha20poly1305_init_push + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char out[crypto_secretstream_xchacha20poly1305_INITBYTES], + const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]); + +SODIUM_EXPORT +int crypto_secretstream_xchacha20poly1305_init_pull + (crypto_secretstream_xchacha20poly1305_state *state, + const unsigned char in[crypto_secretstream_xchacha20poly1305_INITBYTES], + const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]); + +SODIUM_EXPORT +void crypto_secretstream_xchacha20poly1305_rekey + (crypto_secretstream_xchacha20poly1305_state *state); + +SODIUM_EXPORT +int crypto_secretstream_xchacha20poly1305_push + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *out, unsigned long long *outlen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, unsigned char tag); + +SODIUM_EXPORT +int crypto_secretstream_xchacha20poly1305_pull + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p, + const unsigned char *in, unsigned long long inlen, + const unsigned char *ad, unsigned long long adlen); + +#ifdef __cplusplus +} +#endif + +#endif