1 /* $OpenBSD: e_chacha20poly1305.c,v 1.21 2019/03/27 15:34:01 jsing Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Reyk Floter <reyk@openbsd.org> 5 * Copyright (c) 2014, Google Inc. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 14 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 16 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <stdint.h> 21 #include <string.h> 22 23 #include <openssl/opensslconf.h> 24 25 #if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) 26 27 #include <openssl/err.h> 28 #include <openssl/evp.h> 29 #include <openssl/chacha.h> 30 #include <openssl/poly1305.h> 31 32 #include "evp_locl.h" 33 34 #define POLY1305_TAG_LEN 16 35 36 #define CHACHA20_CONSTANT_LEN 4 37 #define CHACHA20_IV_LEN 8 38 #define CHACHA20_NONCE_LEN (CHACHA20_CONSTANT_LEN + CHACHA20_IV_LEN) 39 #define XCHACHA20_NONCE_LEN 24 40 41 struct aead_chacha20_poly1305_ctx { 42 unsigned char key[32]; 43 unsigned char tag_len; 44 }; 45 46 static int 47 aead_chacha20_poly1305_init(EVP_AEAD_CTX *ctx, const unsigned char *key, 48 size_t key_len, size_t tag_len) 49 { 50 struct aead_chacha20_poly1305_ctx *c20_ctx; 51 52 if (tag_len == 0) 53 tag_len = POLY1305_TAG_LEN; 54 55 if (tag_len > POLY1305_TAG_LEN) { 56 EVPerror(EVP_R_TOO_LARGE); 57 return 0; 58 } 59 60 /* Internal error - EVP_AEAD_CTX_init should catch this. */ 61 if (key_len != sizeof(c20_ctx->key)) 62 return 0; 63 64 c20_ctx = malloc(sizeof(struct aead_chacha20_poly1305_ctx)); 65 if (c20_ctx == NULL) 66 return 0; 67 68 memcpy(&c20_ctx->key[0], key, key_len); 69 c20_ctx->tag_len = tag_len; 70 ctx->aead_state = c20_ctx; 71 72 return 1; 73 } 74 75 static void 76 aead_chacha20_poly1305_cleanup(EVP_AEAD_CTX *ctx) 77 { 78 struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 79 80 freezero(c20_ctx, sizeof(*c20_ctx)); 81 } 82 83 static void 84 poly1305_update_with_length(poly1305_state *poly1305, 85 const unsigned char *data, size_t data_len) 86 { 87 size_t j = data_len; 88 unsigned char length_bytes[8]; 89 unsigned i; 90 91 for (i = 0; i < sizeof(length_bytes); i++) { 92 length_bytes[i] = j; 93 j >>= 8; 94 } 95 96 if (data != NULL) 97 CRYPTO_poly1305_update(poly1305, data, data_len); 98 CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes)); 99 } 100 101 static void 102 poly1305_update_with_pad16(poly1305_state *poly1305, 103 const unsigned char *data, size_t data_len) 104 { 105 static const unsigned char zero_pad16[16]; 106 size_t pad_len; 107 108 CRYPTO_poly1305_update(poly1305, data, data_len); 109 110 /* pad16() is defined in RFC 7539 2.8.1. */ 111 if ((pad_len = data_len % 16) == 0) 112 return; 113 114 CRYPTO_poly1305_update(poly1305, zero_pad16, 16 - pad_len); 115 } 116 117 static int 118 aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out, 119 size_t *out_len, size_t max_out_len, const unsigned char *nonce, 120 size_t nonce_len, const unsigned char *in, size_t in_len, 121 const unsigned char *ad, size_t ad_len) 122 { 123 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 124 unsigned char poly1305_key[32]; 125 poly1305_state poly1305; 126 const unsigned char *iv; 127 const uint64_t in_len_64 = in_len; 128 uint64_t ctr; 129 130 /* The underlying ChaCha implementation may not overflow the block 131 * counter into the second counter word. Therefore we disallow 132 * individual operations that work on more than 2TB at a time. 133 * in_len_64 is needed because, on 32-bit platforms, size_t is only 134 * 32-bits and this produces a warning because it's always false. 135 * Casting to uint64_t inside the conditional is not sufficient to stop 136 * the warning. */ 137 if (in_len_64 >= (1ULL << 32) * 64 - 64) { 138 EVPerror(EVP_R_TOO_LARGE); 139 return 0; 140 } 141 142 if (max_out_len < in_len + c20_ctx->tag_len) { 143 EVPerror(EVP_R_BUFFER_TOO_SMALL); 144 return 0; 145 } 146 147 if (nonce_len != ctx->aead->nonce_len) { 148 EVPerror(EVP_R_IV_TOO_LARGE); 149 return 0; 150 } 151 152 ctr = (uint64_t)((uint32_t)(nonce[0]) | (uint32_t)(nonce[1]) << 8 | 153 (uint32_t)(nonce[2]) << 16 | (uint32_t)(nonce[3]) << 24) << 32; 154 iv = nonce + CHACHA20_CONSTANT_LEN; 155 156 memset(poly1305_key, 0, sizeof(poly1305_key)); 157 CRYPTO_chacha_20(poly1305_key, poly1305_key, 158 sizeof(poly1305_key), c20_ctx->key, iv, ctr); 159 160 CRYPTO_poly1305_init(&poly1305, poly1305_key); 161 poly1305_update_with_pad16(&poly1305, ad, ad_len); 162 CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, iv, ctr + 1); 163 poly1305_update_with_pad16(&poly1305, out, in_len); 164 poly1305_update_with_length(&poly1305, NULL, ad_len); 165 poly1305_update_with_length(&poly1305, NULL, in_len); 166 167 if (c20_ctx->tag_len != POLY1305_TAG_LEN) { 168 unsigned char tag[POLY1305_TAG_LEN]; 169 CRYPTO_poly1305_finish(&poly1305, tag); 170 memcpy(out + in_len, tag, c20_ctx->tag_len); 171 *out_len = in_len + c20_ctx->tag_len; 172 return 1; 173 } 174 175 CRYPTO_poly1305_finish(&poly1305, out + in_len); 176 *out_len = in_len + POLY1305_TAG_LEN; 177 return 1; 178 } 179 180 static int 181 aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out, 182 size_t *out_len, size_t max_out_len, const unsigned char *nonce, 183 size_t nonce_len, const unsigned char *in, size_t in_len, 184 const unsigned char *ad, size_t ad_len) 185 { 186 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 187 unsigned char mac[POLY1305_TAG_LEN]; 188 unsigned char poly1305_key[32]; 189 const unsigned char *iv = nonce; 190 poly1305_state poly1305; 191 const uint64_t in_len_64 = in_len; 192 size_t plaintext_len; 193 uint64_t ctr = 0; 194 195 if (in_len < c20_ctx->tag_len) { 196 EVPerror(EVP_R_BAD_DECRYPT); 197 return 0; 198 } 199 200 /* The underlying ChaCha implementation may not overflow the block 201 * counter into the second counter word. Therefore we disallow 202 * individual operations that work on more than 2TB at a time. 203 * in_len_64 is needed because, on 32-bit platforms, size_t is only 204 * 32-bits and this produces a warning because it's always false. 205 * Casting to uint64_t inside the conditional is not sufficient to stop 206 * the warning. */ 207 if (in_len_64 >= (1ULL << 32) * 64 - 64) { 208 EVPerror(EVP_R_TOO_LARGE); 209 return 0; 210 } 211 212 if (nonce_len != ctx->aead->nonce_len) { 213 EVPerror(EVP_R_IV_TOO_LARGE); 214 return 0; 215 } 216 217 plaintext_len = in_len - c20_ctx->tag_len; 218 219 if (max_out_len < plaintext_len) { 220 EVPerror(EVP_R_BUFFER_TOO_SMALL); 221 return 0; 222 } 223 224 ctr = (uint64_t)((uint32_t)(nonce[0]) | (uint32_t)(nonce[1]) << 8 | 225 (uint32_t)(nonce[2]) << 16 | (uint32_t)(nonce[3]) << 24) << 32; 226 iv = nonce + CHACHA20_CONSTANT_LEN; 227 228 memset(poly1305_key, 0, sizeof(poly1305_key)); 229 CRYPTO_chacha_20(poly1305_key, poly1305_key, 230 sizeof(poly1305_key), c20_ctx->key, iv, ctr); 231 232 CRYPTO_poly1305_init(&poly1305, poly1305_key); 233 poly1305_update_with_pad16(&poly1305, ad, ad_len); 234 poly1305_update_with_pad16(&poly1305, in, plaintext_len); 235 poly1305_update_with_length(&poly1305, NULL, ad_len); 236 poly1305_update_with_length(&poly1305, NULL, plaintext_len); 237 238 CRYPTO_poly1305_finish(&poly1305, mac); 239 240 if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) { 241 EVPerror(EVP_R_BAD_DECRYPT); 242 return 0; 243 } 244 245 CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, iv, ctr + 1); 246 *out_len = plaintext_len; 247 return 1; 248 } 249 250 static int 251 aead_xchacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out, 252 size_t *out_len, size_t max_out_len, const unsigned char *nonce, 253 size_t nonce_len, const unsigned char *in, size_t in_len, 254 const unsigned char *ad, size_t ad_len) 255 { 256 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 257 unsigned char poly1305_key[32]; 258 unsigned char subkey[32]; 259 poly1305_state poly1305; 260 261 if (max_out_len < in_len + c20_ctx->tag_len) { 262 EVPerror(EVP_R_BUFFER_TOO_SMALL); 263 return 0; 264 } 265 266 if (nonce_len != ctx->aead->nonce_len) { 267 EVPerror(EVP_R_IV_TOO_LARGE); 268 return 0; 269 } 270 271 CRYPTO_hchacha_20(subkey, c20_ctx->key, nonce); 272 273 CRYPTO_chacha_20(out, in, in_len, subkey, nonce + 16, 1); 274 275 memset(poly1305_key, 0, sizeof(poly1305_key)); 276 CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), 277 subkey, nonce + 16, 0); 278 279 CRYPTO_poly1305_init(&poly1305, poly1305_key); 280 poly1305_update_with_pad16(&poly1305, ad, ad_len); 281 poly1305_update_with_pad16(&poly1305, out, in_len); 282 poly1305_update_with_length(&poly1305, NULL, ad_len); 283 poly1305_update_with_length(&poly1305, NULL, in_len); 284 285 if (c20_ctx->tag_len != POLY1305_TAG_LEN) { 286 unsigned char tag[POLY1305_TAG_LEN]; 287 CRYPTO_poly1305_finish(&poly1305, tag); 288 memcpy(out + in_len, tag, c20_ctx->tag_len); 289 *out_len = in_len + c20_ctx->tag_len; 290 return 1; 291 } 292 293 CRYPTO_poly1305_finish(&poly1305, out + in_len); 294 *out_len = in_len + POLY1305_TAG_LEN; 295 return 1; 296 } 297 298 static int 299 aead_xchacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out, 300 size_t *out_len, size_t max_out_len, const unsigned char *nonce, 301 size_t nonce_len, const unsigned char *in, size_t in_len, 302 const unsigned char *ad, size_t ad_len) 303 { 304 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 305 unsigned char mac[POLY1305_TAG_LEN]; 306 unsigned char poly1305_key[32]; 307 unsigned char subkey[32]; 308 poly1305_state poly1305; 309 size_t plaintext_len; 310 311 if (in_len < c20_ctx->tag_len) { 312 EVPerror(EVP_R_BAD_DECRYPT); 313 return 0; 314 } 315 316 if (nonce_len != ctx->aead->nonce_len) { 317 EVPerror(EVP_R_IV_TOO_LARGE); 318 return 0; 319 } 320 321 plaintext_len = in_len - c20_ctx->tag_len; 322 323 if (max_out_len < plaintext_len) { 324 EVPerror(EVP_R_BUFFER_TOO_SMALL); 325 return 0; 326 } 327 328 CRYPTO_hchacha_20(subkey, c20_ctx->key, nonce); 329 330 memset(poly1305_key, 0, sizeof(poly1305_key)); 331 CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), 332 subkey, nonce + 16, 0); 333 334 CRYPTO_poly1305_init(&poly1305, poly1305_key); 335 poly1305_update_with_pad16(&poly1305, ad, ad_len); 336 poly1305_update_with_pad16(&poly1305, in, plaintext_len); 337 poly1305_update_with_length(&poly1305, NULL, ad_len); 338 poly1305_update_with_length(&poly1305, NULL, plaintext_len); 339 340 CRYPTO_poly1305_finish(&poly1305, mac); 341 if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) { 342 EVPerror(EVP_R_BAD_DECRYPT); 343 return 0; 344 } 345 346 CRYPTO_chacha_20(out, in, plaintext_len, subkey, nonce + 16, 1); 347 348 *out_len = plaintext_len; 349 return 1; 350 } 351 352 /* RFC 7539 */ 353 static const EVP_AEAD aead_chacha20_poly1305 = { 354 .key_len = 32, 355 .nonce_len = CHACHA20_NONCE_LEN, 356 .overhead = POLY1305_TAG_LEN, 357 .max_tag_len = POLY1305_TAG_LEN, 358 359 .init = aead_chacha20_poly1305_init, 360 .cleanup = aead_chacha20_poly1305_cleanup, 361 .seal = aead_chacha20_poly1305_seal, 362 .open = aead_chacha20_poly1305_open, 363 }; 364 365 const EVP_AEAD * 366 EVP_aead_chacha20_poly1305() 367 { 368 return &aead_chacha20_poly1305; 369 } 370 371 static const EVP_AEAD aead_xchacha20_poly1305 = { 372 .key_len = 32, 373 .nonce_len = XCHACHA20_NONCE_LEN, 374 .overhead = POLY1305_TAG_LEN, 375 .max_tag_len = POLY1305_TAG_LEN, 376 377 .init = aead_chacha20_poly1305_init, 378 .cleanup = aead_chacha20_poly1305_cleanup, 379 .seal = aead_xchacha20_poly1305_seal, 380 .open = aead_xchacha20_poly1305_open, 381 }; 382 383 const EVP_AEAD * 384 EVP_aead_xchacha20_poly1305() 385 { 386 return &aead_xchacha20_poly1305; 387 } 388 389 #endif /* !OPENSSL_NO_CHACHA && !OPENSSL_NO_POLY1305 */ 390