1 /* $OpenBSD: e_chacha20poly1305.c,v 1.13 2016/04/13 13:25:05 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 #define CHACHA20_NONCE_LEN_OLD 8 36 37 /* 38 * The informational RFC 7539, "ChaCha20 and Poly1305 for IETF Protocols", 39 * introduced a modified AEAD construction that is incompatible with the 40 * common style that has been already used in TLS. The IETF version also 41 * adds a constant (salt) that is prepended to the nonce. 42 */ 43 #define CHACHA20_CONSTANT_LEN 4 44 #define CHACHA20_IV_LEN 8 45 #define CHACHA20_NONCE_LEN (CHACHA20_CONSTANT_LEN + CHACHA20_IV_LEN) 46 47 struct aead_chacha20_poly1305_ctx { 48 unsigned char key[32]; 49 unsigned char tag_len; 50 }; 51 52 static int 53 aead_chacha20_poly1305_init(EVP_AEAD_CTX *ctx, const unsigned char *key, 54 size_t key_len, size_t tag_len) 55 { 56 struct aead_chacha20_poly1305_ctx *c20_ctx; 57 58 if (tag_len == 0) 59 tag_len = POLY1305_TAG_LEN; 60 61 if (tag_len > POLY1305_TAG_LEN) { 62 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_INIT, EVP_R_TOO_LARGE); 63 return 0; 64 } 65 66 /* Internal error - EVP_AEAD_CTX_init should catch this. */ 67 if (key_len != sizeof(c20_ctx->key)) 68 return 0; 69 70 c20_ctx = malloc(sizeof(struct aead_chacha20_poly1305_ctx)); 71 if (c20_ctx == NULL) 72 return 0; 73 74 memcpy(&c20_ctx->key[0], key, key_len); 75 c20_ctx->tag_len = tag_len; 76 ctx->aead_state = c20_ctx; 77 78 return 1; 79 } 80 81 static void 82 aead_chacha20_poly1305_cleanup(EVP_AEAD_CTX *ctx) 83 { 84 struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 85 86 explicit_bzero(c20_ctx->key, sizeof(c20_ctx->key)); 87 free(c20_ctx); 88 } 89 90 static void 91 poly1305_update_with_length(poly1305_state *poly1305, 92 const unsigned char *data, size_t data_len) 93 { 94 size_t j = data_len; 95 unsigned char length_bytes[8]; 96 unsigned i; 97 98 for (i = 0; i < sizeof(length_bytes); i++) { 99 length_bytes[i] = j; 100 j >>= 8; 101 } 102 103 if (data != NULL) 104 CRYPTO_poly1305_update(poly1305, data, data_len); 105 CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes)); 106 } 107 108 static void 109 poly1305_update_with_pad16(poly1305_state *poly1305, 110 const unsigned char *data, size_t data_len) 111 { 112 static const unsigned char zero_pad16[16]; 113 size_t pad_len; 114 115 CRYPTO_poly1305_update(poly1305, data, data_len); 116 117 /* pad16() is defined in RFC 7539 2.8.1. */ 118 if ((pad_len = data_len % 16) == 0) 119 return; 120 121 CRYPTO_poly1305_update(poly1305, zero_pad16, 16 - pad_len); 122 } 123 124 static int 125 aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out, 126 size_t *out_len, size_t max_out_len, const unsigned char *nonce, 127 size_t nonce_len, const unsigned char *in, size_t in_len, 128 const unsigned char *ad, size_t ad_len) 129 { 130 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 131 unsigned char poly1305_key[32]; 132 poly1305_state poly1305; 133 const unsigned char *iv; 134 const uint64_t in_len_64 = in_len; 135 uint64_t ctr; 136 137 /* The underlying ChaCha implementation may not overflow the block 138 * counter into the second counter word. Therefore we disallow 139 * individual operations that work on more than 2TB at a time. 140 * in_len_64 is needed because, on 32-bit platforms, size_t is only 141 * 32-bits and this produces a warning because it's always false. 142 * Casting to uint64_t inside the conditional is not sufficient to stop 143 * the warning. */ 144 if (in_len_64 >= (1ULL << 32) * 64 - 64) { 145 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL, EVP_R_TOO_LARGE); 146 return 0; 147 } 148 149 if (max_out_len < in_len + c20_ctx->tag_len) { 150 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL, 151 EVP_R_BUFFER_TOO_SMALL); 152 return 0; 153 } 154 155 if (nonce_len != ctx->aead->nonce_len) { 156 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL, EVP_R_IV_TOO_LARGE); 157 return 0; 158 } 159 160 if (nonce_len == CHACHA20_NONCE_LEN_OLD) { 161 /* Google's draft-agl-tls-chacha20poly1305-04, Nov 2013 */ 162 163 memset(poly1305_key, 0, sizeof(poly1305_key)); 164 CRYPTO_chacha_20(poly1305_key, poly1305_key, 165 sizeof(poly1305_key), c20_ctx->key, nonce, 0); 166 167 CRYPTO_poly1305_init(&poly1305, poly1305_key); 168 poly1305_update_with_length(&poly1305, ad, ad_len); 169 CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1); 170 poly1305_update_with_length(&poly1305, out, in_len); 171 } else if (nonce_len == CHACHA20_NONCE_LEN) { 172 /* RFC 7539, May 2015 */ 173 174 ctr = (uint64_t)(nonce[0] | nonce[1] << 8 | 175 nonce[2] << 16 | nonce[3] << 24) << 32; 176 iv = nonce + CHACHA20_CONSTANT_LEN; 177 178 memset(poly1305_key, 0, sizeof(poly1305_key)); 179 CRYPTO_chacha_20(poly1305_key, poly1305_key, 180 sizeof(poly1305_key), c20_ctx->key, iv, ctr); 181 182 CRYPTO_poly1305_init(&poly1305, poly1305_key); 183 poly1305_update_with_pad16(&poly1305, ad, ad_len); 184 CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, iv, ctr + 1); 185 poly1305_update_with_pad16(&poly1305, out, in_len); 186 poly1305_update_with_length(&poly1305, NULL, ad_len); 187 poly1305_update_with_length(&poly1305, NULL, in_len); 188 } 189 190 if (c20_ctx->tag_len != POLY1305_TAG_LEN) { 191 unsigned char tag[POLY1305_TAG_LEN]; 192 CRYPTO_poly1305_finish(&poly1305, tag); 193 memcpy(out + in_len, tag, c20_ctx->tag_len); 194 *out_len = in_len + c20_ctx->tag_len; 195 return 1; 196 } 197 198 CRYPTO_poly1305_finish(&poly1305, out + in_len); 199 *out_len = in_len + POLY1305_TAG_LEN; 200 return 1; 201 } 202 203 static int 204 aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out, 205 size_t *out_len, size_t max_out_len, const unsigned char *nonce, 206 size_t nonce_len, const unsigned char *in, size_t in_len, 207 const unsigned char *ad, size_t ad_len) 208 { 209 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 210 unsigned char mac[POLY1305_TAG_LEN]; 211 unsigned char poly1305_key[32]; 212 const unsigned char *iv = nonce; 213 poly1305_state poly1305; 214 const uint64_t in_len_64 = in_len; 215 size_t plaintext_len; 216 uint64_t ctr = 0; 217 218 if (in_len < c20_ctx->tag_len) { 219 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_BAD_DECRYPT); 220 return 0; 221 } 222 223 /* The underlying ChaCha implementation may not overflow the block 224 * counter into the second counter word. Therefore we disallow 225 * individual operations that work on more than 2TB at a time. 226 * in_len_64 is needed because, on 32-bit platforms, size_t is only 227 * 32-bits and this produces a warning because it's always false. 228 * Casting to uint64_t inside the conditional is not sufficient to stop 229 * the warning. */ 230 if (in_len_64 >= (1ULL << 32) * 64 - 64) { 231 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_TOO_LARGE); 232 return 0; 233 } 234 235 if (nonce_len != ctx->aead->nonce_len) { 236 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_IV_TOO_LARGE); 237 return 0; 238 } 239 240 plaintext_len = in_len - c20_ctx->tag_len; 241 242 if (max_out_len < plaintext_len) { 243 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, 244 EVP_R_BUFFER_TOO_SMALL); 245 return 0; 246 } 247 248 if (nonce_len == CHACHA20_NONCE_LEN_OLD) { 249 /* Google's draft-agl-tls-chacha20poly1305-04, Nov 2013 */ 250 251 memset(poly1305_key, 0, sizeof(poly1305_key)); 252 CRYPTO_chacha_20(poly1305_key, poly1305_key, 253 sizeof(poly1305_key), c20_ctx->key, nonce, 0); 254 255 CRYPTO_poly1305_init(&poly1305, poly1305_key); 256 poly1305_update_with_length(&poly1305, ad, ad_len); 257 poly1305_update_with_length(&poly1305, in, plaintext_len); 258 } else if (nonce_len == CHACHA20_NONCE_LEN) { 259 /* RFC 7539, May 2015 */ 260 261 ctr = (uint64_t)(nonce[0] | nonce[1] << 8 | 262 nonce[2] << 16 | nonce[3] << 24) << 32; 263 iv = nonce + CHACHA20_CONSTANT_LEN; 264 265 memset(poly1305_key, 0, sizeof(poly1305_key)); 266 CRYPTO_chacha_20(poly1305_key, poly1305_key, 267 sizeof(poly1305_key), c20_ctx->key, iv, ctr); 268 269 CRYPTO_poly1305_init(&poly1305, poly1305_key); 270 poly1305_update_with_pad16(&poly1305, ad, ad_len); 271 poly1305_update_with_pad16(&poly1305, in, plaintext_len); 272 poly1305_update_with_length(&poly1305, NULL, ad_len); 273 poly1305_update_with_length(&poly1305, NULL, plaintext_len); 274 } 275 276 CRYPTO_poly1305_finish(&poly1305, mac); 277 278 if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) { 279 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_BAD_DECRYPT); 280 return 0; 281 } 282 283 CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, iv, ctr + 1); 284 *out_len = plaintext_len; 285 return 1; 286 } 287 288 static const EVP_AEAD aead_chacha20_poly1305 = { 289 .key_len = 32, 290 .nonce_len = CHACHA20_NONCE_LEN, 291 .overhead = POLY1305_TAG_LEN, 292 .max_tag_len = POLY1305_TAG_LEN, 293 294 .init = aead_chacha20_poly1305_init, 295 .cleanup = aead_chacha20_poly1305_cleanup, 296 .seal = aead_chacha20_poly1305_seal, 297 .open = aead_chacha20_poly1305_open, 298 }; 299 300 static const EVP_AEAD aead_chacha20_poly1305_old = { 301 .key_len = 32, 302 .nonce_len = CHACHA20_NONCE_LEN_OLD, 303 .overhead = POLY1305_TAG_LEN, 304 .max_tag_len = POLY1305_TAG_LEN, 305 306 .init = aead_chacha20_poly1305_init, 307 .cleanup = aead_chacha20_poly1305_cleanup, 308 .seal = aead_chacha20_poly1305_seal, 309 .open = aead_chacha20_poly1305_open, 310 }; 311 312 const EVP_AEAD * 313 EVP_aead_chacha20_poly1305() 314 { 315 return &aead_chacha20_poly1305; 316 } 317 318 const EVP_AEAD * 319 EVP_aead_chacha20_poly1305_old() 320 { 321 return &aead_chacha20_poly1305_old; 322 } 323 324 #endif /* !OPENSSL_NO_CHACHA && !OPENSSL_NO_POLY1305 */ 325