diff options
-rw-r--r-- | cipher/cipher-ocb.c | 31 | ||||
-rw-r--r-- | tests/basic.c | 41 |
2 files changed, 66 insertions, 6 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) diff --git a/tests/basic.c b/tests/basic.c index 869b3818..6ebc0568 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 |