Home | History | Annotate | Line # | Download | only in xchacha20poly1305
      1 #include <stdint.h>
      2 #include <stdlib.h>
      3 #include <limits.h>
      4 #include <string.h>
      5 
      6 #include "core.h"
      7 #include "crypto_aead_chacha20poly1305.h"
      8 #include "crypto_aead_xchacha20poly1305.h"
      9 #include "crypto_core_hchacha20.h"
     10 #include "crypto_onetimeauth_poly1305.h"
     11 #include "crypto_secretstream_xchacha20poly1305.h"
     12 #include "randombytes.h"
     13 #include "utils.h"
     14 
     15 #include "private/common.h"
     16 
     17 #define crypto_secretstream_xchacha20poly1305_COUNTERBYTES  4U
     18 #define crypto_secretstream_xchacha20poly1305_INONCEBYTES   8U
     19 
     20 #define STATE_COUNTER(STATE) ((STATE)->nonce)
     21 #define STATE_INONCE(STATE)  ((STATE)->nonce + \
     22                               crypto_secretstream_xchacha20poly1305_COUNTERBYTES)
     23 
     24 static const unsigned char _pad0[16] = { 0 };
     25 
     26 static inline void
     27 _crypto_secretstream_xchacha20poly1305_counter_reset
     28     (crypto_secretstream_xchacha20poly1305_state *state)
     29 {
     30     memset(STATE_COUNTER(state), 0,
     31            crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
     32     STATE_COUNTER(state)[0] = 1;
     33 }
     34 
     35 void
     36 crypto_secretstream_xchacha20poly1305_keygen
     37    (unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES])
     38 {
     39     randombytes_buf(k, crypto_secretstream_xchacha20poly1305_KEYBYTES);
     40 }
     41 
     42 int
     43 crypto_secretstream_xchacha20poly1305_init_push
     44    (crypto_secretstream_xchacha20poly1305_state *state,
     45     unsigned char out[crypto_secretstream_xchacha20poly1305_HEADERBYTES],
     46     const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES])
     47 {
     48     COMPILER_ASSERT(crypto_secretstream_xchacha20poly1305_HEADERBYTES ==
     49                     crypto_core_hchacha20_INPUTBYTES +
     50                     crypto_secretstream_xchacha20poly1305_INONCEBYTES);
     51     COMPILER_ASSERT(crypto_secretstream_xchacha20poly1305_HEADERBYTES ==
     52                     crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
     53     COMPILER_ASSERT(sizeof state->nonce ==
     54                     crypto_secretstream_xchacha20poly1305_INONCEBYTES +
     55                     crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
     56 
     57     randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES);
     58     crypto_core_hchacha20(state->k, out, k, NULL);
     59     _crypto_secretstream_xchacha20poly1305_counter_reset(state);
     60     memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES,
     61            crypto_secretstream_xchacha20poly1305_INONCEBYTES);
     62     memset(state->_pad, 0, sizeof state->_pad);
     63 
     64     return 0;
     65 }
     66 
     67 int
     68 crypto_secretstream_xchacha20poly1305_init_pull
     69    (crypto_secretstream_xchacha20poly1305_state *state,
     70     const unsigned char in[crypto_secretstream_xchacha20poly1305_HEADERBYTES],
     71     const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES])
     72 {
     73     crypto_core_hchacha20(state->k, in, k, NULL);
     74     _crypto_secretstream_xchacha20poly1305_counter_reset(state);
     75     memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES,
     76            crypto_secretstream_xchacha20poly1305_INONCEBYTES);
     77     memset(state->_pad, 0, sizeof state->_pad);
     78 
     79     return 0;
     80 }
     81 
     82 void
     83 crypto_secretstream_xchacha20poly1305_rekey
     84     (crypto_secretstream_xchacha20poly1305_state *state)
     85 {
     86     unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES +
     87                                      crypto_secretstream_xchacha20poly1305_INONCEBYTES];
     88     size_t        i;
     89 
     90     for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
     91         new_key_and_inonce[i] = state->k[i];
     92     }
     93     for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
     94         new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] =
     95             STATE_INONCE(state)[i];
     96     }
     97     crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce,
     98                                     sizeof new_key_and_inonce,
     99                                     state->nonce, state->k);
    100     for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
    101         state->k[i] = new_key_and_inonce[i];
    102     }
    103     for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
    104         STATE_INONCE(state)[i] =
    105             new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i];
    106     }
    107     _crypto_secretstream_xchacha20poly1305_counter_reset(state);
    108 }
    109 
    110 int
    111 crypto_secretstream_xchacha20poly1305_push
    112    (crypto_secretstream_xchacha20poly1305_state *state,
    113     unsigned char *out, unsigned long long *outlen_p,
    114     const unsigned char *m, unsigned long long mlen,
    115     const unsigned char *ad, unsigned long long adlen, unsigned char tag)
    116 {
    117     crypto_onetimeauth_poly1305_state poly1305_state;
    118     unsigned char                     block[64U];
    119     unsigned char                     slen[8U];
    120     unsigned char                    *c;
    121     unsigned char                    *mac;
    122 
    123     if (outlen_p != NULL) {
    124         *outlen_p = 0U;
    125     }
    126     if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
    127         sodium_misuse();
    128     }
    129     crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
    130     crypto_onetimeauth_poly1305_init(&poly1305_state, block);
    131     sodium_memzero(block, sizeof block);
    132 
    133     crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
    134     crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
    135                                        (0x10 - adlen) & 0xf);
    136     memset(block, 0, sizeof block);
    137     block[0] = tag;
    138 
    139     crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
    140                                        state->nonce, 1U, state->k);
    141     crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
    142     out[0] = block[0];
    143 
    144     c = out + (sizeof tag);
    145     crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k);
    146     crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
    147     crypto_onetimeauth_poly1305_update
    148         (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
    149 
    150     STORE64_LE(slen, (uint64_t) adlen);
    151     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
    152     STORE64_LE(slen, (sizeof block) + mlen);
    153     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
    154 
    155     mac = c + mlen;
    156     crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
    157     sodium_memzero(&poly1305_state, sizeof poly1305_state);
    158 
    159     COMPILER_ASSERT(crypto_onetimeauth_poly1305_BYTES >=
    160                     crypto_secretstream_xchacha20poly1305_INONCEBYTES);
    161     XOR_BUF(STATE_INONCE(state), mac,
    162             crypto_secretstream_xchacha20poly1305_INONCEBYTES);
    163     sodium_increment(STATE_COUNTER(state),
    164                      crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
    165     if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
    166         sodium_is_zero(STATE_COUNTER(state),
    167                        crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
    168         crypto_secretstream_xchacha20poly1305_rekey(state);
    169     }
    170     if (outlen_p != NULL) {
    171         *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen;
    172     }
    173     return 0;
    174 }
    175 
    176 int
    177 crypto_secretstream_xchacha20poly1305_pull
    178    (crypto_secretstream_xchacha20poly1305_state *state,
    179     unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p,
    180     const unsigned char *in, unsigned long long inlen,
    181     const unsigned char *ad, unsigned long long adlen)
    182 {
    183     crypto_onetimeauth_poly1305_state poly1305_state;
    184     unsigned char                     block[64U];
    185     unsigned char                     slen[8U];
    186     unsigned char                     mac[crypto_onetimeauth_poly1305_BYTES];
    187     const unsigned char              *c;
    188     const unsigned char              *stored_mac;
    189     unsigned long long                mlen;
    190     unsigned char                     tag;
    191 
    192     if (mlen_p != NULL) {
    193         *mlen_p = 0U;
    194     }
    195     if (tag_p != NULL) {
    196         *tag_p = 0xff;
    197     }
    198     if (inlen < crypto_secretstream_xchacha20poly1305_ABYTES) {
    199         return -1;
    200     }
    201     mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
    202     if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
    203         sodium_misuse();
    204     }
    205     crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
    206     crypto_onetimeauth_poly1305_init(&poly1305_state, block);
    207     sodium_memzero(block, sizeof block);
    208 
    209     crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
    210     crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
    211                                        (0x10 - adlen) & 0xf);
    212 
    213     memset(block, 0, sizeof block);
    214     block[0] = in[0];
    215     crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
    216                                        state->nonce, 1U, state->k);
    217     tag = block[0];
    218     block[0] = in[0];
    219     crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
    220 
    221     c = in + (sizeof tag);
    222     crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
    223     crypto_onetimeauth_poly1305_update
    224         (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
    225 
    226     STORE64_LE(slen, (uint64_t) adlen);
    227     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
    228     STORE64_LE(slen, (sizeof block) + mlen);
    229     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
    230 
    231     crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
    232     sodium_memzero(&poly1305_state, sizeof poly1305_state);
    233 
    234     stored_mac = c + mlen;
    235     if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
    236         sodium_memzero(mac, sizeof mac);
    237         return -1;
    238     }
    239 
    240     crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k);
    241     XOR_BUF(STATE_INONCE(state), mac,
    242             crypto_secretstream_xchacha20poly1305_INONCEBYTES);
    243     sodium_increment(STATE_COUNTER(state),
    244                      crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
    245     if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
    246         sodium_is_zero(STATE_COUNTER(state),
    247                        crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
    248         crypto_secretstream_xchacha20poly1305_rekey(state);
    249     }
    250     if (mlen_p != NULL) {
    251         *mlen_p = mlen;
    252     }
    253     if (tag_p != NULL) {
    254         *tag_p = tag;
    255     }
    256     return 0;
    257 }
    258 
    259 size_t
    260 crypto_secretstream_xchacha20poly1305_statebytes(void)
    261 {
    262     return sizeof(crypto_secretstream_xchacha20poly1305_state);
    263 }
    264 
    265 size_t
    266 crypto_secretstream_xchacha20poly1305_abytes(void)
    267 {
    268     return crypto_secretstream_xchacha20poly1305_ABYTES;
    269 }
    270 
    271 size_t
    272 crypto_secretstream_xchacha20poly1305_headerbytes(void)
    273 {
    274     return crypto_secretstream_xchacha20poly1305_HEADERBYTES;
    275 }
    276 
    277 size_t
    278 crypto_secretstream_xchacha20poly1305_keybytes(void)
    279 {
    280     return crypto_secretstream_xchacha20poly1305_KEYBYTES;
    281 }
    282 
    283 size_t
    284 crypto_secretstream_xchacha20poly1305_messagebytes_max(void)
    285 {
    286     return crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX;
    287 }
    288 
    289 unsigned char
    290 crypto_secretstream_xchacha20poly1305_tag_message(void)
    291 {
    292     return crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
    293 }
    294 
    295 unsigned char
    296 crypto_secretstream_xchacha20poly1305_tag_push(void)
    297 {
    298     return crypto_secretstream_xchacha20poly1305_TAG_PUSH;
    299 }
    300 
    301 unsigned char
    302 crypto_secretstream_xchacha20poly1305_tag_rekey(void)
    303 {
    304     return crypto_secretstream_xchacha20poly1305_TAG_REKEY;
    305 }
    306 
    307 unsigned char
    308 crypto_secretstream_xchacha20poly1305_tag_final(void)
    309 {
    310     return crypto_secretstream_xchacha20poly1305_TAG_FINAL;
    311 }
    312