summaryrefslogtreecommitdiff
path: root/chacha-poly1305.c
diff options
context:
space:
mode:
Diffstat (limited to 'chacha-poly1305.c')
-rw-r--r--chacha-poly1305.c68
1 files changed, 36 insertions, 32 deletions
diff --git a/chacha-poly1305.c b/chacha-poly1305.c
index 35c4bfe7..c5109b86 100644
--- a/chacha-poly1305.c
+++ b/chacha-poly1305.c
@@ -2,7 +2,7 @@
AEAD mechanism based on chacha and poly1305.
- Copyright (C) 2014 Niels Möller
+ Copyright (C) 2014, 2015 Niels Möller
This file is part of GNU Nettle.
@@ -31,6 +31,20 @@
not, see http://www.gnu.org/licenses/.
*/
+/* This implements chacha-poly1305 according to
+ draft-irtf-cfrg-chacha20-poly1305-08. The inputs to poly1305 are:
+
+ associated data
+ zero padding
+ ciphertext
+ zero padding
+ length of associated data (64-bit, little endian)
+ length of ciphertext (64-bit, little endian)
+
+ where the padding fields are 0-15 zero bytes, filling up to a
+ 16-byte boundary.
+*/
+
#if HAVE_CONFIG_H
# include "config.h"
#endif
@@ -62,7 +76,7 @@ chacha_poly1305_set_nonce (struct chacha_poly1305_ctx *ctx,
uint8_t subkey[32];
} u;
- chacha_set_nonce (&ctx->chacha, nonce);
+ chacha_set_nonce96 (&ctx->chacha, nonce);
/* Generate authentication key */
_chacha_core (u.x, ctx->chacha.state, CHACHA_ROUNDS);
poly1305_set_key (&ctx->poly1305, u.subkey);
@@ -84,6 +98,17 @@ poly1305_update (struct chacha_poly1305_ctx *ctx,
MD_UPDATE (ctx, length, data, COMPRESS, (void) 0);
}
+static void
+poly1305_pad (struct chacha_poly1305_ctx *ctx)
+{
+ if (ctx->index)
+ {
+ memset (ctx->block + ctx->index, 0,
+ POLY1305_BLOCK_SIZE - ctx->index);
+ _poly1305_block(&ctx->poly1305, ctx->block, 1);
+ ctx->index = 0;
+ }
+}
void
chacha_poly1305_update (struct chacha_poly1305_ctx *ctx,
size_t length, const uint8_t *data)
@@ -102,12 +127,8 @@ chacha_poly1305_encrypt (struct chacha_poly1305_ctx *ctx,
return;
assert (ctx->data_size % CHACHA_POLY1305_BLOCK_SIZE == 0);
- if (!ctx->data_size)
- {
- uint8_t buf[8];
- LE_WRITE_UINT64 (buf, ctx->auth_size);
- poly1305_update (ctx, sizeof(buf), buf);
- }
+ poly1305_pad (ctx);
+
chacha_crypt (&ctx->chacha, length, dst, src);
poly1305_update (ctx, length, dst);
ctx->data_size += length;
@@ -121,12 +142,8 @@ chacha_poly1305_decrypt (struct chacha_poly1305_ctx *ctx,
return;
assert (ctx->data_size % CHACHA_POLY1305_BLOCK_SIZE == 0);
- if (!ctx->data_size)
- {
- uint8_t buf[8];
- LE_WRITE_UINT64 (buf, ctx->auth_size);
- poly1305_update (ctx, sizeof(buf), buf);
- }
+ poly1305_pad (ctx);
+
poly1305_update (ctx, length, src);
chacha_crypt (&ctx->chacha, length, dst, src);
ctx->data_size += length;
@@ -136,27 +153,14 @@ void
chacha_poly1305_digest (struct chacha_poly1305_ctx *ctx,
size_t length, uint8_t *digest)
{
- uint8_t buf[8];
- if (!ctx->data_size)
- {
- LE_WRITE_UINT64 (buf, ctx->auth_size);
- poly1305_update (ctx, sizeof(buf), buf);
- }
- LE_WRITE_UINT64 (buf, ctx->data_size);
- poly1305_update (ctx, sizeof(buf), buf);
+ uint8_t buf[16];
- /* Final bytes. FIXME: Duplicated in poly1305_aes128.c */
- if (ctx->index > 0)
- {
- assert (ctx->index < POLY1305_BLOCK_SIZE);
+ poly1305_pad (ctx);
+ LE_WRITE_UINT64 (buf, ctx->auth_size);
+ LE_WRITE_UINT64 (buf + 8, ctx->data_size);
- ctx->block[ctx->index] = 1;
- memset (ctx->block + ctx->index + 1,
- 0, POLY1305_BLOCK_SIZE - 1 - ctx->index);
+ _poly1305_block (&ctx->poly1305, buf, 1);
- _poly1305_block (&ctx->poly1305, ctx->block, 0);
- }
-
poly1305_digest (&ctx->poly1305, &ctx->s);
memcpy (digest, &ctx->s.b, length);
}