[PATCH] Fix in-place encryption for OCB mode
Jussi Kivilinna
jussi.kivilinna at iki.fi
Mon Feb 23 20:21:33 CET 2015
* cipher/cipher-ocb.c (ocb_checksum): New.
(ocb_crypt): Move checksum calculation outside main crypt loop, do
checksum calculation for encryption before inbuf is overwritten.
* tests/basic.c (check_ocb_cipher): Rename to ...
(do_check_ocb_cipher): ... to this and add argument for testing
in-place encryption/decryption.
(check_ocb_cipher): New.
--
Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
cipher/cipher-ocb.c | 31 ++++++++++++++++++++++++++++---
tests/basic.c | 41 ++++++++++++++++++++++++++++++++++++++---
2 files changed, 66 insertions(+), 6 deletions(-)
diff --git a/cipher/cipher-ocb.c b/cipher/cipher-ocb.c
index 25466f0..652683c 100644
--- a/cipher/cipher-ocb.c
+++ b/cipher/cipher-ocb.c
@@ -299,6 +299,21 @@ _gcry_cipher_ocb_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf,
}
+/* Checksumming for encrypt and decrypt. */
+static void ocb_checksum(unsigned char *chksum, const unsigned char *plainbuf,
+ size_t nblks)
+{
+ while (nblks > 0)
+ {
+ /* Checksum_i = Checksum_{i-1} xor P_i */
+ buf_xor_1(chksum, plainbuf, OCB_BLOCK_LEN);
+
+ plainbuf += OCB_BLOCK_LEN;
+ nblks--;
+ }
+}
+
+
/* Common code for encrypt and decrypt. */
static gcry_err_code_t
ocb_crypt (gcry_cipher_hd_t c, int encrypt,
@@ -308,6 +323,7 @@ ocb_crypt (gcry_cipher_hd_t c, int encrypt,
unsigned char l_tmp[OCB_BLOCK_LEN];
unsigned int burn = 0;
unsigned int nburn;
+ size_t nblks = inbuflen / OCB_BLOCK_LEN;
/* Check that a nonce and thus a key has been set and that we are
not yet in end of data state. */
@@ -324,6 +340,12 @@ ocb_crypt (gcry_cipher_hd_t c, int encrypt,
else if ((inbuflen % OCB_BLOCK_LEN))
return GPG_ERR_INV_LENGTH; /* We support only full blocks for now. */
+ if (encrypt)
+ {
+ /* Checksum_i = Checksum_{i-1} xor P_i */
+ ocb_checksum (c->u_ctr.ctr, inbuf, nblks);
+ }
+
/* Encrypt all full blocks. */
while (inbuflen >= OCB_BLOCK_LEN)
{
@@ -341,15 +363,18 @@ ocb_crypt (gcry_cipher_hd_t c, int encrypt,
burn = nburn > burn ? nburn : burn;
buf_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN);
- /* Checksum_i = Checksum_{i-1} xor P_i */
- buf_xor_1 (c->u_ctr.ctr, encrypt? inbuf : outbuf, OCB_BLOCK_LEN);
-
inbuf += OCB_BLOCK_LEN;
inbuflen -= OCB_BLOCK_LEN;
outbuf += OCB_BLOCK_LEN;
outbuflen =- OCB_BLOCK_LEN;
}
+ if (!encrypt)
+ {
+ /* Checksum_i = Checksum_{i-1} xor P_i */
+ ocb_checksum (c->u_ctr.ctr, outbuf - nblks * OCB_BLOCK_LEN, nblks);
+ }
+
/* Encrypt final partial block. Note that we expect INBUFLEN to be
shorter than OCB_BLOCK_LEN (see above). */
if (inbuflen)
diff --git a/tests/basic.c b/tests/basic.c
index 869b381..6ebc056 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -2781,7 +2781,7 @@ check_ccm_cipher (void)
static void
-check_ocb_cipher (void)
+do_check_ocb_cipher (int inplace)
{
/* Note that we use hex strings and not binary strings in TV. That
makes it easier to maintain the test vectors. */
@@ -3028,7 +3028,18 @@ check_ocb_cipher (void)
err = gcry_cipher_final (hde);
if (!err)
- err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN, plain, plainlen);
+ {
+ if (inplace)
+ {
+ memcpy(out, plain, plainlen);
+ err = gcry_cipher_encrypt (hde, out, plainlen, NULL, 0);
+ }
+ else
+ {
+ err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
+ plain, plainlen);
+ }
+ }
if (err)
{
fail ("cipher-ocb, gcry_cipher_encrypt failed (tv %d): %s\n",
@@ -3075,7 +3086,19 @@ check_ocb_cipher (void)
/* Now for the decryption. */
err = gcry_cipher_final (hdd);
if (!err)
- err = gcry_cipher_decrypt (hdd, out, plainlen, NULL, 0);
+ {
+ if (inplace)
+ {
+ err = gcry_cipher_decrypt (hdd, out, plainlen, NULL, 0);
+ }
+ else
+ {
+ unsigned char tmp[MAX_DATA_LEN];
+
+ memcpy(tmp, out, plainlen);
+ err = gcry_cipher_decrypt (hdd, out, plainlen, tmp, plainlen);
+ }
+ }
if (err)
{
fail ("cipher-ocb, gcry_cipher_decrypt (tv %d) failed: %s\n",
@@ -3130,6 +3153,18 @@ check_ocb_cipher (void)
static void
+check_ocb_cipher (void)
+{
+ /* Check OCB cipher with separate destination and source buffers for
+ * encryption/decryption. */
+ do_check_ocb_cipher(0);
+
+ /* Check OCB cipher with inplace encrypt/decrypt. */
+ do_check_ocb_cipher(1);
+}
+
+
+static void
check_stream_cipher (void)
{
static const struct tv
More information about the Gcrypt-devel
mailing list