urbit/pkg/libaes_siv
Brendan Hay ce3cbf0857
build: rework all nix expressions to support hercules-ci builds
This also removes nixcrpkgs and OSX cross compilation in favour of
compiling on the target. x86_64/musl targets are still supported
on Linux.

All sources are now managed via niv (see nix/sources.json) and Haskell
package sets are provided/organised via IOHK's haskell.nix.

Some effort has been made to expose similar top-level attributes for
development, but in some cases there have been changes. Please see
the comments in the top-level default.nix and ci.nix files for usage.
2020-10-27 13:55:49 +01:00
..
aes_siv.c jets: switch openssl to the loom allocator. 2020-05-29 15:51:53 -07:00
aes_siv.h aes_siv: vendors libaes_siv since it isn't in nix. 2020-05-20 13:51:59 -07:00
config.h aes_siv: vendors libaes_siv since it isn't in nix. 2020-05-20 13:51:59 -07:00
COPYING aes_siv: vendors libaes_siv since it isn't in nix. 2020-05-20 13:51:59 -07:00
Makefile aes_siv: vendors libaes_siv since it isn't in nix. 2020-05-20 13:51:59 -07:00
README.md aes_siv: vendors libaes_siv since it isn't in nix. 2020-05-20 13:51:59 -07:00
README.urbit.md aes_siv: vendors libaes_siv since it isn't in nix. 2020-05-20 13:51:59 -07:00
shell.nix build: rework all nix expressions to support hercules-ci builds 2020-10-27 13:55:49 +01:00

libaes_siv

This is an RFC5297-compliant C implementation of AES-SIV written by Daniel Franke on behalf of Akamai Technologies. It is published under the Apache License (v2.0). It uses OpenSSL for the underlying AES and CMAC implementations and follows a similar interface style.

An AES_SIV implementation forked from libaes_siv has been merged into the OpenSSL master branch. 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 for authenticated encryption with associated data designed to be maximally resistant to accidental 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.

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 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 >= 3.1
  • OpenSSL >=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 (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

NOTE: Out-of-source builds are allowed, but out-of-source manpage builds require a2x's -D option, which may provoke an apparently bogus warning from a2x.

If you want to build on an OS X machine, install the Xcode development environment and the command line tools, then use either the Homebrew package manager or the MacPorts package manager to install cmake and OpenSSL.

Homebrew (https://brew.sh/):

    brew install cmake openssl &&
    cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/openssl . &&
    make &&
    make test &&
    sudo make install

MacPorts (https://www.macports.org/):

    sudo port install cmake openssl &&
    cmake . &&
    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 in 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. It produces clean output from Valgrind and from Clang's undefined behavior sanitizer, and is verified using 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.