[Git][NTPsec/ntpsec][master] 2 commits: Import libaes_siv from https://github.com/dfoxfranke/libaes_siv

Matt Selsky gitlab at mg.gitlab.com
Wed Feb 20 13:49:52 UTC 2019


Matt Selsky pushed to branch master at NTPsec / ntpsec


Commits:
e16190d3 by Matt Selsky at 2019-02-20T13:45:59Z
Import libaes_siv from https://github.com/dfoxfranke/libaes_siv

This is a snapshot as of https://github.com/dfoxfranke/libaes_siv/commit/35622050f7bd21901099a4e91228a69eb4a8d6a1,
with the cmake build system removed

- - - - -
0d6daaa0 by Matt Selsky at 2019-02-20T13:45:59Z
Build using the included libaes_siv library

- - - - -


14 changed files:

- + libaes_siv/AES_SIV_CTX_new.adoc
- + libaes_siv/AES_SIV_Encrypt.adoc
- + libaes_siv/AES_SIV_Init.adoc
- + libaes_siv/README.md
- + libaes_siv/aes_siv.c
- + libaes_siv/aes_siv.h
- + libaes_siv/aes_siv_test.c
- + libaes_siv/bench.c
- + libaes_siv/config.h.in
- + libaes_siv/demo.c
- + libaes_siv/tests.c
- + libaes_siv/wscript
- ntpd/wscript
- wscript


Changes:

=====================================
libaes_siv/AES_SIV_CTX_new.adoc
=====================================
@@ -0,0 +1,69 @@
+AES_SIV_CTX_new(3)
+==================
+:doctype: manpage
+
+NAME
+----
+
+AES_SIV_CTX_new, AES_SIV_CTX_copy, AES_SIV_CTX_cleanup, AES_SIV_CTX_free - manage AES-SIV contexts
+
+SYNOPSIS
+--------
+
+[source,c]
+----
+#include <aes_siv.h>
+
+typedef struct AES_SIV_CTX_st AES_SIV_CTX;
+
+AES_SIV_CTX* AES_SIV_CTX_new();
+int AES_SIV_CTX_copy(AES_SIV_CTX *dst, AES_SIV_CTX const* src);
+void AES_SIV_CTX_cleanup(AES_SIV_CTX *ctx);
+void AES_SIV_CTX_free(AES_SIV_CTX *ctx);
+----
+
+DESCRIPTION
+-----------
+
+An *AES_SIV_CTX* is an opaque structure which holds context for
+AES-SIV operations.  A single +AES_SIV_CTX+ may be allocated and used
+repeatedly for multiple operations, so long as it is only used for one
+operation at a time.
+
+The *AES_SIV_CTX_new()* function allocates and returns a new,
+uninitialized +AES_SIV_CTX+.
+
+The *AES_SIV_CTX_copy()* function copies the contents of _src_
+into _dst_.
+
+The *AES_SIV_CTX_cleanup()* function erases the contents of _ctx_,
+rendering it uninitialized but still allocated.
+
+The *AES_SIV_CTX_free()* function frees the memory associated with
+`ctx`.
+
+NOTES
+-----
+
+AES_SIV_CTX_new() and AES_SIV_CTX_free() are the only functions in
+libaes_siv which allocate or free heap memory. They do so by calling
+OPENSSL_malloc() and OPENSSL_free(), so they will make use of any
+custom allocators provided to OpenSSL via CRYPTO_set_mem_functions().
+
+AES_SIV_CTX_cleanup() will securely erase all heap data asociated with
+the AES_SIV_CTX. libaes_siv does not attempt to sanitize the stack
+since compiler behaviors such as register spilling make such attempts
+too unreliable to be worthwhile.
+
+RETURN VALUES
+-------------
+
+*AES_SIV_CTX_new()* returns a pointer to the newly-allocated context
+structure on success, or NULL on failure.
+
+*AES_SIV_CTX_copy()* returns 1 on success, 0 on failure.
+
+SEE ALSO
+--------
+
+*AES_SIV_Encrypt*(3), *AES_SIV_Init*(3), RFC 5297


=====================================
libaes_siv/AES_SIV_Encrypt.adoc
=====================================
@@ -0,0 +1,79 @@
+AES_SIV_Encrypt(3)
+==================
+:doctype: manpage
+
+NAME
+----
+
+AES_SIV_Encrypt, AES_SIV_Decrypt - AES-SIV high-level interface
+
+SYNOPSIS
+--------
+
+[source,c]
+----
+#include <aes_siv.h>
+
+int AES_SIV_Encrypt(AES_SIV_CTX *ctx,
+                    unsigned char *out, size_t *out_len,
+                    unsigned char const* key, size_t key_len,
+                    unsigned char const* nonce, size_t nonce_len,
+                    unsigned char const* plaintext, size_t plaintext_len,
+                    unsigned char const* ad, size_t ad_len);
+
+int AES_SIV_Decrypt(AES_SIV_CTX *ctx,
+                    unsigned char *out, size_t *out_len,
+                    unsigned char const* key, size_t key_len,
+                    unsigned char const* nonce, size_t nonce_len,
+                    unsigned char const* ciphertext, size_t ciphertext_len,
+                    unsigned char const* ad, size_t ad_len);
+----
+
+DESCRIPTION
+-----------
+
+These functions provide a high-level interface for AES-SIV encryption
+and decryption, complying with RFC 5297.
+
+*AES_SIV_Encrypt()* uses the provided _ctx_ to encrypt the provided
+_plaintext_ and associated data _ad_ using the provided _key_ and
+_nonce_, and outputs up to _*out_len_ bytes of ciphertext into the
+memory pointed to by _out_. It sets _*out_len_ to the actual output
+length, which will always be _plaintext_len_ + 16.
+
+*AES_SIV_Decrypt()* uses the provided _ctx_ to authenticate and
+decrypt the provided _ciphertext_ and associated data _ad_ using the
+provided _key_ and _nonce_, and outputs up to _*out_len_ bytes of
+plaintext into the memory pointed to by _out_. It sets _*out_len_ to
+the actual output length, which will always be _ciphertext_len_ - 16.
+
+_key_len_ is given in bytes and must be 32, 48, or 64.
+
+For deterministic encryption, the _nonce_ may be NULL; note that this
+is distinct from providing a zero-length nonce; see NOTES.
+
+NOTES
+-----
+
+The output of +AES_SIV_Encrypt()+ is formatted as a 16-byte
+authentication tag followed by the actual ciphertext. Plaintext may be
+encrypted in-place by letting _plaintext_ equal +&out[16]+. Similarly,
+ciphertext may be authenticated and decrypted in-place by letting
+_out_ equal +&ciphertext[16]+.
+
+RFC 5297 defines AES-SIV in such a way that deterministic use (i.e,
+not providing a nonce) is distinct from providing a nonce of zero
+length. The latter (a zero-length-onnce) is supported by libaes_siv
+but not recommended, and RFC 5297 is ambiguous as to whether it ought
+to be permitted: the operation is clearly defined, but the IANA
+registrations for AES-SIV's RFC 5116 interface specify an N_MIN of 1.
+
+RETURN VALUE
+------------
+
+These functions return 1 on success and 0 on failure.
+
+SEE ALSO
+--------
+
+*AES_SIV_CTX_new*(3), *AES_SIV_Init*(3), RFC 5297


