diff options
author | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2015-02-28 18:04:34 +0200 |
---|---|---|
committer | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2015-02-28 18:04:34 +0200 |
commit | 5e66a4f8d5a63f58caeee367433dd8dd32346083 (patch) | |
tree | a535c3d472f3f8e501f43b721030aadc8c216ebd /cipher/cipher-ocb.c | |
parent | 505decf5369970219ddc9e78a20f97c623957b78 (diff) | |
download | libgcrypt-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/cipher-ocb.c')
-rw-r--r-- | cipher/cipher-ocb.c | 31 |
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) |