summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2011-04-11 19:36:48 (GMT)
committerWerner Koch <wk@gnupg.org>2011-04-11 19:36:48 (GMT)
commiteaee23fe56ca2d6bbbde8e883568b6b46445a240 (patch)
treecb746373efae0141cd15dad414d903922ea7eec6
parent3c18377a55085faf4df745034056bac53565effa (diff)
downloadlibgcrypt-eaee23fe56ca2d6bbbde8e883568b6b46445a240.tar.gz
libgcrypt-eaee23fe56ca2d6bbbde8e883568b6b46445a240.tar.xz
CTR mode may now be used with arbitrary long data chunks.
-rw-r--r--NEWS2
-rw-r--r--cipher/ChangeLog5
-rw-r--r--cipher/cipher.c42
-rw-r--r--tests/ChangeLog2
-rw-r--r--tests/basic.c50
5 files changed, 90 insertions, 11 deletions
diff --git a/NEWS b/NEWS
index add5152..b8d50e5 100644
--- a/NEWS
+++ b/NEWS
@@ -31,6 +31,8 @@ Noteworthy changes in version 1.5.x (unreleased)
* New cipher algorithm mode for AES-WRAP. [also in 1.4.6]
+ * CTR mode may now be used with data chunks of arbitrary length.
+
* Fixed minor memory leak in DSA key generation. [also in 1.4.5]
* No more switching to FIPS mode if /proc/version is not
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index 4cde857..ce955a1 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,5 +1,10 @@
2011-04-11 Werner Koch <wk@g10code.com>
+ * cipher.c (_gcry_cipher_setctr): Clear unused lastiv info.
+ (gcry_cipher_ctl) <GCRYCTL_SET_CTR>: Implement by calling
+ _gcry_cipher_setctr.
+ (do_ctr_encrypt): Save last counter and reuse it.
+
* cipher.c (do_ctr_encrypt): Allow arbitrary length inputs to
match the 1.4 behaviour.
diff --git a/cipher/cipher.c b/cipher/cipher.c
index e5bb2e0..90fdb17 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -219,8 +219,9 @@ struct gcry_cipher_handle
unsigned char ctr[MAX_BLOCKSIZE];
} u_ctr;
+ /* Space to save an IV or CTR for chaining operations. */
unsigned char lastiv[MAX_BLOCKSIZE];
- int unused; /* Number of unused bytes in the IV. */
+ int unused; /* Number of unused bytes in LASTIV. */
/* What follows are two contexts of the cipher in use. The first
one needs to be aligned well enough for the cipher operation
@@ -1456,6 +1457,22 @@ do_ctr_encrypt (gcry_cipher_hd_t c,
if (outbuflen < inbuflen)
return GPG_ERR_BUFFER_TOO_SHORT;
+ /* First process a left over encrypted counter. */
+ if (c->unused)
+ {
+ gcry_assert (c->unused < blocksize);
+ i = blocksize - c->unused;
+ for (n=0; c->unused && n < inbuflen; c->unused--, n++, i++)
+ {
+ /* XOR input with encrypted counter and store in output. */
+ outbuf[n] = inbuf[n] ^ c->lastiv[i];
+ }
+ inbuf += n;
+ outbuf += n;
+ inbuflen -= n;
+ }
+
+
/* Use a bulk method if available. */
nblocks = inbuflen / blocksize;
if (nblocks && c->bulk.ctr_enc)
@@ -1490,6 +1507,12 @@ do_ctr_encrypt (gcry_cipher_hd_t c,
outbuf[n] = inbuf[n] ^ tmp[n % blocksize];
}
+ /* Save the unused bytes of the counter. */
+ n %= blocksize;
+ c->unused = (blocksize - n) % blocksize;
+ if (c->unused)
+ memcpy (c->lastiv+n, tmp+n, c->unused);
+
wipememory (tmp, sizeof tmp);
}
@@ -1884,9 +1907,15 @@ gpg_error_t
_gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen)
{
if (ctr && ctrlen == hd->cipher->blocksize)
- memcpy (hd->u_ctr.ctr, ctr, hd->cipher->blocksize);
+ {
+ memcpy (hd->u_ctr.ctr, ctr, hd->cipher->blocksize);
+ hd->unused = 0;
+ }
else if (!ctr || !ctrlen)
- memset (hd->u_ctr.ctr, 0, hd->cipher->blocksize);
+ {
+ memset (hd->u_ctr.ctr, 0, hd->cipher->blocksize);
+ hd->unused = 0;
+ }
else
return gpg_error (GPG_ERR_INV_ARG);
return 0;
@@ -1945,12 +1974,7 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen)
break;
case GCRYCTL_SET_CTR: /* Deprecated; use gcry_cipher_setctr. */
- if (buffer && buflen == h->cipher->blocksize)
- memcpy (h->u_ctr.ctr, buffer, h->cipher->blocksize);
- else if (buffer == NULL || buflen == 0)
- memset (h->u_ctr.ctr, 0, h->cipher->blocksize);
- else
- rc = GPG_ERR_INV_ARG;
+ rc = gpg_err_code (_gcry_cipher_setctr (h, buffer, buflen));
break;
case 61: /* Disable weak key detection (private). */
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 3793149..ccaf3bd 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -2,7 +2,7 @@
* basic.c (mismatch): New.
(check_ctr_cipher): Remove length error code checks. Add
- truncation checks.
+ truncation and streaming checks.
2011-04-04 Werner Koch <wk@g10code.com>
diff --git a/tests/basic.c b/tests/basic.c
index a20e731..2216476 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -365,7 +365,7 @@ check_ctr_cipher (void)
unsigned char plaintext[MAX_DATA_LEN];
int inlen;
char out[MAX_DATA_LEN];
- } data[5];
+ } data[8];
} tv[] =
{
/* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf */
@@ -470,6 +470,54 @@ check_ctr_cipher (void)
{"", 0, "" }
}
},
+ /* Tests to see whether it works correctly as a stream cipher. */
+ { 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" },
+ {"\x51\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
+ 17,
+ "\xff\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e\x5b\x4f\x09\x02\x0d\xb0\x3e\xab" },
+ {"\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_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" },
+ {"\xc1\xbe",
+ 2,
+ "\x4d\x61" },
+ {"\xe2\x2e\x40",
+ 3,
+ "\x91\xb6\x20" },
+ {"\x9f",
+ 1,
+ "\xe3" },
+ {"\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+ 9,
+ "\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" },
+ {"\x51\x30\xc8\x1c\x46\xa3\x5c\xe4\x11",
+ 9,
+ "\xff\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e" },
+
+ { "", 0, "" }
+ }
+ },
#if USE_CAST5
/* A selfmade test vector using an 64 bit block cipher. */
{ GCRY_CIPHER_CAST5,