[PATCH] cipher: GCM: check that length of supplied tag is one of valid lengths
Jussi Kivilinna
jussi.kivilinna at iki.fi
Thu Mar 24 17:22:57 CET 2016
* cipher/cipher-gcm.c (is_tag_length_valid): New.
(_gcry_cipher_gcm_tag): Check that 'outbuflen' has valid tag length.
* tests/basic.c (_check_gcm_cipher): Add test-vectors with different
valid tag lengths and negative test vectors with invalid lengths.
--
NIST SP 800-38D limits tag lengths to following:
128, 120, 112, 104, 96, 64 and 32.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
0 files changed
diff --git a/cipher/cipher-gcm.c b/cipher/cipher-gcm.c
index 712641e..ea099ef 100644
--- a/cipher/cipher-gcm.c
+++ b/cipher/cipher-gcm.c
@@ -769,12 +769,32 @@ _gcry_cipher_gcm_geniv (gcry_cipher_hd_t c,
#endif
+static int
+is_tag_length_valid(size_t taglen)
+{
+ switch (taglen)
+ {
+ /* Allowed tag lengths from NIST SP 800-38D. */
+ case 128 / 8:
+ case 120 / 8:
+ case 112 / 8:
+ case 104 / 8:
+ case 96 / 8:
+ case 64 / 8:
+ case 32 / 8:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
static gcry_err_code_t
_gcry_cipher_gcm_tag (gcry_cipher_hd_t c,
byte * outbuf, size_t outbuflen, int check)
{
- if (outbuflen < GCRY_GCM_BLOCK_LEN)
- return GPG_ERR_BUFFER_TOO_SHORT;
+ if (!is_tag_length_valid(outbuflen))
+ return GPG_ERR_INV_LENGTH;
if (c->u_mode.gcm.datalen_over_limits)
return GPG_ERR_INV_LENGTH;
@@ -815,17 +835,11 @@ _gcry_cipher_gcm_tag (gcry_cipher_hd_t c,
if (!check)
{
- /* NB: We already checked that OUTBUF is large enough to hold
- the result. */
- memcpy (outbuf, c->u_mode.gcm.u_tag.tag, GCRY_GCM_BLOCK_LEN);
+ memcpy (outbuf, c->u_mode.gcm.u_tag.tag, outbuflen);
}
else
{
- /* OUTBUFLEN gives the length of the user supplied tag in OUTBUF
- * and thus we need to compare its length first. */
- if (outbuflen != GCRY_GCM_BLOCK_LEN
- || !buf_eq_const (outbuf, c->u_mode.gcm.u_tag.tag,
- GCRY_GCM_BLOCK_LEN))
+ if (!buf_eq_const (outbuf, c->u_mode.gcm.u_tag.tag, outbuflen))
return GPG_ERR_CHECKSUM;
}
diff --git a/tests/basic.c b/tests/basic.c
index 36a83d0..39957ad 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -1304,6 +1304,8 @@ _check_gcm_cipher (unsigned int step)
int inlen;
char out[MAX_DATA_LEN];
char tag[MAX_DATA_LEN];
+ int taglen;
+ int should_fail;
} tv[] =
{
/* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf */
@@ -1319,6 +1321,78 @@ _check_gcm_cipher (unsigned int step)
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12,
"", 0,
+ "",
+ 0,
+ "",
+ "\x58\xe2\xfc\xce\xfa\x7e\x30\x61\x36\x7f\x1d\x57\xa4\xe7\x45",
+ 15 },
+ { GCRY_CIPHER_AES,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12,
+ "", 0,
+ "",
+ 0,
+ "",
+ "\x58\xe2\xfc\xce\xfa\x7e\x30\x61\x36\x7f\x1d\x57\xa4\xe7",
+ 14 },
+ { GCRY_CIPHER_AES,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12,
+ "", 0,
+ "",
+ 0,
+ "",
+ "\x58\xe2\xfc\xce\xfa\x7e\x30\x61\x36\x7f\x1d\x57\xa4",
+ 13 },
+ { GCRY_CIPHER_AES,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12,
+ "", 0,
+ "",
+ 0,
+ "",
+ "\x58\xe2\xfc\xce\xfa\x7e\x30\x61\x36\x7f\x1d\x57",
+ 12 },
+ { GCRY_CIPHER_AES,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12,
+ "", 0,
+ "",
+ 0,
+ "",
+ "\x58\xe2\xfc\xce\xfa\x7e\x30\x61\x36\x7f\x1d",
+ 11, 1 },
+ { GCRY_CIPHER_AES,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12,
+ "", 0,
+ "",
+ 0,
+ "",
+ "\x58\xe2\xfc\xce\xfa\x7e\x30\x61",
+ 8 },
+ { GCRY_CIPHER_AES,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12,
+ "", 0,
+ "",
+ 0,
+ "",
+ "\x58\xe2\xfc\xce",
+ 4 },
+ { GCRY_CIPHER_AES,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12,
+ "", 0,
+ "",
+ 0,
+ "",
+ "\x58",
+ 1, 1 },
+ { GCRY_CIPHER_AES,
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 12,
+ "", 0,
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
16,
"\x03\x88\xda\xce\x60\xb6\xa3\x92\xf3\x28\xc2\xb9\x71\xb2\xfe\x78",
@@ -1570,9 +1644,14 @@ _check_gcm_cipher (unsigned int step)
if (memcmp (tv[i].plaintext, out, tv[i].inlen))
fail ("aes-gcm, decrypt mismatch entry %d (step %d)\n", i, step);
- err = gcry_cipher_gettag (hde, out, GCRY_GCM_BLOCK_LEN);
+ taglen2 = tv[i].taglen ? tv[i].taglen : GCRY_GCM_BLOCK_LEN;
+
+ err = gcry_cipher_gettag (hde, out, taglen2);
if (err)
{
+ if (tv[i].should_fail)
+ goto next_tv;
+
fail ("aes-gcm, gcry_cipher_gettag(%d) failed: %s\n",
i, gpg_strerror (err));
gcry_cipher_close (hde);
@@ -1580,11 +1659,10 @@ _check_gcm_cipher (unsigned int step)
return;
}
- if (memcmp (tv[i].tag, out, GCRY_GCM_BLOCK_LEN))
+ if (memcmp (tv[i].tag, out, taglen2))
fail ("aes-gcm, encrypt tag mismatch entry %d\n", i);
-
- err = gcry_cipher_checktag (hdd, out, GCRY_GCM_BLOCK_LEN);
+ err = gcry_cipher_checktag (hdd, out, taglen2);
if (err)
{
fail ("aes-gcm, gcry_cipher_checktag(%d) failed: %s\n",
@@ -1660,17 +1738,22 @@ _check_gcm_cipher (unsigned int step)
if (memcmp (tv[i].out, out, tv[i].inlen))
fail ("aes-gcm, encrypt mismatch entry %d, (byte-buf)\n", i);
- err = gcry_cipher_gettag (hde, tag, GCRY_GCM_BLOCK_LEN);
+ taglen2 = tv[i].taglen ? tv[i].taglen : GCRY_GCM_BLOCK_LEN;
+
+ err = gcry_cipher_gettag (hde, tag, taglen2);
if (err)
{
- fail ("aes-gcm, gcry_cipher_gettag(%d) (byte-buf) failed: %s\n",
- i, gpg_strerror (err));
+ if (tv[i].should_fail)
+ goto next_tv;
+
+ fail ("aes-gcm, gcry_cipher_gettag(%d, %d) (byte-buf) failed: %s\n",
+ i, taglen2, gpg_strerror (err));
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
return;
}
- if (memcmp (tv[i].tag, tag, GCRY_GCM_BLOCK_LEN))
+ if (memcmp (tv[i].tag, tag, taglen2))
fail ("aes-gcm, encrypt tag mismatch entry %d, (byte-buf)\n", i);
for (byteNum = 0; byteNum < tv[i].inlen; ++byteNum)
@@ -1689,7 +1772,7 @@ _check_gcm_cipher (unsigned int step)
if (memcmp (tv[i].plaintext, out, tv[i].inlen))
fail ("aes-gcm, decrypt mismatch entry %d\n", i);
- err = gcry_cipher_checktag (hdd, tag, GCRY_GCM_BLOCK_LEN);
+ err = gcry_cipher_checktag (hdd, tag, taglen2);
if (err)
{
fail ("aes-gcm, gcry_cipher_checktag(%d) (byte-buf) failed: %s\n",
@@ -1699,6 +1782,15 @@ _check_gcm_cipher (unsigned int step)
return;
}
+ if (tv[i].should_fail)
+ {
+ fail ("aes-gcm, negative test succeeded %d\n", i);
+ gcry_cipher_close (hde);
+ gcry_cipher_close (hdd);
+ return;
+ }
+
+next_tv:
gcry_cipher_close (hde);
gcry_cipher_close (hdd);
}
More information about the Gcrypt-devel
mailing list