Smaller OQS_AES128 public API and support use of OpenSSL AES for faster operations. (#40)

* Make OQS_AES128 use a void schedule pointer.

* Fewer functions in AES public API.

* Reorganize RAND_urandom_aesctr to not use cache for n.

* Focus AES API on ECB mode rather than raw operations.

* Optionally use OpenSSL for AES.
This commit is contained in:
Douglas Stebila 2016-10-28 00:22:34 -04:00 committed by GitHub
parent 2777bfd449
commit 1698c32989
10 changed files with 452 additions and 159 deletions

View File

@ -44,22 +44,23 @@ matrix:
- cd astyle/build/gcc && make && export PATH=$(pwd)/bin:$PATH && cd ../../../
- os: linux
compiler: gcc
env: CC_OQS=gcc-6
env: CC_OQS=gcc-6 USE_OPENSSL=1
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-6
- libssl-dev
before_install:
- wget http://downloads.sourceforge.net/project/astyle/astyle/astyle%202.05.1/astyle_2.05.1_linux.tar.gz
- tar xzf astyle_2.05.1_linux.tar.gz
- cd astyle/build/gcc && make && export PATH=$(pwd)/bin:$PATH && cd ../../../
- os: osx
compiler: clang
env: CC_OQS=clang AES_NI=0
env: CC_OQS=clang AES_NI=0 USE_OPENSSL=1
before_install:
- brew install astyle
- brew install astyle openssl
script:
- make

View File

@ -9,8 +9,7 @@ CURL=curl
RANLIB=ranlib
LN=ln -s
DEFAULTS= -O3 -std=gnu11 -Wpedantic -Wall -Wextra -DOQS_RAND_DEFAULT_URANDOM_CHACHA20 -DOQS_KEX_DEFAULT_BCNS15
CFLAGS=$(DEFAULTS) -DCONSTANT_TIME
CFLAGS= -O3 -std=gnu11 -Wpedantic -Wall -Wextra -DCONSTANT_TIME
LDFLAGS=-lm
INCLUDES=-Iinclude
@ -31,6 +30,19 @@ else
CFLAGS += -DAES_DISABLE_NI
endif
ifdef USE_OPENSSL
CFLAGS += -DUSE_OPENSSL
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
OPENSSL_DIR=/usr
endif
ifeq ($(UNAME_S),Darwin)
OPENSSL_DIR=/usr/local/opt/openssl
endif
INCLUDES += -I$(OPENSSL_DIR)/include
LDFLAGS += -L$(OPENSSL_DIR)/lib -lcrypto
endif
.PHONY: all check clean prettyprint
all: links lib tests

View File

@ -1,51 +1,188 @@
#include <assert.h>
#include "aes.h"
#include "aes_local.h"
void OQS_AES128_load_schedule(const uint8_t *key, uint8_t *schedule) {
#ifndef AES_DISABLE_NI
OQS_AES128_load_schedule_ni(key, schedule);
void OQS_AES128_load_schedule(const uint8_t *key, void **schedule, int for_encryption) {
#ifdef USE_OPENSSL
oqs_aes128_load_schedule_ossl(key, schedule, for_encryption);
#else
OQS_AES128_load_schedule_c(key, schedule);
for_encryption++; // need some dummy operation to avoid unused parameter warning
#ifndef AES_DISABLE_NI
oqs_aes128_load_schedule_ni(key, schedule);
#else
oqs_aes128_load_schedule_c(key, schedule);
#endif
}
void OQS_AES128_enc(const uint8_t *plaintext, const uint8_t *schedule, uint8_t *ciphertext) {
#ifndef AES_DISABLE_NI
OQS_AES128_enc_ni(plaintext, schedule, ciphertext);
#else
OQS_AES128_enc_c(plaintext, schedule, ciphertext);
#endif
}
void OQS_AES128_dec(const uint8_t *ciphertext, const uint8_t *schedule, uint8_t *plaintext) {
#ifndef AES_DISABLE_NI
OQS_AES128_dec_ni(ciphertext, schedule, plaintext);
void OQS_AES128_free_schedule(void *schedule) {
#ifdef USE_OPENSSL
oqs_aes128_free_schedule_ossl(schedule);
#else
OQS_AES128_dec_c(ciphertext, schedule, plaintext);
#ifndef AES_DISABLE_NI
oqs_aes128_free_schedule_ni(schedule);
#else
oqs_aes128_free_schedule_c(schedule);
#endif
#endif
}
void OQS_AES128_ECB_enc(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext) {
uint8_t schedule[OQS_AES128_SCHEDULE_NUMBYTES];
OQS_AES128_load_schedule(key, schedule);
assert(plaintext_len % 16 == 0);
for (size_t block = 0; block < plaintext_len / 16; block++) {
OQS_AES128_enc(plaintext + (16 * block), schedule, ciphertext + (16 * block));
}
}
void OQS_AES128_ECB_enc_sch(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *schedule, uint8_t *ciphertext) {
assert(plaintext_len % 16 == 0);
for (size_t block = 0; block < plaintext_len / 16; block++) {
OQS_AES128_enc(plaintext + (16 * block), schedule, ciphertext + (16 * block));
}
#ifdef USE_OPENSSL
oqs_aes128_ecb_enc_ossl(plaintext, plaintext_len, key, ciphertext);
#else
#ifndef AES_DISABLE_NI
oqs_aes128_ecb_enc_ni(plaintext, plaintext_len, key, ciphertext);
#else
oqs_aes128_ecb_enc_c(plaintext, plaintext_len, key, ciphertext);
#endif
#endif
}
void OQS_AES128_ECB_dec(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext) {
uint8_t schedule[OQS_AES128_SCHEDULE_NUMBYTES];
OQS_AES128_load_schedule(key, schedule);
assert(ciphertext_len % 16 == 0);
for (size_t block = 0; block < ciphertext_len / 16; block++) {
OQS_AES128_dec(ciphertext + (16 * block), schedule, plaintext + (16 * block));
#ifdef USE_OPENSSL
oqs_aes128_ecb_dec_ossl(ciphertext, ciphertext_len, key, plaintext);
#else
#ifndef AES_DISABLE_NI
oqs_aes128_ecb_dec_ni(ciphertext, ciphertext_len, key, plaintext);
#else
oqs_aes128_ecb_dec_c(ciphertext, ciphertext_len, key, plaintext);
#endif
#endif
}
void OQS_AES128_ECB_enc_sch(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext) {
#ifdef USE_OPENSSL
oqs_aes128_ecb_enc_sch_ossl(plaintext, plaintext_len, schedule, ciphertext);
#else
#ifndef AES_DISABLE_NI
oqs_aes128_ecb_enc_sch_ni(plaintext, plaintext_len, schedule, ciphertext);
#else
oqs_aes128_ecb_enc_sch_c(plaintext, plaintext_len, schedule, ciphertext);
#endif
#endif
}
void OQS_AES128_ECB_dec_sch(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext) {
#ifdef USE_OPENSSL
oqs_aes128_ecb_dec_sch_ossl(ciphertext, ciphertext_len, schedule, plaintext);
#else
#ifndef AES_DISABLE_NI
oqs_aes128_ecb_dec_sch_ni(ciphertext, ciphertext_len, schedule, plaintext);
#else
oqs_aes128_ecb_dec_sch_c(ciphertext, ciphertext_len, schedule, plaintext);
#endif
#endif
}
inline void oqs_aes128_ecb_enc_ni(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext) {
void *schedule = NULL;
oqs_aes128_load_schedule_ni(key, &schedule);
oqs_aes128_ecb_enc_sch_ni(plaintext, plaintext_len, schedule, ciphertext);
oqs_aes128_free_schedule_ni(schedule);
}
inline void oqs_aes128_ecb_enc_c(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext) {
void *schedule = NULL;
oqs_aes128_load_schedule_c(key, &schedule);
oqs_aes128_ecb_enc_sch_c(plaintext, plaintext_len, schedule, ciphertext);
oqs_aes128_free_schedule_c(schedule);
}
inline void oqs_aes128_ecb_enc_sch_ni(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext) {
assert(plaintext_len % 16 == 0);
for (size_t block = 0; block < plaintext_len / 16; block++) {
oqs_aes128_enc_ni(plaintext + (16 * block), schedule, ciphertext + (16 * block));
}
}
inline void oqs_aes128_ecb_enc_sch_c(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext) {
assert(plaintext_len % 16 == 0);
for (size_t block = 0; block < plaintext_len / 16; block++) {
oqs_aes128_enc_c(plaintext + (16 * block), schedule, ciphertext + (16 * block));
}
}
inline void oqs_aes128_ecb_dec_ni(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext) {
void *schedule = NULL;
oqs_aes128_load_schedule_ni(key, &schedule);
oqs_aes128_ecb_dec_sch_ni(ciphertext, ciphertext_len, schedule, plaintext);
oqs_aes128_free_schedule_ni(schedule);
}
inline void oqs_aes128_ecb_dec_c(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext) {
void *schedule = NULL;
oqs_aes128_load_schedule_c(key, &schedule);
oqs_aes128_ecb_dec_sch_c(ciphertext, ciphertext_len, schedule, plaintext);
oqs_aes128_free_schedule_c(schedule);
}
inline void oqs_aes128_ecb_dec_sch_ni(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext) {
assert(ciphertext_len % 16 == 0);
for (size_t block = 0; block < ciphertext_len / 16; block++) {
oqs_aes128_dec_ni(ciphertext + (16 * block), schedule, plaintext + (16 * block));
}
}
inline void oqs_aes128_ecb_dec_sch_c(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext) {
assert(ciphertext_len % 16 == 0);
for (size_t block = 0; block < ciphertext_len / 16; block++) {
oqs_aes128_dec_c(ciphertext + (16 * block), schedule, plaintext + (16 * block));
}
}
#ifdef USE_OPENSSL
#include <openssl/evp.h>
inline void oqs_aes128_load_schedule_ossl(const uint8_t *key, void **schedule, int for_encryption) {
EVP_CIPHER_CTX *aes_ctx = EVP_CIPHER_CTX_new();
assert(aes_ctx != NULL);
if (for_encryption) {
assert(1 == EVP_EncryptInit_ex(aes_ctx, EVP_aes_128_ecb(), NULL, key, NULL));
} else {
assert(1 == EVP_DecryptInit_ex(aes_ctx, EVP_aes_128_ecb(), NULL, key, NULL));
}
EVP_CIPHER_CTX_set_padding(aes_ctx, 0);
*schedule = aes_ctx;
}
inline void oqs_aes128_free_schedule_ossl(void *schedule) {
if (schedule != NULL) {
EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *) schedule);
}
}
inline void oqs_aes128_ecb_enc_ossl(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext) {
void *schedule = NULL;
oqs_aes128_load_schedule_ossl(key, &schedule, 1);
oqs_aes128_ecb_enc_sch_ossl(plaintext, plaintext_len, schedule, ciphertext);
oqs_aes128_free_schedule_ossl(schedule);
}
inline void oqs_aes128_ecb_dec_ossl(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext) {
void *schedule = NULL;
oqs_aes128_load_schedule_ossl(key, &schedule, 0);
oqs_aes128_ecb_dec_sch_ossl(ciphertext, ciphertext_len, schedule, plaintext);
oqs_aes128_free_schedule_ossl(schedule);
}
inline void oqs_aes128_ecb_enc_sch_ossl(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext) {
assert(plaintext_len % 16 == 0);
int outlen;
assert(1 == EVP_EncryptUpdate((EVP_CIPHER_CTX *) schedule, ciphertext, &outlen, plaintext, plaintext_len));
assert((size_t) outlen == plaintext_len);
assert(1 == EVP_EncryptFinal_ex((EVP_CIPHER_CTX *) schedule, ciphertext, &outlen));
}
inline void oqs_aes128_ecb_dec_sch_ossl(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext) {
assert(ciphertext_len % 16 == 0);
int outlen;
assert(1 == EVP_DecryptUpdate((EVP_CIPHER_CTX *) schedule, plaintext, &outlen, ciphertext, ciphertext_len));
assert((size_t) outlen == ciphertext_len);
assert(1 == EVP_DecryptFinal_ex((EVP_CIPHER_CTX *) schedule, plaintext, &outlen));
}
#endif

View File

@ -10,44 +10,25 @@
#include <stdint.h>
#include <stdlib.h>
#define OQS_AES128_SCHEDULE_NUMBYTES 20 * 16
/**
* Function to fill a key schedule given an inital key
*
* @param key Initial Key
* @param schedule Abstract data structure for a key schedule
* @param forEncryption 1 if key schedule is for encryption, 0 if for decryption
*/
void OQS_AES128_load_schedule(const uint8_t *key, void **schedule, int for_encryption);
/**
* Function to fill a key schedule given an inital key
*
* @param key Initial Key
* @param schedule a 16*20 byte array to store the key schedual
*/
void OQS_AES128_load_schedule(const uint8_t *key, uint8_t *schedule);
/**
* AES 128 encryption function
*
* @param plaintext Plaintext message to encrypt (16-byte array)
* @param schedule Schedule generated with OQS_AES128_load_schedule
* @param ciphertext 16-byte array to store ciphertext
*/
void OQS_AES128_enc(const uint8_t *plaintext, const uint8_t *schedule, uint8_t *ciphertext);
/**
* AES 128 decryption function
*
* @param ciphertext Ciphertext message to decrypt (16-byte array)
* @param schedule Schedule generated with OQS_AES128_load_schedule
* @param plaintext 16-byte array to store ciphertext
*/
void OQS_AES128_dec(const uint8_t *ciphertext, const uint8_t *schedule, uint8_t *plaintext);
* Function to free a key schedule
*
* @param schedule Schedule generated with OQS_AES128_load_schedule
*/
void OQS_AES128_free_schedule(void *schedule);
void OQS_AES128_ECB_enc(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext);
void OQS_AES128_ECB_dec(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext);
void OQS_AES128_ECB_enc_sch(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *schedule, uint8_t *ciphertext);
void OQS_AES128_load_schedule_ni(const uint8_t *key, uint8_t *schedule);
void OQS_AES128_enc_ni(const uint8_t *plaintext, const uint8_t *schedule, uint8_t *ciphertext);
void OQS_AES128_dec_ni(const uint8_t *ciphertext, const uint8_t *schedule, uint8_t *plaintext);
void OQS_AES128_load_schedule_c(const uint8_t *key, uint8_t *schedule);
void OQS_AES128_enc_c(const uint8_t *plaintext, const uint8_t *schedule, uint8_t *ciphertext);
void OQS_AES128_dec_c(const uint8_t *ciphertext, const uint8_t *schedule, uint8_t *plaintext);
void OQS_AES128_ECB_enc_sch(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext);
void OQS_AES128_ECB_dec_sch(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext);
#endif

View File

@ -209,7 +209,10 @@ static void key_schedule_core(byte *a, int i) {
// Expand the 16-byte key to 11 round keys (176 bytes)
// http://en.wikipedia.org/wiki/Rijndael_key_schedule#The_key_schedule
void OQS_AES128_load_schedule_c(const uint8_t *key, uint8_t *schedule) {
void oqs_aes128_load_schedule_c(const uint8_t *key, void **_schedule) {
*_schedule = malloc(16 * 11);
assert(*_schedule != NULL);
uint8_t *schedule = (uint8_t *) *_schedule;
int bytes = 16; // The count of how many bytes we've created so far
int i = 1; // The rcon iteration value i is set to 1
int j; // For repeating the second stage 3 times
@ -234,6 +237,12 @@ void OQS_AES128_load_schedule_c(const uint8_t *key, uint8_t *schedule) {
}
}
void oqs_aes128_free_schedule_c(void *schedule) {
if (schedule != NULL) {
free(schedule);
}
}
// Apply the shift rows step on the 16 byte cipher state
// http://en.wikipedia.org/wiki/Advanced_Encryption_Standard#The_ShiftRows_step
static void shift_rows(byte *state) {
@ -295,7 +304,8 @@ static void mix_cols_inv (byte *state) {
mix_col_inv(state + 12);
}
void OQS_AES128_enc_c(const uint8_t *plaintext, const uint8_t *schedule, uint8_t *ciphertext) {
void oqs_aes128_enc_c(const uint8_t *plaintext, const void *_schedule, uint8_t *ciphertext) {
const uint8_t *schedule = (const uint8_t *) _schedule;
int i; // To count the rounds
// First Round
@ -316,7 +326,8 @@ void OQS_AES128_enc_c(const uint8_t *plaintext, const uint8_t *schedule, uint8_t
xor_round_key(ciphertext, schedule, 10);
}
void OQS_AES128_dec_c(const uint8_t *ciphertext, const uint8_t *schedule, uint8_t *plaintext) {
void oqs_aes128_dec_c(const uint8_t *ciphertext, const void *_schedule, uint8_t *plaintext) {
const uint8_t *schedule = (const uint8_t *) _schedule;
int i; // To count the rounds
// Reverse the final Round

40
src/aes/aes_local.h Normal file
View File

@ -0,0 +1,40 @@
/**
* \file aes_local.h
* \brief Header defining additional internal functions for OQS AES
*/
#ifndef __OQS_AES_LOCAL_H
#define __OQS_AES_LOCAL_H
#include <stdint.h>
#include <stdlib.h>
void oqs_aes128_load_schedule_ni(const uint8_t *key, void **schedule);
void oqs_aes128_free_schedule_ni(void *schedule);
void oqs_aes128_enc_ni(const uint8_t *plaintext, const void *schedule, uint8_t *ciphertext);
void oqs_aes128_dec_ni(const uint8_t *ciphertext, const void *schedule, uint8_t *plaintext);
void oqs_aes128_ecb_enc_ni(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext);
void oqs_aes128_ecb_dec_ni(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext);
void oqs_aes128_ecb_enc_sch_ni(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext);
void oqs_aes128_ecb_dec_sch_ni(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext);
void oqs_aes128_load_schedule_c(const uint8_t *key, void **schedule);
void oqs_aes128_free_schedule_c(void *schedule);
void oqs_aes128_enc_c(const uint8_t *plaintext, const void *schedule, uint8_t *ciphertext);
void oqs_aes128_dec_c(const uint8_t *ciphertext, const void *schedule, uint8_t *plaintext);
void oqs_aes128_ecb_enc_c(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext);
void oqs_aes128_ecb_dec_c(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext);
void oqs_aes128_ecb_enc_sch_c(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext);
void oqs_aes128_ecb_dec_sch_c(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext);
#ifdef USE_OPENSSL
void oqs_aes128_load_schedule_ossl(const uint8_t *key, void **schedule, int for_encryption);
void oqs_aes128_free_schedule_ossl(void *schedule);
void oqs_aes128_ecb_enc_ossl(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext);
void oqs_aes128_ecb_dec_ossl(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext);
void oqs_aes128_ecb_enc_sch_ossl(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext);
void oqs_aes128_ecb_dec_sch_ossl(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext);
#endif
#endif

View File

@ -7,16 +7,20 @@
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#ifdef AES_DISABLE_NI
#include <assert.h>
void OQS_AES128_load_schedule_ni(UNUSED const uint8_t *key, UNUSED uint8_t *_schedule) {
void oqs_aes128_load_schedule_ni(UNUSED const uint8_t *key, UNUSED void **_schedule) {
assert(0);
}
void OQS_AES128_enc_ni(UNUSED const uint8_t *plaintext, UNUSED const uint8_t *_schedule, UNUSED uint8_t *ciphertext) {
void oqs_aes128_free_schedule_ni(UNUSED void *_schedule) {
assert(0);
}
void OQS_AES128_dec_ni(UNUSED const uint8_t *ciphertext, UNUSED const uint8_t *_schedule, UNUSED uint8_t *plaintext) {
void oqs_aes128_enc_ni(UNUSED const uint8_t *plaintext, UNUSED const void *_schedule, UNUSED uint8_t *ciphertext) {
assert(0);
}
void oqs_aes128_dec_ni(UNUSED const uint8_t *ciphertext, UNUSED const void *_schedule, UNUSED uint8_t *plaintext) {
assert(0);
}
#else
@ -38,8 +42,10 @@ static __m128i key_expand(__m128i key, __m128i keygened) {
#define key_exp(k, rcon) key_expand(k, _mm_aeskeygenassist_si128(k, rcon))
void OQS_AES128_load_schedule_ni(const uint8_t *key, uint8_t *_schedule) {
__m128i *schedule = (__m128i * )_schedule;
void oqs_aes128_load_schedule_ni(const uint8_t *key, void **_schedule) {
*_schedule = malloc(20 * 16);
assert(*_schedule != NULL);
__m128i *schedule = (__m128i * )*_schedule;
schedule[0] = _mm_loadu_si128((const __m128i *) key);
schedule[1] = key_exp(schedule[0], 0x01);
schedule[2] = key_exp(schedule[1], 0x02);
@ -59,7 +65,13 @@ void OQS_AES128_load_schedule_ni(const uint8_t *key, uint8_t *_schedule) {
}
}
void OQS_AES128_enc_ni(const uint8_t *plaintext, const uint8_t *_schedule, uint8_t *ciphertext) {
void oqs_aes128_free_schedule_ni(void *schedule) {
if (schedule != NULL) {
free(schedule);
}
}
void oqs_aes128_enc_ni(const uint8_t *plaintext, const void *_schedule, uint8_t *ciphertext) {
__m128i *schedule = (__m128i * )_schedule;
__m128i m = _mm_loadu_si128((__m128i *) plaintext);
@ -72,7 +84,7 @@ void OQS_AES128_enc_ni(const uint8_t *plaintext, const uint8_t *_schedule, uint8
_mm_storeu_si128((__m128i *) ciphertext, m);
}
void OQS_AES128_dec_ni(const uint8_t *ciphertext, const uint8_t *_schedule, uint8_t *plaintext) {
void oqs_aes128_dec_ni(const uint8_t *ciphertext, const void *_schedule, uint8_t *plaintext) {
__m128i *schedule = (__m128i * )_schedule;
__m128i m = _mm_loadu_si128((__m128i *) ciphertext);

View File

@ -5,6 +5,7 @@
#include <oqs/rand.h>
#include "aes.h"
#include "aes_local.h"
#include "../ds_benchmark.h"
#define BENCH_DURATION 1
@ -27,12 +28,14 @@ static void print_bytes(uint8_t *bytes, size_t num_bytes) {
}
static int test_aes128_correctness_c(OQS_RAND *rand) {
uint8_t key[16], schedule[OQS_AES128_SCHEDULE_NUMBYTES], plaintext[16], ciphertext[16], decrypted[16];
uint8_t key[16], plaintext[16], ciphertext[16], decrypted[16];
void *schedule = NULL;
OQS_RAND_n(rand, key, 16);
OQS_RAND_n(rand, plaintext, 16);
OQS_AES128_load_schedule_c(key, schedule);
OQS_AES128_enc_c(plaintext, schedule, ciphertext);
OQS_AES128_dec_c(ciphertext, schedule, decrypted);
oqs_aes128_load_schedule_c(key, &schedule);
oqs_aes128_enc_c(plaintext, schedule, ciphertext);
oqs_aes128_dec_c(ciphertext, schedule, decrypted);
oqs_aes128_free_schedule_c(schedule);
if (memcmp(plaintext, decrypted, 16) == 0) {
return EXIT_SUCCESS;
} else {
@ -47,12 +50,14 @@ static int test_aes128_correctness_c(OQS_RAND *rand) {
#ifndef AES_DISABLE_NI
static int test_aes128_correctness_ni(OQS_RAND *rand) {
uint8_t key[16], schedule[OQS_AES128_SCHEDULE_NUMBYTES], plaintext[16], ciphertext[16], decrypted[16];
uint8_t key[16], plaintext[16], ciphertext[16], decrypted[16];
void *schedule = NULL;
OQS_RAND_n(rand, key, 16);
OQS_RAND_n(rand, plaintext, 16);
OQS_AES128_load_schedule_ni(key, schedule);
OQS_AES128_enc_ni(plaintext, schedule, ciphertext);
OQS_AES128_dec_ni(ciphertext, schedule, decrypted);
oqs_aes128_load_schedule_ni(key, &schedule);
oqs_aes128_enc_ni(plaintext, schedule, ciphertext);
oqs_aes128_dec_ni(ciphertext, schedule, decrypted);
oqs_aes128_free_schedule_ni(schedule);
if (memcmp(plaintext, decrypted, 16) == 0) {
return EXIT_SUCCESS;
} else {
@ -65,13 +70,16 @@ static int test_aes128_correctness_ni(OQS_RAND *rand) {
}
static int test_aes128_c_equals_ni(OQS_RAND *rand) {
uint8_t key[16], schedule_c[OQS_AES128_SCHEDULE_NUMBYTES], schedule_ni[OQS_AES128_SCHEDULE_NUMBYTES], plaintext[16], ciphertext_c[16], ciphertext_ni[16];
uint8_t key[16], plaintext[16], ciphertext_c[16], ciphertext_ni[16];
void *schedule_c = NULL, *schedule_ni = NULL;
OQS_RAND_n(rand, key, 16);
OQS_RAND_n(rand, plaintext, 16);
OQS_AES128_load_schedule_c(key, schedule_c);
OQS_AES128_load_schedule_ni(key, schedule_ni);
OQS_AES128_enc_c(plaintext, schedule_c, ciphertext_c);
OQS_AES128_enc_ni(plaintext, schedule_ni, ciphertext_ni);
oqs_aes128_load_schedule_c(key, &schedule_c);
oqs_aes128_load_schedule_ni(key, &schedule_ni);
oqs_aes128_enc_c(plaintext, schedule_c, ciphertext_c);
oqs_aes128_enc_ni(plaintext, schedule_ni, ciphertext_ni);
oqs_aes128_free_schedule_c(schedule_c);
oqs_aes128_free_schedule_ni(schedule_ni);
if (memcmp(ciphertext_c, ciphertext_ni, 16) == 0) {
return EXIT_SUCCESS;
} else {
@ -82,15 +90,37 @@ static int test_aes128_c_equals_ni(OQS_RAND *rand) {
return EXIT_FAILURE;
}
}
#endif
static int test_aes128_ecb_correctness(OQS_RAND *rand) {
uint8_t key[16], schedule[OQS_AES128_SCHEDULE_NUMBYTES], plaintext[320], ciphertext[320], decrypted[320];
static int test_aes128_ecb_correctness_ni(OQS_RAND *rand) {
uint8_t key[16], plaintext[320], ciphertext[320], decrypted[320];
void *schedule = NULL;
OQS_RAND_n(rand, key, 16);
OQS_RAND_n(rand, plaintext, 320);
OQS_AES128_load_schedule(key, schedule);
OQS_AES128_ECB_enc(plaintext, 320, schedule, ciphertext);
OQS_AES128_ECB_dec(ciphertext, 320, schedule, decrypted);
oqs_aes128_load_schedule_ni(key, &schedule);
oqs_aes128_ecb_enc_ni(plaintext, 320, schedule, ciphertext);
oqs_aes128_ecb_dec_ni(ciphertext, 320, schedule, decrypted);
oqs_aes128_free_schedule_ni(schedule);
if (memcmp(plaintext, decrypted, 320) == 0) {
return EXIT_SUCCESS;
} else {
print_bytes(plaintext, 320);
printf("\n");
print_bytes(decrypted, 320);
printf("\n");
return EXIT_FAILURE;
}
}
#endif
static int test_aes128_ecb_correctness_c(OQS_RAND *rand) {
uint8_t key[16], plaintext[320], ciphertext[320], decrypted[320];
void *schedule = NULL;
OQS_RAND_n(rand, key, 16);
OQS_RAND_n(rand, plaintext, 320);
oqs_aes128_load_schedule_c(key, &schedule);
oqs_aes128_ecb_enc_c(plaintext, 320, schedule, ciphertext);
oqs_aes128_ecb_dec_c(ciphertext, 320, schedule, decrypted);
oqs_aes128_free_schedule_c(schedule);
if (memcmp(plaintext, decrypted, 320) == 0) {
return EXIT_SUCCESS;
} else {
@ -102,23 +132,74 @@ static int test_aes128_ecb_correctness(OQS_RAND *rand) {
}
}
static void speed_aes128_c(OQS_RAND *rand) {
uint8_t key[16], schedule[OQS_AES128_SCHEDULE_NUMBYTES], plaintext[16], ciphertext[16], decrypted[16];
#ifdef USE_OPENSSL
static int test_aes128_ecb_correctness_ossl(OQS_RAND *rand) {
uint8_t key[16], plaintext[320], ciphertext[320], decrypted[320];
void *schedule = NULL;
OQS_RAND_n(rand, key, 16);
OQS_RAND_n(rand, plaintext, 16);
TIME_OPERATION_SECONDS(OQS_AES128_load_schedule_c(key, schedule), "OQS_AES128_load_schedule_c", BENCH_DURATION);
TIME_OPERATION_SECONDS(OQS_AES128_enc_c(plaintext, schedule, ciphertext), "OQS_AES128_enc_c", BENCH_DURATION);
TIME_OPERATION_SECONDS(OQS_AES128_dec_c(ciphertext, schedule, decrypted), "OQS_AES128_dec_c", BENCH_DURATION);
OQS_RAND_n(rand, plaintext, 320);
oqs_aes128_load_schedule_ossl(key, &schedule, 1);
oqs_aes128_ecb_enc_ossl(plaintext, 320, schedule, ciphertext);
oqs_aes128_free_schedule_ossl(schedule);
oqs_aes128_load_schedule_ossl(key, &schedule, 0);
oqs_aes128_ecb_dec_ossl(ciphertext, 320, schedule, decrypted);
oqs_aes128_free_schedule_ossl(schedule);
if (memcmp(plaintext, decrypted, 320) == 0) {
return EXIT_SUCCESS;
} else {
print_bytes(plaintext, 320);
printf("\n");
print_bytes(decrypted, 320);
printf("\n");
return EXIT_FAILURE;
}
}
#endif
static void speed_aes128_c(OQS_RAND *rand) {
uint8_t key[16], plaintext[320], ciphertext[320], decrypted[320];
void *schedule = NULL;
OQS_RAND_n(rand, key, 16);
OQS_RAND_n(rand, plaintext, 320);
TIME_OPERATION_SECONDS(oqs_aes128_load_schedule_c(key, &schedule), "oqs_aes128_load_schedule_c", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_enc_c(plaintext, schedule, ciphertext), "oqs_aes128_enc_c", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_dec_c(ciphertext, schedule, decrypted), "oqs_aes128_dec_c", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_ecb_enc_c(plaintext, 320, key, ciphertext), "oqs_aes128_ecb_enc_c", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_ecb_dec_c(ciphertext, 320, key, decrypted), "oqs_aes128_ecb_dec_c", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_ecb_enc_sch_c(plaintext, 320, schedule, ciphertext), "oqs_aes128_ecb_enc_sch_c", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_ecb_dec_sch_c(ciphertext, 320, schedule, decrypted), "oqs_aes128_ecb_dec_sch_c", BENCH_DURATION);
}
#ifndef AES_DISABLE_NI
static void speed_aes128_ni(OQS_RAND *rand) {
uint8_t key[16], schedule[OQS_AES128_SCHEDULE_NUMBYTES], plaintext[16], ciphertext[16], decrypted[16];
uint8_t key[16], plaintext[320], ciphertext[320], decrypted[320];
void *schedule = NULL;
OQS_RAND_n(rand, key, 16);
OQS_RAND_n(rand, plaintext, 16);
TIME_OPERATION_SECONDS(OQS_AES128_load_schedule_ni(key, schedule), "OQS_AES128_load_schedule_ni", BENCH_DURATION);
TIME_OPERATION_SECONDS(OQS_AES128_enc_ni(plaintext, schedule, ciphertext), "OQS_AES128_enc_ni", BENCH_DURATION);
TIME_OPERATION_SECONDS(OQS_AES128_dec_ni(ciphertext, schedule, decrypted), "OQS_AES128_dec_ni", BENCH_DURATION);
OQS_RAND_n(rand, plaintext, 320);
TIME_OPERATION_SECONDS(oqs_aes128_load_schedule_ni(key, &schedule), "oqs_aes128_load_schedule_ni", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_enc_ni(plaintext, schedule, ciphertext), "oqs_aes128_enc_ni", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_dec_ni(ciphertext, schedule, decrypted), "oqs_aes128_dec_ni", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_ecb_enc_ni(plaintext, 320, key, ciphertext), "oqs_aes128_ecb_enc_ni", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_ecb_dec_ni(ciphertext, 320, key, decrypted), "oqs_aes128_ecb_dec_ni", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_ecb_enc_sch_ni(plaintext, 320, schedule, ciphertext), "oqs_aes128_ecb_enc_sch_ni", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_ecb_dec_sch_ni(ciphertext, 320, schedule, decrypted), "oqs_aes128_ecb_dec_sch_ni", BENCH_DURATION);
}
#endif
#ifdef USE_OPENSSL
static void speed_aes128_ossl(OQS_RAND *rand) {
uint8_t key[16], plaintext[320], ciphertext[320];
void *schedule = NULL;
OQS_RAND_n(rand, key, 16);
OQS_RAND_n(rand, plaintext, 320);
TIME_OPERATION_SECONDS(oqs_aes128_load_schedule_ossl(key, &schedule, 1), "oqs_aes128_load_schedule_ossl 1", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_load_schedule_ossl(key, &schedule, 0), "oqs_aes128_load_schedule_ossl 0", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_ecb_enc_ossl(plaintext, 320, key, ciphertext), "oqs_aes128_ecb_enc_ossl", BENCH_DURATION);
TIME_OPERATION_SECONDS(oqs_aes128_ecb_dec_ossl(ciphertext, 320, key, plaintext), "oqs_aes128_ecb_dec_ossl", BENCH_DURATION);
oqs_aes128_load_schedule_ossl(key, &schedule, 1);
TIME_OPERATION_SECONDS(oqs_aes128_ecb_enc_sch_ossl(plaintext, 320, schedule, ciphertext), "oqs_aes128_ecb_enc_sch_ossl", BENCH_DURATION);
oqs_aes128_load_schedule_ossl(key, &schedule, 0);
TIME_OPERATION_SECONDS(oqs_aes128_ecb_dec_sch_ossl(ciphertext, 320, schedule, plaintext), "oqs_aes128_ecb_dec_sch_ossl", BENCH_DURATION);
}
#endif
@ -135,13 +216,22 @@ int main() {
TEST_REPEATEDLY(test_aes128_correctness_ni(rand));
TEST_REPEATEDLY(test_aes128_c_equals_ni(rand));
#endif
TEST_REPEATEDLY(test_aes128_ecb_correctness(rand));
TEST_REPEATEDLY(test_aes128_ecb_correctness_c(rand));
#ifndef AES_DISABLE_NI
TEST_REPEATEDLY(test_aes128_ecb_correctness_ni(rand));
#endif
#ifdef USE_OPENSSL
TEST_REPEATEDLY(test_aes128_ecb_correctness_ossl(rand));
#endif
printf("Tests passed.\n\n");
printf("=== test_aes performance ===\n");
PRINT_TIMER_HEADER
speed_aes128_c(rand);
#ifndef AES_DISABLE_NI
speed_aes128_ni(rand);
#endif
#ifdef USE_OPENSSL
speed_aes128_ossl(rand);
#endif
PRINT_TIMER_FOOTER
ret = EXIT_SUCCESS;

View File

@ -82,8 +82,8 @@ int oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly(uint16_t *out, const uint16_t
}
assert(params->seed_len == 16);
uint8_t aes_key_schedule[OQS_AES128_SCHEDULE_NUMBYTES];
OQS_AES128_load_schedule(params->seed, aes_key_schedule);
void *aes_key_schedule = NULL;
OQS_AES128_load_schedule(params->seed, &aes_key_schedule, 1);
for (i = 0; i < params->n; i++) {
// go through A's rows
@ -107,6 +107,8 @@ int oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly(uint16_t *out, const uint16_t
}
}
OQS_AES128_free_schedule(aes_key_schedule);
ret = 1;
goto cleanup;
@ -153,8 +155,8 @@ int oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly(uint16_t *out, const uint16_t
}
assert(params->seed_len == 16);
uint8_t aes_key_schedule[OQS_AES128_SCHEDULE_NUMBYTES];
OQS_AES128_load_schedule(params->seed, aes_key_schedule);
void *aes_key_schedule = NULL;
OQS_AES128_load_schedule(params->seed, &aes_key_schedule, 1);
for (kk = 0; kk < params->n; kk += params->stripe_step) {
// Go through A's columns, 8 (== params->stripe_step) columns at a time.
@ -165,7 +167,6 @@ int oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly(uint16_t *out, const uint16_t
a_cols[i * params->stripe_step + 1] = kk;
}
assert(params->seed_len == 16);
OQS_AES128_ECB_enc_sch((uint8_t *) a_cols, a_colslen, aes_key_schedule, (uint8_t *) a_cols);
// transpose a_cols to have access to it in the column-major order.
@ -185,6 +186,8 @@ int oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly(uint16_t *out, const uint16_t
}
}
OQS_AES128_free_schedule(aes_key_schedule);
ret = 1;
goto cleanup;

View File

@ -15,21 +15,19 @@
#include <oqs/rand.h>
#include <oqs/rand_urandom_aesctr.h>
#include <oqs/aes.h>
#include <assert.h>
typedef struct OQS_RAND_urandom_aesctr_ctx {
union {
uint8_t ba[16];
uint64_t ui[2];
} ctr;
uint8_t schedule[20 * 16];
typedef struct oqs_rand_urandom_aesctr_ctx {
uint64_t ctr;
void *schedule;
uint8_t cache[64];
size_t cache_next_byte;
} OQS_RAND_urandom_aesctr_ctx;
} oqs_rand_urandom_aesctr_ctx;
static OQS_RAND_urandom_aesctr_ctx *OQS_RAND_urandom_aesctr_ctx_new() {
static oqs_rand_urandom_aesctr_ctx *oqs_rand_urandom_aesctr_ctx_new() {
int fd = 0;
OQS_RAND_urandom_aesctr_ctx *rand_ctx = NULL;
rand_ctx = (OQS_RAND_urandom_aesctr_ctx *) malloc(sizeof(OQS_RAND_urandom_aesctr_ctx));
oqs_rand_urandom_aesctr_ctx *rand_ctx = NULL;
rand_ctx = (oqs_rand_urandom_aesctr_ctx *) malloc(sizeof(oqs_rand_urandom_aesctr_ctx));
if (rand_ctx == NULL) {
goto err;
}
@ -50,13 +48,10 @@ static OQS_RAND_urandom_aesctr_ctx *OQS_RAND_urandom_aesctr_ctx_new() {
if (r != 16) {
goto err;
}
r = read(fd, &rand_ctx->ctr.ba[8], 8);
if (r != 8) {
goto err;
}
#endif
OQS_AES128_load_schedule(key, rand_ctx->schedule);
OQS_AES128_load_schedule(key, &rand_ctx->schedule, 1);
rand_ctx->cache_next_byte = 64; // cache is empty
rand_ctx->ctr = 0;
goto okay;
err:
if (rand_ctx) {
@ -75,53 +70,64 @@ okay:
return rand_ctx;
}
static void OQS_RAND_urandom_aesctr_fill_cache(OQS_RAND *r) {
OQS_RAND_urandom_aesctr_ctx *rand_ctx = (OQS_RAND_urandom_aesctr_ctx *) r->ctx;
for (int i = 0; i < 4; i++) {
OQS_AES128_enc(rand_ctx->ctr.ba, rand_ctx->schedule, &rand_ctx->cache[i * 16]);
rand_ctx->ctr.ui[0]++;
void OQS_RAND_urandom_aesctr_n(OQS_RAND *r, uint8_t *out, size_t n) {
oqs_rand_urandom_aesctr_ctx *rand_ctx = (oqs_rand_urandom_aesctr_ctx *) r->ctx;
uint64_t *out_64 = (uint64_t *) out;
for (size_t i = 0; i < n / 16; i++) {
out_64[i] = rand_ctx->ctr;
rand_ctx->ctr++;
}
OQS_AES128_ECB_enc_sch(out, n, rand_ctx->schedule, out);
for (size_t i = 0; i < n % 16; i++) {
out[16 * (n / 16) + i] = OQS_RAND_urandom_aesctr_8(r);
}
}
static void OQS_RAND_urandom_aesctr_fill_cache(OQS_RAND *r) {
oqs_rand_urandom_aesctr_ctx *rand_ctx = (oqs_rand_urandom_aesctr_ctx *) r->ctx;
OQS_RAND_urandom_aesctr_n(r, rand_ctx->cache, sizeof(rand_ctx->cache));
rand_ctx->cache_next_byte = 0;
}
void OQS_RAND_urandom_aesctr_n(OQS_RAND *r, uint8_t *out, size_t n) {
OQS_RAND_urandom_aesctr_ctx *rand_ctx = (OQS_RAND_urandom_aesctr_ctx *) r->ctx;
while (n > 0) {
if (n + rand_ctx->cache_next_byte < 64) {
memcpy(out, &rand_ctx->cache[rand_ctx->cache_next_byte], n);
rand_ctx->cache_next_byte += n;
n = 0;
} else {
size_t bytes_left = 64 - rand_ctx->cache_next_byte;
memcpy(out, &rand_ctx->cache[rand_ctx->cache_next_byte], bytes_left);
out += bytes_left;
n -= bytes_left;
OQS_RAND_urandom_aesctr_fill_cache(r);
}
}
}
uint8_t OQS_RAND_urandom_aesctr_8(OQS_RAND *r) {
uint8_t out;
OQS_RAND_urandom_aesctr_n(r, (uint8_t *)&out, 1);
oqs_rand_urandom_aesctr_ctx *rand_ctx = (oqs_rand_urandom_aesctr_ctx *) r->ctx;
if (rand_ctx->cache_next_byte > sizeof(rand_ctx->cache) - 1) {
OQS_RAND_urandom_aesctr_fill_cache(r);
}
uint8_t out = rand_ctx->cache[rand_ctx->cache_next_byte];
rand_ctx->cache_next_byte += 1;
return out;
}
uint32_t OQS_RAND_urandom_aesctr_32(OQS_RAND *r) {
oqs_rand_urandom_aesctr_ctx *rand_ctx = (oqs_rand_urandom_aesctr_ctx *) r->ctx;
if (rand_ctx->cache_next_byte > sizeof(rand_ctx->cache) - 4) {
OQS_RAND_urandom_aesctr_fill_cache(r);
}
uint32_t out;
OQS_RAND_urandom_aesctr_n(r, (uint8_t *)&out, 4);
memcpy(&out, &rand_ctx->cache[rand_ctx->cache_next_byte], 4);
rand_ctx->cache_next_byte += 4;
return out;
}
uint64_t OQS_RAND_urandom_aesctr_64(OQS_RAND *r) {
oqs_rand_urandom_aesctr_ctx *rand_ctx = (oqs_rand_urandom_aesctr_ctx *) r->ctx;
if (rand_ctx->cache_next_byte > sizeof(rand_ctx->cache) - 8) {
OQS_RAND_urandom_aesctr_fill_cache(r);
}
uint64_t out;
OQS_RAND_urandom_aesctr_n(r, (uint8_t *)&out, 8);
memcpy(&out, &rand_ctx->cache[rand_ctx->cache_next_byte], 8);
rand_ctx->cache_next_byte += 8;
return out;
}
void OQS_RAND_urandom_aesctr_free(OQS_RAND *r) {
if (r) {
oqs_rand_urandom_aesctr_ctx *rand_ctx = (oqs_rand_urandom_aesctr_ctx *) r->ctx;
if (rand_ctx) {
OQS_AES128_free_schedule(rand_ctx->schedule);
}
free(r->ctx);
free(r->method_name);
}
@ -134,7 +140,7 @@ OQS_RAND *OQS_RAND_urandom_aesctr_new() {
return NULL;
}
r->method_name = strdup("urandom_aesctr");
r->ctx = OQS_RAND_urandom_aesctr_ctx_new();
r->ctx = oqs_rand_urandom_aesctr_ctx_new();
if (r->ctx == NULL || r->method_name == NULL) {
OQS_RAND_urandom_aesctr_free(r);
return NULL;