aboutsummaryrefslogtreecommitdiffstats
path: root/g10/decrypt-data.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2018-02-27 20:11:20 +0000
committerWerner Koch <[email protected]>2018-02-27 20:11:34 +0000
commit618b86325f776f7250ad2bb09680e4bb427d7e50 (patch)
treef76c4c3098457b07dd92b9af2167abf1cf7320e8 /g10/decrypt-data.c
parentgpg: Factor common code out of the AEAD decryption function. (diff)
downloadgnupg-618b86325f776f7250ad2bb09680e4bb427d7e50.tar.gz
gnupg-618b86325f776f7250ad2bb09680e4bb427d7e50.zip
gpg: Simplify the AEAD decryption function.
* g10/decrypt-data.c (aead_set_nonce, aead_set_ad): Merge into ... (aead_set_nonce_and_ad): new single function. Change callers. (decrypt_data): Do not set the nonce and ad here. (aead_underflow): Get rid of the LAST_CHUNK_DONE hack. -- The main change here is that we now re-init the context only right before we decrypt and not after a checktag. Signed-off-by: Werner Koch <[email protected]>
Diffstat (limited to 'g10/decrypt-data.c')
-rw-r--r--g10/decrypt-data.c92
1 files changed, 41 insertions, 51 deletions
diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c
index b00f2bce1..5594d9055 100644
--- a/g10/decrypt-data.c
+++ b/g10/decrypt-data.c
@@ -117,11 +117,15 @@ release_dfx_context (decode_filter_ctx_t dfx)
}
-/* Set the nonce for AEAD. This also reset the decryption machinery
- * so that the handle can be used for a new chunk. */
+/* Set the nonce and the additional data for the current chunk. This
+ * also reset the decryption machinery * so that the handle can be
+ * used for a new chunk. If FINAL is set the final AEAD chunk is
+ * processed. */
static gpg_error_t
-aead_set_nonce (decode_filter_ctx_t dfx)
+aead_set_nonce_and_ad (decode_filter_ctx_t dfx, int final)
{
+ gpg_error_t err;
+ unsigned char ad[21];
unsigned char nonce[16];
int i;
@@ -151,16 +155,9 @@ aead_set_nonce (decode_filter_ctx_t dfx)
if (DBG_CRYPTO)
log_printhex (nonce, i, "nonce:");
- return gcry_cipher_setiv (dfx->cipher_hd, nonce, i);
-}
-
-
-/* Set the additional data for the current chunk. If FINAL is set the
- * final AEAD chunk is processed. */
-static gpg_error_t
-aead_set_ad (decode_filter_ctx_t dfx, int final)
-{
- unsigned char ad[21];
+ err = gcry_cipher_setiv (dfx->cipher_hd, nonce, i);
+ if (err)
+ return err;
ad[0] = (0xc0 | PKT_ENCRYPTED_AEAD);
ad[1] = 1;
@@ -371,14 +368,6 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
goto leave;
}
- rc = aead_set_nonce (dfx);
- if (rc)
- goto leave;
-
- rc = aead_set_ad (dfx, 0);
- if (rc)
- goto leave;
-
}
else /* CFB encryption. */
{
@@ -606,7 +595,6 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
size_t totallen = 0; /* The number of bytes to return on success or EOF. */
size_t off = 0; /* The offset into the buffer. */
size_t len; /* The current number of bytes in BUF+OFF. */
- int last_chunk_done = 0; /* Flag that we processed the last chunk. */
log_assert (size > 48); /* Our code requires at least this size. */
@@ -655,10 +643,10 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
}
/* log_printhex (dfx->holdback, dfx->holdbacklen, "holdback:"); */
- /* Decrypt the buffer. This requires a loop because a chunk may end
- * within the buffer. */
+ /* Decrypt the buffer. This first requires a loop to handle the
+ * case when a chunk ends within the buffer. */
if (DBG_FILTER)
- log_debug ("decrypt loop: chunklen=%ju total=%ju size=%zu len=%zu%s\n",
+ log_debug ("decrypt: chunklen=%ju total=%ju size=%zu len=%zu%s\n",
(uintmax_t)dfx->chunklen, (uintmax_t)dfx->total, size, len,
dfx->eof_seen? " eof":"");
@@ -669,6 +657,15 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
if (DBG_FILTER)
log_debug ("chunksize will be reached: n=%zu\n", n);
+
+ if (!dfx->chunklen)
+ {
+ /* First data for this chunk - prepare. */
+ err = aead_set_nonce_and_ad (dfx, 0);
+ if (err)
+ goto leave;
+ }
+
/* log_printhex (buf, n, "ciph:"); */
gcry_cipher_final (dfx->cipher_hd);
err = gcry_cipher_decrypt (dfx->cipher_hd, buf+off, n, NULL, 0);
@@ -710,7 +707,6 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
err = gpg_error (GPG_ERR_TRUNCATED);
goto leave;
}
- last_chunk_done = 1;
}
else
{
@@ -735,25 +731,23 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
err = aead_checktag (dfx, 0, tagbuf);
if (err)
goto leave;
+ dfx->chunklen = 0;
+ dfx->chunkindex++;
- /* Prepare a new chunk. */
- if (!last_chunk_done)
+ continue;
+ }
+
+ /* The bulk decryption of our buffer. */
+ if (len)
+ {
+ if (!dfx->chunklen)
{
- dfx->chunklen = 0;
- dfx->chunkindex++;
- err = aead_set_nonce (dfx);
- if (err)
- goto leave;
- err = aead_set_ad (dfx, 0);
+ /* First data for this chunk - prepare. */
+ err = aead_set_nonce_and_ad (dfx, 0);
if (err)
goto leave;
}
- continue;
- }
-
- if (!last_chunk_done)
- {
if (dfx->eof_seen)
{
/* This is the last block of the last chunk. Its length may
@@ -777,28 +771,24 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
if (dfx->eof_seen)
{
if (DBG_FILTER)
- log_debug ("eof seen: holdback buffer has the %s.\n",
- last_chunk_done? "final tag":"last and final tag");
+ log_debug ("eof seen: holdback buffer has the last and final tag\n");
- if (!last_chunk_done)
+ log_assert (dfx->holdbacklen >= 32);
+ if (dfx->chunklen)
{
- log_assert (dfx->holdbacklen >= 32);
err = aead_checktag (dfx, 0, dfx->holdback);
if (err)
goto leave;
+ dfx->chunklen = 0;
+ dfx->chunkindex++;
}
/* Check the final chunk. */
- if (dfx->chunklen)
- dfx->chunkindex++;
- err = aead_set_nonce (dfx);
- if (err)
- goto leave;
- err = aead_set_ad (dfx, 1);
+ err = aead_set_nonce_and_ad (dfx, 1);
if (err)
goto leave;
gcry_cipher_final (dfx->cipher_hd);
- /* Decrypt an empty string. */
+ /* Decrypt an empty string (using HOLDBACK as a dummy). */
err = gcry_cipher_decrypt (dfx->cipher_hd, dfx->holdback, 0, NULL, 0);
if (err)
{
@@ -806,7 +796,7 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
gpg_strerror (err));
goto leave;
}
- err = aead_checktag (dfx, 1, dfx->holdback+(last_chunk_done?0:16));
+ err = aead_checktag (dfx, 1, dfx->holdback+16);
if (err)
goto leave;
err = gpg_error (GPG_ERR_EOF);