GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/evp/e_chacha20poly1305.c Lines: 78 101 77.2 %
Date: 2017-11-07 Branches: 20 32 62.5 %

Line Branch Exec Source
1
/* $OpenBSD: e_chacha20poly1305.c,v 1.18 2017/08/28 17:48:02 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
40
struct aead_chacha20_poly1305_ctx {
41
	unsigned char key[32];
42
	unsigned char tag_len;
43
};
44
45
static int
46
aead_chacha20_poly1305_init(EVP_AEAD_CTX *ctx, const unsigned char *key,
47
    size_t key_len, size_t tag_len)
48
{
49
	struct aead_chacha20_poly1305_ctx *c20_ctx;
50
51
112
	if (tag_len == 0)
52
32
		tag_len = POLY1305_TAG_LEN;
53
54
56
	if (tag_len > POLY1305_TAG_LEN) {
55
		EVPerror(EVP_R_TOO_LARGE);
56
		return 0;
57
	}
58
59
	/* Internal error - EVP_AEAD_CTX_init should catch this. */
60
56
	if (key_len != sizeof(c20_ctx->key))
61
		return 0;
62
63
56
	c20_ctx = malloc(sizeof(struct aead_chacha20_poly1305_ctx));
64
56
	if (c20_ctx == NULL)
65
		return 0;
66
67
56
	memcpy(&c20_ctx->key[0], key, key_len);
68
56
	c20_ctx->tag_len = tag_len;
69
56
	ctx->aead_state = c20_ctx;
70
71
56
	return 1;
72
56
}
73
74
static void
75
aead_chacha20_poly1305_cleanup(EVP_AEAD_CTX *ctx)
76
{
77
112
	struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
78
79
56
	freezero(c20_ctx, sizeof(*c20_ctx));
80
56
}
81
82
static void
83
poly1305_update_with_length(poly1305_state *poly1305,
84
    const unsigned char *data, size_t data_len)
85
{
86
	size_t j = data_len;
87
608
	unsigned char length_bytes[8];
88
	unsigned i;
89
90
5472
	for (i = 0; i < sizeof(length_bytes); i++) {
91
2432
		length_bytes[i] = j;
92
2432
		j >>= 8;
93
	}
94
95
304
	if (data != NULL)
96
		CRYPTO_poly1305_update(poly1305, data, data_len);
97
304
	CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes));
98
304
}
99
100
static void
101
poly1305_update_with_pad16(poly1305_state *poly1305,
102
    const unsigned char *data, size_t data_len)
103
{
104
	static const unsigned char zero_pad16[16];
105
	size_t pad_len;
106
107
608
	CRYPTO_poly1305_update(poly1305, data, data_len);
108
109
	/* pad16() is defined in RFC 7539 2.8.1. */
110
304
	if ((pad_len = data_len % 16) == 0)
111
82
		return;
112
113
222
	CRYPTO_poly1305_update(poly1305, zero_pad16, 16 - pad_len);
114
526
}
115
116
static int
117
aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out,
118
    size_t *out_len, size_t max_out_len, const unsigned char *nonce,
119
    size_t nonce_len, const unsigned char *in, size_t in_len,
120
    const unsigned char *ad, size_t ad_len)
121
{
122
144
	const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
123
72
	unsigned char poly1305_key[32];
124
72
	poly1305_state poly1305;
125
	const unsigned char *iv;
126
	const uint64_t in_len_64 = in_len;
127
	uint64_t ctr;
128
129
	/* The underlying ChaCha implementation may not overflow the block
130
	 * counter into the second counter word. Therefore we disallow
131
	 * individual operations that work on more than 2TB at a time.
132
	 * in_len_64 is needed because, on 32-bit platforms, size_t is only
133
	 * 32-bits and this produces a warning because it's always false.
134
	 * Casting to uint64_t inside the conditional is not sufficient to stop
135
	 * the warning. */
136
72
	if (in_len_64 >= (1ULL << 32) * 64 - 64) {
137
		EVPerror(EVP_R_TOO_LARGE);
138
		return 0;
139
	}
140
141
72
	if (max_out_len < in_len + c20_ctx->tag_len) {
142
		EVPerror(EVP_R_BUFFER_TOO_SMALL);
143
		return 0;
144
	}
145
146
72
	if (nonce_len != ctx->aead->nonce_len) {
147
		EVPerror(EVP_R_IV_TOO_LARGE);
148
		return 0;
149
	}
150
151
216
	ctr = (uint64_t)(nonce[0] | nonce[1] << 8 |
152
216
	    nonce[2] << 16 | nonce[3] << 24) << 32;
153
72
	iv = nonce + CHACHA20_CONSTANT_LEN;
154
155
72
	memset(poly1305_key, 0, sizeof(poly1305_key));
156
72
	CRYPTO_chacha_20(poly1305_key, poly1305_key,
157
72
	    sizeof(poly1305_key), c20_ctx->key, iv, ctr);
158
159
72
	CRYPTO_poly1305_init(&poly1305, poly1305_key);
160
72
	poly1305_update_with_pad16(&poly1305, ad, ad_len);
161
72
	CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, iv, ctr + 1);
