#include "memxor.h"
#include "nettle-internal.h"
#include "macros.h"
+#include "md-internal.h"
#include "ctr-internal.h"
#include "block-internal.h"
#include "bswap-internal.h"
gcm_hash_sizes(key, &ctx->iv, 0, length);
}
- ctx->ctr = ctx->iv;
- /* Increment the rightmost 32 bits. */
- INCREMENT (4, ctx->ctr.b + GCM_BLOCK_SIZE - 4);
-
- /* Reset the rest of the message-dependent state. */
+ /* Reset the message-dependent state. */
block16_zero(&ctx->x);
ctx->auth_size = ctx->data_size = 0;
}
gcm_update(struct gcm_ctx *ctx, const struct gcm_key *key,
size_t length, const uint8_t *data)
{
- assert(ctx->auth_size % GCM_BLOCK_SIZE == 0);
- assert(ctx->data_size == 0);
+ unsigned index;
- gcm_hash(key, &ctx->x, length, data);
+ assert (!ctx->data_size);
+ if (!length)
+ return;
+ index = ctx->auth_size & (GCM_BLOCK_SIZE - 1);
ctx->auth_size += length;
+
+ if (index > 0)
+ {
+ /* Attempt to fill buffer. */
+ MD_FILL_OR_RETURN (ctx->ctr.b, index, length, data);
+ _ghash_update (key, &ctx->x, 1, ctx->ctr.b);
+ }
+
+ data = _ghash_update (key, &ctx->x, length / GCM_BLOCK_SIZE, data);
+ /* Copy leftover data. */
+ index = length & (GCM_BLOCK_SIZE - 1);
+ memcpy (ctx->ctr.b, data, index);
+}
+
+/* Must be called at end of accociated data, i.e., by the first call
+ of either gcm_encrypt, gcm_decrypt or gcm_digest. */
+static void
+gcm_pad_adata (struct gcm_ctx *ctx, const struct gcm_key *key)
+{
+ unsigned index = ctx->auth_size & (GCM_BLOCK_SIZE - 1);
+ if (index > 0)
+ {
+ memset (ctx->ctr.b + index, 0, GCM_BLOCK_SIZE - index);
+ _ghash_update (key, &ctx->x, 1, ctx->ctr.b);
+ }
}
static nettle_fill16_func gcm_fill;
}
#endif
+/* Pad any associated data, and then initialize the ctr field for
+ encrypt/decrypt operation. */
+static void
+gcm_init_crypt (struct gcm_ctx *ctx, const struct gcm_key *key)
+{
+ gcm_pad_adata (ctx, key);
+ ctx->ctr = ctx->iv;
+ /* Increment the rightmost 32 bits. */
+ INCREMENT (4, ctx->ctr.b + GCM_BLOCK_SIZE - 4);
+}
+
void
gcm_encrypt (struct gcm_ctx *ctx, const struct gcm_key *key,
const void *cipher, nettle_cipher_func *f,
{
assert(ctx->data_size % GCM_BLOCK_SIZE == 0);
+ if (!length)
+ return;
+
+ if (!ctx->data_size)
+ gcm_init_crypt (ctx, key);
+
_nettle_ctr_crypt16(cipher, f, gcm_fill, ctx->ctr.b, length, dst, src);
gcm_hash(key, &ctx->x, length, dst);
{
assert(ctx->data_size % GCM_BLOCK_SIZE == 0);
+ if (!length)
+ return;
+
+ if (!ctx->data_size)
+ gcm_init_crypt (ctx, key);
+
gcm_hash(key, &ctx->x, length, src);
_nettle_ctr_crypt16(cipher, f, gcm_fill, ctx->ctr.b, length, dst, src);
union nettle_block16 buffer;
assert (length <= GCM_BLOCK_SIZE);
+ if (!ctx->data_size)
+ gcm_pad_adata (ctx, key);
gcm_hash_sizes(key, &ctx->x, ctx->auth_size, ctx->data_size);
#include <string.h>
-/* Internal helper macros for Merkle-Damgård hash functions. Assumes the context
- structs includes the following fields:
-
- uint8_t block[...]; // Buffer holding one block
- unsigned int index; // Index into block
-*/
-
-#define MD_FILL_OR_RETURN(ctx, length, data) \
+/* Internal helper macros for Merkle-Damgård hash functions. */
+#define MD_FILL_OR_RETURN(block, index, length, data) \
do { \
- unsigned __md_left = sizeof((ctx)->block) - (ctx)->index; \
+ unsigned __md_left = sizeof(block) - index; \
if ((length) < __md_left) \
{ \
- memcpy((ctx)->block + (ctx)->index, (data), (length)); \
- (ctx)->index += (length); \
+ memcpy(block + index, (data), (length)); \
+ index += (length); \
return; \
} \
- memcpy((ctx)->block + (ctx)->index, (data), __md_left); \
+ memcpy(block + index, (data), __md_left); \
(data) += __md_left; \
(length) -= __md_left; \
} while(0)
assert (nonce->length == aead->nonce_size);
aead->set_nonce(ctx, nonce->data);
}
- if (aead->update && authtext->length)
- aead->update(ctx, authtext->length, authtext->data);
-
- if (offset > 0)
- aead->encrypt(ctx, offset, out + out_align, in + in_align);
-
- if (offset < cleartext->length)
- aead->encrypt(ctx, cleartext->length - offset,
- out + out_align + offset, in + in_align + offset);
+ if (aead->update)
+ {
+ size_t a_offset = offset <= authtext->length ? offset : authtext->length;
+ aead->update(ctx, a_offset, authtext->data);
+ aead->update(ctx, 0, NULL);
+ aead->update(ctx, authtext->length - a_offset, authtext->data + a_offset);
+ }
+ aead->encrypt(ctx, offset, out + out_align, in + in_align);
+ aead->encrypt(ctx, 0, out + out_align, NULL);
+ aead->encrypt(ctx, cleartext->length - offset,
+ out + out_align + offset, in + in_align + offset);
if (!MEMEQ(cleartext->length, out + out_align, ciphertext->data))
{