Skip to content

Commit

Permalink
Make common algorithms pluggable
Browse files Browse the repository at this point in the history
This allows applications to replace the implementation of common
cryptographic algorithms at runtime, by setting callback functions for
each operations with OQS_AES_set_callbacks, OQS_SHA2_set_callbacks,
OQS_SHA3_set_callbacks, and OQS_SHA3_x4_callbacks.  Those functions
may be called once before OQS_init; otherwise the default
implementation will be used.

Signed-off-by: Daiki Ueno <[email protected]>
  • Loading branch information
ueno committed Mar 7, 2024
1 parent fdb9d9d commit 5a38316
Show file tree
Hide file tree
Showing 19 changed files with 1,091 additions and 320 deletions.
17 changes: 9 additions & 8 deletions src/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ if(${OQS_USE_AES_OPENSSL})
set(AES_IMPL aes/aes_ossl.c)
set(OSSL_HELPERS ossl_helpers.c)
else()
set(AES_IMPL aes/aes.c aes/aes_c.c)
set(AES_IMPL aes/aes_impl.c aes/aes_c.c)
if (OQS_DIST_X86_64_BUILD OR OQS_USE_AES_INSTRUCTIONS)
set(AES_IMPL ${AES_IMPL} aes/aes128_ni.c)
set(AES_IMPL ${AES_IMPL} aes/aes256_ni.c)
Expand All @@ -47,7 +47,7 @@ if(${OQS_USE_SHA2_OPENSSL})
set(SHA2_IMPL sha2/sha2_ossl.c)
set(OSSL_HELPERS ossl_helpers.c)
else()
set(SHA2_IMPL sha2/sha2.c sha2/sha2_c.c)
set(SHA2_IMPL sha2/sha2_impl.c sha2/sha2_c.c)
if (OQS_DIST_ARM64_V8_BUILD)
set(SHA2_IMPL ${SHA2_IMPL} sha2/sha2_armv8.c)
set_source_files_properties(sha2/sha2_armv8.c PROPERTIES COMPILE_FLAGS -mcpu=cortex-a53+crypto)
Expand All @@ -71,21 +71,22 @@ else() # using XKCP
set(SHA3_IMPL sha3/xkcp_sha3.c sha3/xkcp_sha3x4.c)
endif()

