summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/evp/e_chacha20poly1305.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libcrypto/evp/e_chacha20poly1305.c')
-rw-r--r--src/lib/libcrypto/evp/e_chacha20poly1305.c324
1 files changed, 0 insertions, 324 deletions
diff --git a/src/lib/libcrypto/evp/e_chacha20poly1305.c b/src/lib/libcrypto/evp/e_chacha20poly1305.c
deleted file mode 100644
index e5395ad8ca..0000000000
--- a/src/lib/libcrypto/evp/e_chacha20poly1305.c
+++ /dev/null
@@ -1,324 +0,0 @@
1/* $OpenBSD: e_chacha20poly1305.c,v 1.14 2016/04/28 16:06:53 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
47struct aead_chacha20_poly1305_ctx {
48 unsigned char key[32];
49 unsigned char tag_len;
50};
51
52static int
53aead_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
81static void
82aead_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
90static void
91poly1305_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
108static void
109poly1305_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
124static int
125aead_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
203static int
204aead_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
288static 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
300static 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
312const EVP_AEAD *
313EVP_aead_chacha20_poly1305()
314{
315 return &aead_chacha20_poly1305;
316}
317
318const EVP_AEAD *
319EVP_aead_chacha20_poly1305_old()
320{
321 return &aead_chacha20_poly1305_old;
322}
323
324#endif /* !OPENSSL_NO_CHACHA && !OPENSSL_NO_POLY1305 */