/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0" * * Written by Nir Drucker and Shay Gueron, * AWS Cryptographic Algorithms Group. * (ndrucker@amazon.com, gueron@amazon.com) */ #include "openssl_utils.h" #include "utilities.h" #include #include #include #ifdef USE_OPENSSL_GF2M # define MAX_OPENSSL_INV_TRIALS 1000 _INLINE_ void BN_CTX_cleanup(BN_CTX *ctx) { if(ctx) { BN_CTX_end(ctx); BN_CTX_free(ctx); } } DEFINE_POINTER_CLEANUP_FUNC(BN_CTX *, BN_CTX_cleanup); // Loading (big) numbers into OpenSSL should use Big Endian representation. // Therefore, the bytes ordering of the number should be reversed. _INLINE_ void reverse_endian(OUT uint8_t *res, IN const uint8_t *in, IN const uint32_t n) { uint32_t i; for(i = 0; i < (n / 2); i++) { uint64_t tmp = in[i]; res[i] = in[n - 1 - i]; res[n - 1 - i] = tmp; } // If the number of blocks is odd, swap also the middle block. if(n % 2) { res[i] = in[i]; } } _INLINE_ ret_t ossl_bn2bin(OUT uint8_t *out, IN const BIGNUM *in, IN const uint32_t size) { assert(size <= N_SIZE); uint8_t be_tmp[N_SIZE] = {0}; memset(out, 0, size); if(BN_bn2bin(in, be_tmp) == -1) { BIKE_ERROR(EXTERNAL_LIB_ERROR_OPENSSL); } reverse_endian(out, be_tmp, BN_num_bytes(in)); return SUCCESS; } _INLINE_ ret_t ossl_bin2bn(IN BIGNUM *out, OUT const uint8_t *in, IN const uint32_t size) { assert(size <= N_SIZE); uint8_t be_tmp[N_SIZE] = {0}; reverse_endian(be_tmp, in, size); if(BN_bin2bn(be_tmp, size, out) == 0) { BIKE_ERROR(EXTERNAL_LIB_ERROR_OPENSSL); } return SUCCESS; } ret_t ossl_add(OUT uint8_t res_bin[R_SIZE], IN const uint8_t a_bin[R_SIZE], IN const uint8_t b_bin[R_SIZE]) { DEFER_CLEANUP(BN_CTX *bn_ctx = BN_CTX_new(), BN_CTX_cleanup_pointer); BIGNUM *r = NULL; BIGNUM *a = NULL; BIGNUM *b = NULL; if(NULL == bn_ctx) { BIKE_ERROR(EXTERNAL_LIB_ERROR_OPENSSL); } BN_CTX_start(bn_ctx); r = BN_CTX_get(bn_ctx); a = BN_CTX_get(bn_ctx); b = BN_CTX_get(bn_ctx); if((NULL == r) || (NULL == a) || (NULL == b)) { BIKE_ERROR(EXTERNAL_LIB_ERROR_OPENSSL); } POSIX_GUARD(ossl_bin2bn(a, a_bin, R_SIZE)); POSIX_GUARD(ossl_bin2bn(b, b_bin, R_SIZE)); if(BN_GF2m_add(r, a, b) == 0) { BIKE_ERROR(EXTERNAL_LIB_ERROR_OPENSSL); } POSIX_GUARD(ossl_bn2bin(res_bin, r, R_SIZE)); return SUCCESS; } // Perform a cyclic product by using OpenSSL. _INLINE_ ret_t ossl_cyclic_product(OUT BIGNUM *r, IN const BIGNUM *a, IN const BIGNUM *b, BN_CTX * bn_ctx) { BIGNUM *m = BN_CTX_get(bn_ctx); if(NULL == m) { BIKE_ERROR(EXTERNAL_LIB_ERROR_OPENSSL); } // m = x^PARAM_R - 1 if((BN_set_bit(m, R_BITS) == 0) || (BN_set_bit(m, 0) == 0)) { BIKE_ERROR(EXTERNAL_LIB_ERROR_OPENSSL); } // r = a*b mod m if(BN_GF2m_mod_mul(r, a, b, m, bn_ctx) == 0) { BIKE_ERROR(EXTERNAL_LIB_ERROR_OPENSSL); } return SUCCESS; } // Perform a cyclic product by using OpenSSL. ret_t cyclic_product(OUT uint8_t res_bin[R_SIZE], IN const uint8_t a_bin[R_SIZE], IN const uint8_t b_bin[R_SIZE]) { DEFER_CLEANUP(BN_CTX *bn_ctx = BN_CTX_new(), BN_CTX_cleanup_pointer); BIGNUM *r = NULL; BIGNUM *a = NULL; BIGNUM *b = NULL; if(NULL == bn_ctx) { BIKE_ERROR(EXTERNAL_LIB_ERROR_OPENSSL); } BN_CTX_start(bn_ctx); r = BN_CTX_get(bn_ctx); a = BN_CTX_get(bn_ctx); b = BN_CTX_get(bn_ctx); if((NULL == r) || (NULL == a) || (NULL == b)) { BIKE_ERROR(EXTERNAL_LIB_ERROR_OPENSSL); } POSIX_GUARD(ossl_bin2bn(a, a_bin, R_SIZE)); POSIX_GUARD(ossl_bin2bn(b, b_bin, R_SIZE)); POSIX_GUARD(ossl_cyclic_product(r, a, b, bn_ctx)); POSIX_GUARD(ossl_bn2bin(res_bin, r, R_SIZE)); return SUCCESS; } #endif // USE_OPENSSL_GF2M