GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/crypto/../../libssl/src/crypto/evp/e_chacha20poly1305.c Lines: 99 117 84.6 %
Date: 2016-12-06 Branches: 28 40 70.0 %

Line Branch Exec Source
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
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
81
{
56
	struct aead_chacha20_poly1305_ctx *c20_ctx;
57
58
81
	if (tag_len == 0)
59
1
		tag_len = POLY1305_TAG_LEN;
60
61
81
	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
81
	if (key_len != sizeof(c20_ctx->key))
68
		return 0;
69
70
81
	c20_ctx = malloc(sizeof(struct aead_chacha20_poly1305_ctx));
71
81
	if (c20_ctx == NULL)
72
		return 0;
73
74
81
	memcpy(&c20_ctx->key[0], key, key_len);
75
81
	c20_ctx->tag_len = tag_len;
76
81
	ctx->aead_state = c20_ctx;
77
78
81
	return 1;
79
}
80
81
static void
82
aead_chacha20_poly1305_cleanup(EVP_AEAD_CTX *ctx)
83
81
{
84
81
	struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
85
86
81
	explicit_bzero(c20_ctx->key, sizeof(c20_ctx->key));
87
81
	free(c20_ctx);
88
81
}
89
90
static void
91
poly1305_update_with_length(poly1305_state *poly1305,
92
    const unsigned char *data, size_t data_len)
93
486
{
94
486
	size_t j = data_len;
95
	unsigned char length_bytes[8];
96
	unsigned i;
97
98
4374
	for (i = 0; i < sizeof(length_bytes); i++) {
99
3888
		length_bytes[i] = j;
100
3888
		j >>= 8;
101
	}
102
103
486
	if (data != NULL)
104
462
		CRYPTO_poly1305_update(poly1305, data, data_len);
105
486
	CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes));
106
486
}
107
108
static void
109
poly1305_update_with_pad16(poly1305_state *poly1305,
110
    const unsigned char *data, size_t data_len)
111
24
{
112
	static const unsigned char zero_pad16[16];
113
	size_t pad_len;
114
115
24
	CRYPTO_poly1305_update(poly1305, data, data_len);
116
117
	/* pad16() is defined in RFC 7539 2.8.1. */
118
24
	if ((pad_len = data_len % 16) == 0)
119
3
		return;
120
121
21
	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
81
{
130
81
	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
81
	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
81
	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
81
	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
81
	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
81
	if (nonce_len == CHACHA20_NONCE_LEN_OLD) {
161
		/* Google's draft-agl-tls-chacha20poly1305-04, Nov 2013 */
162
163
77
		memset(poly1305_key, 0, sizeof(poly1305_key));
164
77
		CRYPTO_chacha_20(poly1305_key, poly1305_key,
165
		    sizeof(poly1305_key), c20_ctx->key, nonce, 0);
166
167
77
		CRYPTO_poly1305_init(&poly1305, poly1305_key);
168
77
		poly1305_update_with_length(&poly1305, ad, ad_len);
169
77
		CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1);
170
77
		poly1305_update_with_length(&poly1305, out, in_len);
171
4
	} else if (nonce_len == CHACHA20_NONCE_LEN) {
172
		/* RFC 7539, May 2015 */
173
174
4
		ctr = (uint64_t)(nonce[0] | nonce[1] << 8 |
175
		    nonce[2] << 16 | nonce[3] << 24) << 32;
176
4
		iv = nonce + CHACHA20_CONSTANT_LEN;
177
178
4
		memset(poly1305_key, 0, sizeof(poly1305_key));
179
4
		CRYPTO_chacha_20(poly1305_key, poly1305_key,
180
		    sizeof(poly1305_key), c20_ctx->key, iv, ctr);
181
182
4
		CRYPTO_poly1305_init(&poly1305, poly1305_key);
183
4
		poly1305_update_with_pad16(&poly1305, ad, ad_len);
184
4
		CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, iv, ctr + 1);
185
4
		poly1305_update_with_pad16(&poly1305, out, in_len);
186
4
		poly1305_update_with_length(&poly1305, NULL, ad_len);
187
4
		poly1305_update_with_length(&poly1305, NULL, in_len);
188
	}
189
190
81
	if (c20_ctx->tag_len != POLY1305_TAG_LEN) {
191
		unsigned char tag[POLY1305_TAG_LEN];
192
15
		CRYPTO_poly1305_finish(&poly1305, tag);
193
15
		memcpy(out + in_len, tag, c20_ctx->tag_len);
194
15
		*out_len = in_len + c20_ctx->tag_len;
195
15
		return 1;
196
	}
197
198
66
	CRYPTO_poly1305_finish(&poly1305, out + in_len);
199
66
	*out_len = in_len + POLY1305_TAG_LEN;
200
66
	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
162
{
209
162
	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
162
	const unsigned char *iv = nonce;
213
	poly1305_state poly1305;
214
162
	const uint64_t in_len_64 = in_len;
215
	size_t plaintext_len;
216
162
	uint64_t ctr = 0;
217
218
162
	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
162
	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
162
	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
162
	plaintext_len = in_len - c20_ctx->tag_len;
241
242
162
	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
162
	if (nonce_len == CHACHA20_NONCE_LEN_OLD) {
249
		/* Google's draft-agl-tls-chacha20poly1305-04, Nov 2013 */
250
251
154
		memset(poly1305_key, 0, sizeof(poly1305_key));
252
154
		CRYPTO_chacha_20(poly1305_key, poly1305_key,
253
		    sizeof(poly1305_key), c20_ctx->key, nonce, 0);
254
255
154
		CRYPTO_poly1305_init(&poly1305, poly1305_key);
256
154
		poly1305_update_with_length(&poly1305, ad, ad_len);
257
154
		poly1305_update_with_length(&poly1305, in, plaintext_len);
258
8
	} else if (nonce_len == CHACHA20_NONCE_LEN) {
259
		/* RFC 7539, May 2015 */
260
261
8
		ctr = (uint64_t)(nonce[0] | nonce[1] << 8 |
262
		    nonce[2] << 16 | nonce[3] << 24) << 32;
263
8
		iv = nonce + CHACHA20_CONSTANT_LEN;
264
265
8
		memset(poly1305_key, 0, sizeof(poly1305_key));
266
8
		CRYPTO_chacha_20(poly1305_key, poly1305_key,
267
		    sizeof(poly1305_key), c20_ctx->key, iv, ctr);
268
269
8
		CRYPTO_poly1305_init(&poly1305, poly1305_key);
270
8
		poly1305_update_with_pad16(&poly1305, ad, ad_len);
271
8
		poly1305_update_with_pad16(&poly1305, in, plaintext_len);
272
8
		poly1305_update_with_length(&poly1305, NULL, ad_len);
273
8
		poly1305_update_with_length(&poly1305, NULL, plaintext_len);
274
	}
275
276
162
	CRYPTO_poly1305_finish(&poly1305, mac);
277
278
162
	if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) {
279
81
		EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_BAD_DECRYPT);
280
81
		return 0;
281
	}
282
283
81
	CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, iv, ctr + 1);
284
81
	*out_len = plaintext_len;
285
81
	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
4
{
315
4
	return &aead_chacha20_poly1305;
316
}
317
318
const EVP_AEAD *
319
EVP_aead_chacha20_poly1305_old()
320
77
{
321
77
	return &aead_chacha20_poly1305_old;
322
}
323
324
#endif  /* !OPENSSL_NO_CHACHA && !OPENSSL_NO_POLY1305 */