Introduce a new crypto_secretstream_*() API

No high-level API yet, since there is no high-level AEAD API.
This commit is contained in:
Frank Denis 2017-08-16 13:23:17 +02:00
parent 45f2759d86
commit df7ad26328
5 changed files with 322 additions and 0 deletions

View File

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

View File

@ -0,0 +1,235 @@
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#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);
}

View File

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

View File

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

View File

@ -0,0 +1,84 @@
#ifndef crypto_secretstream_xchacha20poly1305_H
#define crypto_secretstream_xchacha20poly1305_H
#include <stddef.h>
#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