=====================================
libaes_siv/AES_SIV_Init.adoc
=====================================
@@ -0,0 +1,114 @@
+AES_SIV_Init(3)
+===============
+:doctype: manpage
+
+NAME
+----
+
+AES_SIV_Init, AES_SIV_AssociateData, AES_SIV_EncryptFinal, AES_SIV_DecryptFinal - AES-SIV low-level interface
+
+SYNOPSIS
+--------
+
+[source,c]
+----
+#include <aes_siv.h>
+
+int AES_SIV_Init(AES_SIV_CTX *ctx, unsigned char const* key, size_t key_len);
+int AES_SIV_AssociateData(AES_SIV_CTX *ctx, unsigned char const* data, size_t len);
+int AES_SIV_EncryptFinal(AES_SIV_CTX *ctx,
+                         unsigned char *v_out, unsigned char *c_out,
+                         unsigned char const* plaintext, size_t len);
+int AES_SIV_DecryptFinal(AES_SIV_CTX *ctx, unsigned char *out,
+                         unsigned char const* v, unsigned char const* c,
+                         size_t len);
+----
+
+DESCRIPTION
+-----------
+
+These functions provide a low-level interface for AES-SIV encryption
+and decryption, complying with RFC 5297.
+
+*AES_SIV_Init()* prepares _ctx_ for encrypting or decrypting data
+under the given _key_.
+
+*AES_SIV_AssociateData*() adds a block of associated data to *ctx*.
+This function is also used for adding a _nonce_; see NOTES for details.
+
+*AES_SIV_EncryptFinal()* encrypts the provided _plaintext_, writing a
+16-byte authentication tag to _v_out_ and ciphertext to _c_out_.  The
+ciphertext written to _c_out_ will be equal in length to the
+plaintext, with both lengths given by _len_.
+
+*AES_SIV_DecryptFinal()* decrypts and verifies the provided ciphertext
+_c_ and 16-byte authentication tag _v_, writing plaintext to _out_.
+The plaintext will be equal in length to _c_, with both lengths
+given by _len_.
+
+RETURN VALUE
+------------
+
+These functions return 1 on success, 0 on failure.
+
+NOTES
+-----
+
+When encrypting or decrypting/authenticating multiple messages under
+the same key, these functions may be used to achieve better
+performance than is possible using the high-level API by caching the
+result of of key setup. After calling +AES_SIV_Init+(), retain the
+resulting _ctx_ structure and use +AES_SIV_CTX_copy+() to make a copy
+of it for each message being encrypted or decrypted.
+
+The arguments to a typical AEAD encryption function consist of a key,
+a nonce, associated data, and plaintext. However, RFC 5297 defines
+AES-SIV as accepting an arbitrary number of associated data arguments,
+and specifies that the nonce should be given as the final such
+argument.  This low-level API is structured accordingly. The
+high-level functions +AES_SIV_Encrypt+() and +AES_SIV_Decrypt+() are
+implemented on top of it approximately as follows; error-handling is
+omitted for brevity.
+
+[source,c]
+----
+int AES_SIV_Encrypt(AES_SIV_CTX *ctx,
+                    unsigned char *out, size_t *out_len,
+                    unsigned char const* key, size_t key_len,
+                    unsigned char const* nonce, size_t nonce_len,
+                    unsigned char const* plaintext, size_t plaintext_len,
+                    unsigned char const *ad, size_t ad_len) {
+        *out_len = plaintext_len + 16;
+
+        /* Do not copy-paste this code; it is missing return-value
+           checking.*/
+        AES_SIV_Init(ctx, key, key_len);
+        AES_SIV_AssociateData(ctx, ad, ad_len;
+        if(nonce) AES_SIV_AssociateData(ctx, nonce, nonce_len);
+        AES_SIV_EncryptFinal(ctx, out, out+16, plaintext, plaintext_len);
+        return 1;
+}
+
+int AES_SIV_Decrypt(AES_SIV_CTX *ctx,
+                    unsigned char *out, size_t *out_len,
+                    unsigned char const* key, size_t key_len,
+                    unsigned char const* nonce, size_t nonce_len,
+                    unsigned char const* ciphertext, size_t ciphertext_len,
+                    unsigned char const *ad, size_t ad_len) {
+        *out_len = ciphertext_len - 16;
+
+        /* Do not copy-paste this code; it is missing return-value
+           checking.*/
+        AES_SIV_Init(ctx, key, key_len);
+        AES_SIV_AssociateData(ctx, ad, ad_len);
+        if(nonce) AES_SIV_AssociateData(ctx, nonce, nonce_len);
+        AES_SIV_DecryptFinal(ctx, out, ciphertext, ciphertext + 16,
+                             ciphertext_len - 16);
+        return 1;
+}
+----
+
+SEE ALSO
+--------
+
+*AES_SIV_CTX_new*(3), *AES_SIV_Encrypt*(3), RFC 5297


=====================================
libaes_siv/README.md
=====================================
@@ -0,0 +1,184 @@
+# libaes_siv
+
+This is an [RFC5297](https://tools.ietf.org/html/rfc5297)-compliant C
+implementation of AES-SIV written by Daniel Franke on behalf of
+[Akamai Technologies](https://www.akamai.com). It is published under
+the [Apache License
+(v2.0)](https://www.apache.org/licenses/LICENSE-2.0).  It uses OpenSSL
+for the underlying
+[AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) and
+[CMAC](https://en.wikipedia.org/wiki/One-key_MAC) implementations and
+follows a similar interface style.
+
+An AES_SIV implementation forked from libaes_siv has been [merged into
+the OpenSSL master branch](https://github.com/openssl/openssl/pull/3540).
+However, the two implementations are not API-compatible; see section
+"OpenSSL API Comparison" below.
+
+## Overview of SIV mode
+
+Synthetic Initialization Vector (SIV) mode is a [block cipher mode of
+operation](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation)
+for [authenticated encryption with associated
+data](https://en.wikipedia.org/wiki/Authenticated_encryption) designed
+to be maximally resistant to accidental
+[nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce) reuse.  If
+two messages are accidentally encrypted using the same nonce and the
+same associated data, the attacker learns nothing except whether or
+not the plaintexts of the two messages are identical to each other.
+SIV mode also permits the nonce to be intentionally omitted, resulting
+in a [deterministic encryption
+scheme](https://en.wikipedia.org/wiki/Deterministic_encryption).
+
+Here are a couple common situations where AES-SIV may be an
+appropriate choice of AEAD scheme:
+
+1. You can't count on the system doing the encrypting to reliably
+   generate a unique nonce for every message. For example, the system
+   may be an embedded device with no good entropy source, or may be a
+   VM subject to be snapshotted and restored.
+
+2. You want your encryption to be deterministic so that an
+   intermediating party such as a caching proxy, provided only with
+   ciphertext, can perform deduplication.
+
+The drawback to SIV mode is that it requires two passes over its
+input. This makes it potentially clumsy for use with large messages
+since the entire message must be held in memory at one time. SIV mode
+is also a bit slower than most widely-used block cipher modes (but
+can still be quite fast — see performance numbers below).
+
+Be aware that with *any* encryption scheme, including SIV, repeating
+or omitting a nonce can still be [fatal to
+security](https://xkcd.com/257) if your plaintexts have low entropy,
+e.g., if each message consists only of a single bit.
+
+Keys for SIV mode are twice the length of the keys for the underlying
+block cipher. For example, keys for AES-128-SIV are 256 bits long,
+and keys for AES-256-SIV are 512 bits long.
+
+## Build instructions
+
+Build dependencies:
+
+* Any ISO C89 compiler (GCC or Clang recommended). No C99 language
+  features are required, however `<stdint.h>` must be available and
+  must define `uint64_t`. `char` must be 8 bits and arithmetic must be
+  two's complement.
+* [CMake](https://cmake.org) >= 3.1
+* [OpenSSL](https://openssl.org) >=1.0.1 (libcrypto only). A recent
+  release from the 1.0.2 branch or later is strongly recommended since
+  1.0.1 was EOL'ed at the end of 2016. Furthermore, OpenSSL versions prior
+  to 1.0.1n and 1.0.2b have known bugs which impact `libaes_siv` and
+  will cause failures in its test suite. LibreSSL is not supported.
+* [Asciidoc](http://asciidoc.org) (only required for building man pages)
+
+Running benchmarks requires a POSIX.1-2001 compliant OS, including
+the `clock_gettime` system call.
+
+To build and install on POSIX-like platforms:
+```
+    cmake . &&
+    make &&
+    make test &&
+    sudo make install
+```
+
+If you want to build on an OS X machine, install the Xcode development
+environment and the command line tools, then use the Homebrew package
+manager https://brew.sh/ to install cmake and OpenSSL:
+```
+    brew install cmake openssl &&
+    cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/openssl . &&
+    make &&
+    make test &&
+    sudo make install
+```
+
+To create a native Windows build, you will first need to build
+OpenSSL.  Install Visual Studio, CMake, ActiveState Perl, and NASM, and
+ensure that `nasm.exe` is somewhere in your `%PATH%`. From a VS developer
+command prompt, unpack the OpenSSL sources and run
+```
+    perl Configure VC-WIN64A
+    nmake
+```
+Then to build `libaes_siv`, run
+```
+    cmake -G "NMake Makefiles" -DOPENSSL_ROOT_DIR=\path\to\openssl .
+    nmake
+    nmake test
+```
+
+## Usage
+
+See the manual pages for API documentation, and the test vectors
+in `tests.c` for simple usage examples.  You can also use the `demo` command
+line program to encrypt and decrypt data.
+
+## OpenSSL API Comparison
+
+In December 2018, OpenSSL merged an AES-SIV implementation derived
+from libaes_siv. As of February 2019 this implementation has not been
+released yet; it will appear some time post-1.1.1. However, despite
+the two implementations' common ancestry, they are not API-compatible.
+The OpenSSL team had to make an ugly-but-necessary compromise into order
+to shoehorn SIV mode into OpenSSL's EVP API, which is a streaming API
+that was never designed to support SIV's two-pass operation. When used for
+SIV operations, the EVP API is forced to return an error if you invoke
+`EVP_(En|De)crypt_Update` more than once for the same message.
+
+When designing libaes_siv, I rejected this behavior as an unacceptable
+breakdown of the API contract and opted to dispense with the EVP
+abstraction altogether rather than permit it to leak. libaes_siv's API
+remains stylistically similar to EVP, but is nonetheless distinct and
+avoids the above pitfall.
+
+## Performance
+
+On the author's Intel Core i7-6560U laptop, libaes_siv can process
+approximately 796 MiB of plaintext or ciphertext or 963 MiB of
+associated data per second using 256-bit keys
+(i.e., AES-128). Encrypting a zero-byte message takes approximately
+990ns. To obtain numbers for your own system, run `make bench &&
+./bench`.
+
+## Software assurance
+
+libaes_siv's test suite includes all test vectors from RFC 5297 and
+achieves 100% code coverage according to
+[gcov](https://gcc.gnu.org/onlinedocs/gcc/Gcov.html). It produces
+clean output from [Valgrind](https://valgrind.org) and from Clang's
+[undefined behavior
+sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html),
+and is verified using [ctgrind](https://github.com/agl/ctgrind) to run
+in constant time.
+
+Nonetheless, libaes_siv should at present be considered beta-quality
+code. It has not yet been tested on platforms other than x86-64 Linux
+or benefited from any significant amount of user feedback, and
+the codebase is in need of additional review by cryptographers and
+expert C programmers.
+
+## Bugs and pull requests
+
+Use the GitHub issue tracker. For reporting sensitive security issues,
+contact the author directly. (Note: I no longer use PGP. Please
+request my Signal details if necessary).
+
+## A note on version numbers
+
+libaes_siv version numbers are of the form `<major>.<minor>.<patch>`
+and follow a semantic versioning scheme. The major version number
+will be incremented with any backward-incompatible ABI change. The
+minor version number will be incremented if new functionality is
+added without impacting ABI backward-compatibility. The patch
+version number will be incremented for releases that make no
+externally-visible changes.
+
+As a result of this scheme, on ELF platforms, the .so version will
+be the same as the release version.
+
+Version numbers indicate nothing about code quality or maturity.  No
+code known or suspected to be less suitable for production use than
+previous releases will ever be tagged with a version number.


=====================================
libaes_siv/aes_siv.c
=====================================
@@ -0,0 +1,589 @@
+/* Copyright (c) 2017-2019 Akamai Technologies, Inc.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define _POSIX_C_SOURCE 200112L
+#define _ISOC99_SOURCE 1
+
+#include "config.h"
+#include "aes_siv.h"
+
+#include <assert.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#ifdef ENABLE_DEBUG_OUTPUT
+#include <stdio.h>
+#endif
+#ifdef _MSC_VER
+/* For _byteswap_uint64 */
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+#include <openssl/cmac.h>
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+
+#ifdef ENABLE_CTGRIND
+#include <ctgrind.h>
+#endif
+
+#if CHAR_BIT != 8
+#error "libaes_siv requires an 8-bit char type"
+#endif
+
+#if -1 != ~0
+#error "libaes_siv requires a two's-complement architecture"
+#endif
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
+#undef inline
+#elif defined(__GNUC__) || defined(__clang__)
+#define inline __inline__
+#elif defined(_MSC_VER)
+#define inline __inline
+#else
+#define inline
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+#define LIKELY(cond) __builtin_expect(cond, 1)
+#define UNLIKELY(cond) __builtin_expect(cond, 0)
+#else
+#define LIKELY(cond) cond
+#define UNLIKELY(cond) cond
+#endif
+
+#ifndef ENABLE_CTGRIND
+static inline void ct_poison(const void *data, size_t len) {
+        (void)data;
+        (void)len;
+}
+static inline void ct_unpoison(const void *data, size_t len) {
+        (void)data;
+        (void)len;
+}
+#endif
+
+static void debug(const char *label, const unsigned char *hex, size_t len) {
+/* ENABLE_CTGRIND has to override ENABLE_DEBUG_OUTPUT since sensitive data
+   gets printed.
+*/
+#if defined(ENABLE_DEBUG_OUTPUT) && !defined(ENABLE_CTGRIND)
+        size_t i;
+        printf("%16s: ", label);
+        for (i = 0; i < len; i++) {
+                if (i > 0 && i % 16 == 0) {
+                        printf("\n                  ");
+                }
+                printf("%.2x", (int)hex[i]);
+                if (i > 0 && i % 4 == 3) {
+                        printf(" ");
+                }
+        }
+        printf("\n");
+#else
+        (void)label;
+        (void)hex;
+        (void)len;
+#endif
+}
+
+typedef union block_un {
+        uint64_t word[2];
+        unsigned char byte[16];
+} block;
+
+const union {
+        uint64_t word;
+        char byte[8];
+} endian = {0x0102030405060708};
+
+#define I_AM_BIG_ENDIAN (endian.byte[0] == 1 && \
+                         endian.byte[1] == 2 && \
+                         endian.byte[2] == 3 && \
+                         endian.byte[3] == 4 && \
+                         endian.byte[4] == 5 && \
+                         endian.byte[5] == 6 && \
+                         endian.byte[6] == 7 && \
+                         endian.byte[7] == 8)
+
+#define I_AM_LITTLE_ENDIAN (endian.byte[0] == 8 && \
+                            endian.byte[1] == 7 && \
+                            endian.byte[2] == 6 && \
+                            endian.byte[3] == 5 && \
+                            endian.byte[4] == 4 && \
+                            endian.byte[5] == 3 && \
+                            endian.byte[6] == 2 && \
+                            endian.byte[7] == 1)
+
+#if defined(__GNUC__) || defined(__clang__)
+static inline uint64_t bswap64(uint64_t x) { return __builtin_bswap64(x); }
+#elif defined(_MSC_VER)
+static inline uint64_t bswap64(uint64_t x) { return _byteswap_uint64(x); }
+#else
+
+static inline uint32_t rotl(uint32_t x) { return (x << 8) | (x >> 24); }
+static inline uint32_t rotr(uint32_t x) { return (x >> 8) | (x << 24); }
+
+static inline uint64_t bswap64(uint64_t x) {
+        uint32_t high = (uint32_t)(x >> 32);
+        uint32_t low = (uint32_t)x;
+
+        high = (rotl(high) & 0x00ff00ff) | (rotr(high) & 0xff00ff00);
+        low = (rotl(low) & 0x00ff00ff) | (rotr(low) & 0xff00ff00);
+        return ((uint64_t)low) << 32 | (uint64_t)high;
+}
+#endif
+
+static inline uint64_t getword(block const *block, size_t i) {
+#ifndef ENABLE_DEBUG_WEIRD_ENDIAN
+        if (I_AM_BIG_ENDIAN) {
+                return block->word[i];
+        } else if (I_AM_LITTLE_ENDIAN) {
+                return bswap64(block->word[i]);
+        } else {
+#endif
+                i <<= 3;
+                return ((uint64_t)block->byte[i + 7]) |
+                       ((uint64_t)block->byte[i + 6] << 8) |
+                       ((uint64_t)block->byte[i + 5] << 16) |
+                       ((uint64_t)block->byte[i + 4] << 24) |
+                       ((uint64_t)block->byte[i + 3] << 32) |
+                       ((uint64_t)block->byte[i + 2] << 40) |
+                       ((uint64_t)block->byte[i + 1] << 48) |
+                       ((uint64_t)block->byte[i] << 56);
+#ifndef ENABLE_DEBUG_WEIRD_ENDIAN
+        }
+#endif
+}
+
+static inline void putword(block *block, size_t i, uint64_t x) {
+#ifndef ENABLE_DEBUG_WEIRD_ENDIAN
+        if (I_AM_BIG_ENDIAN) {
+                block->word[i] = x;
+        } else if (I_AM_LITTLE_ENDIAN) {
+                block->word[i] = bswap64(x);
+        } else {
+#endif
+                i <<= 3;
+                block->byte[i] = (unsigned char)(x >> 56);
+                block->byte[i + 1] = (unsigned char)((x >> 48) & 0xff);
+                block->byte[i + 2] = (unsigned char)((x >> 40) & 0xff);
+                block->byte[i + 3] = (unsigned char)((x >> 32) & 0xff);
+                block->byte[i + 4] = (unsigned char)((x >> 24) & 0xff);
+                block->byte[i + 5] = (unsigned char)((x >> 16) & 0xff);
+                block->byte[i + 6] = (unsigned char)((x >> 8) & 0xff);
+                block->byte[i + 7] = (unsigned char)(x & 0xff);
+#ifndef ENABLE_DEBUG_WEIRD_ENDIAN
+        }
+#endif
+}
+
+static inline void xorblock(block *x, block const *y) {
+        x->word[0] ^= y->word[0];
+        x->word[1] ^= y->word[1];
+}
+
+/* Doubles `block`, which is 16 bytes representing an element
+   of GF(2**128) modulo the irreducible polynomial
+   x**128 + x**7 + x**2 + x + 1. */
+static inline void dbl(block *block) {
+        uint64_t high = getword(block, 0);
+        uint64_t low = getword(block, 1);
+        uint64_t high_carry = high & (((uint64_t)1) << 63);
+        uint64_t low_carry = low & (((uint64_t)1) << 63);
+        /* Assumes two's-complement arithmetic */
+        int64_t low_mask = -((int64_t)(high_carry >> 63)) & 0x87;
+        uint64_t high_mask = low_carry >> 63;
+        high = (high << 1) | high_mask;
+        low = (low << 1) ^ (uint64_t)low_mask;
+        putword(block, 0, high);
+        putword(block, 1, low);
+}
+
+struct AES_SIV_CTX_st {
+        /* d stores intermediate results of S2V; it corresponds to D from the
+           pseudocode in section 2.4 of RFC 5297. */
+        block d;
+        EVP_CIPHER_CTX *cipher_ctx;
+        /* SIV_AES_Init() sets up cmac_ctx_init. cmac_ctx is a scratchpad used
+           by SIV_AES_AssociateData() and SIV_AES_(En|De)cryptFinal. */
+        CMAC_CTX *cmac_ctx_init, *cmac_ctx;
+};
+
+void AES_SIV_CTX_cleanup(AES_SIV_CTX *ctx) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+        EVP_CIPHER_CTX_reset(ctx->cipher_ctx);
+#else
+        EVP_CIPHER_CTX_cleanup(ctx->cipher_ctx);
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && OPENSSL_VERSION_NUMBER <= 0x10100060L
+	/* Workaround for an OpenSSL bug that causes a double free
+	   if you call CMAC_CTX_cleanup() before CMAC_CTX_free().
+	   https://github.com/openssl/openssl/pull/2798
+	*/
+	CMAC_CTX_free(ctx->cmac_ctx_init);
+	ctx->cmac_ctx_init = CMAC_CTX_new();
+	CMAC_CTX_free(ctx->cmac_ctx);
+	ctx->cmac_ctx = CMAC_CTX_new();
+#else
+        CMAC_CTX_cleanup(ctx->cmac_ctx_init);
+        CMAC_CTX_cleanup(ctx->cmac_ctx);
+#endif
+        OPENSSL_cleanse(&ctx->d, sizeof ctx->d);
+}
+
+void AES_SIV_CTX_free(AES_SIV_CTX *ctx) {
+        if (ctx) {
+                EVP_CIPHER_CTX_free(ctx->cipher_ctx);
+                CMAC_CTX_free(ctx->cmac_ctx_init);
+                CMAC_CTX_free(ctx->cmac_ctx);
+		OPENSSL_cleanse(&ctx->d, sizeof ctx->d);
+                free(ctx);
+        }
+}
+
+AES_SIV_CTX *AES_SIV_CTX_new(void) {
+        AES_SIV_CTX *ctx = malloc(sizeof(struct AES_SIV_CTX_st));
+        if (UNLIKELY(ctx == NULL)) {
+                return NULL;
+        }
+
+        ctx->cipher_ctx = EVP_CIPHER_CTX_new();
+        ctx->cmac_ctx_init = CMAC_CTX_new();
+        ctx->cmac_ctx = CMAC_CTX_new();
+
+        if (UNLIKELY(ctx->cipher_ctx == NULL ||
+                     ctx->cmac_ctx_init == NULL ||
+                     ctx->cmac_ctx == NULL)) {
+                AES_SIV_CTX_free(ctx);
+                return NULL;
+        }
+
+        return ctx;
+}
+
+int AES_SIV_CTX_copy(AES_SIV_CTX *dst, AES_SIV_CTX const *src) {
+        memcpy(&dst->d, &src->d, sizeof src->d);
+        if(UNLIKELY(EVP_CIPHER_CTX_copy(dst->cipher_ctx, src->cipher_ctx)
+                    != 1)) {
+                return 0;
+        }
+        if (UNLIKELY(CMAC_CTX_copy(dst->cmac_ctx_init, src->cmac_ctx_init)
+                     != 1)) {
+                return 0;
+        }
+        /* Not necessary to copy cmac_ctx since it's just temporary
+         * storage */
+        return 1;
+}
+
+int AES_SIV_Init(AES_SIV_CTX *ctx, unsigned char const *key, size_t key_len) {
+        static const unsigned char zero[] = {0, 0, 0, 0, 0, 0, 0, 0,
+                                             0, 0, 0, 0, 0, 0, 0, 0};
+        size_t out_len;
+        int ret = 0;
+
+        ct_poison(key, sizeof key);
+
+        switch (key_len) {
+        case 32:
+                if (UNLIKELY(CMAC_Init(ctx->cmac_ctx_init, key, 16,
+                                       EVP_aes_128_cbc(), NULL) != 1)) {
+                        goto done;
+                }
+                if (UNLIKELY(EVP_EncryptInit_ex(ctx->cipher_ctx,
+                                                EVP_aes_128_ctr(),
+                                                NULL, key + 16, NULL) != 1)) {
+                        goto done;
+                }
+                break;
+        case 48:
+                if (UNLIKELY(CMAC_Init(ctx->cmac_ctx_init, key, 24,
+                                       EVP_aes_192_cbc(), NULL) != 1)) {
+                        goto done;
+                }
+                if (UNLIKELY(EVP_EncryptInit_ex(ctx->cipher_ctx,
+                                                EVP_aes_192_ctr(),
+                                                NULL, key + 24, NULL) != 1)) {
+                        goto done;
+                }
+                break;
+        case 64:
+                if (UNLIKELY(CMAC_Init(ctx->cmac_ctx_init, key, 32,
+                                       EVP_aes_256_cbc(), NULL) != 1)) {
+                        goto done;
+                }
+                if (UNLIKELY(EVP_EncryptInit_ex(ctx->cipher_ctx,
+                                                EVP_aes_256_ctr(),
+                                                NULL, key + 32, NULL) != 1)) {
+                        goto done;
+                }
+                break;
+        default:
+                goto done;
+        }
+
+        if (UNLIKELY(CMAC_CTX_copy(ctx->cmac_ctx, ctx->cmac_ctx_init) != 1)) {
+                goto done;
+        }
+        if (UNLIKELY(CMAC_Update(ctx->cmac_ctx, zero, sizeof zero) != 1)) {
+                goto done;
+        }
+        out_len = sizeof ctx->d;
+        if (UNLIKELY(CMAC_Final(ctx->cmac_ctx, ctx->d.byte, &out_len) != 1)) {
+                goto done;
+        }
+        debug("CMAC(zero)", ctx->d.byte, out_len);
+        ret = 1;
+
+ done:
+        ct_unpoison(key, key_len);
+        return ret;
+}
+
+int AES_SIV_AssociateData(AES_SIV_CTX *ctx, unsigned char const *data,
+                          size_t len) {
+        block cmac_out;
+        size_t out_len = sizeof cmac_out;
+        int ret = 0;
+
+        ct_poison(data, len);
+
+        dbl(&ctx->d);
+        debug("double()", ctx->d.byte, 16);
+
+        if (UNLIKELY(CMAC_CTX_copy(ctx->cmac_ctx, ctx->cmac_ctx_init) != 1)) {
+                goto done;
+        }
+        if (UNLIKELY(CMAC_Update(ctx->cmac_ctx, data, len) != 1)) {
+                goto done;
+        }
+        if (UNLIKELY(CMAC_Final(ctx->cmac_ctx, cmac_out.byte, &out_len) != 1)) {
+                goto done;
+        }
+        assert(out_len == 16);
+        debug("CMAC(ad)", cmac_out.byte, 16);
+
+        xorblock(&ctx->d, &cmac_out);
+        debug("xor", ctx->d.byte, 16);
+        ret = 1;
+
+done:
+        ct_unpoison(data, len);
+        return ret;
+}
+
+static inline int do_s2v_p(AES_SIV_CTX *ctx, block *out,
+                           unsigned char const* in, size_t len) {
+        block t;
+        size_t out_len = sizeof out->byte;
+
+        if (UNLIKELY(CMAC_CTX_copy(ctx->cmac_ctx, ctx->cmac_ctx_init) != 1)) {
+                return 0;
+        }
+
+        if(len >= 16) {
+                if(UNLIKELY(CMAC_Update(ctx->cmac_ctx, in, len - 16) != 1)) {
+                        return 0;
+                }
+                debug("xorend part 1", in, len - 16);
+                memcpy(&t, in + (len-16), 16);
+                xorblock(&t, &ctx->d);
+                debug("xorend part 2", t.byte, 16);
+                if(UNLIKELY(CMAC_Update(ctx->cmac_ctx, t.byte, 16) != 1)) {
+                        return 0;
+                }
+        } else {
+                size_t i;
+                memcpy(&t, in, len);
+                t.byte[len] = 0x80;
+                for(i = len + 1; i < 16; i++) {
+                        t.byte[i] = 0;
+                }
+                debug("pad", t.byte, 16);
+                dbl(&ctx->d);
+                xorblock(&t, &ctx->d);
+                debug("xor", t.byte, 16);
+                if(UNLIKELY(CMAC_Update(ctx->cmac_ctx, t.byte, 16) != 1)) {
+                        return 0;
+                }
+        }
+        if(UNLIKELY(CMAC_Final(ctx->cmac_ctx, out->byte, &out_len) != 1)) {
+                return 0;
+        }
+        assert(out_len == 16);
+        debug("CMAC(final)", out->byte, 16);
+        return 1;
+}
+
+static inline int do_encrypt(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                             unsigned char const *in, size_t len, block *icv) {
+#ifdef ENABLE_DEBUG_TINY_CHUNK_SIZE
+        const int chunk_size = 7;
+#else
+        const int chunk_size = 1 << 30;
+#endif
+        size_t len_remaining = len;
+        int out_len;
+        int ret;
+
+        if(UNLIKELY(EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, icv->byte)
+                    != 1)) {
+                return 0;
+        }
+
+        while(UNLIKELY(len_remaining > (size_t)chunk_size)) {
+                out_len = chunk_size;
+                if(UNLIKELY(EVP_EncryptUpdate(ctx, out, &out_len, in, out_len)
+                            != 1)) {
+                        return 0;
+                }
+                assert(out_len == chunk_size);
+                out += out_len;
+                in += out_len;
+                len_remaining -= (size_t)out_len;
+        }
+
+        out_len = (int)len_remaining;
+        ret = EVP_EncryptUpdate(ctx, out, &out_len, in, out_len);
+        assert(!ret || out_len == (int)len_remaining);
+        return ret;
+}
+
+int AES_SIV_EncryptFinal(AES_SIV_CTX *ctx, unsigned char *v_out,
+                         unsigned char *c_out, unsigned char const *plaintext,
+                         size_t len) {
+        block q;
+        int ret = 0;
+
+        ct_poison(plaintext, len);
+
+        if(UNLIKELY(do_s2v_p(ctx, &q, plaintext, len) != 1)) {
+                goto done;
+        }
+
+        ct_unpoison(&q, sizeof q);
+        memcpy(v_out, &q, 16);
+        q.byte[8] &= 0x7f;
+        q.byte[12] &= 0x7f;
+
+        if(UNLIKELY(do_encrypt(ctx->cipher_ctx, c_out, plaintext, len, &q)
+                    != 1)) {
+                goto done;
+        }
+
+        ret = 1;
+        debug("ciphertext", c_out, len);
+
+done:
+        ct_unpoison(plaintext, len);
+        ct_unpoison(c_out, len);
+        ct_unpoison(v_out, 16);
+        return ret;
+}
+
+int AES_SIV_DecryptFinal(AES_SIV_CTX *ctx, unsigned char *out,
+                         unsigned char const *v, unsigned char const *c,
+                         size_t len) {
+        block t, q;
+        size_t i;
+        uint64_t result;
+        int ret = 0;
+
+        ct_poison(c, len);
+
+        memcpy(&q, v, 16);
+        q.byte[8] &= 0x7f;
+        q.byte[12] &= 0x7f;
+
+        if(UNLIKELY(do_encrypt(ctx->cipher_ctx, out, c, len, &q) != 1)) {
+                goto done;
+        }
+        debug("plaintext", out, len);
+
+        if(UNLIKELY(do_s2v_p(ctx, &t, out, len) != 1)) {
+                goto done;
+        }
+
+        for (i = 0; i < 16; i++) {
+                t.byte[i] ^= v[i];
+        }
+
+        result = t.word[0] | t.word[1];
+        ct_unpoison(&result, sizeof result);
+        ret = !result;
+
+        if(ret) {
+                ct_unpoison(out, len);
+        } else {
+                OPENSSL_cleanse(out, len);
+        }
+
+done:
+        ct_unpoison(c, len);
+        return ret;
+}
+
+int AES_SIV_Encrypt(AES_SIV_CTX *ctx, unsigned char *out, size_t *out_len,
+                    unsigned char const *key, size_t key_len,
+                    unsigned char const *nonce, size_t nonce_len,
+                    unsigned char const *plaintext, size_t plaintext_len,
+                    unsigned char const *ad, size_t ad_len) {
+        if (UNLIKELY(*out_len < plaintext_len + 16)) {
+                return 0;
+        }
+        *out_len = plaintext_len + 16;
+
+        if (UNLIKELY(AES_SIV_Init(ctx, key, key_len) != 1)) {
+                return 0;
+        }
+        if (UNLIKELY(AES_SIV_AssociateData(ctx, ad, ad_len) != 1)) {
+                return 0;
+        }
+        if (nonce != NULL &&
+            UNLIKELY(AES_SIV_AssociateData(ctx, nonce, nonce_len) != 1)) {
+                return 0;
+        }
+        if (UNLIKELY(AES_SIV_EncryptFinal(ctx, out, out + 16, plaintext,
+                                          plaintext_len) != 1)) {
+                return 0;
+        }
+
+        debug("IV || C", out, *out_len);
+        return 1;
+}
+
+int AES_SIV_Decrypt(AES_SIV_CTX *ctx, unsigned char *out, size_t *out_len,
+                    unsigned char const *key, size_t key_len,
+                    unsigned char const *nonce, size_t nonce_len,
+                    unsigned char const *ciphertext, size_t ciphertext_len,
+                    unsigned char const *ad, size_t ad_len) {
+        if (UNLIKELY(ciphertext_len < 16)) {
+                return 0;
+        }
+        if (UNLIKELY(*out_len < ciphertext_len - 16)) {
+                return 0;
+        }
+        *out_len = ciphertext_len - 16;
+
+        if (UNLIKELY(AES_SIV_Init(ctx, key, key_len) != 1)) {
+                return 0;
+        }
+        if (UNLIKELY(AES_SIV_AssociateData(ctx, ad, ad_len) != 1)) {
+                return 0;
+        }
+        if (nonce != NULL &&
+            UNLIKELY(AES_SIV_AssociateData(ctx, nonce, nonce_len) != 1)) {
+                return 0;
+        }
+        if (UNLIKELY(AES_SIV_DecryptFinal(ctx, out, ciphertext, ciphertext + 16,
+                                          ciphertext_len - 16) != 1)) {
+                return 0;
+        }
+        debug("plaintext", out, *out_len);
+        return 1;
+}


=====================================
libaes_siv/aes_siv.h
=====================================
@@ -0,0 +1,57 @@
+/* Copyright (c) 2017-2019 Akamai Technologies, Inc.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef AES_SIV_H_
+#define AES_SIV_H_
+
+#include <stddef.h>
+
+#define LIBAES_SIV_VERSION_MAJOR 1
+#define LIBAES_SIV_VERSION_MINOR 0
+#define LIBAES_SIV_VERSION_PATCH 1
+
+#define LIBAES_SIV_VERSION ((LIBAES_SIV_VERSION_MAJOR << 16) + \
+                            (LIBAES_SIV_VERSION_MINOR << 8) +  \
+                            LIBAES_SIV_VERSION_PATCH)
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct AES_SIV_CTX_st AES_SIV_CTX;
+
+AES_SIV_CTX *AES_SIV_CTX_new(void);
+int AES_SIV_CTX_copy(AES_SIV_CTX *dst, AES_SIV_CTX const *src);
+void AES_SIV_CTX_cleanup(AES_SIV_CTX *ctx);
+void AES_SIV_CTX_free(AES_SIV_CTX *ctx);
+
+int AES_SIV_Init(AES_SIV_CTX *ctx, unsigned char const *key, size_t key_len);
+int AES_SIV_AssociateData(AES_SIV_CTX *ctx, unsigned char const *data,
+                          size_t len);
+int AES_SIV_EncryptFinal(AES_SIV_CTX *ctx, unsigned char *v_out,
+                         unsigned char *c_out, unsigned char const *plaintext,
+                         size_t len);
+int AES_SIV_DecryptFinal(AES_SIV_CTX *ctx, unsigned char *out,
+                         unsigned char const *v, unsigned char const *c,
+                         size_t len);
+
+int AES_SIV_Encrypt(AES_SIV_CTX *ctx, unsigned char *out, size_t *out_len,
+                    unsigned char const *key, size_t key_len,
+                    unsigned char const *nonce, size_t nonce_len,
+                    unsigned char const *plaintext, size_t plaintext_len,
+                    unsigned char const *ad, size_t ad_len);
+
+int AES_SIV_Decrypt(AES_SIV_CTX *ctx, unsigned char *out, size_t *out_len,
+                    unsigned char const *key, size_t key_len,
+                    unsigned char const *nonce, size_t nonce_len,
+                    unsigned char const *ciphertext, size_t ciphertext_len,
+                    unsigned char const *ad, size_t ad_len);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif


=====================================
libaes_siv/aes_siv_test.c
=====================================
@@ -0,0 +1,3 @@
+#define ENABLE_DEBUG_OUTPUT 1
+#undef NDEBUG
+#include "aes_siv.c"


=====================================
libaes_siv/bench.c
=====================================
@@ -0,0 +1,185 @@
+/* Copyright (c) 2017 Akamai Technologies, Inc.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "config.h"
+#include "aes_siv.h"
+
+#define _POSIX_C_SOURCE 200112L
+
+#include <math.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+static const unsigned char key[64];
+static const unsigned char ad[65536];
+static const unsigned char nonce[16];
+static unsigned char in[65536+16];
+static unsigned char out[65536+16];
+
+static const struct {
+        size_t key_len;
+        size_t nonce_len;
+        size_t in_len;
+        size_t ad_len;
+} call_list[] = {
+        { 32, 0, 0, 0 },
+        { 32, 0, 65536, 0 },
+        { 32, 0, 0, 65536 },
+        { 32, 0, 65536, 65536 },
+        { 32, 0, 1536, 0 },
+        { 32, 0, 0, 1536 },
+        { 32, 0, 1536, 1536 },
+        { 32, 0, 64, 0},
+        { 32, 0, 0, 64},
+        { 32, 0, 64, 64},
+        { 32, 16, 0, 0 },
+        { 32, 16, 65536, 0 },
+        { 32, 16, 0, 65536 },
+        { 32, 16, 65536, 65536 },
+        { 32, 16, 1536, 0 },
+        { 32, 16, 0, 1536 },
+        { 32, 16, 1536, 1536 },
+        { 32, 16, 64, 0},
+        { 32, 16, 0, 64},
+        { 32, 16, 64, 64},
+
+        { 48, 0, 0, 0 },
+        { 48, 0, 65536, 0 },
+        { 48, 0, 0, 65536 },
+        { 48, 0, 65536, 65536 },
+        { 48, 0, 1536, 0 },
+        { 48, 0, 0, 1536 },
+        { 48, 0, 1536, 1536 },
+        { 48, 0, 64, 0},
+        { 48, 0, 0, 64},
+        { 48, 0, 64, 64},
+        { 48, 16, 0, 0 },
+        { 48, 16, 65536, 0 },
+        { 48, 16, 0, 65536 },
+        { 48, 16, 65536, 65536 },
+        { 48, 16, 1536, 0 },
+        { 48, 16, 0, 1536 },
+        { 48, 16, 1536, 1536 },
+        { 48, 16, 64, 0},
+        { 48, 16, 0, 64},
+        { 48, 16, 64, 64},
+
+        { 64, 0, 0, 0 },
+        { 64, 0, 65536, 0 },
+        { 64, 0, 0, 65536 },
+        { 64, 0, 65536, 65536 },
+        { 64, 0, 1536, 0 },
+        { 64, 0, 0, 1536 },
+        { 64, 0, 1536, 1536 },
+        { 64, 0, 64, 0},
+        { 64, 0, 0, 64},
+        { 64, 0, 64, 64},
+        { 64, 16, 0, 0 },
+        { 64, 16, 65536, 0 },
+        { 64, 16, 0, 65536 },
+        { 64, 16, 65536, 65536 },
+        { 64, 16, 1536, 0 },
+        { 64, 16, 0, 1536 },
+        { 64, 16, 1536, 1536 },
+        { 64, 16, 64, 0},
+        { 64, 16, 0, 64},
+        { 64, 16, 64, 64},
+
+        { 0, 0, 0, 0 }
+};
+
+static volatile int alarm_rung;
+static void alarm_handler(int num) {
+  (void)num;
+  alarm_rung = 1;
+}
+
+typedef int (*fn)(AES_SIV_CTX *, unsigned char *, size_t *,
+                  unsigned char const*, size_t,
+                  unsigned char const*, size_t,
+                  unsigned char const*, size_t,
+                  unsigned char const*, size_t);
+static void
+call(fn fn, AES_SIV_CTX *ctx,
+     size_t key_len,
+     size_t nonce_len, size_t in_len,
+     size_t ad_len) {
+
+        size_t out_len = sizeof out;
+        size_t count;
+        struct timespec start, end;
+        double rate;
+
+        printf("%3u bit key, %2u byte nonce, %5u byte input, %5u byte associated data: ",
+               (unsigned)(key_len * 8), (unsigned)nonce_len,
+	       (unsigned)in_len, (unsigned)ad_len);
+        fflush(stdout);
+
+        alarm_rung = 0;
+        alarm(3);
+
+        if(clock_gettime(CLOCK_MONOTONIC, &start)) {
+                perror("clock_gettime");
+                exit(1);
+        }
+        for(count = 0; !alarm_rung; count++) {
+                fn(ctx, out, &out_len, key, key_len,
+                   nonce_len > 0 ? nonce : NULL, nonce_len,
+                   in, in_len, ad, ad_len);
+        }
+        if(clock_gettime(CLOCK_MONOTONIC, &end)) {
+                perror("clock_gettime");
+                exit(1);
+        }
+
+        rate = (double)count /
+                ((double)(end.tv_sec) - (double)(start.tv_sec) +
+                 ((double)end.tv_nsec - (double)start.tv_nsec)/1000000000.);
+        printf("%12.2f calls/second (%11.2f ns/call, %8.2f MiB/s)\n",
+               rate,
+               1000000000./rate,
+               scalbn(rate * (double)(ad_len + in_len),
+                      -20));
+}
+
+int main(void) {
+        size_t i;
+        struct sigaction act;
+        AES_SIV_CTX *ctx = AES_SIV_CTX_new();
+
+        memset(&act, 0, sizeof act);
+        act.sa_handler = alarm_handler;
+        if(sigaction(SIGALRM, &act, NULL)) {
+                perror("sigaction");
+                exit(1);
+        }
+
+        for(i=0; call_list[i].key_len != 0; i++) {
+                printf("Encrypt, ");
+                call(AES_SIV_Encrypt, ctx,
+                     call_list[i].key_len, call_list[i].nonce_len,
+                     call_list[i].in_len, call_list[i].ad_len);
+
+
+                printf("Decrypt, ");
+                memcpy(in, out, call_list[i].in_len + 16);
+                call(AES_SIV_Decrypt, ctx,
+                     call_list[i].key_len, call_list[i].nonce_len,
+                     call_list[i].in_len + 16, call_list[i].ad_len);
+
+                printf("Forgery, ");
+                memset(in, 0, sizeof in);
+                call(AES_SIV_Decrypt, ctx,
+                     call_list[i].key_len, call_list[i].nonce_len,
+                     call_list[i].in_len + 16, call_list[i].ad_len);
+
+        }
+
+        AES_SIV_CTX_free(ctx);
+        return 0;
+}


=====================================
libaes_siv/config.h.in
=====================================
@@ -0,0 +1,19 @@
+#ifndef AES_SIV_CONFIG_H_
+#define AES_SIV_CONFIG_H_
+
+/* Enable ct_poison() and ct_unpoison() hooks for testing with
+   ctgrind. */
+#cmakedefine ENABLE_CTGRIND 1
+
+/* Enable this to get test coverage for the portable versions of
+   putword() and getword() when you don't happen to have a PDP-11
+   in your test farm.
+*/
+#cmakedefine ENABLE_DEBUG_WEIRD_ENDIAN 1
+
+/* Enable this to get test coverage for the while loop in do_encrypt()
+   without having to have a multi-gigabyte test case that'll take
+   forever for Valgrind to crunch through
+*/
+#cmakedefine ENABLE_DEBUG_TINY_CHUNK_SIZE 1
+#endif


=====================================
libaes_siv/demo.c
=====================================
@@ -0,0 +1,263 @@
+/* Copyright (c) 2019 Akamai Technologies, Inc.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/** @file
+ * Demo program for libaes-siv
+ */
+
+#define _POSIX_C_SOURCE 200112L
+#define _ISOC99_SOURCE 1
+
+#include "aes_siv.h"
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Load a file into memory.
+ * @param[in] filename pathname of the file to load.
+ * @param[out] the buf pointer will be set to a new malloc buffer which contains the file data.
+ * @param[out] the len pointer will be set to the size of buf in bytes, which is the same as the file size in bytes.
+ * @return 0 upon success, the file could be read and the buf,len output parameters have been set.
+ * @return -1 on error; errno will be set.
+ */
+static int load_file(const char *filename, unsigned char **buf, size_t *len)
+{
+  FILE *f = NULL;
+  unsigned char *buf_ = NULL;
+  size_t len_;
+  long ftell_len;
+  int saved_errno;
+
+  /* Get file size */
+  f = fopen(filename, "rb");
+  if (f == NULL) {
+    goto fail;
+  }
+
+  if (fseek(f, 0, SEEK_END) < 0) {
+    goto fail;
+  }
+
+  ftell_len = ftell(f);
+  if(ftell_len < 0) {
+    goto fail;
+  }
+  len_ = (size_t)ftell_len;
+
+  if(fseek(f, 0, SEEK_SET) < 0) {
+    goto fail;
+  }
+
+  /* allocate memory and read */
+  buf_ = (unsigned char*) malloc(len_);
+  if (buf_ == NULL) {
+    goto fail;
+  }
+  if (fread(buf_, 1, len_, f) != len_) {
+    assert(errno);
+    goto fail;
+  }
+
+  fclose(f);
+  f = NULL;
+  *buf = buf_;
+  *len = len_;
+  return 0;
+
+  fail:
+  saved_errno = errno;
+  if(f != NULL) {
+    fclose(f);
+  }
+  free(buf_);
+  errno = saved_errno;
+  return -1;
+}
+
+void help(void)
+{
+  fprintf(stderr, "Usage: aes_siv_test [-d] <key file> <ad file> [nonce file]\n");
+  fprintf(stderr, "This program encrypts or decrypts STDIN to STDOUT using the AES-SIV algorithm.\n");
+  fprintf(stderr, "-d           Decrypt STDIN, by default STDIN is encrypted\n");
+  fprintf(stderr, "<key file>   Filename which is read for key data, must have a size of 32, 48, 64 bytes.\n");
+  fprintf(stderr, "<ad file>    Filename which is used for associate data. Can have any size.\n");
+  fprintf(stderr, "[nonce file] Optional filename which is used for nonce data. Can have any size.\n");
+}
+
+int main(int argc, char const* argv[])
+{
+  int arg = 1;
+  int decrypt_mode = 0;
+  const char *key_file = NULL;
+  const char *nonce_file = NULL;
+  const char *ad_file = NULL;
+  unsigned char *key = NULL;
+  size_t key_len = 0;
+  unsigned char *nonce = NULL;
+  size_t nonce_len = 0;
+  unsigned char *ad = NULL;
+  size_t ad_len = 0;
+  unsigned char *out = NULL;
+  size_t out_len = 0;
+  size_t plaintext_allocated = 1024;
+  unsigned char *plaintext = malloc(plaintext_allocated);
+  size_t plaintext_len = 0;
+  AES_SIV_CTX *ctx = NULL;
+
+  if(plaintext == NULL) {
+    perror("malloc");
+    goto fail;
+  }
+
+  /* Parse command line */
+  arg = 1;
+  if (arg < argc && strcmp(argv[arg], "-d") == 0)
+  {
+    decrypt_mode = 1;
+    ++arg;
+  }
+
+  if(arg >= argc)
+  {
+    fprintf(stderr, "Missing key filename\n\n");
+    help();
+    goto fail;
+  }
+  key_file = argv[arg++];
+
+  if(arg >= argc)
+  {
+    fprintf(stderr, "Missing associate data filename\n\n");
+    help();
+    goto fail;
+  }
+  ad_file = argv[arg++];
+
+  if(arg < argc)
+  {
+    nonce_file = argv[arg++];
+  }
+
+  if(arg < argc)
+  {
+    fprintf(stderr, "Unknown command line argument: %s\n\n", argv[arg]);
+    help();
+    goto fail;
+  }
+
+  /* Load files */
+  if(load_file(key_file, &key, &key_len) < 0)
+  {
+    fprintf(stderr, "Could not load key file %s : %s\n", key_file, strerror(errno));
+    goto fail;
+  }
+
+  assert(key != NULL);
+  if(! (key_len == 32 ||
+        key_len == 48 ||
+        key_len == 64))
+  {
+    fprintf(stderr, "Invalid key length %zu bytes, must be one of 32, 48, or 64\n", key_len);
+    goto fail;
+  }
+  
+  if(load_file(ad_file, &ad, &ad_len) < 0)
+  {
+    fprintf(stderr, "Could not load associated data file %s : %s\n", ad_file, strerror(errno));
+    goto fail;
+  }
+  assert(ad);
+  assert(ad_len > 0);
+  if(load_file(nonce_file, &nonce, &nonce_len) < 0)
+  {
+    fprintf(stderr, "could not load nonce file %s : %s\n", nonce_file, strerror(errno));
+    goto fail;
+  }
+
+  /* Read all of STDIN */
+  while(!feof(stdin))
+  {
+    unsigned char buf[1024];
+    unsigned char *plaintext_new;
+    size_t r = fread(buf, 1, sizeof(buf), stdin);
+    if(r > 0)
+    {
+      if(plaintext_len + r > plaintext_allocated)
+      {
+        plaintext_allocated *= 2;
+        plaintext_new = realloc(plaintext, plaintext_allocated);
+        if(plaintext_new == NULL)
+        {
+          perror("realloc");
+          goto fail;
+        }
+        plaintext = plaintext_new;
+      }
+      assert(plaintext_len + r <= plaintext_allocated);
+      memcpy(plaintext + plaintext_len, buf, r);
+      plaintext_len += r;
+    } else if(ferror(stdin)) {
+      perror("fread");
+      goto fail;
+    }
+  }
+
+  /* allocate output buffer */
+  out_len = plaintext_len + 16;
+  out = (unsigned char*) malloc(out_len);
+  if (out == NULL)
+  {
+    perror("malloc");
+    goto fail;
+  }
+
+  /* do AES-SIV */
+  ctx = AES_SIV_CTX_new();
+  if (ctx == NULL)
+  {
+    perror("AES_SIV_CTX_new");
+    goto fail;
+  }
+  if (decrypt_mode)
+  {
+    if (AES_SIV_Decrypt(ctx, out, &out_len, key, key_len, nonce, nonce_len, plaintext, plaintext_len, ad, ad_len) != 1)
+    {
+      fprintf(stderr, "Could not decrypt AES-SIV\n");
+      goto fail;
+    }
+  }
+  else
+  {
+    if (AES_SIV_Encrypt(ctx, out, &out_len, key, key_len, nonce, nonce_len, plaintext, plaintext_len, ad, ad_len) != 1)
+    {
+      fprintf(stderr, "Could not encrypt AES-SIV\n");
+      goto fail;
+    }
+  }
+  AES_SIV_CTX_free(ctx);
+
+  /* write to stdout */
+  if(fwrite(out, 1, out_len, stdout) < out_len) {
+    perror("fwrite");
+    goto fail;
+  }
+  
+  free(plaintext);
+  free(key);
+  free(ad);
+  free(nonce);
+  free(out);
+  return EXIT_SUCCESS;
+
+ fail:
+  free(plaintext);
+  free(key);
+  free(ad);
+  free(nonce);
+  free(out);
+  return EXIT_FAILURE;
+}


=====================================
libaes_siv/tests.c
=====================================
@@ -0,0 +1,584 @@
+/* Copyright (c) 2017-2019 Akamai Technologies, Inc.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define _POSIX_C_SOURCE 200112L
+#define _ISOC99_SOURCE 1
+
+#include "config.h"
+#include "aes_siv.h"
+
+#undef NDEBUG
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/opensslv.h>
+
+static void debug(const char *label, const unsigned char *hex, size_t len) {
+        size_t i;
+        printf("%16s: ", label);
+        for (i = 0; i < len; i++) {
+                if (i > 0 && i % 16 == 0)
+                        printf("\n                  ");
+                printf("%.2x", (int)hex[i]);
+                if (i > 0 && i % 4 == 3)
+                        printf(" ");
+        }
+        printf("\n");
+}
+
+static int fail_allocation_counter = -1;
+
+static void* mock_malloc(size_t num) {
+        if(fail_allocation_counter < 0) {
+                return malloc(num);
+        }
+        if(fail_allocation_counter-- == 0) {
+                return NULL;
+        }
+        return malloc(num);
+}
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+static void* mock_malloc_ex(size_t num, const char *file, int line) {
+	(void)file;
+	(void)line;
+	return mock_malloc(num);
+}
+
+static void *mock_realloc_ex(void *mem, size_t num, const char *file, int line) {
+	(void)file;
+	(void)line;
+	return realloc(mem, num);
+}
+
+static void mock_free_ex(void *mem, const char* file, int line) {
+	(void)file;
+	(void)line;
+	free(mem);
+}
+#endif
+
+/* This needs to be the first test case because CRYPTO_set_mem_functions()
+   will fail once any allocations have happened.
+*/
+static void test_malloc_failure(void) {
+        int ret, i=0;
+        AES_SIV_CTX *ctx;
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L	
+        ret = CRYPTO_set_mem_functions(mock_malloc, realloc, free);
+#else
+	ret = CRYPTO_set_mem_functions(mock_malloc_ex, mock_realloc_ex, mock_free_ex);
+#endif
+        assert(ret == 1);
+
+        printf("Test allocation failure:\n" );
+
+        do {
+                fail_allocation_counter = i++;
+        } while((ctx = AES_SIV_CTX_new()) == NULL);
+        assert(i > 1);
+        printf("AES_SIV_CTX_new() succeeds after %d successful allocations.\n", i-1);
+        AES_SIV_CTX_free(ctx);
+        fail_allocation_counter = -1;
+}
+
+static void test_cleanup_before_free(void) {
+	printf("Test cleanup before free: ");
+	AES_SIV_CTX *ctx = AES_SIV_CTX_new();
+	assert(ctx != NULL);
+	AES_SIV_CTX_cleanup(ctx);
+	AES_SIV_CTX_free(ctx);
+	printf("OK\n");
+}	
+
+static void test_vector_1(void) {
+        const unsigned char key[] = {
+                0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+                0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+                0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+                0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+        };
+
+        const unsigned char ad[] = {
+                0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
+        };
+
+        const unsigned char plaintext[] = {
+                0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee};
+
+        const unsigned char ciphertext[] = {
+                0x85, 0x63, 0x2d, 0x07, 0xc6, 0xe8, 0xf3, 0x7f,
+                0x95, 0x0a, 0xcd, 0x32, 0x0a, 0x2e, 0xcc, 0x93,
+                0x40, 0xc0, 0x2b, 0x96, 0x90, 0xc4, 0xdc, 0x04,
+                0xda, 0xef, 0x7f, 0x6a, 0xfe, 0x5c
+        };
+
+        unsigned char ciphertext_out[256];
+        unsigned char plaintext_out[256];
+
+        size_t plaintext_len = sizeof plaintext_out;
+        size_t ciphertext_len = sizeof ciphertext_out;
+
+        AES_SIV_CTX *ctx;
+        int ret;
+
+        printf("Test vector 1:\n");
+        debug("key", key, sizeof key);
+        debug("AD", ad, sizeof ad);
+        debug("plaintext", plaintext, sizeof plaintext);
+        debug("exp. ciphertext", ciphertext, sizeof ciphertext);
+
+        ctx = AES_SIV_CTX_new();
+        assert(ctx != NULL);
+
+        printf("Encryption:\n");
+        ret = AES_SIV_Encrypt(ctx, ciphertext_out, &ciphertext_len, key,
+                              sizeof key, NULL, 0, plaintext, sizeof plaintext,
+                              ad, sizeof ad);
+        assert(ret == 1);
+        assert(ciphertext_len == sizeof ciphertext);
+        assert(!memcmp(ciphertext, ciphertext_out, ciphertext_len));
+
+        printf("Decryption:\n");
+        ret = AES_SIV_Decrypt(ctx, plaintext_out, &plaintext_len, key,
+                              sizeof key, NULL, 0, ciphertext_out,
+                              ciphertext_len, ad, sizeof ad);
+        assert(ret == 1);
+        assert(plaintext_len == sizeof plaintext);
+        assert(!memcmp(plaintext, plaintext_out, plaintext_len));
+        AES_SIV_CTX_free(ctx);
+}
+
+static void test_vector_2(void) {
+        const unsigned char key[] = {
+                0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
+                0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
+                0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+                0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
+        };
+
+        const unsigned char ad1[] = {
+                0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+                0xde, 0xad, 0xda, 0xda, 0xde, 0xad, 0xda, 0xda,
+                0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
+                0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00
+        };
+
+        const unsigned char ad2[] = {
+                0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
+                0x90, 0xa0
+        };
+
+        const unsigned char nonce[] = {
+                0x09, 0xf9, 0x11, 0x02, 0x9d, 0x74, 0xe3, 0x5b,
+                0xd8, 0x41, 0x56, 0xc5, 0x63, 0x56, 0x88, 0xc0
+        };
+
+        const unsigned char plaintext[] = {
+                0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+                0x73, 0x6f, 0x6d, 0x65, 0x20, 0x70, 0x6c, 0x61,
+                0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x74,
+                0x6f, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70,
+                0x74, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20,
+                0x53, 0x49, 0x56, 0x2d, 0x41, 0x45, 0x53
+        };
+
+        const unsigned char ciphertext[] = {
+                0x7b, 0xdb, 0x6e, 0x3b, 0x43, 0x26, 0x67, 0xeb,
+                0x06, 0xf4, 0xd1, 0x4b, 0xff, 0x2f, 0xbd, 0x0f,
+                0xcb, 0x90, 0x0f, 0x2f, 0xdd, 0xbe, 0x40, 0x43,
+                0x26, 0x60, 0x19, 0x65, 0xc8, 0x89, 0xbf, 0x17,
+                0xdb, 0xa7, 0x7c, 0xeb, 0x09, 0x4f, 0xa6, 0x63,
+                0xb7, 0xa3, 0xf7, 0x48, 0xba, 0x8a, 0xf8, 0x29,
+                0xea, 0x64, 0xad, 0x54, 0x4a, 0x27, 0x2e, 0x9c,
+                0x48, 0x5b, 0x62, 0xa3, 0xfd, 0x5c, 0x0d
+        };
+
+        unsigned char ciphertext_out[256];
+        unsigned char plaintext_out[256];
+
+        AES_SIV_CTX *ctx;
+        int ret;
+
+        printf("Test vector 2:\n");
+        debug("key", key, sizeof key);
+        debug("AD1", ad1, sizeof ad1);
+        debug("AD2", ad2, sizeof ad2);
+        debug("nonce", nonce, sizeof nonce);
+        debug("plaintext", plaintext, sizeof plaintext);
+        debug("exp. ciphertext", ciphertext, sizeof ciphertext);
+
+        ctx = AES_SIV_CTX_new();
+        assert(ctx != NULL);
+
+        printf("Encryption:\n");
+        ret = AES_SIV_Init(ctx, key, sizeof key);
+        assert(ret == 1);
+        ret = AES_SIV_AssociateData(ctx, ad1, sizeof ad1);
+        assert(ret == 1);
+        ret = AES_SIV_AssociateData(ctx, ad2, sizeof ad2);
+        assert(ret == 1);
+        ret = AES_SIV_AssociateData(ctx, nonce, sizeof nonce);
+        assert(ret == 1);
+        ret = AES_SIV_EncryptFinal(ctx, ciphertext_out, ciphertext_out + 16,
+                                   plaintext, sizeof plaintext);
+        assert(ret == 1);
+        debug("IV || C", ciphertext_out, sizeof plaintext + 16);
+        assert(!memcmp(ciphertext_out, ciphertext, sizeof ciphertext));
+
+        printf("Decryption:\n");
+        ret = AES_SIV_Init(ctx, key, sizeof key);
+        assert(ret == 1);
+        ret = AES_SIV_AssociateData(ctx, ad1, sizeof ad1);
+        assert(ret == 1);
+        ret = AES_SIV_AssociateData(ctx, ad2, sizeof ad2);
+        assert(ret == 1);
+        ret = AES_SIV_AssociateData(ctx, nonce, sizeof nonce);
+        assert(ret == 1);
+        ret = AES_SIV_DecryptFinal(ctx, plaintext_out, ciphertext_out,
+                                   ciphertext_out + 16, sizeof plaintext);
+        assert(ret == 1);
+        debug("plaintext", plaintext_out, sizeof plaintext);
+        assert(!memcmp(plaintext_out, plaintext, sizeof plaintext));
+        AES_SIV_CTX_free(ctx);
+}
+
+static void test_384bit(void) {
+        const unsigned char key[] = {
+                0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+                0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+                0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+                0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+                0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+                0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0
+        };
+
+        const unsigned char ad[] = {
+                0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
+        };
+
+        const unsigned char plaintext[] = {
+                0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee
+        };
+
+        const unsigned char ciphertext[] = {
+                0x89, 0xe8, 0x69, 0xb9, 0x32, 0x56, 0x78, 0x51,
+                0x54, 0xf0, 0x96, 0x39, 0x62, 0xfe, 0x07, 0x40,
+                0xef, 0xf3, 0x56, 0xe4, 0x2d, 0xec, 0x1f, 0x4f,
+                0xeb, 0xde, 0xd3, 0x66, 0x42, 0xf2
+        };
+
+        unsigned char ciphertext_out[256];
+        unsigned char plaintext_out[256];
+
+        size_t plaintext_len = sizeof plaintext_out;
+        size_t ciphertext_len = sizeof ciphertext_out;
+
+        AES_SIV_CTX *ctx;
+        int ret;
+
+        printf("384-bit key test:\n");
+        debug("key", key, sizeof key);
+        debug("AD", ad, sizeof ad);
+        debug("plaintext", plaintext, sizeof plaintext);
+        debug("exp. ciphertext", ciphertext, sizeof ciphertext);
+
+        ctx = AES_SIV_CTX_new();
+        assert(ctx != NULL);
+
+        printf("Encryption:\n");
+        ret = AES_SIV_Encrypt(ctx, ciphertext_out, &ciphertext_len, key,
+                              sizeof key, NULL, 0, plaintext, sizeof plaintext,
+                              ad, sizeof ad);
+        assert(ret == 1);
+        assert(ciphertext_len == sizeof ciphertext);
+        assert(!memcmp(ciphertext, ciphertext_out, ciphertext_len));
+
+        printf("Decryption:\n");
+        ret = AES_SIV_Decrypt(ctx, plaintext_out, &plaintext_len, key,
+                              sizeof key, NULL, 0, ciphertext_out,
+                              ciphertext_len, ad, sizeof ad);
+        assert(ret == 1);
+        assert(plaintext_len == sizeof plaintext);
+        assert(!memcmp(plaintext, plaintext_out, plaintext_len));
+        AES_SIV_CTX_free(ctx);
+}
+
+static void test_512bit(void) {
+        const unsigned char key[] = {
+                0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+                0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+                0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+                0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+                0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+                0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+                0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+                0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0
+        };
+
+        const unsigned char ad[] = {
+                0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
+        };
+
+        const unsigned char plaintext[] = {
+                0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee
+        };
+
+        const unsigned char ciphertext[] = {
+                0x72, 0x4d, 0xfb, 0x2e, 0xaf, 0x94, 0xdb, 0xb1,
+                0x9b, 0x0b, 0xa3, 0xa2, 0x99, 0xa0, 0x80, 0x1e,
+                0xf3, 0xb0, 0x5a, 0x55, 0x49, 0x8e, 0xc2, 0x55,
+                0x26, 0x90, 0xb8, 0x98, 0x10, 0xe4
+        };
+
+        unsigned char ciphertext_out[256];
+        unsigned char plaintext_out[256];
+
+        size_t plaintext_len = sizeof plaintext_out;
+        size_t ciphertext_len = sizeof ciphertext_out;
+
+        AES_SIV_CTX *ctx;
+        int ret;
+
+        printf("512-bit key test:\n");
+        debug("key", key, sizeof key);
+        debug("AD", ad, sizeof ad);
+        debug("plaintext", plaintext, sizeof plaintext);
+        debug("exp. ciphertext", ciphertext, sizeof ciphertext);
+
+        ctx = AES_SIV_CTX_new();
+        assert(ctx != NULL);
+
+        printf("Encryption:\n");
+        ret = AES_SIV_Encrypt(ctx, ciphertext_out, &ciphertext_len, key,
+                              sizeof key, NULL, 0, plaintext, sizeof plaintext,
+                              ad, sizeof ad);
+        assert(ret == 1);
+        assert(ciphertext_len == sizeof ciphertext);
+        assert(!memcmp(ciphertext, ciphertext_out, ciphertext_len));
+
+        printf("Decryption:\n");
+        ret = AES_SIV_Decrypt(ctx, plaintext_out, &plaintext_len, key,
+                              sizeof key, NULL, 0, ciphertext_out,
+                              ciphertext_len, ad, sizeof ad);
+        assert(ret == 1);
+        assert(plaintext_len == sizeof plaintext);
+        assert(!memcmp(plaintext, plaintext_out, plaintext_len));
+        AES_SIV_CTX_free(ctx);
+}
+
+static void test_highlevel_with_nonce(void) {
+        const unsigned char key[] = {
+                0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+                0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+                0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+                0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+        };
+
+        const unsigned char ad[] = {
+                0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
+        };
+
+        const unsigned char nonce[] = {
+                0x09, 0xf9, 0x11, 0x02, 0x9d, 0x74, 0xe3, 0x5b,
+                0xd8, 0x41, 0x56, 0xc5, 0x63, 0x56, 0x88, 0xc0
+        };
+
+        const unsigned char plaintext[] = {
+                0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee
+        };
+
+        unsigned char ciphertext_out[256];
+        unsigned char plaintext_out[256];
+
+        size_t plaintext_len = sizeof plaintext_out;
+        size_t ciphertext_len = sizeof ciphertext_out;
+
+        AES_SIV_CTX *ctx;
+        int ret;
+
+        printf("Test high-level interface with non-NULL nonce:\n");
+        debug("key", key, sizeof key);
+        debug("AD", ad, sizeof ad);
+        debug("nonce", nonce, sizeof nonce);
+        debug("plaintext", plaintext, sizeof plaintext);
+
+        ctx = AES_SIV_CTX_new();
+        assert(ctx != NULL);
+
+        printf("Encryption:\n");
+        ret = AES_SIV_Encrypt(ctx, ciphertext_out, &ciphertext_len, key,
+                              sizeof key, nonce, sizeof nonce, plaintext,
+                              sizeof plaintext, ad, sizeof ad);
+        assert(ret == 1);
+
+        printf("Decryption:\n");
+        ret = AES_SIV_Decrypt(ctx, plaintext_out, &plaintext_len, key,
+                              sizeof key, nonce, sizeof nonce, ciphertext_out,
+                              ciphertext_len, ad, sizeof ad);
+        assert(ret == 1);
+        assert(plaintext_len == sizeof plaintext);
+        assert(!memcmp(plaintext, plaintext_out, plaintext_len));
+        AES_SIV_CTX_free(ctx);
+}
+
+static void test_copy(void) {
+        const unsigned char key[] = {
+                0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+                0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+                0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+                0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+        };
+
+        const unsigned char ad[] = {
+                0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+                0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
+        };
+
+        const unsigned char plaintext1[] = {
+                0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee
+        };
+
+        const unsigned char plaintext2[] = {
+                0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xef
+        };
+
+        const unsigned char ciphertext[] = {
+                0x85, 0x63, 0x2d, 0x07, 0xc6, 0xe8, 0xf3, 0x7f,
+                0x95, 0x0a, 0xcd, 0x32, 0x0a, 0x2e, 0xcc, 0x93,
+                0x40, 0xc0, 0x2b, 0x96, 0x90, 0xc4, 0xdc, 0x04,
+                0xda, 0xef, 0x7f, 0x6a, 0xfe, 0x5c
+        };
+
+        unsigned char ciphertext1_out[256], ciphertext2_out[256];
+
+        AES_SIV_CTX *ctx1, *ctx2, *ctx3;
+        int ret;
+
+        ctx1 = AES_SIV_CTX_new();
+        assert(ctx1 != NULL);
+        ctx2 = AES_SIV_CTX_new();
+        assert(ctx2 != NULL);
+        ctx3 = AES_SIV_CTX_new();
+        assert(ctx3 != NULL);
+
+        ret = AES_SIV_Init(ctx1, key, sizeof key);
+        assert(ret == 1);
+        ret = AES_SIV_CTX_copy(ctx2, ctx1);
+        assert(ret == 1);
+
+        ret = AES_SIV_AssociateData(ctx1, ad, sizeof ad);
+        assert(ret == 1);
+        ret = AES_SIV_AssociateData(ctx2, ad, sizeof ad);
+        assert(ret == 1);
+
+        ret = AES_SIV_CTX_copy(ctx3, ctx1);
+        assert(ret == 1);
+
+        ret = AES_SIV_EncryptFinal(ctx1, ciphertext1_out, ciphertext1_out + 16,
+                                   plaintext1, sizeof plaintext1);
+        assert(ret == 1);
+        assert(!memcmp(ciphertext, ciphertext1_out, sizeof ciphertext));
+
+        ret = AES_SIV_EncryptFinal(ctx2, ciphertext2_out, ciphertext2_out + 16,
+                                   plaintext1, sizeof plaintext1);
+        assert(ret == 1);
+        assert(!memcmp(ciphertext, ciphertext2_out, sizeof ciphertext));
+
+        ret = AES_SIV_EncryptFinal(ctx3, ciphertext2_out, ciphertext2_out + 16,
+                                   plaintext2, sizeof plaintext2);
+        assert(ret == 1);
+        assert(memcmp(ciphertext, ciphertext2_out, sizeof ciphertext));
+
+        AES_SIV_CTX_free(ctx1);
+        AES_SIV_CTX_free(ctx2);
+        AES_SIV_CTX_free(ctx3);
+}
+
+static void test_bad_key(void) {
+        static const unsigned char key[40];
+        static const unsigned char ad[16];
+        static const unsigned char plaintext[16];
+
+        unsigned char ciphertext_out[256];
+        size_t ciphertext_len = sizeof ciphertext_out;
+
+        AES_SIV_CTX *ctx;
+        int ret;
+
+        printf("Test bad key size: ");
+
+        ctx = AES_SIV_CTX_new();
+        assert(ctx != NULL);
+
+        ret = AES_SIV_Encrypt(ctx, ciphertext_out, &ciphertext_len, key,
+                              sizeof key, NULL, 0, plaintext, sizeof plaintext,
+                              ad, sizeof ad);
+        assert(ret == 0);
+
+        ret = AES_SIV_Init(ctx, key, sizeof key);
+        assert(ret == 0);
+
+        AES_SIV_CTX_free(ctx);
+        printf("OK\n");
+}
+
+static void test_decrypt_failure(void) {
+        static const unsigned char key[32];
+        static const unsigned char ad[16];
+        static const unsigned char ciphertext[32];
+
+        unsigned char plaintext_out[256];
+        size_t plaintext_len = sizeof plaintext_out;
+
+        AES_SIV_CTX *ctx;
+        int ret;
+
+        printf("Test decryption failure:\n");
+
+        ctx = AES_SIV_CTX_new();
+        assert(ctx != NULL);
+
+        ret = AES_SIV_Decrypt(ctx, plaintext_out, &plaintext_len, key,
+                              sizeof key, NULL, 0, ciphertext,
+                              sizeof ciphertext, ad, sizeof ad);
+        assert(ret == 0);
+
+        AES_SIV_CTX_free(ctx);
+}
+
+int main(void) {
+        test_malloc_failure();
+	test_cleanup_before_free();
+        test_vector_1();
+        test_vector_2();
+        test_384bit();
+        test_512bit();
+        test_highlevel_with_nonce();
+        test_copy();
+        test_bad_key();
+        test_decrypt_failure();
+        return 0;
+}


=====================================
libaes_siv/wscript
=====================================
@@ -0,0 +1,10 @@
+def build(ctx):
+    # libaes_siv has warnings when built with -Wshadow, so make sure to use
+    # -Wno-shadow
+    ctx.env.CFLAGS_cstlib = ['-Wno-shadow']
+
+    ctx(
+        target="aes_siv",
+        features="c cstlib bld_include" ,
+        source="aes_siv.c",
+    )


=====================================
ntpd/wscript
=====================================
@@ -66,10 +66,10 @@ def build(ctx):
 
     ctx(
         features="c bld_include src_include",
-        includes=ctx.env.PLATFORM_INCLUDES,
+        includes=["%s/libaes_siv/" % srcnode] + ctx.env.PLATFORM_INCLUDES,
         source=libntpd_source,
         target="libntpd_obj",
-        use="SSL CRYPTO AES_SIV",
+        use="SSL CRYPTO aes_siv",
     )
 
     ctx(
@@ -129,7 +129,7 @@ def build(ctx):
         source=ntpd_source,
         target="ntpd",
         use="libntpd_obj ntp M parse RT CAP SECCOMP PTHREAD NTPD "
-            "SSL CRYPTO AES_SIV DNS_SD %s SOCKET NSL SCF" % use_refclock,
+            "SSL CRYPTO DNS_SD %s SOCKET NSL SCF" % use_refclock,
     )
 
     ctx.manpage(8, "ntpd-man.adoc")


=====================================
wscript
=====================================
@@ -613,9 +613,6 @@ int main(int argc, char **argv) {
     ):
         ctx.check_cc(msg="Checking for OpenSSL's crypto library",
                      lib="crypto", mandatory=True)
-    # Someday this will likely become part of OpenSSL.
-    ctx.check_cc(msg="Checking for libaes_siv",
-                 lib="aes_siv", mandatory=True)
 
     # Optional functions.  Do all function checks here, otherwise
     # we're likely to duplicate them.
@@ -1023,6 +1020,7 @@ def build(ctx):
         # required by the generic and Trimble refclocks
         ctx.recurse("libparse")
     ctx.recurse("libntp")
+    ctx.recurse("libaes_siv")
     ctx.recurse("ntpd")
     ctx.recurse("ntpfrob")
     ctx.recurse("ntptime")



View it on GitLab: https://gitlab.com/NTPsec/ntpsec/compare/164e325b246640cd6305776ed5d0f2a826a03ea4...0d6daaa05b98dca4371d28053aa211849a1a6ffe

-- 
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/compare/164e325b246640cd6305776ed5d0f2a826a03ea4...0d6daaa05b98dca4371d28053aa211849a1a6ffe
You're receiving this email because of your account on gitlab.com.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ntpsec.org/pipermail/vc/attachments/20190220/22593370/attachment-0001.html>


More information about the vc mailing list