162
72
	poly1305_update_with_pad16(&poly1305, out, in_len);
163
72
	poly1305_update_with_length(&poly1305, NULL, ad_len);
164
72
	poly1305_update_with_length(&poly1305, NULL, in_len);
165
166
72
	if (c20_ctx->tag_len != POLY1305_TAG_LEN) {
167
		unsigned char tag[POLY1305_TAG_LEN];
168
		CRYPTO_poly1305_finish(&poly1305, tag);
169
		memcpy(out + in_len, tag, c20_ctx->tag_len);
170
		*out_len = in_len + c20_ctx->tag_len;
171
		return 1;
172
	}
173
174
72
	CRYPTO_poly1305_finish(&poly1305, out + in_len);
175
72
	*out_len = in_len + POLY1305_TAG_LEN;
176
72
	return 1;
177
72
}
178
179
static int
180
aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
181
    size_t *out_len, size_t max_out_len, const unsigned char *nonce,
182
    size_t nonce_len, const unsigned char *in, size_t in_len,
183
    const unsigned char *ad, size_t ad_len)
184
{
185
160
	const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
186
80
	unsigned char mac[POLY1305_TAG_LEN];
187
80
	unsigned char poly1305_key[32];
188
	const unsigned char *iv = nonce;
189
80
	poly1305_state poly1305;
190
	const uint64_t in_len_64 = in_len;
191
	size_t plaintext_len;
192
	uint64_t ctr = 0;
193
194
80
	if (in_len < c20_ctx->tag_len) {
195
		EVPerror(EVP_R_BAD_DECRYPT);
196
		return 0;
197
	}
198
199
	/* The underlying ChaCha implementation may not overflow the block
200
	 * counter into the second counter word. Therefore we disallow
201
	 * individual operations that work on more than 2TB at a time.
202
	 * in_len_64 is needed because, on 32-bit platforms, size_t is only
203
	 * 32-bits and this produces a warning because it's always false.
204
	 * Casting to uint64_t inside the conditional is not sufficient to stop
205
	 * the warning. */
206
80
	if (in_len_64 >= (1ULL << 32) * 64 - 64) {
207
		EVPerror(EVP_R_TOO_LARGE);
208
		return 0;
209
	}
210
211
80
	if (nonce_len != ctx->aead->nonce_len) {
212
		EVPerror(EVP_R_IV_TOO_LARGE);
213
		return 0;
214
	}
215
216
80
	plaintext_len = in_len - c20_ctx->tag_len;
217
218
80
	if (max_out_len < plaintext_len) {
219
		EVPerror(EVP_R_BUFFER_TOO_SMALL);
220
		return 0;
221
	}
222
223
240
	ctr = (uint64_t)(nonce[0] | nonce[1] << 8 |
224
240
	    nonce[2] << 16 | nonce[3] << 24) << 32;
225
80
	iv = nonce + CHACHA20_CONSTANT_LEN;
226
227
80
	memset(poly1305_key, 0, sizeof(poly1305_key));
228
80
	CRYPTO_chacha_20(poly1305_key, poly1305_key,
229
80
	    sizeof(poly1305_key), c20_ctx->key, iv, ctr);
230
231
80
	CRYPTO_poly1305_init(&poly1305, poly1305_key);
232
80
	poly1305_update_with_pad16(&poly1305, ad, ad_len);
233
80
	poly1305_update_with_pad16(&poly1305, in, plaintext_len);
234
80
	poly1305_update_with_length(&poly1305, NULL, ad_len);
235
80
	poly1305_update_with_length(&poly1305, NULL, plaintext_len);
236
237
80
	CRYPTO_poly1305_finish(&poly1305, mac);
238
239
80
	if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) {
240
24
		EVPerror(EVP_R_BAD_DECRYPT);
241
24
		return 0;
242
	}
243
244
56
	CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, iv, ctr + 1);
245
56
	*out_len = plaintext_len;
246
56
	return 1;
247
80
}
248
249
/* RFC 7539 */
250
static const EVP_AEAD aead_chacha20_poly1305 = {
251
	.key_len = 32,
252
	.nonce_len = CHACHA20_NONCE_LEN,
253
	.overhead = POLY1305_TAG_LEN,
254
	.max_tag_len = POLY1305_TAG_LEN,
255
256
	.init = aead_chacha20_poly1305_init,
257
	.cleanup = aead_chacha20_poly1305_cleanup,
258
	.seal = aead_chacha20_poly1305_seal,
259
	.open = aead_chacha20_poly1305_open,
260
};
261
262
const EVP_AEAD *
263
EVP_aead_chacha20_poly1305()
264
{
265
80
	return &aead_chacha20_poly1305;
266
}
267
268
#endif  /* !OPENSSL_NO_CHACHA && !OPENSSL_NO_POLY1305 */