]> git.ipfire.org Git - thirdparty/nettle.git/commitdiff
Implement OCB mode
authorNiels Möller <nisse@lysator.liu.se>
Sat, 18 Sep 2021 08:00:02 +0000 (10:00 +0200)
committerNiels Möller <nisse@lysator.liu.se>
Mon, 6 Feb 2023 19:20:01 +0000 (20:20 +0100)
ChangeLog
Makefile.in
nettle-meta.h
ocb-aes128-meta.c [new file with mode: 0644]
ocb.c [new file with mode: 0644]
ocb.h [new file with mode: 0644]
testsuite/Makefile.in
testsuite/ocb-test.c [new file with mode: 0644]

index 618c57dc60b014ad0420da660e35219f73285f95..5974e54592a3209ea9a43cb5b01ee713d0d3fb50 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
        * 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>
 
index cd4993e840c5f8e06a60dbac92024a1f983802da..4f4242e058c370986cbc9e144bba24e2b4f4c8d7 100644 (file)
@@ -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 \
index 19dc96c5b3a93f7fe1ac4f6e32e2151e35435017..2b548d7afb94aa636f31159198b8ef437374bbf1 100644 (file)
@@ -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 (file)
index 0000000..efd94a9
--- /dev/null
@@ -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 (file)
index 0000000..91ab3b1
--- /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 (file)
index 0000000..67bbe74
--- /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 */
index 025ab72d92eb98871214eb29940aaf28b3b7bdae..be0cb9658e180c93e106084f7a07ac51cb86973e 100644 (file)
@@ -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 (file)
index 0000000..abeea71
--- /dev/null
@@ -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 */
+}