summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2011-04-11 17:21:47 (GMT)
committerWerner Koch <wk@gnupg.org>2011-04-11 17:21:47 (GMT)
commit3c18377a55085faf4df745034056bac53565effa (patch)
treee84bdc5da3c8471a23aac4f495f02890c1a9744f
parent50c35d1f2a0c8cb1f7480ba0bd046088b636afb9 (diff)
downloadlibgcrypt-3c18377a55085faf4df745034056bac53565effa.tar.gz
libgcrypt-3c18377a55085faf4df745034056bac53565effa.tar.xz
Allow for truncation in CTR mode.
This re-enables the behaviour of Libgcrypt 1.4. Such truncation is used by libotr and the current error-ed out here. The bug was introduced due to a rewrite of the function and the undocumented feature of truncating OTR data.
-rw-r--r--cipher/ChangeLog5
-rw-r--r--cipher/cipher.c12
-rw-r--r--tests/ChangeLog6
-rw-r--r--tests/basic.c136
4 files changed, 124 insertions, 35 deletions
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index df27bab..4cde857 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,8 @@
+2011-04-11 Werner Koch <wk@g10code.com>
+
+ * cipher.c (do_ctr_encrypt): Allow arbitrary length inputs to
+ match the 1.4 behaviour.
+
2011-04-04 Werner Koch <wk@g10code.com>
* ecc.c (compute_keygrip): Release L1 while parsing "curve".
diff --git a/cipher/cipher.c b/cipher/cipher.c
index a2f8bb9..e5bb2e0 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -1453,22 +1453,22 @@ do_ctr_encrypt (gcry_cipher_hd_t c,
unsigned int blocksize = c->cipher->blocksize;
unsigned int nblocks;
- /* FIXME: This code does only work on complete blocks. */
-
if (outbuflen < inbuflen)
return GPG_ERR_BUFFER_TOO_SHORT;
- if ((inbuflen % blocksize))
- return GPG_ERR_INV_LENGTH;
-
+ /* Use a bulk method if available. */
nblocks = inbuflen / blocksize;
if (nblocks && c->bulk.ctr_enc)
{
c->bulk.ctr_enc (&c->context.c, c->u_ctr.ctr, outbuf, inbuf, nblocks);
inbuf += nblocks * blocksize;
outbuf += nblocks * blocksize;
+ inbuflen -= nblocks * blocksize;
}
- else
+
+ /* If we don't have a bulk method use the standard method. We also
+ use this method for the a remaining partial block. */
+ if (inbuflen)
{
unsigned char tmp[MAX_BLOCKSIZE];
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 0f5918a..3793149 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,9 @@
+2011-04-11 Werner Koch <wk@g10code.com>
+
+ * basic.c (mismatch): New.
+ (check_ctr_cipher): Remove length error code checks. Add
+ truncation checks.
+
2011-04-04 Werner Koch <wk@g10code.com>
* keygrip.c (main): Add option --repetitions.
diff --git a/tests/basic.c b/tests/basic.c
index 185091e..a20e731 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -69,6 +69,22 @@ fail (const char *format, ...)
}
static void
+mismatch (const void *expected, size_t expectedlen,
+ const void *computed, size_t computedlen)
+{
+ const unsigned char *p;
+
+ fprintf (stderr, "expected:");
+ for (p = expected; expectedlen; p++, expectedlen--)
+ fprintf (stderr, " %02x", *p);
+ fprintf (stderr, "\ncomputed:");
+ for (p = computed; computedlen; p++, computedlen--)
+ fprintf (stderr, " %02x", *p);
+ fprintf (stderr, "\n");
+}
+
+
+static void
die (const char *format, ...)
{
va_list arg_ptr;
@@ -349,8 +365,7 @@ check_ctr_cipher (void)
unsigned char plaintext[MAX_DATA_LEN];
int inlen;
char out[MAX_DATA_LEN];
- }
- data[MAX_DATA_LEN];
+ } data[5];
} tv[] =
{
/* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf */
@@ -369,6 +384,8 @@ check_ctr_cipher (void)
{ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
16,
"\x1e\x03\x1d\xda\x2f\xbe\x03\xd1\x79\x21\x70\xa0\xf3\x00\x9c\xee" },
+
+ { "", 0, "" }
}
},
{ GCRY_CIPHER_AES192,
@@ -387,6 +404,7 @@ check_ctr_cipher (void)
{ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
16,
"\x4f\x78\xa7\xf6\xd2\x98\x09\x58\x5a\x97\xda\xec\x58\xc6\xb0\x50" },
+ { "", 0, "" }
}
},
{ GCRY_CIPHER_AES256,
@@ -404,7 +422,80 @@ check_ctr_cipher (void)
"\x2b\x09\x30\xda\xa2\x3d\xe9\x4c\xe8\x70\x17\xba\x2d\x84\x98\x8d" },
{ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
16,
- "\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6\x13\xc2\xdd\x08\x45\x79\x41\xa6" }
+ "\xdf\xc9\xc5\x8d\xb6\x7a\xad\xa6\x13\xc2\xdd\x08\x45\x79\x41\xa6" },
+ { "", 0, "" }
+ }
+ },
+ /* Some truncation tests. With a truncated second block and
+ also with a single truncated block. */
+ { GCRY_CIPHER_AES,
+ "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ {{"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+ 16,
+ "\x87\x4d\x61\x91\xb6\x20\xe3\x26\x1b\xef\x68\x64\x99\x0d\xb6\xce" },
+ {"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e",
+ 15,
+ "\x98\x06\xf6\x6b\x79\x70\xfd\xff\x86\x17\x18\x7b\xb9\xff\xfd" },
+ {"", 0, "" }
+ }
+ },
+ { GCRY_CIPHER_AES,
+ "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ {{"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+ 16,
+ "\x87\x4d\x61\x91\xb6\x20\xe3\x26\x1b\xef\x68\x64\x99\x0d\xb6\xce" },
+ {"\xae",
+ 1,
+ "\x98" },
+ {"", 0, "" }
+ }
+ },
+ { GCRY_CIPHER_AES,
+ "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ {{"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17",
+ 15,
+ "\x87\x4d\x61\x91\xb6\x20\xe3\x26\x1b\xef\x68\x64\x99\x0d\xb6" },
+ {"", 0, "" }
+ }
+ },
+ { GCRY_CIPHER_AES,
+ "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ {{"\x6b",
+ 1,
+ "\x87" },
+ {"", 0, "" }
+ }
+ },
+#if USE_CAST5
+ /* A selfmade test vector using an 64 bit block cipher. */
+ { GCRY_CIPHER_CAST5,
+ "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8",
+ {{"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+ 16,
+ "\xe8\xa7\xac\x68\xca\xca\xa0\x20\x10\xcb\x1b\xcc\x79\x2c\xc4\x48" },
+ {"\xae\x2d\x8a\x57\x1e\x03\xac\x9c",
+ 8,
+ "\x16\xe8\x72\x77\xb0\x98\x29\x68" },
+ {"\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
+ 8,
+ "\x9a\xb3\xa8\x03\x3b\xb4\x14\xba" },
+ {"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\xa1\x00",
+ 10,
+ "\x31\x5e\xd3\xfb\x1b\x8d\xd1\xf9\xb0\x83" },
+ { "", 0, "" }
+ }
+ },
+#endif /*USE_CAST5*/
+ { 0,
+ "",
+ "",
+ {
+ {"", 0, "" }
}
}
};
@@ -417,6 +508,9 @@ check_ctr_cipher (void)
fprintf (stderr, " Starting CTR cipher checks.\n");
for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
{
+ if (!tv[i].algo)
+ continue;
+
err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_CTR, 0);
if (!err)
err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_CTR, 0);
@@ -485,7 +579,11 @@ check_ctr_cipher (void)
}
if (memcmp (tv[i].data[j].out, out, tv[i].data[j].inlen))
- fail ("aes-ctr, encrypt mismatch entry %d:%d\n", i, j);
+ {
+ fail ("aes-ctr, encrypt mismatch entry %d:%d\n", i, j);
+ mismatch (tv[i].data[j].out, tv[i].data[j].inlen,
+ out, tv[i].data[j].inlen);
+ }
err = gcry_cipher_decrypt (hdd, out, tv[i].data[j].inlen, NULL, 0);
if (err)
@@ -498,7 +596,11 @@ check_ctr_cipher (void)
}
if (memcmp (tv[i].data[j].plaintext, out, tv[i].data[j].inlen))
- fail ("aes-ctr, decrypt mismatch entry %d:%d\n", i, j);
+ {
+ fail ("aes-ctr, decrypt mismatch entry %d:%d\n", i, j);
+ mismatch (tv[i].data[j].plaintext, tv[i].data[j].inlen,
+ out, tv[i].data[j].inlen);
+ }
}
@@ -509,18 +611,6 @@ check_ctr_cipher (void)
if (err)
fail ("aes-ctr, encryption failed for valid input");
- err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
- "1234567890123456", 15);
- if (gpg_err_code (err) != GPG_ERR_INV_LENGTH)
- fail ("aes-ctr, too short input returned wrong error: %s\n",
- gpg_strerror (err));
-
- err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
- "12345678901234567", 17);
- if (gpg_err_code (err) != GPG_ERR_INV_LENGTH)
- fail ("aes-ctr, too long input returned wrong error: %s\n",
- gpg_strerror (err));
-
err = gcry_cipher_encrypt (hde, out, 15,
"1234567890123456", 16);
if (gpg_err_code (err) != GPG_ERR_BUFFER_TOO_SHORT)
@@ -545,18 +635,6 @@ check_ctr_cipher (void)
if (err)
fail ("aes-ctr, decryption failed for valid input");
- err = gcry_cipher_decrypt (hde, out, MAX_DATA_LEN,
- "1234567890123456", 15);
- if (gpg_err_code (err) != GPG_ERR_INV_LENGTH)
- fail ("aes-ctr, too short input returned wrong error: %s\n",
- gpg_strerror (err));
-
- err = gcry_cipher_decrypt (hde, out, MAX_DATA_LEN,
- "12345678901234567", 17);
- if (gpg_err_code (err) != GPG_ERR_INV_LENGTH)
- fail ("aes-ctr, too long input returned wrong error: %s\n",
- gpg_strerror (err));
-
err = gcry_cipher_decrypt (hde, out, 15,
"1234567890123456", 16);
if (gpg_err_code (err) != GPG_ERR_BUFFER_TOO_SHORT)