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