summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/evp/e_chacha20poly1305.c
diff options
context:
space:
mode:
authorreyk <>2015-11-02 15:40:53 +0000
committerreyk <>2015-11-02 15:40:53 +0000
commitb743c75edf0dc70962a2ed0c5221ecb8841d7525 (patch)
tree40446be7b959dce9252457817e67737c7606706c /src/lib/libcrypto/evp/e_chacha20poly1305.c
parent3b76990c68663b08d77297a05a8104c2f1528064 (diff)
downloadopenbsd-b743c75edf0dc70962a2ed0c5221ecb8841d7525.tar.gz
openbsd-b743c75edf0dc70962a2ed0c5221ecb8841d7525.tar.bz2
openbsd-b743c75edf0dc70962a2ed0c5221ecb8841d7525.zip
Add EVP_aead_chacha20_poly1305_ietf() - The informational RFC 7539,
"ChaCha20 and Poly1305 for IETF Protocols", introduced a modified AEAD construction that is incompatible with the common style that has been already used in TLS with EVP_aead_chacha20_poly1305(). The IETF version also adds a constant (salt) that is prepended to the nonce. OK mikeb@ jsing@
Diffstat (limited to 'src/lib/libcrypto/evp/e_chacha20poly1305.c')
-rw-r--r--src/lib/libcrypto/evp/e_chacha20poly1305.c129
1 files changed, 111 insertions, 18 deletions
diff --git a/src/lib/libcrypto/evp/e_chacha20poly1305.c b/src/lib/libcrypto/evp/e_chacha20poly1305.c
index 9deb40b72a..47551c4578 100644
--- a/src/lib/libcrypto/evp/e_chacha20poly1305.c
+++ b/src/lib/libcrypto/evp/e_chacha20poly1305.c
@@ -1,5 +1,7 @@
1/* $OpenBSD: e_chacha20poly1305.c,v 1.10 2015/09/10 15:56:25 jsing Exp $ */ 1/* $OpenBSD: e_chacha20poly1305.c,v 1.11 2015/11/02 15:40:53 reyk Exp $ */
2
2/* 3/*
4 * Copyright (c) 2015 Reyk Floter <reyk@openbsd.org>
3 * Copyright (c) 2014, Google Inc. 5 * Copyright (c) 2014, Google Inc.
4 * 6 *
5 * Permission to use, copy, modify, and/or distribute this software for any 7 * Permission to use, copy, modify, and/or distribute this software for any
@@ -32,6 +34,16 @@
32#define POLY1305_TAG_LEN 16 34#define POLY1305_TAG_LEN 16
33#define CHACHA20_NONCE_LEN 8 35#define CHACHA20_NONCE_LEN 8
34 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 that has been already used in TLS. The IETF version
41 * also 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_IETF (CHACHA20_CONSTANT_LEN + CHACHA20_IV_LEN)
46
35struct aead_chacha20_poly1305_ctx { 47struct aead_chacha20_poly1305_ctx {
36 unsigned char key[32]; 48 unsigned char key[32];
37 unsigned char tag_len; 49 unsigned char tag_len;
@@ -88,10 +100,27 @@ poly1305_update_with_length(poly1305_state *poly1305,
88 j >>= 8; 100 j >>= 8;
89 } 101 }
90 102
91 CRYPTO_poly1305_update(poly1305, data, data_len); 103 if (data != NULL)
104 CRYPTO_poly1305_update(poly1305, data, data_len);
92 CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes)); 105 CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes));
93} 106}
94 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
95static int 124static int
96aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out, 125aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out,
97 size_t *out_len, size_t max_out_len, const unsigned char *nonce, 126 size_t *out_len, size_t max_out_len, const unsigned char *nonce,
@@ -101,7 +130,9 @@ aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out,
101 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 130 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
102 unsigned char poly1305_key[32]; 131 unsigned char poly1305_key[32];
103 poly1305_state poly1305; 132 poly1305_state poly1305;
133 const unsigned char *iv;
104 const uint64_t in_len_64 = in_len; 134 const uint64_t in_len_64 = in_len;
135 uint64_t ctr;
105 136
106 /* The underlying ChaCha implementation may not overflow the block 137 /* The underlying ChaCha implementation may not overflow the block
107 * counter into the second counter word. Therefore we disallow 138 * counter into the second counter word. Therefore we disallow
@@ -121,19 +152,40 @@ aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out,
121 return 0; 152 return 0;
122 } 153 }
123 154
124 if (nonce_len != CHACHA20_NONCE_LEN) { 155 if (nonce_len != ctx->aead->nonce_len) {
125 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL, EVP_R_IV_TOO_LARGE); 156 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL, EVP_R_IV_TOO_LARGE);
126 return 0; 157 return 0;
127 } 158 }
128 159
129 memset(poly1305_key, 0, sizeof(poly1305_key)); 160 if (nonce_len == CHACHA20_NONCE_LEN) {
130 CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), 161 /* Google's draft-agl-tls-chacha20poly1305-04, Nov 2013 */
131 c20_ctx->key, nonce, 0); 162
132 163 memset(poly1305_key, 0, sizeof(poly1305_key));
133 CRYPTO_poly1305_init(&poly1305, poly1305_key); 164 CRYPTO_chacha_20(poly1305_key, poly1305_key,
134 poly1305_update_with_length(&poly1305, ad, ad_len); 165 sizeof(poly1305_key), c20_ctx->key, nonce, 0);
135 CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1); 166
136 poly1305_update_with_length(&poly1305, out, in_len); 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_IETF) {
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 }
137 189
138 if (c20_ctx->tag_len != POLY1305_TAG_LEN) { 190 if (c20_ctx->tag_len != POLY1305_TAG_LEN) {
139 unsigned char tag[POLY1305_TAG_LEN]; 191 unsigned char tag[POLY1305_TAG_LEN];
@@ -157,9 +209,11 @@ aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
157 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; 209 const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
158 unsigned char mac[POLY1305_TAG_LEN]; 210 unsigned char mac[POLY1305_TAG_LEN];
159 unsigned char poly1305_key[32]; 211 unsigned char poly1305_key[32];
212 const unsigned char *iv;
160 poly1305_state poly1305; 213 poly1305_state poly1305;
161 const uint64_t in_len_64 = in_len; 214 const uint64_t in_len_64 = in_len;
162 size_t plaintext_len; 215 size_t plaintext_len;
216 uint64_t ctr;
163 217
164 if (in_len < c20_ctx->tag_len) { 218 if (in_len < c20_ctx->tag_len) {
165 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_BAD_DECRYPT); 219 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_BAD_DECRYPT);
@@ -178,7 +232,7 @@ aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
178 return 0; 232 return 0;
179 } 233 }
180 234
181 if (nonce_len != CHACHA20_NONCE_LEN) { 235 if (nonce_len != ctx->aead->nonce_len) {
182 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_IV_TOO_LARGE); 236 EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_IV_TOO_LARGE);
183 return 0; 237 return 0;
184 } 238 }
@@ -191,13 +245,34 @@ aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
191 return 0; 245 return 0;
192 } 246 }
193 247
194 memset(poly1305_key, 0, sizeof(poly1305_key)); 248 if (nonce_len == CHACHA20_NONCE_LEN) {
195 CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), 249 /* Google's draft-agl-tls-chacha20poly1305-04, Nov 2013 */
196 c20_ctx->key, nonce, 0); 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_IETF) {
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 }
197 275
198 CRYPTO_poly1305_init(&poly1305, poly1305_key);
199 poly1305_update_with_length(&poly1305, ad, ad_len);
200 poly1305_update_with_length(&poly1305, in, plaintext_len);
201 CRYPTO_poly1305_finish(&poly1305, mac); 276 CRYPTO_poly1305_finish(&poly1305, mac);
202 277
203 if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) { 278 if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) {
@@ -222,10 +297,28 @@ static const EVP_AEAD aead_chacha20_poly1305 = {
222 .open = aead_chacha20_poly1305_open, 297 .open = aead_chacha20_poly1305_open,
223}; 298};
224 299
300static const EVP_AEAD aead_chacha20_poly1305_ietf = {
301 .key_len = 32,
302 .nonce_len = CHACHA20_NONCE_LEN_IETF,
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
225const EVP_AEAD * 312const EVP_AEAD *
226EVP_aead_chacha20_poly1305() 313EVP_aead_chacha20_poly1305()
227{ 314{
228 return &aead_chacha20_poly1305; 315 return &aead_chacha20_poly1305;
229} 316}
230 317
318const EVP_AEAD *
319EVP_aead_chacha20_poly1305_ietf()
320{
321 return &aead_chacha20_poly1305_ietf;
322}
323
231#endif /* !OPENSSL_NO_CHACHA && !OPENSSL_NO_POLY1305 */ 324#endif /* !OPENSSL_NO_CHACHA && !OPENSSL_NO_POLY1305 */