mirror of
git://git.gnupg.org/gnupg.git
synced 2025-04-13 22:21:09 +02:00
gpg: Factor common code out of the AEAD decryption function.
* g10/decrypt-data.c (aead_underflow): Factor reading and checking code code out to ... (fill_buffer, aead_checktag): new functions. -- Here is a simple test script to check against a set of encrypted files with naming convention like "symenc-aead-eax-c6-56.asc" # ------------------------ >8 ------------------------ set -e GPG=../g10/gpg for file in "$@"; do echo "${file##*/}" | ( IFS=- read dummy1 dummy2 mode cbyte len rest len="${len%.*}" cbyte="${cbyte#c}" [ "$dummy1" != "symenc" -o "$dummy2" != "aead" ] && continue echo "checking mode=$mode chunkbyte=$cbyte length=$len" if ! $GPG --no-options --rfc4880bis --batch --passphrase "abc" \ -d < $file >tmp.plain 2>/dev/null; then echo "Decryption failed for $file" >&2 exit 2 fi plainlen=$(wc -c <tmp.plain) if [ $plainlen -ne $len ]; then echo "Plaintext length mismatch for $file (want=$len have=$plainlen)" >&2 exit 2 fi ) done echo "all files are okay" >&2 # ------------------------ 8< ------------------------ Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
b703ba725d
commit
ad989373f1
@ -192,6 +192,28 @@ aead_set_ad (decode_filter_ctx_t dfx, int final)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper to check the 16 byte tag in TAGBUF. The FINAL flag is only
|
||||||
|
* for debug messages. */
|
||||||
|
static gpg_error_t
|
||||||
|
aead_checktag (decode_filter_ctx_t dfx, int final, const void *tagbuf)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
|
||||||
|
if (DBG_FILTER)
|
||||||
|
log_printhex (tagbuf, 16, "tag:");
|
||||||
|
err = gcry_cipher_checktag (dfx->cipher_hd, tagbuf, 16);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("gcry_cipher_checktag%s failed: %s\n",
|
||||||
|
final? " (final)":"", gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (DBG_FILTER)
|
||||||
|
log_debug ("%stag is valid\n", final?"final ":"");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Decrypt the data, specified by ED with the key DEK.
|
* Decrypt the data, specified by ED with the key DEK.
|
||||||
*/
|
*/
|
||||||
@ -531,6 +553,49 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Fill BUFFER with up to NBYTES-OFFSET from STREAM utilizing
|
||||||
|
* information from the context DFX. Returns the new offset which is
|
||||||
|
* the number of bytes read plus the original offset. On EOF the
|
||||||
|
* respective flag in DFX is set. */
|
||||||
|
static size_t
|
||||||
|
fill_buffer (decode_filter_ctx_t dfx, iobuf_t stream,
|
||||||
|
byte *buffer, size_t nbytes, size_t offset)
|
||||||
|
{
|
||||||
|
size_t nread = offset;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
if (dfx->partial)
|
||||||
|
{
|
||||||
|
for (; nread < nbytes; nread++ )
|
||||||
|
{
|
||||||
|
if ((c = iobuf_get (stream)) == -1)
|
||||||
|
{
|
||||||
|
dfx->eof_seen = 1; /* Normal EOF. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buffer[nread] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (; nread < nbytes && dfx->length; nread++, dfx->length--)
|
||||||
|
{
|
||||||
|
c = iobuf_get (stream);
|
||||||
|
if (c == -1)
|
||||||
|
{
|
||||||
|
dfx->eof_seen = 3; /* Premature EOF. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buffer[nread] = c;
|
||||||
|
}
|
||||||
|
if (!dfx->length)
|
||||||
|
dfx->eof_seen = 1; /* Normal EOF. */
|
||||||
|
}
|
||||||
|
|
||||||
|
return nread;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The core of the AEAD decryption. This is the underflow function of
|
/* The core of the AEAD decryption. This is the underflow function of
|
||||||
* the aead_decode_filter. */
|
* the aead_decode_filter. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
@ -542,7 +607,6 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
|
|||||||
size_t off = 0; /* The offset into the buffer. */
|
size_t off = 0; /* The offset into the buffer. */
|
||||||
size_t len; /* The current number of bytes in BUF+OFF. */
|
size_t len; /* The current number of bytes in BUF+OFF. */
|
||||||
int last_chunk_done = 0; /* Flag that we processed the last chunk. */
|
int last_chunk_done = 0; /* Flag that we processed the last chunk. */
|
||||||
int c;
|
|
||||||
|
|
||||||
log_assert (size > 48); /* Our code requires at least this size. */
|
log_assert (size > 48); /* Our code requires at least this size. */
|
||||||
|
|
||||||
@ -560,39 +624,12 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
|
|||||||
* chunksize. After the last data byte from the last chunk 32 more
|
* chunksize. After the last data byte from the last chunk 32 more
|
||||||
* bytes are expected for the last chunk's tag and the following
|
* bytes are expected for the last chunk's tag and the following
|
||||||
* final chunk's tag. To detect the EOF we need to try reading at least
|
* final chunk's tag. To detect the EOF we need to try reading at least
|
||||||
* one further byte; however we try to ready 16 extra bytes to avoid
|
* one further byte; however we try to read 16 extra bytes to avoid
|
||||||
* single byte reads in some lower layers. The outcome is that we
|
* single byte reads in some lower layers. The outcome is that we
|
||||||
* have up to 48 extra extra octets which we will later put into the
|
* have up to 48 extra extra octets which we will later put into the
|
||||||
* holdback buffer for the next invocation (which handles the EOF
|
* holdback buffer for the next invocation (which handles the EOF
|
||||||
* case). */
|
* case). */
|
||||||
if (dfx->partial)
|
len = fill_buffer (dfx, a, buf, size, len);
|
||||||
{
|
|
||||||
for (; len < size; len++ )
|
|
||||||
{
|
|
||||||
if ((c = iobuf_get (a)) == -1)
|
|
||||||
{
|
|
||||||
dfx->eof_seen = 1; /* Normal EOF. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf[len] = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (; len < size && dfx->length; len++, dfx->length--)
|
|
||||||
{
|
|
||||||
c = iobuf_get (a);
|
|
||||||
if (c == -1)
|
|
||||||
{
|
|
||||||
dfx->eof_seen = 3; /* Premature EOF. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf[len] = c;
|
|
||||||
}
|
|
||||||
if (!dfx->length)
|
|
||||||
dfx->eof_seen = 1; /* Normal EOF. */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len < 32)
|
if (len < 32)
|
||||||
{
|
{
|
||||||
/* Not enough data for the last two tags. */
|
/* Not enough data for the last two tags. */
|
||||||
@ -673,47 +710,19 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
|
|||||||
err = gpg_error (GPG_ERR_TRUNCATED);
|
err = gpg_error (GPG_ERR_TRUNCATED);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
len = 0;
|
|
||||||
last_chunk_done = 1;
|
last_chunk_done = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
len = dfx->holdbacklen;
|
len = 0;
|
||||||
if (dfx->partial)
|
dfx->holdbacklen = fill_buffer (dfx, a, dfx->holdback, 48,
|
||||||
{
|
dfx->holdbacklen);
|
||||||
for (; len < 48; len++ )
|
if (dfx->holdbacklen < 32)
|
||||||
{
|
|
||||||
if ((c = iobuf_get (a)) == -1)
|
|
||||||
{
|
|
||||||
dfx->eof_seen = 1; /* Normal EOF. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dfx->holdback[len] = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (; len < 48 && dfx->length; len++, dfx->length--)
|
|
||||||
{
|
|
||||||
c = iobuf_get (a);
|
|
||||||
if (c == -1)
|
|
||||||
{
|
|
||||||
dfx->eof_seen = 3; /* Premature EOF. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dfx->holdback[len] = c;
|
|
||||||
}
|
|
||||||
if (!dfx->length)
|
|
||||||
dfx->eof_seen = 1; /* Normal EOF. */
|
|
||||||
}
|
|
||||||
if (len < 32)
|
|
||||||
{
|
{
|
||||||
/* Not enough data for the last two tags. */
|
/* Not enough data for the last two tags. */
|
||||||
err = gpg_error (GPG_ERR_TRUNCATED);
|
err = gpg_error (GPG_ERR_TRUNCATED);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
dfx->holdbacklen = len;
|
|
||||||
len = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else /* We already have the full tag. */
|
else /* We already have the full tag. */
|
||||||
@ -723,18 +732,9 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
|
|||||||
memmove (buf + off, buf + off + 16, len - 16);
|
memmove (buf + off, buf + off + 16, len - 16);
|
||||||
len -= 16;
|
len -= 16;
|
||||||
}
|
}
|
||||||
if (DBG_CRYPTO)
|
err = aead_checktag (dfx, 0, tagbuf);
|
||||||
log_printhex (tagbuf, 16, "tag:");
|
|
||||||
err = gcry_cipher_checktag (dfx->cipher_hd, tagbuf, 16);
|
|
||||||
if (err)
|
if (err)
|
||||||
{
|
goto leave;
|
||||||
if (DBG_FILTER)
|
|
||||||
log_debug ("gcry_cipher_checktag failed (1): %s\n",
|
|
||||||
gpg_strerror (err));
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
if (DBG_FILTER)
|
|
||||||
log_debug ("tag is valid\n");
|
|
||||||
|
|
||||||
/* Prepare a new chunk. */
|
/* Prepare a new chunk. */
|
||||||
if (!last_chunk_done)
|
if (!last_chunk_done)
|
||||||
@ -783,18 +783,9 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
|
|||||||
if (!last_chunk_done)
|
if (!last_chunk_done)
|
||||||
{
|
{
|
||||||
log_assert (dfx->holdbacklen >= 32);
|
log_assert (dfx->holdbacklen >= 32);
|
||||||
|
err = aead_checktag (dfx, 0, dfx->holdback);
|
||||||
if (DBG_FILTER)
|
|
||||||
log_printhex (dfx->holdback, 16, "tag:");
|
|
||||||
err = gcry_cipher_checktag (dfx->cipher_hd, dfx->holdback, 16);
|
|
||||||
if (err)
|
if (err)
|
||||||
{
|
goto leave;
|
||||||
log_error ("gcry_cipher_checktag failed (2): %s\n",
|
|
||||||
gpg_strerror (err));
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
if (DBG_FILTER)
|
|
||||||
log_debug ("tag is valid\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the final chunk. */
|
/* Check the final chunk. */
|
||||||
@ -815,19 +806,9 @@ aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len)
|
|||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
if (DBG_CRYPTO)
|
err = aead_checktag (dfx, 1, dfx->holdback+(last_chunk_done?0:16));
|
||||||
log_printhex (dfx->holdback+(last_chunk_done?0:16), 16, "tag:");
|
|
||||||
err = gcry_cipher_checktag (dfx->cipher_hd,
|
|
||||||
dfx->holdback+(last_chunk_done?0:16), 16);
|
|
||||||
if (err)
|
if (err)
|
||||||
{
|
goto leave;
|
||||||
if (DBG_FILTER)
|
|
||||||
log_debug ("gcry_cipher_checktag failed (final): %s\n",
|
|
||||||
gpg_strerror (err));
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
if (DBG_FILTER)
|
|
||||||
log_debug ("final tag is valid\n");
|
|
||||||
err = gpg_error (GPG_ERR_EOF);
|
err = gpg_error (GPG_ERR_EOF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user