summaryrefslogtreecommitdiff
path: root/cipher/cipher-ocb.c
diff options
context:
space:
mode:
Diffstat (limited to 'cipher/cipher-ocb.c')
-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)