add_library(common OBJECT ${AES_IMPL}
${SHA2_IMPL}
${SHA3_IMPL}
add_library(common OBJECT ${AES_IMPL} aes/aes.c
${SHA2_IMPL} sha2/sha2.c
${SHA3_IMPL} sha3/sha3.c sha3/sha3x4.c
${OSSL_HELPERS}
common.c
pqclean_shims/fips202.c
pqclean_shims/fips202x4.c
rand/rand.c)

# Implementations of the internal API to be exposed to test programs
add_library(internal OBJECT ${AES_IMPL}
${SHA2_IMPL}
${SHA3_IMPL}
add_library(internal OBJECT ${AES_IMPL} aes/aes.c
${SHA2_IMPL} sha2/sha2.c
${SHA3_IMPL} sha3/sha3.c sha3/sha3x4.c
${OSSL_HELPERS}
common.c
rand/rand.c
rand/rand_nist.c)
set_property(TARGET internal PROPERTY C_VISIBILITY_PRESET default)

Expand Down
117 changes: 24 additions & 93 deletions src/common/aes/aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,129 +9,60 @@
#include "aes.h"
#include "aes_local.h"

#if defined(OQS_DIST_X86_64_BUILD)
#define C_OR_NI_OR_ARM(stmt_c, stmt_ni, stmt_arm) \
do { \
if (OQS_CPU_has_extension(OQS_CPU_EXT_AES)) { \
stmt_ni; \
} else { \
stmt_c; \
} \
} while(0)
#elif defined(OQS_DIST_ARM64_V8_BUILD)
#define C_OR_NI_OR_ARM(stmt_c, stmt_ni, stmt_arm) \
do { \
if (OQS_CPU_has_extension(OQS_CPU_EXT_ARM_AES)) { \
stmt_arm; \
} else { \
stmt_c; \
} \
} while(0)
#elif defined(OQS_USE_AES_INSTRUCTIONS)
#define C_OR_NI_OR_ARM(stmt_c, stmt_ni, stmt_arm) \
stmt_ni
#elif defined(OQS_USE_ARM_AES_INSTRUCTIONS)
#define C_OR_NI_OR_ARM(stmt_c, stmt_ni, stmt_arm) \
stmt_arm
#else
#define C_OR_NI_OR_ARM(stmt_c, stmt_ni, stmt_arm) \
stmt_c
#endif

void OQS_AES128_ECB_load_schedule(const uint8_t *key, void **_schedule) {
C_OR_NI_OR_ARM(
oqs_aes128_load_schedule_c(key, _schedule),
oqs_aes128_load_schedule_ni(key, _schedule),
oqs_aes128_load_schedule_no_bitslice(key, _schedule)
);
static struct OQS_AES_callbacks *callbacks = &aes_default_callbacks;

OQS_API void OQS_AES_set_callbacks(struct OQS_AES_callbacks *new_callbacks) {
callbacks = new_callbacks;
}

void OQS_AES128_ECB_load_schedule(const uint8_t *key, void **schedule) {
callbacks->AES128_ECB_load_schedule(key, schedule);
}

void OQS_AES128_free_schedule(void *schedule) {
C_OR_NI_OR_ARM(
oqs_aes128_free_schedule_c(schedule),
oqs_aes128_free_schedule_ni(schedule),
oqs_aes128_free_schedule_no_bitslice(schedule)
);
callbacks->AES128_free_schedule(schedule);
}

void OQS_AES256_ECB_load_schedule(const uint8_t *key, void **_schedule) {
C_OR_NI_OR_ARM(
oqs_aes256_load_schedule_c(key, _schedule),
oqs_aes256_load_schedule_ni(key, _schedule),
oqs_aes256_load_schedule_no_bitslice(key, _schedule)
);
void OQS_AES256_ECB_load_schedule(const uint8_t *key, void **schedule) {
callbacks->AES256_ECB_load_schedule(key, schedule);
}

void OQS_AES256_CTR_inc_init(const uint8_t *key, void **_schedule) {
OQS_AES256_ECB_load_schedule(key, _schedule);
void OQS_AES256_CTR_inc_init(const uint8_t *key, void **schedule) {
callbacks->AES256_CTR_inc_init(key, schedule);
}

void OQS_AES256_CTR_inc_iv(const uint8_t *iv, size_t iv_len, void *_schedule) {
C_OR_NI_OR_ARM(
oqs_aes256_load_iv_c(iv, iv_len, _schedule),
oqs_aes256_load_iv_ni(iv, iv_len, _schedule),
oqs_aes256_load_iv_armv8(iv, iv_len, _schedule)
);
void OQS_AES256_CTR_inc_iv(const uint8_t *iv, size_t iv_len, void *schedule) {
callbacks->AES256_CTR_inc_iv(iv, iv_len, schedule);
}

void OQS_AES256_CTR_inc_ivu64(uint64_t iv, void *_schedule) {
C_OR_NI_OR_ARM(
oqs_aes256_load_iv_u64_c(iv, _schedule),
oqs_aes256_load_iv_u64_ni(iv, _schedule),
(void) iv; (void) _schedule
);
void OQS_AES256_CTR_inc_ivu64(uint64_t iv, void *schedule) {
callbacks->AES256_CTR_inc_ivu64(iv, schedule);
}

void OQS_AES256_free_schedule(void *schedule) {
C_OR_NI_OR_ARM(
oqs_aes256_free_schedule_c(schedule),
oqs_aes256_free_schedule_ni(schedule),
oqs_aes256_free_schedule_no_bitslice(schedule)
);
callbacks->AES256_free_schedule(schedule);
}

void OQS_AES128_ECB_enc(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext) {
void *schedule = NULL;
OQS_AES128_ECB_load_schedule(key, &schedule);
OQS_AES128_ECB_enc_sch(plaintext, plaintext_len, schedule, ciphertext);
OQS_AES128_free_schedule(schedule);
callbacks->AES128_ECB_enc(plaintext, plaintext_len, key, ciphertext);
}

void OQS_AES128_ECB_enc_sch(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext) {
C_OR_NI_OR_ARM(
oqs_aes128_ecb_enc_sch_c(plaintext, plaintext_len, schedule, ciphertext),
oqs_aes128_ecb_enc_sch_ni(plaintext, plaintext_len, schedule, ciphertext),
oqs_aes128_ecb_enc_sch_armv8(plaintext, plaintext_len, schedule, ciphertext)
);
callbacks->AES128_ECB_enc_sch(plaintext, plaintext_len, schedule, ciphertext);
}

void OQS_AES256_ECB_enc(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext) {
void *schedule = NULL;
OQS_AES256_ECB_load_schedule(key, &schedule);
OQS_AES256_ECB_enc_sch(plaintext, plaintext_len, schedule, ciphertext);
OQS_AES256_free_schedule(schedule);
callbacks->AES256_ECB_enc(plaintext, plaintext_len, key, ciphertext);
}

void OQS_AES256_ECB_enc_sch(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext) {
C_OR_NI_OR_ARM(
oqs_aes256_ecb_enc_sch_c(plaintext, plaintext_len, schedule, ciphertext),
oqs_aes256_ecb_enc_sch_ni(plaintext, plaintext_len, schedule, ciphertext),
oqs_aes256_ecb_enc_sch_armv8(plaintext, plaintext_len, schedule, ciphertext)
);
callbacks->AES256_ECB_enc_sch(plaintext, plaintext_len, schedule, ciphertext);
}

void OQS_AES256_CTR_inc_stream_iv(const uint8_t *iv, const size_t iv_len, const void *schedule, uint8_t *out, size_t out_len) {
C_OR_NI_OR_ARM(
oqs_aes256_ctr_enc_sch_c(iv, iv_len, schedule, out, out_len),
oqs_aes256_ctr_enc_sch_ni(iv, iv_len, schedule, out, out_len),
oqs_aes256_ctr_enc_sch_armv8(iv, iv_len, schedule, out, out_len)
);
callbacks->AES256_CTR_inc_stream_iv(iv, iv_len, schedule, out, out_len);
}

void OQS_AES256_CTR_inc_stream_blks(void *schedule, uint8_t *out, size_t out_blks) {
C_OR_NI_OR_ARM(
oqs_aes256_ctr_enc_sch_upd_blks_c(schedule, out, out_blks),
oqs_aes256_ctr_enc_sch_upd_blks_ni(schedule, out, out_blks),
oqs_aes256_ctr_enc_sch_upd_blks_armv8(schedule, out, out_blks)
);
callbacks->AES256_CTR_inc_stream_blks(schedule, out, out_blks);
}
28 changes: 28 additions & 0 deletions src/common/aes/aes.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include <stdint.h>
#include <stdlib.h>

#include <oqs/common.h>

#if defined(__cplusplus)
extern "C" {
#endif
Expand Down Expand Up @@ -147,6 +149,32 @@ void OQS_AES256_CTR_inc_stream_iv(const uint8_t *iv, size_t iv_len, const void *
*/
void OQS_AES256_CTR_inc_stream_blks(void *ctx, uint8_t *out, size_t out_blks);

struct OQS_AES_callbacks {
void (*AES128_ECB_load_schedule)(const uint8_t *key, void **ctx);
void (*AES128_free_schedule)(void *ctx);
void (*AES128_ECB_enc)(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext);
void (*AES128_ECB_enc_sch)(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext);
void (*AES256_ECB_load_schedule)(const uint8_t *key, void **ctx);
void (*AES256_CTR_inc_init)(const uint8_t *key, void **ctx);
void (*AES256_CTR_inc_iv)(const uint8_t *iv, size_t iv_len, void *ctx);
void (*AES256_CTR_inc_ivu64)(uint64_t iv, void *ctx);
void (*AES256_free_schedule)(void *ctx);
void (*AES256_ECB_enc)(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext);
void (*AES256_ECB_enc_sch)(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext);
void (*AES256_CTR_inc_stream_iv)(const uint8_t *iv, size_t iv_len, const void *ctx, uint8_t *out, size_t out_len);
void (*AES256_CTR_inc_stream_blks)(void *ctx, uint8_t *out, size_t out_blks);
};

/**
* Set callback functions for AES operations.
*
* This function may be called at most once before OQS_init to replace
* the implementation of AES operations.
*
* @param[in] new_callbacks Callback functions defined in OQS_AES_callbacks
*/
OQS_API void OQS_AES_set_callbacks(struct OQS_AES_callbacks *new_callbacks);

#if defined(__cplusplus)
} // extern "C"
#endif
Expand Down
Loading

0 comments on commit 5a38316

Please sign in to comment.