summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2015-11-02 15:40:54 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2015-11-02 15:40:54 +0000
commita9f81ded5a5cd081f18d0bb0eb8e8beca2dfc150 (patch)
tree42556ad871f45613998f5523cb1fb8d238894128
parent88926ed46e5566b42936ae88a8c69cff8fbb0afd (diff)
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@
-rw-r--r--lib/libcrypto/evp/e_chacha20poly1305.c129
-rw-r--r--lib/libcrypto/evp/evp.h3
2 files changed, 113 insertions, 19 deletions
diff --git a/lib/libcrypto/evp/e_chacha20poly1305.c b/lib/libcrypto/evp/e_chacha20poly1305.c
index 9deb40b72af..47551c4578c 100644
--- a/lib/libcrypto/evp/e_chacha20poly1305.c
+++ b/lib/libcrypto/evp/e_chacha20poly1305.c
@@ -1,5 +1,7 @@
-/* $OpenBSD: e_chacha20poly1305.c,v 1.10 2015/09/10 15:56:25 jsing Exp $ */
+/* $OpenBSD: e_chacha20poly1305.c,v 1.11 2015/11/02 15:40:53 reyk Exp $ */
+
/*
+ * Copyright (c) 2015 Reyk Floter <reyk@openbsd.org>
* Copyright (c) 2014, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -32,6 +34,16 @@
#define POLY1305_TAG_LEN 16
#define CHACHA20_NONCE_LEN 8
+/*
+ * The informational RFC 7539, "ChaCha20 and Poly1305 for IETF Protocols",
+ * introduced a modified AEAD construction that is incompatible with the
+ * common style that that has been already used in TLS. The IETF version
+ * also adds a constant (salt) that is prepended to the nonce.
+ */
+#define CHACHA20_CONSTANT_LEN 4
+#define CHACHA20_IV_LEN 8
+#define CHACHA20_NONCE_LEN_IETF (CHACHA20_CONSTANT_LEN + CHACHA20_IV_LEN)
+
struct aead_chacha20_poly1305_ctx {
unsigned char key[32];
unsigned char tag_len;
@@ -88,10 +100,27 @@ poly1305_update_with_length(poly1305_state *poly1305,
j >>= 8;
}
- CRYPTO_poly1305_update(poly1305, data, data_len);
+ if (data != NULL)
+ CRYPTO_poly1305_update(poly1305, data, data_len);
CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes));
}
+static void
+poly1305_update_with_pad16(poly1305_state *poly1305,
+ const unsigned char *data, size_t data_len)
+{
+ static const unsigned char zero_pad16[16];
+ size_t pad_len;
+
+ CRYPTO_poly1305_update(poly1305, data, data_len);
+
+ /* pad16() is defined in RFC 7539 2.8.1. */
+ if ((pad_len = data_len % 16) == 0)
+ return;
+
+ CRYPTO_poly1305_update(poly1305, zero_pad16, 16 - pad_len);
+}
+
static int
aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, unsigned char *out,
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,
const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
unsigned char poly1305_key[32];
poly1305_state poly1305;
+ const unsigned char *iv;
const uint64_t in_len_64 = in_len;
+ uint64_t ctr;
/* The underlying ChaCha implementation may not overflow the block
* 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,
return 0;
}
- if (nonce_len != CHACHA20_NONCE_LEN) {
+ if (nonce_len != ctx->aead->nonce_len) {
EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_SEAL, EVP_R_IV_TOO_LARGE);
return 0;
}
- memset(poly1305_key, 0, sizeof(poly1305_key));
- CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key),
- c20_ctx->key, nonce, 0);
-
- CRYPTO_poly1305_init(&poly1305, poly1305_key);
- poly1305_update_with_length(&poly1305, ad, ad_len);
- CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1);
- poly1305_update_with_length(&poly1305, out, in_len);
+ if (nonce_len == CHACHA20_NONCE_LEN) {
+ /* Google's draft-agl-tls-chacha20poly1305-04, Nov 2013 */
+
+ memset(poly1305_key, 0, sizeof(poly1305_key));
+ CRYPTO_chacha_20(poly1305_key, poly1305_key,
+ sizeof(poly1305_key), c20_ctx->key, nonce, 0);
+
+ CRYPTO_poly1305_init(&poly1305, poly1305_key);
+ poly1305_update_with_length(&poly1305, ad, ad_len);
+ CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1);
+ poly1305_update_with_length(&poly1305, out, in_len);
+ } else if (nonce_len == CHACHA20_NONCE_LEN_IETF) {
+ /* RFC 7539, May 2015 */
+
+ ctr = (uint64_t)(nonce[0] | nonce[1] << 8 |
+ nonce[2] << 16 | nonce[3] << 24) << 32;
+ iv = nonce + CHACHA20_CONSTANT_LEN;
+
+ memset(poly1305_key, 0, sizeof(poly1305_key));
+ CRYPTO_chacha_20(poly1305_key, poly1305_key,
+ sizeof(poly1305_key), c20_ctx->key, iv, ctr);
+
+ CRYPTO_poly1305_init(&poly1305, poly1305_key);
+ poly1305_update_with_pad16(&poly1305, ad, ad_len);
+ CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, iv, ctr + 1);
+ poly1305_update_with_pad16(&poly1305, out, in_len);
+ poly1305_update_with_length(&poly1305, NULL, ad_len);
+ poly1305_update_with_length(&poly1305, NULL, in_len);
+ }
if (c20_ctx->tag_len != POLY1305_TAG_LEN) {
unsigned char tag[POLY1305_TAG_LEN];
@@ -157,9 +209,11 @@ aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
unsigned char mac[POLY1305_TAG_LEN];
unsigned char poly1305_key[32];
+ const unsigned char *iv;
poly1305_state poly1305;
const uint64_t in_len_64 = in_len;
size_t plaintext_len;
+ uint64_t ctr;
if (in_len < c20_ctx->tag_len) {
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,
return 0;
}
- if (nonce_len != CHACHA20_NONCE_LEN) {
+ if (nonce_len != ctx->aead->nonce_len) {
EVPerr(EVP_F_AEAD_CHACHA20_POLY1305_OPEN, EVP_R_IV_TOO_LARGE);
return 0;
}
@@ -191,13 +245,34 @@ aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, unsigned char *out,
return 0;
}
- memset(poly1305_key, 0, sizeof(poly1305_key));
- CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key),
- c20_ctx->key, nonce, 0);
+ if (nonce_len == CHACHA20_NONCE_LEN) {
+ /* Google's draft-agl-tls-chacha20poly1305-04, Nov 2013 */
+
+ memset(poly1305_key, 0, sizeof(poly1305_key));
+ CRYPTO_chacha_20(poly1305_key, poly1305_key,
+ sizeof(poly1305_key), c20_ctx->key, nonce, 0);
+
+ CRYPTO_poly1305_init(&poly1305, poly1305_key);
+ poly1305_update_with_length(&poly1305, ad, ad_len);
+ poly1305_update_with_length(&poly1305, in, plaintext_len);
+ } else if (nonce_len == CHACHA20_NONCE_LEN_IETF) {
+ /* RFC 7539, May 2015 */
+
+ ctr = (uint64_t)(nonce[0] | nonce[1] << 8 |
+ nonce[2] << 16 | nonce[3] << 24) << 32;
+ iv = nonce + CHACHA20_CONSTANT_LEN;
+
+ memset(poly1305_key, 0, sizeof(poly1305_key));
+ CRYPTO_chacha_20(poly1305_key, poly1305_key,
+ sizeof(poly1305_key), c20_ctx->key, iv, ctr);
+
+ CRYPTO_poly1305_init(&poly1305, poly1305_key);
+ poly1305_update_with_pad16(&poly1305, ad, ad_len);
+ poly1305_update_with_pad16(&poly1305, in, plaintext_len);
+ poly1305_update_with_length(&poly1305, NULL, ad_len);
+ poly1305_update_with_length(&poly1305, NULL, plaintext_len);
+ }
- CRYPTO_poly1305_init(&poly1305, poly1305_key);
- poly1305_update_with_length(&poly1305, ad, ad_len);
- poly1305_update_with_length(&poly1305, in, plaintext_len);
CRYPTO_poly1305_finish(&poly1305, mac);
if (timingsafe_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) {
@@ -222,10 +297,28 @@ static const EVP_AEAD aead_chacha20_poly1305 = {
.open = aead_chacha20_poly1305_open,
};
+static const EVP_AEAD aead_chacha20_poly1305_ietf = {
+ .key_len = 32,
+ .nonce_len = CHACHA20_NONCE_LEN_IETF,
+ .overhead = POLY1305_TAG_LEN,
+ .max_tag_len = POLY1305_TAG_LEN,
+
+ .init = aead_chacha20_poly1305_init,
+ .cleanup = aead_chacha20_poly1305_cleanup,
+ .seal = aead_chacha20_poly1305_seal,
+ .open = aead_chacha20_poly1305_open,
+};
+
const EVP_AEAD *
EVP_aead_chacha20_poly1305()
{
return &aead_chacha20_poly1305;
}
+const EVP_AEAD *
+EVP_aead_chacha20_poly1305_ietf()
+{
+ return &aead_chacha20_poly1305_ietf;
+}
+
#endif /* !OPENSSL_NO_CHACHA && !OPENSSL_NO_POLY1305 */
diff --git a/lib/libcrypto/evp/evp.h b/lib/libcrypto/evp/evp.h
index 2ddbf6142ed..1ec24879c01 100644
--- a/lib/libcrypto/evp/evp.h
+++ b/lib/libcrypto/evp/evp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: evp.h,v 1.48 2015/09/14 01:45:03 doug Exp $ */
+/* $OpenBSD: evp.h,v 1.49 2015/11/02 15:40:53 reyk Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@@ -1215,6 +1215,7 @@ const EVP_AEAD *EVP_aead_aes_256_gcm(void);
#if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
/* EVP_aead_chacha20_poly1305 is ChaCha20 with a Poly1305 authenticator. */
const EVP_AEAD *EVP_aead_chacha20_poly1305(void);
+const EVP_AEAD *EVP_aead_chacha20_poly1305_ietf(void);
#endif
/* EVP_AEAD_key_length returns the length of the keys used. */