From 305cc878d395475c46b4ef52f4764bd0c85bf8ac Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Sat, 18 Apr 2015 17:41:34 +0300 Subject: Add OCB bulk crypt/auth functions for AES/AES-NI * cipher/cipher-internal.h (gcry_cipher_handle): Add bulk.ocb_crypt and bulk.ocb_auth. (_gcry_cipher_ocb_get_l): New prototype. * cipher/cipher-ocb.c (get_l): Rename to ... (_gcry_cipher_ocb_get_l): ... this. (_gcry_cipher_ocb_authenticate, ocb_crypt): Use bulk function when available. * cipher/cipher.c (_gcry_cipher_open_internal): Setup OCB bulk functions for AES. * cipher/rijndael-aesni.c (get_l, aesni_ocb_enc, aes_ocb_dec) (_gcry_aes_aesni_ocb_crypt, _gcry_aes_aesni_ocb_auth): New. * cipher/rijndael.c [USE_AESNI] (_gcry_aes_aesni_ocb_crypt) (_gcry_aes_aesni_ocb_auth): New prototypes. (_gcry_aes_ocb_crypt, _gcry_aes_ocb_auth): New. * src/cipher.h (_gcry_aes_ocb_crypt, _gcry_aes_ocb_auth): New prototypes. * tests/basic.c (check_ocb_cipher_largebuf): New. (check_ocb_cipher): Add large buffer encryption/decryption test. -- Patch adds bulk encryption/decryption/authentication code for AES-NI accelerated AES. Benchmark on Intel i5-4570 (3200 Mhz, turbo off): Before: AES | nanosecs/byte mebibytes/sec cycles/byte OCB enc | 2.12 ns/B 449.7 MiB/s 6.79 c/B OCB dec | 2.12 ns/B 449.6 MiB/s 6.79 c/B OCB auth | 2.07 ns/B 459.9 MiB/s 6.64 c/B After: AES | nanosecs/byte mebibytes/sec cycles/byte OCB enc | 0.292 ns/B 3262.5 MiB/s 0.935 c/B OCB dec | 0.297 ns/B 3212.2 MiB/s 0.950 c/B OCB auth | 0.260 ns/B 3666.1 MiB/s 0.832 c/B Signed-off-by: Jussi Kivilinna --- tests/basic.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) (limited to 'tests/basic.c') diff --git a/tests/basic.c b/tests/basic.c index 6ebc0568..1175b386 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -3152,6 +3152,172 @@ do_check_ocb_cipher (int inplace) } +static void +check_ocb_cipher_largebuf (int algo, int keylen, const char *tagexpect) +{ + static const unsigned char key[32] = + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; + static const unsigned char nonce[12] = + "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x00\x01\x02\x03"; + const size_t buflen = 1024 * 1024 * 2 + 32; + unsigned char *inbuf; + unsigned char *outbuf; + gpg_error_t err = 0; + gcry_cipher_hd_t hde, hdd; + unsigned char tag[16]; + int i; + + inbuf = xmalloc(buflen); + if (!inbuf) + { + fail ("out-of-memory\n"); + return; + } + outbuf = xmalloc(buflen); + if (!outbuf) + { + fail ("out-of-memory\n"); + xfree(inbuf); + return; + } + + for (i = 0; i < buflen; i++) + inbuf[i] = 'a'; + + err = gcry_cipher_open (&hde, algo, GCRY_CIPHER_MODE_OCB, 0); + if (!err) + err = gcry_cipher_open (&hdd, algo, GCRY_CIPHER_MODE_OCB, 0); + if (err) + { + fail ("cipher-ocb, gcry_cipher_open failed (large, algo %d): %s\n", + algo, gpg_strerror (err)); + goto out_free; + } + + err = gcry_cipher_setkey (hde, key, keylen); + if (!err) + err = gcry_cipher_setkey (hdd, key, keylen); + if (err) + { + fail ("cipher-ocb, gcry_cipher_setkey failed (large, algo %d): %s\n", + algo, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + goto out_free; + } + + err = gcry_cipher_setiv (hde, nonce, 12); + if (!err) + err = gcry_cipher_setiv (hdd, nonce, 12); + if (err) + { + fail ("cipher-ocb, gcry_cipher_setiv failed (large, algo %d): %s\n", + algo, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + goto out_free; + } + + err = gcry_cipher_authenticate (hde, inbuf, buflen); + if (err) + { + fail ("cipher-ocb, gcry_cipher_authenticate failed (large, algo %d): %s\n", + algo, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + goto out_free; + } + + err = gcry_cipher_final (hde); + if (!err) + { + err = gcry_cipher_encrypt (hde, outbuf, buflen, inbuf, buflen); + } + if (err) + { + fail ("cipher-ocb, gcry_cipher_encrypt failed (large, algo %d): %s\n", + algo, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + goto out_free; + } + + /* Check that the tag matches. */ + err = gcry_cipher_gettag (hde, tag, 16); + if (err) + { + fail ("cipher_ocb, gcry_cipher_gettag failed (large, algo %d): %s\n", + algo, gpg_strerror (err)); + } + if (memcmp (tagexpect, tag, 16)) + { + mismatch (tagexpect, 16, tag, 16); + fail ("cipher-ocb, encrypt tag mismatch (large, algo %d)\n", algo); + } + + err = gcry_cipher_authenticate (hdd, inbuf, buflen); + if (err) + { + fail ("cipher-ocb, gcry_cipher_authenticate failed (large, algo %d): %s\n", + algo, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + goto out_free; + } + + /* Now for the decryption. */ + err = gcry_cipher_final (hdd); + if (!err) + { + err = gcry_cipher_decrypt (hdd, outbuf, buflen, NULL, 0); + } + if (err) + { + fail ("cipher-ocb, gcry_cipher_decrypt (large, algo %d) failed: %s\n", + algo, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + goto out_free; + } + + /* We still have TAG from the encryption. */ + err = gcry_cipher_checktag (hdd, tag, 16); + if (err) + { + fail ("cipher-ocb, gcry_cipher_checktag failed (large, algo %d): %s\n", + algo, gpg_strerror (err)); + } + + /* Check that the decrypt output matches the original plaintext. */ + if (memcmp (inbuf, outbuf, buflen)) + { + /*mismatch (inbuf, buflen, outbuf, buflen);*/ + fail ("cipher-ocb, decrypt data mismatch (large, algo %d)\n", algo); + } + + /* Check that gettag also works for decryption. */ + err = gcry_cipher_gettag (hdd, tag, 16); + if (err) + { + fail ("cipher_ocb, decrypt gettag failed (large, algo %d): %s\n", + algo, gpg_strerror (err)); + } + if (memcmp (tagexpect, tag, 16)) + { + mismatch (tagexpect, 16, tag, 16); + fail ("cipher-ocb, decrypt tag mismatch (large, algo %d)\n", algo); + } + + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + +out_free: + xfree(outbuf); + xfree(inbuf); +} + + static void check_ocb_cipher (void) { @@ -3161,6 +3327,14 @@ check_ocb_cipher (void) /* Check OCB cipher with inplace encrypt/decrypt. */ do_check_ocb_cipher(1); + + /* Check large buffer encryption/decryption. */ + check_ocb_cipher_largebuf(GCRY_CIPHER_AES, 16, + "\xf5\xf3\x12\x7d\x58\x2d\x96\xe8" + "\x33\xfd\x7a\x4f\x42\x60\x5d\x20"); + check_ocb_cipher_largebuf(GCRY_CIPHER_AES256, 32, + "\xfa\x26\xa5\xbf\xf6\x7d\x3a\x8d" + "\xfe\x96\x67\xc9\xc8\x41\x03\x51"); } -- cgit v1.2.1