summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels Möller <nisse@lysator.liu.se>2021-09-18 10:00:02 +0200
committerNiels Möller <nisse@lysator.liu.se>2023-02-06 20:20:01 +0100
commitc05ab7d805a2b45fd00979c18145c95fca47ecdb (patch)
treef33bfd27e2eb459fea49c2668cbc5c5f4d7b50c1
parenteb48e209db6fb6d6ce0005de88ba362b6fcbe933 (diff)
downloadnettle-c05ab7d805a2b45fd00979c18145c95fca47ecdb.tar.gz
Implement OCB mode
-rw-r--r--ChangeLog14
-rw-r--r--Makefile.in3
-rw-r--r--nettle-meta.h1
-rw-r--r--ocb-aes128-meta.c110
-rw-r--r--ocb.c256
-rw-r--r--ocb.h106
-rw-r--r--testsuite/Makefile.in2
-rw-r--r--testsuite/ocb-test.c147
8 files changed, 637 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 618c57dc..5974e545 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -714,6 +714,20 @@
* nettle.texinfo: Delete explicit node pointers in nettle.texinfo
Instead, rely on makeinfo's automatic pointer creation.
(Cipher functions): Split into nodes, with proper menu.
+2021-09-18 Niels Möller <nisse@lysator.liu.se>
+
+ Implement OCB mode. RFC 7253.
+ * ocb.c (ocb_set_key, ocb_set_nonce, ocb_update, ocb_encrypt)
+ (ocb_decrypt, ocb_digest): New file and functions.
+ * ocb.h: Corresponding header file.
+ * ocb-aes128-meta.c (nettle_ocb_aes128): New aead struct.
+ * Makefile.in (nettle_SOURCES): Add new source files.
+ (HEADERS): Add ocb.h.
+ * testsuite/ocb-test.c: New tests.
+ * testsuite/Makefile.in (TS_NETTLE_SOURCES): Add ocb-test.c
+
+ * testsuite/testutils.c (test_aead): Check plaintext/ciphertext
+ before checking digest.
2021-09-14 Niels Möller <nisse@lysator.liu.se>
diff --git a/Makefile.in b/Makefile.in
index cd4993e8..4f4242e0 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -134,6 +134,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c aes-decrypt-table.c \
nettle-lookup-hash.c \
nettle-meta-aeads.c nettle-meta-armors.c \
nettle-meta-ciphers.c nettle-meta-hashes.c nettle-meta-macs.c \
+ ocb.c ocb-aes128-meta.c \
pbkdf2.c pbkdf2-hmac-gosthash94.c pbkdf2-hmac-sha1.c \
pbkdf2-hmac-sha256.c pbkdf2-hmac-sha384.c pbkdf2-hmac-sha512.c \
poly1305-aes.c poly1305-internal.c poly1305-update.c \
@@ -238,7 +239,7 @@ HEADERS = aes.h arcfour.h arctwo.h asn1.h blowfish.h balloon.h \
md5.h md5-compat.h \
memops.h memxor.h \
nettle-meta.h nettle-types.h \
- pbkdf2.h \
+ ocb.h pbkdf2.h \
pgp.h pkcs1.h pss.h pss-mgf1.h realloc.h ripemd160.h rsa.h \
salsa20.h sexp.h serpent.h \
sha.h sha1.h sha2.h sha3.h sm3.h sm4.h streebog.h twofish.h \
diff --git a/nettle-meta.h b/nettle-meta.h
index 19dc96c5..2b548d7a 100644
--- a/nettle-meta.h
+++ b/nettle-meta.h
@@ -203,6 +203,7 @@ extern const struct nettle_aead nettle_gcm_camellia256;
extern const struct nettle_aead nettle_gcm_sm4;
extern const struct nettle_aead nettle_eax_aes128;
extern const struct nettle_aead nettle_chacha_poly1305;
+extern const struct nettle_aead nettle_ocb_aes128; /* With 128-bit tag */
struct nettle_armor
{
diff --git a/ocb-aes128-meta.c b/ocb-aes128-meta.c
new file mode 100644
index 00000000..efd94a9c
--- /dev/null
+++ b/ocb-aes128-meta.c
@@ -0,0 +1,110 @@
+/* ocb-aes128-meta.c
+
+ Copyright (C) 2021 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "aes.h"
+#include "ocb.h"
+#include "nettle-meta.h"
+
+#define OCB_IV_SIZE 12
+
+struct ocb_aes128_ctx
+{
+ struct ocb_key key;
+ struct ocb_ctx ocb;
+ struct aes128_ctx encrypt;
+ struct aes128_ctx decrypt;
+};
+
+static void
+ocb_aes128_set_key (struct ocb_aes128_ctx *ctx, const uint8_t *key)
+{
+ aes128_set_encrypt_key (&ctx->encrypt, key);
+ aes128_set_decrypt_key (&ctx->decrypt, key);
+ ocb_set_key (&ctx->key, &ctx->encrypt, (nettle_cipher_func *) aes128_encrypt);
+}
+
+static void
+ocb_aes128_set_nonce (struct ocb_aes128_ctx *ctx,
+ const uint8_t *iv)
+{
+ ocb_set_nonce (&ctx->ocb, &ctx->encrypt, (nettle_cipher_func *) aes128_encrypt,
+ OCB_DIGEST_SIZE, OCB_IV_SIZE, iv);
+}
+
+static void
+ocb_aes128_update (struct ocb_aes128_ctx *ctx,
+ size_t length, const uint8_t *data)
+{
+ ocb_update (&ctx->ocb, &ctx->key, &ctx->encrypt, (nettle_cipher_func *) aes128_encrypt,
+ length, data);
+}
+
+static void
+ocb_aes128_encrypt(struct ocb_aes128_ctx *ctx,
+ size_t length, uint8_t *dst, const uint8_t *src)
+{
+ ocb_encrypt (&ctx->ocb, &ctx->key, &ctx->encrypt, (nettle_cipher_func *) aes128_encrypt,
+ length, dst, src);
+}
+
+static void
+ocb_aes128_decrypt(struct ocb_aes128_ctx *ctx,
+ size_t length, uint8_t *dst, const uint8_t *src)
+{
+ ocb_decrypt (&ctx->ocb, &ctx->key, &ctx->encrypt, (nettle_cipher_func *) aes128_encrypt,
+ &ctx->decrypt, (nettle_cipher_func *) aes128_decrypt,
+ length, dst, src);
+}
+
+static void
+ocb_aes128_digest(struct ocb_aes128_ctx *ctx, size_t length, uint8_t *digest)
+{
+ ocb_digest (&ctx->ocb, &ctx->key, &ctx->encrypt, (nettle_cipher_func *) aes128_encrypt,
+ length, digest);
+}
+
+const struct nettle_aead
+nettle_ocb_aes128 =
+ { "ocb_aes128", sizeof(struct ocb_aes128_ctx),
+ OCB_BLOCK_SIZE, AES128_KEY_SIZE,
+ OCB_IV_SIZE, OCB_DIGEST_SIZE,
+ (nettle_set_key_func *) ocb_aes128_set_key,
+ (nettle_set_key_func *) ocb_aes128_set_key,
+ (nettle_set_key_func *) ocb_aes128_set_nonce,
+ (nettle_hash_update_func *) ocb_aes128_update,
+ (nettle_crypt_func *) ocb_aes128_encrypt,
+ (nettle_crypt_func *) ocb_aes128_decrypt,
+ (nettle_hash_digest_func *) ocb_aes128_digest
+ };
diff --git a/ocb.c b/ocb.c
new file mode 100644
index 00000000..91ab3b17
--- /dev/null
+++ b/ocb.c
@@ -0,0 +1,256 @@
+/* ocb.c
+
+ OCB AEAD mode, RFC 7253
+
+ Copyright (C) 2021 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include "ocb.h"
+#include "block-internal.h"
+
+/* Returns 64 bits from the concatenation (u0, u1), starting from bit offset. */
+static inline uint64_t
+extract(uint64_t u0, uint64_t u1, unsigned offset)
+{
+ if (offset == 0)
+ return u0;
+#if WORDS_BIGENDIAN
+ return (u0 << offset) | (u1 >> (64 - offset));
+#else
+ uint64_t t;
+ u0 = __builtin_bswap64(u0);
+ u1 = __builtin_bswap64(u1);
+ t = (u0 << offset) | (u1 >> (64 - offset));
+ return __builtin_bswap64(t);
+#endif
+}
+
+void
+ocb_set_key (struct ocb_key *key, const void *cipher, nettle_cipher_func *f)
+{
+ static const union nettle_block16 zero_block;
+ f (cipher, OCB_BLOCK_SIZE, key->L[0].b, zero_block.b);
+ block16_mulx_be (&key->L[1], &key->L[0]);
+ block16_mulx_be (&key->L[2], &key->L[1]);
+}
+
+static void
+update_offset(const struct ocb_key *key,
+ union nettle_block16 *offset, size_t i)
+{
+ unsigned ntz = __builtin_ctzll(i);
+ if (ntz > 0)
+ {
+ union nettle_block16 diff;
+ block16_mulx_be (&diff, &key->L[2]);
+ while (--ntz > 0)
+ block16_mulx_be (&diff, &diff);
+
+ block16_xor (offset, &diff);
+ }
+ else
+ block16_xor (offset, &key->L[2]);
+}
+
+static void
+pad_block (union nettle_block16 *block, size_t length, const uint8_t *data)
+{
+ memcpy (block->b, data, length);
+ block->b[length] = 0x80;
+ memset (block->b + length + 1, 0, OCB_BLOCK_SIZE - 1 - length);
+}
+
+void
+ocb_set_nonce (struct ocb_ctx *ctx,
+ const void *cipher, nettle_cipher_func *f,
+ size_t tag_length,
+ size_t nonce_length, const uint8_t *nonce)
+{
+ union nettle_block16 top;
+ uint64_t stretch;
+
+ unsigned bottom;
+ assert (nonce_length < 16);
+ assert (tag_length > 0);
+ assert (tag_length <= 16);
+
+ /* Bit size, or zero for tag_length == 16 */
+ top.b[0] = (tag_length & 15) << 4;
+ memset (top.b + 1, 0, 15 - nonce_length);
+ top.b[15 - nonce_length] |= 1;
+ memcpy (top.b + 16 - nonce_length, nonce, nonce_length);
+ bottom = top.b[15] & 0x3f;
+ top.b[15] &= 0xc0;
+
+ f (cipher, OCB_BLOCK_SIZE, top.b, top.b);
+
+ stretch = top.u64[0];
+#if WORDS_BIGENDIAN
+ stretch ^= (top.u64[0] << 8) | (top.u64[1] >> 56);
+#else
+ stretch ^= (top.u64[0] >> 8) | (top.u64[1] << 56);
+#endif
+
+ ctx->initial.u64[0] = extract(top.u64[0], top.u64[1], bottom);
+ ctx->initial.u64[1] = extract(top.u64[1], stretch, bottom);
+ ctx->sum.u64[0] = ctx->sum.u64[1] = 0;
+ ctx->checksum.u64[0] = ctx->checksum.u64[1] = 0;
+
+ ctx->data_count = ctx->message_count = 0;
+}
+
+void
+ocb_update (struct ocb_ctx *ctx, const struct ocb_key *key,
+ const void *cipher, nettle_cipher_func *f,
+ size_t length, const uint8_t *data)
+{
+ if (data == 0)
+ return;
+
+ assert (ctx->message_count == 0);
+
+ if (ctx->data_count == 0)
+ ctx->offset.u64[0] = ctx->offset.u64[1] = 0;
+
+ for (; length >= OCB_BLOCK_SIZE;
+ length -= OCB_BLOCK_SIZE, data += OCB_BLOCK_SIZE)
+ {
+ union nettle_block16 block;
+ update_offset (key, &ctx->offset, ++ctx->data_count);
+ memxor3 (block.b, ctx->offset.b, data, OCB_BLOCK_SIZE);
+ f (cipher, OCB_BLOCK_SIZE, block.b, block.b);
+ block16_xor (&ctx->sum, &block);
+ }
+ if (length > 0)
+ {
+ union nettle_block16 block;
+ pad_block (&block, length, data);
+ block16_xor (&ctx->offset, &key->L[0]);
+ block16_xor (&block, &ctx->offset);
+
+ f (cipher, OCB_BLOCK_SIZE, block.b, block.b);
+ block16_xor (&ctx->sum, &block);
+ }
+}
+
+void
+ocb_encrypt (struct ocb_ctx *ctx, const struct ocb_key *key,
+ const void *cipher, nettle_cipher_func *f,
+ size_t length, uint8_t *dst, const uint8_t *src)
+{
+ if (length == 0)
+ return;
+
+ if (ctx->message_count == 0)
+ ctx->offset = ctx->initial;
+
+ for (; length >= OCB_BLOCK_SIZE;
+ length -= OCB_BLOCK_SIZE, src += OCB_BLOCK_SIZE, dst += OCB_BLOCK_SIZE)
+ {
+ union nettle_block16 block;
+ memxor (ctx->checksum.b, src, OCB_BLOCK_SIZE);
+ update_offset (key, &ctx->offset, ++ctx->message_count);
+
+ memxor3 (block.b, ctx->offset.b, src, OCB_BLOCK_SIZE);
+ f (cipher, OCB_BLOCK_SIZE, block.b, block.b);
+
+ memxor3 (dst, ctx->offset.b, block.b, OCB_BLOCK_SIZE);
+ }
+
+ if (length > 0)
+ {
+ union nettle_block16 block;
+ pad_block (&block, length, src);
+ block16_xor (&ctx->checksum, &block);
+
+ block16_xor (&ctx->offset, &key->L[0]);
+ f (cipher, OCB_BLOCK_SIZE, block.b, ctx->offset.b);
+ memxor3 (dst, block.b, src, length);
+ ctx->message_count++;
+ }
+}
+
+void
+ocb_decrypt (struct ocb_ctx *ctx, const struct ocb_key *key,
+ const void *encrypt_ctx, nettle_cipher_func *encrypt,
+ const void *decrypt_ctx, nettle_cipher_func *decrypt,
+ size_t length, uint8_t *dst, const uint8_t *src)
+{
+ if (length == 0)
+ return;
+
+ if (ctx->message_count == 0)
+ ctx->offset = ctx->initial;
+
+ for (; length >= OCB_BLOCK_SIZE;
+ length -= OCB_BLOCK_SIZE, src += OCB_BLOCK_SIZE, dst += OCB_BLOCK_SIZE)
+ {
+ union nettle_block16 block;
+ update_offset (key, &ctx->offset, ++ctx->message_count);
+
+ memxor3 (block.b, ctx->offset.b, src, OCB_BLOCK_SIZE);
+ decrypt (decrypt_ctx, OCB_BLOCK_SIZE, block.b, block.b);
+
+ memxor3 (dst, ctx->offset.b, block.b, OCB_BLOCK_SIZE);
+ memxor (ctx->checksum.b, dst, OCB_BLOCK_SIZE);
+ }
+
+ if (length > 0)
+ {
+ union nettle_block16 block;
+
+ block16_xor (&ctx->offset, &key->L[0]);
+ encrypt (encrypt_ctx, OCB_BLOCK_SIZE, block.b, ctx->offset.b);
+ memxor3 (dst, block.b, src, length);
+
+ pad_block (&block, length, dst);
+ block16_xor (&ctx->checksum, &block);
+ ctx->message_count++;
+ }
+}
+
+void
+ocb_digest (struct ocb_ctx *ctx, const struct ocb_key *key,
+ const void *cipher, nettle_cipher_func *f,
+ size_t length, uint8_t *digest)
+{
+ union nettle_block16 block;
+ assert (length <= OCB_DIGEST_SIZE);
+ block16_xor3 (&block, &key->L[1],
+ (ctx->message_count > 0) ? &ctx->offset : &ctx->initial);
+ block16_xor (&block, &ctx->checksum);
+ f (cipher, OCB_BLOCK_SIZE, block.b, block.b);
+ memxor3 (digest, block.b, ctx->sum.b, length);
+}
diff --git a/ocb.h b/ocb.h
new file mode 100644
index 00000000..67bbe748
--- /dev/null
+++ b/ocb.h
@@ -0,0 +1,106 @@
+/* ocb.h
+
+ OCB AEAD mode, RFC 7253
+
+ Copyright (C) 2021 Niels Möller
+
+ This file is part of GNU Nettle.
+
+ GNU Nettle is free software: you can redistribute it and/or
+ modify it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ or both in parallel, as here.
+
+ GNU Nettle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_OCB_H_INCLUDED
+#define NETTLE_OCB_H_INCLUDED
+
+#include "nettle-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Name mangling */
+#define ocb_set_key nettle_ocb_set_key
+#define ocb_set_nonce nettle_ocb_set_nonce
+#define ocb_update nettle_ocb_update
+#define ocb_encrypt nettle_ocb_encrypt
+#define ocb_decrypt nettle_ocb_decrypt
+#define ocb_digest nettle_ocb_digest
+
+#define OCB_BLOCK_SIZE 16
+#define OCB_DIGEST_SIZE 16
+
+struct ocb_key {
+ /* L_*, L_$ and L_0 */
+ union nettle_block16 L[3];
+};
+
+struct ocb_ctx {
+ /* Initial offset, Offset_0 in the spec. */
+ union nettle_block16 initial;
+ /* Offset, updated per block. */
+ union nettle_block16 offset;
+ /* Authentication for the associated data */
+ union nettle_block16 sum;
+ /* Authentication for the message */
+ union nettle_block16 checksum;
+ /* Count of processed blocks. */
+ size_t data_count;
+ size_t message_count;
+};
+
+void
+ocb_set_key (struct ocb_key *key, const void *cipher, nettle_cipher_func *f);
+
+void
+ocb_set_nonce (struct ocb_ctx *ctx,
+ const void *cipher, nettle_cipher_func *f,
+ size_t tag_length, size_t nonce_length, const uint8_t *nonce);
+
+void
+ocb_update (struct ocb_ctx *ctx, const struct ocb_key *key,
+ const void *cipher, nettle_cipher_func *f,
+ size_t length, const uint8_t *data);
+
+void
+ocb_encrypt (struct ocb_ctx *ctx, const struct ocb_key *key,
+ const void *cipher, nettle_cipher_func *f,
+ size_t length, uint8_t *dst, const uint8_t *src);
+
+void
+ocb_decrypt (struct ocb_ctx *ctx, const struct ocb_key *key,
+ const void *encrypt_ctx, nettle_cipher_func *encrypt,
+ const void *decrypt_ctx, nettle_cipher_func *decrypt,
+ size_t length, uint8_t *dst, const uint8_t *src);
+
+void
+ocb_digest (struct ocb_ctx *ctx, const struct ocb_key *key,
+ const void *cipher, nettle_cipher_func *f,
+ size_t length, uint8_t *digest);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_OCB_H_INCLUDED */
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index 025ab72d..be0cb965 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -28,7 +28,7 @@ TS_NETTLE_SOURCES = aes-test.c aes-keywrap-test.c arcfour-test.c arctwo-test.c \
serpent-test.c twofish-test.c version-test.c \
knuth-lfib-test.c \
cbc-test.c cfb-test.c ctr-test.c gcm-test.c eax-test.c ccm-test.c \
- cmac-test.c siv-test.c siv-gcm-test.c \
+ cmac-test.c ocb-test.c siv-test.c siv-gcm-test.c \
poly1305-test.c chacha-poly1305-test.c \
hmac-test.c umac-test.c \
meta-hash-test.c meta-cipher-test.c\
diff --git a/testsuite/ocb-test.c b/testsuite/ocb-test.c
new file mode 100644
index 00000000..abeea714
--- /dev/null
+++ b/testsuite/ocb-test.c
@@ -0,0 +1,147 @@
+#include "testutils.h"
+#include "nettle-internal.h"
+
+void
+test_main(void)
+{
+ /* From RFC 7253 */
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX(""), /* auth data */
+ SHEX(""), /* plaintext */
+ SHEX(""), /* ciphertext */
+ SHEX("BBAA99887766554433221100"), /* nonce */
+ SHEX("785407BFFFC8AD9EDCC5520AC9111EE6")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX("0001020304050607"), /* auth data */
+ SHEX("0001020304050607"), /* plaintext */
+ SHEX("6820B3657B6F615A"), /* ciphertext */
+ SHEX("BBAA99887766554433221101"), /* nonce */
+ SHEX("5725BDA0D3B4EB3A257C9AF1F8F03009")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX("0001020304050607"), /* auth data */
+ SHEX(""), /* plaintext */
+ SHEX(""), /* ciphertext */
+ SHEX("BBAA99887766554433221102"), /* nonce */
+ SHEX("81017F8203F081277152FADE694A0A00")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX(""), /* auth data */
+ SHEX("0001020304050607"), /* plaintext */
+ SHEX("45DD69F8F5AAE724"), /* ciphertext */
+ SHEX("BBAA99887766554433221103"), /* nonce */
+ SHEX("14054CD1F35D82760B2CD00D2F99BFA9")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* auth data */
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* plaintext */
+ SHEX("571D535B60B277188BE5147170A9A22C"), /* ciphertext */
+ SHEX("BBAA99887766554433221104"), /* nonce */
+ SHEX("3AD7A4FF3835B8C5701C1CCEC8FC3358")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* auth data */
+ SHEX(""), /* plaintext */
+ SHEX(""), /* ciphertext */
+ SHEX("BBAA99887766554433221105"), /* nonce */
+ SHEX("8CF761B6902EF764462AD86498CA6B97")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX(""), /* auth data */
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* plaintext */
+ SHEX("5CE88EC2E0692706A915C00AEB8B2396"), /* ciphertext */
+ SHEX("BBAA99887766554433221106"), /* nonce */
+ SHEX("F40E1C743F52436BDF06D8FA1ECA343D")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX("000102030405060708090A0B0C0D0E0F1011121314151617"), /* auth data */
+ SHEX("000102030405060708090A0B0C0D0E0F1011121314151617"), /* plaintext */
+ SHEX("1CA2207308C87C010756104D8840CE1952F09673A448A122"), /* ciphertext */
+ SHEX("BBAA99887766554433221107"), /* nonce */
+ SHEX("C92C62241051F57356D7F3C90BB0E07F")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX("000102030405060708090A0B0C0D0E0F1011121314151617"), /* auth data */
+ SHEX(""), /* plaintext */
+ SHEX(""), /* ciphertext */
+ SHEX("BBAA99887766554433221108"), /* nonce */
+ SHEX("6DC225A071FC1B9F7C69F93B0F1E10DE")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX(""), /* auth data */
+ SHEX("000102030405060708090A0B0C0D0E0F1011121314151617"), /* plaintext */
+ SHEX("221BD0DE7FA6FE993ECCD769460A0AF2D6CDED0C395B1C3C"), /* ciphertext */
+ SHEX("BBAA99887766554433221109"), /* nonce */
+ SHEX("E725F32494B9F914D85C0B1EB38357FF")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX("000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F"), /* auth data */
+ SHEX("000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F"), /* plaintext */
+ SHEX("BD6F6C496201C69296C11EFD138A467ABD3C707924B964DE"
+ "AFFC40319AF5A485"), /* ciphertext */
+ SHEX("BBAA9988776655443322110A"), /* nonce */
+ SHEX("40FBBA186C5553C68AD9F592A79A4240")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX("000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F"), /* auth data */
+ SHEX(""), /* plaintext */
+ SHEX(""), /* ciphertext */
+ SHEX("BBAA9988776655443322110B"), /* nonce */
+ SHEX("FE80690BEE8A485D11F32965BC9D2A32")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX(""), /* auth data */
+ SHEX("000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F"), /* plaintext */
+ SHEX("2942BFC773BDA23CABC6ACFD9BFD5835BD300F0973792EF4"
+ "6040C53F1432BCDF"), /* ciphertext */
+ SHEX("BBAA9988776655443322110C"), /* nonce */
+ SHEX("B5E1DDE3BC18A5F840B52E653444D5DF")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX("000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F2021222324252627"), /* auth data */
+ SHEX("000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F2021222324252627"), /* plaintext */
+ SHEX("D5CA91748410C1751FF8A2F618255B68A0A12E093FF45460"
+ "6E59F9C1D0DDC54B65E8628E568BAD7A"), /* ciphertext */
+ SHEX("BBAA9988776655443322110D"), /* nonce */
+ SHEX("ED07BA06A4A69483A7035490C5769E60")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX("000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F2021222324252627"), /* auth data */
+ SHEX(""), /* plaintext */
+ SHEX(""), /* ciphertext */
+ SHEX("BBAA9988776655443322110E"), /* nonce */
+ SHEX("C5CD9D1850C141E358649994EE701B68")); /* tag */
+
+ test_aead(&nettle_ocb_aes128, NULL,
+ SHEX("000102030405060708090A0B0C0D0E0F"), /* key */
+ SHEX(""), /* auth data */
+ SHEX("000102030405060708090A0B0C0D0E0F1011121314151617"
+ "18191A1B1C1D1E1F2021222324252627"), /* plaintext */
+ SHEX("4412923493C57D5DE0D700F753CCE0D1D2D95060122E9F15"
+ "A5DDBFC5787E50B5CC55EE507BCB084E"), /* ciphertext */
+ SHEX("BBAA9988776655443322110F"), /* nonce */
+ SHEX("479AD363AC366B95 A98CA5F3000B1479")); /* tag */
+}