build: updates libaes_siv, builds from upstream

This commit is contained in:
Joe Bryan 2021-08-03 16:46:40 -04:00
parent 042b115b76
commit 44c7eedbd2
13 changed files with 67 additions and 1112 deletions

View File

@ -95,7 +95,7 @@ let
ge-additions = callPackage ./nix/pkgs/ge-additions { };
libaes_siv = callPackage ./nix/pkgs/libaes_siv { };
libaes_siv = callPackage ./nix/pkgs/libaes_siv { inherit (pkgsNative) cmake; };
libscrypt = callPackage ./nix/pkgs/libscrypt { };

View File

@ -0,0 +1,34 @@
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,6 +5,8 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE Release)
endif("${CMAKE_BUILD_TYPE}" STREQUAL "")
+option(BUILD_SHARED_LIBS "Build shared libraries" ON)
+
include(GNUInstallDirs)
# Warning: don't use the UB sanitizer in production builds. It can introduce timing side-channels
@@ -31,10 +33,12 @@ endif(NOT DISABLE_DOCS)
configure_file(config.h.in config.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
+if(BUILD_SHARED_LIBS)
add_library(aes_siv SHARED aes_siv.c)
target_include_directories(aes_siv PUBLIC ${OPENSSL_INCLUDE_DIR})
target_link_libraries(aes_siv ${OPENSSL_CRYPTO_LIBRARY})
set_target_properties(aes_siv PROPERTIES VERSION "1.0.1" SOVERSION 1)
+endif()
add_library(aes_siv_static STATIC aes_siv.c)
target_include_directories(aes_siv_static PUBLIC ${OPENSSL_INCLUDE_DIR})
@@ -63,7 +67,9 @@ endif(ENABLE_SANITIZER)
add_executable(bench EXCLUDE_FROM_ALL bench.c)
target_link_libraries(bench aes_siv_static)
+if(BUILD_SHARED_LIBS)
install(TARGETS aes_siv LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
+endif()
install(TARGETS aes_siv_static ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES aes_siv.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

View File

@ -1,12 +1,17 @@
{ lib, stdenv, openssl, enableParallelBuilding ? true }:
{ stdenv, sources, cmake, openssl, enableParallelBuilding ? true }:
stdenv.mkDerivation {
name = "libaes_siv";
src = lib.cleanSource ../../../pkg/libaes_siv;
version = sources.libaes_siv.rev;
src = sources.libaes_siv;
patches = [ ./cmakefiles_static.patch ];
nativeBuildInputs = [ cmake ];
buildInputs = [ openssl ];
installFlags = [ "PREFIX=$(out)" ];
cmakeFlags = [
"-DBUILD_SHARED_LIBS=OFF"
];
inherit enableParallelBuilding;
}

View File

@ -77,14 +77,5 @@
"pmnsh": {
"make": "CFLAGS=-I../ed25519"
}
},
"libaes_siv": {
"pmnsh": {
"compat": {
"m1brew": {
"make": "CFLAGS=$(pkg-config --cflags openssl)"
}
}
}
}
}

View File

@ -77,6 +77,30 @@
"url": "https://github.com/input-output-hk/haskell.nix/archive/bbb34dcdf7b90d478002f91713531f418ddf1b53.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"libaes_siv": {
"branch": "master",
"description": null,
"homepage": null,
"pmnsh": {
"compat": {
"m1brew": {
"prepare": "cmake .",
"make": "install CFLAGS=$(pkg-config --cflags openssl)"
},
"mingw": {
"prepare": "cmake -G\"MSYS Makefiles\" -DDISABLE_DOCS:BOOL=ON .",
"make": "install"
}
}
},
"owner":"dfoxfranke",
"repo": "libaes_siv",
"rev": "9681279cfaa6e6399bb7ca3afbbc27fc2e19df4b",
"sha256": "1g4wy0m5wpqx7z6nillppkh5zki9fkx9rdw149qcxh7mc5vlszzi",
"type": "tarball",
"url": "https://github.com/dfoxfranke/libaes_siv/archive/9681279cfaa6e6399bb7ca3afbbc27fc2e19df4b.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"libscrypt": {
"branch": "master",
"description": null,

View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,20 +0,0 @@
CC ?= cc
AR ?= ar
PREFIX ?= ./out
################################################################################
.PHONY: all test install clean
all: aes_siv.c aes_siv.h
$(CC) $(CFLAGS) -Wall -Wextra -Wstrict-prototypes -Wconversion -O3 -fomit-frame-pointer -funroll-loops -ftree-vectorize -DNDEBUG -c aes_siv.c
$(AR) rcs libaes_siv.a aes_siv.o
install: all
@mkdir -p $(PREFIX)/lib/
@mkdir -p $(PREFIX)/include/
cp libaes_siv.a $(PREFIX)/lib/
cp aes_siv.h $(PREFIX)/include/
clean:
rm -rf ./out

View File

@ -1,197 +0,0 @@
# 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.

View File

@ -1,2 +0,0 @@
Vendoring of git@github.com:dfoxfranke/libaes_siv.git.
Code from commit 509550e92a416172b9b8255e275f3a04d5fd4545

View File

@ -1,594 +0,0 @@
/* 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);
/* Prior to OpenSSL 1.0.2b, CMAC_CTX_free() crashes on NULL */
if (LIKELY(ctx->cmac_ctx_init != NULL)) {
CMAC_CTX_free(ctx->cmac_ctx_init);
}
if (LIKELY(ctx->cmac_ctx != NULL)) {
CMAC_CTX_free(ctx->cmac_ctx);
}
OPENSSL_cleanse(&ctx->d, sizeof ctx->d);
OPENSSL_free(ctx);
}
}
AES_SIV_CTX *AES_SIV_CTX_new(void) {
AES_SIV_CTX *ctx = OPENSSL_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, key_len);
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;
}

View File

@ -1,57 +0,0 @@
/* 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

View File

@ -1,19 +0,0 @@
#ifndef AES_SIV_CONFIG_H_
#define AES_SIV_CONFIG_H_
/* Enable ct_poison() and ct_unpoison() hooks for testing with
ctgrind. */
/* #undef ENABLE_CTGRIND */
/* 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.
*/
/* #undef ENABLE_DEBUG_WEIRD_ENDIAN */
/* 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
*/
/* #undef ENABLE_DEBUG_TINY_CHUNK_SIZE */
#endif

View File

@ -1,8 +0,0 @@
let
pkgs = import ../../default.nix { };
in pkgs.shellFor {
name = "libaes_siv";
packages = ps: [ ps.libaes_siv ];
}