summaryrefslogtreecommitdiff
path: root/cipher
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@iki.fi>2015-02-28 18:04:34 +0200
committerJussi Kivilinna <jussi.kivilinna@iki.fi>2015-02-28 18:04:34 +0200
commit5e66a4f8d5a63f58caeee367433dd8dd32346083 (patch)
treea535c3d472f3f8e501f43b721030aadc8c216ebd /cipher
parent505decf5369970219ddc9e78a20f97c623957b78 (diff)
downloadlibgcrypt-5e66a4f8d5a63f58caeee367433dd8dd32346083.tar.gz
Fix in-place encryption for OCB mode
* 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@iki.fi>
Diffstat (limited to 'cipher')
-rw-r--r--cipher/cipher-ocb.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/cipher/cipher-ocb.c b/cipher/cipher-ocb.c
index 25466f0d..652683ca 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)