mirror of
https://github.com/urbit/shrub.git
synced 2024-12-01 06:35:32 +03:00
cc3a139440
This vendors libaes_siv so that we can use it to jet +sivc:aes:crypto.
198 lines
7.9 KiB
Markdown
198 lines
7.9 KiB
Markdown
# 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
|
|
```
|
|
|
|
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](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.
|