diff --git a/CMakeLists.txt b/CMakeLists.txt index 1492306a2..0aa0d32eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -232,7 +232,7 @@ if (NOT USE_ENCLIB) endif() set(USE_ENCLIB "${USE_ENCLIB}" CACHE STRING "The crypto library that SRT uses") -set_property(CACHE USE_ENCLIB PROPERTY STRINGS "openssl" "gnutls" "mbedtls") +set_property(CACHE USE_ENCLIB PROPERTY STRINGS "openssl" "gnutls" "mbedtls" "botan") # Make sure DLLs and executabes go to the same path regardles of subdirectory set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) @@ -404,6 +404,46 @@ if (ENABLE_ENCRYPTION) set (SSL_LIBRARIES ${OPENSSL_LIBRARIES}) message(STATUS "SSL via find_package(OpenSSL): -I ${SSL_INCLUDE_DIRS} -l;${SSL_LIBRARIES}") endif() + elseif ("${USE_ENCLIB}" STREQUAL "botan") + add_definitions(-DUSE_BOTAN=1 -DCRYSPR2) + set (SSL_REQUIRED_MODULES "botan") + find_package(Botan 3.0.0 REQUIRED) + botan_generate( + botan + ffi + nist_keywrap + aes_armv8 + aes_ni + aes_power8 + aes_vperm + idea_sse2 + serpent_avx2 + shacal2_armv8 + shacal2_avx2 + shacal2_x86 + sm4_armv8 + rdseed + sha1_armv8 + sha1_sse2 + sha1_x86 + sha2_32_armv8 + sha2_32_bmi2 + sha2_32_x86 + sha2_64_bmi2 + sha3_bmi2 + zfec_sse2 + zfec_vperm + argon2_avx2 + argon2_ssse3 + processor_rng + chacha_avx2 + ghash_cpu + ghash_vperm + simd + simd_avx2) + target_compile_features("botan" PRIVATE "cxx_std_20") + set (SSL_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}) + set (SSL_LIBRARIES "botan") else() # openssl # Openssl (Direct-AES API) can use CRYSPR2 add_definitions(-DUSE_OPENSSL=1 -DCRYSPR2) @@ -445,11 +485,11 @@ if (ENABLE_ENCRYPTION) message (STATUS "SSL libraries: ${SSL_LIBRARIES}") if (ENABLE_AEAD_API_PREVIEW) - if ("${USE_ENCLIB}" STREQUAL "openssl-evp") + if (("${USE_ENCLIB}" STREQUAL "openssl-evp") OR ("${USE_ENCLIB}" STREQUAL "botan")) add_definitions(-DENABLE_AEAD_API_PREVIEW) message(STATUS "ENCRYPTION AEAD API: ENABLED") else() - message(FATAL_ERROR "ENABLE_AEAD_API_PREVIEW is only available with USE_ENCLIB=openssl-evp!") + message(FATAL_ERROR "ENABLE_AEAD_API_PREVIEW is only available with USE_ENCLIB=[openssl-evp | botan]!") endif() else() message(STATUS "ENCRYPTION AEAD API: DISABLED") @@ -1009,10 +1049,12 @@ if (srt_libspec_shared) endif() if (MICROSOFT) target_link_libraries(${TARGET_srt}_shared PRIVATE ws2_32.lib) - if (OPENSSL_USE_STATIC_LIBS) - target_link_libraries(${TARGET_srt}_shared PRIVATE crypt32.lib) - else() - set_target_properties(${TARGET_srt}_shared PROPERTIES LINK_FLAGS "/DELAYLOAD:libeay32.dll") + if (NOT (ENABLE_ENCRYPTION AND "${USE_ENCLIB}" STREQUAL "botan")) + if (OPENSSL_USE_STATIC_LIBS) + target_link_libraries(${TARGET_srt}_shared PRIVATE crypt32.lib) + else() + set_target_properties(${TARGET_srt}_shared PROPERTIES LINK_FLAGS "/DELAYLOAD:libeay32.dll") + endif() endif() elseif (MINGW) target_link_libraries(${TARGET_srt}_shared PRIVATE wsock32 ws2_32) @@ -1096,6 +1138,10 @@ endif() target_compile_definitions(srt_virtual PRIVATE -DSRT_LOG_SLOWDOWN_FREQ_MS=${SRT_LOG_SLOWDOWN_FREQ_MS}) +if (ENABLE_ENCRYPTION AND "${USE_ENCLIB}" STREQUAL "botan") + add_dependencies(srt_virtual botan) +endif() + if (srt_libspec_shared) if (MICROSOFT) target_link_libraries(${TARGET_srt}_shared PUBLIC Ws2_32.lib) diff --git a/configure-data.tcl b/configure-data.tcl index 2944c1c77..0496f52cd 100644 --- a/configure-data.tcl +++ b/configure-data.tcl @@ -67,7 +67,7 @@ set cmake_options { enable-clang-tsa "Enable Clang's Thread-Safety-Analysis (default: OFF)" atomic-use-srt-sync-mutex "Use mutex to implement atomics (alias: --with-atomic=sync-mutex) (default: OFF)" - use-enclib "Encryption library to be used: openssl(default), gnutls, mbedtls" + use-enclib "Encryption library to be used: openssl(default), gnutls, mbedtls, botan" enable-debug=<0,1,2> "Enable debug mode (0=disabled, 1=debug, 2=rel-with-debug)" pkg-config-executable= "pkg-config executable" openssl-crypto-library= "OpenSSL: Path to a libcrypto library." @@ -374,6 +374,10 @@ proc postprocess {} { if { $::HAVE_DARWIN && !$toolchain_changed } { set use_brew 1 } + if { [info exists ::optval(--use-enclib)] && $::optval(--use-enclib) == "botan"} { + set use_brew 0 + } + if { $use_brew } { foreach item $::cmakeopt { if { [string first "Android" $item] != -1 } { diff --git a/docs/build/build-options.md b/docs/build/build-options.md index c97111ec7..7ca876f5f 100644 --- a/docs/build/build-options.md +++ b/docs/build/build-options.md @@ -61,7 +61,7 @@ Option details are given further below. | [`SRT_LOG_SLOWDOWN_FREQ_MS`](#SRT_LOG_SLOWDOWN_FREQ_MS) | 1.5.2 | `INT` | 1000\* | Reduce the frequency of some frequent logs, milliseconds. | | [`USE_BUSY_WAITING`](#use_busy_waiting) | 1.3.3 | `BOOL` | OFF | Enables more accurate sending times at the cost of potentially higher CPU load. | | [`USE_CXX_STD`](#use_cxx_std) | 1.4.2 | `STRING` | OFF | Enforces using a particular C++ standard (11, 14, 17, etc.) when compiling. | -| [`USE_ENCLIB`](#use_enclib) | 1.3.3 | `STRING` | openssl | Encryption library to be used (`openssl`, `openssl-evp` (since 1.5.1), `gnutls`, `mbedtls`). | +| [`USE_ENCLIB`](#use_enclib) | 1.3.3 | `STRING` | openssl | Encryption library to be used (`openssl`, `openssl-evp` (since 1.5.1), `gnutls`, `mbedtls`, `botan` (since 1.6.0)). | | [`USE_GNUSTL`](#use_gnustl) | 1.3.4 | `BOOL` | OFF | Use `pkg-config` with the `gnustl` package name to extract the header and library path for the C++ standard library. | | [`USE_OPENSSL_PC`](#use_openssl_pc) | 1.3.0 | `BOOL` | ON | Use `pkg-config` to find OpenSSL libraries. | | [`OPENSSL_USE_STATIC_LIBS`](#openssl_use_static_libs) | 1.5.0 | `BOOL` | OFF | Link OpenSSL statically. | @@ -275,8 +275,9 @@ use encryption for the connection. **`--enable-aead-api-preview`** (default: OFF) When ON, the AEAD API is enabled. The `ENABLE_ENCRYPTION` must be enabled as well. -The AEAD functionality is only available if OpenSSL EVP is selected as the crypto provider: -build option should be set to `USE_ENCLIB=openssl-evp`. +The AEAD functionality is only available if either OpenSSL EVP or Botan is selected +as the crypto provider: +build option `-DUSE_ENCLIB=[openssl-evp | botan]`. The AEAD API is to be official in SRT v1.6.0. @@ -600,6 +601,7 @@ Encryption library to be used. Possible options for ``: * openssl-evp (OpenSSL EVP API, since 1.5.1) * gnutls (with nettle) * mbedtls +* botan #### USE_GNUSTL diff --git a/haicrypt/cryspr-botan.c b/haicrypt/cryspr-botan.c new file mode 100644 index 000000000..341811e82 --- /dev/null +++ b/haicrypt/cryspr-botan.c @@ -0,0 +1,380 @@ +/* + * SRT - Secure, Reliable, Transport + * Copyright (c) 2019 Haivision Systems Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + + +/***************************************************************************** +written by + Haivision Systems Inc. + + 2023-03-28 (oviano) + Botan CRYSPR/4SRT (CRYypto Service PRovider for SRT) +*****************************************************************************/ + +#include "hcrypt.h" + +#include + +typedef struct tag_crysprBotanTLS_AES_cb { + CRYSPR_cb ccb; /* CRYSPR control block */ +#ifdef CRYSPR2 + CRYSPR_AESCTX aes_kek_buf; /* Key Encrypting Key (KEK) */ + CRYSPR_AESCTX aes_sek_buf[2]; /* even/odd Stream Encrypting Key (SEK) */ +#endif +} crysprBotan_cb; + + +static const char* get_key_wrap_algo(size_t kek_len) +{ + switch (kek_len) + { + case 16: + return "AES-128"; + case 24: + return "AES-192"; + case 32: + return "AES-256"; + } + + return NULL; +} + +int crysprBotan_Prng(unsigned char *rn, int len) +{ + if (botan_system_rng_get(rn, len) != BOTAN_FFI_SUCCESS) { + return -1; + } + + return 0; +} + +int crysprBotan_AES_SetKey( + int cipher_type, /* One of HCRYPT_CTX_MODE_[CLRTXT|AESECB|AESCTR] */ + bool bEncrypt, /* true:encrypt key, false:decrypt key*/ + const unsigned char *kstr, /* key string */ + size_t kstr_len, /* kstr length in bytes (16, 24, or 32 bytes, for AES128, AES192, or AES256) */ + CRYSPR_AESCTX *aes_key) /* Cryptolib Specific AES key context */ +{ + if (!(cipher_type == HCRYPT_CTX_MODE_AESCTR || cipher_type == HCRYPT_CTX_MODE_AESGCM)) { + return -1; + } + if (!(kstr_len == 16 || kstr_len == 24 || kstr_len == 32)) { + return -1; + } + + const char* algo = NULL; + if (cipher_type == HCRYPT_CTX_MODE_AESCTR) { + if (kstr_len == 16) { + algo = "CTR(AES-128)"; + } + else if (kstr_len == 24) { + algo = "CTR(AES-192)"; + } + else/* if (kstr_len == 32)*/ { + algo = "CTR(AES-256)"; + } + } else if (cipher_type == HCRYPT_CTX_MODE_AESGCM) { + if (kstr_len == 16) { + algo = "AES-128/GCM"; + } + else if (kstr_len == 24) { + algo = "AES-192/GCM"; + } + else/* if (kstr_len == 32)*/ { + algo = "AES-256/GCM"; + } + } + + if (botan_cipher_init( + &aes_key->cipher, + algo, + bEncrypt ? BOTAN_CIPHER_INIT_FLAG_ENCRYPT : BOTAN_CIPHER_INIT_FLAG_DECRYPT) != BOTAN_FFI_SUCCESS) { + return -1; + } + + if (botan_cipher_set_key( + aes_key->cipher, + kstr, + kstr_len) != BOTAN_FFI_SUCCESS) { + return -1; + } + + memcpy(aes_key->kstr, kstr, kstr_len); + aes_key->kstr_len = kstr_len; + + return 0; +} + +int crysprBotan_AES_CtrCipher( + bool bEncrypt, /* true:encrypt, false:decrypt */ + CRYSPR_AESCTX *aes_key, /* CryptoLib AES context */ + unsigned char *iv, /* iv */ + const unsigned char *indata, /* src */ + size_t inlen, /* src length */ + unsigned char *out_txt) /* dest buffer[inlen] */ +{ + (void)bEncrypt; + + if (botan_cipher_start( + aes_key->cipher, + iv, + 16) != BOTAN_FFI_SUCCESS) { + return -1; + } + + size_t out_written = 0; + size_t in_consumed = 0; + if (botan_cipher_update( + aes_key->cipher, + BOTAN_CIPHER_UPDATE_FLAG_FINAL, + out_txt, + inlen, + &out_written, + indata, + inlen, + &in_consumed) != BOTAN_FFI_SUCCESS) { + return -1; + } + if (in_consumed != inlen || out_written != inlen) { + return -1; + } + + return 0; +} + +int crysprBotan_AES_GCMCipher( + bool bEncrypt, /* true:encrypt, false:decrypt */ + CRYSPR_AESCTX* aes_key, /* CryptoLib AES context */ + unsigned char* iv, /* iv */ + const unsigned char* aad, /* associated data */ + size_t aadlen, /* associated data length */ + const unsigned char* indata, /* src */ + size_t inlen, /* src length */ + unsigned char* out_txt, /* dest buffer[inlen] */ + unsigned char* out_tag) /* dest auth tag */ +{ + if (botan_cipher_set_associated_data( + aes_key->cipher, + aad, + aadlen) != BOTAN_FFI_SUCCESS) { + return -1; + } + + if (botan_cipher_start( + aes_key->cipher, + iv, + 16) != BOTAN_FFI_SUCCESS) { + return -1; + } + + size_t out_written = 0; + size_t in_consumed = 0; + if (!bEncrypt) { + if (botan_cipher_update( + aes_key->cipher, + BOTAN_CIPHER_UPDATE_FLAG_FINAL, + out_txt, + inlen, + &out_written, + indata, + inlen + HAICRYPT_AUTHTAG_MAX, + &in_consumed) != BOTAN_FFI_SUCCESS) { + return -1; + } + if (out_written != inlen) { + return -1; + } + } else { + if (botan_cipher_update( + aes_key->cipher, + BOTAN_CIPHER_UPDATE_FLAG_FINAL, + out_txt, + inlen + HAICRYPT_AUTHTAG_MAX, + &out_written, + indata, + inlen, + &in_consumed) != BOTAN_FFI_SUCCESS) { + return -1; + } + if (in_consumed != inlen) { + return -1; + } + memcpy(out_tag, out_txt + inlen, HAICRYPT_AUTHTAG_MAX); + } + + return 0; +} + +static CRYSPR_cb *crysprBotan_Open(CRYSPR_methods *cryspr, size_t max_len) +{ + crysprBotan_cb *aes_data; + + aes_data = (crysprBotan_cb *)crysprHelper_Open(cryspr, sizeof(crysprBotan_cb), max_len); + if (!aes_data) { + return NULL; + } + + CRYSPR_cb *cryspr_cb = &aes_data->ccb; + +#ifdef CRYSPR2 + cryspr_cb->aes_kek = &aes_data->aes_kek_buf; // key encrypting key + cryspr_cb->aes_sek[0] = &aes_data->aes_sek_buf[0]; // stream encrypting key + cryspr_cb->aes_sek[1] = &aes_data->aes_sek_buf[1]; // stream encrypting key +#endif + cryspr_cb->aes_kek->cipher = NULL; + cryspr_cb->aes_sek[0]->cipher = NULL; + cryspr_cb->aes_sek[1]->cipher = NULL; + + return cryspr_cb; +} + +static int crysprBotan_Close(CRYSPR_cb *cryspr_cb) +{ + if (cryspr_cb->aes_kek->cipher) { + botan_cipher_destroy(cryspr_cb->aes_kek->cipher); + cryspr_cb->aes_kek->cipher = NULL; + } + if (cryspr_cb->aes_sek[0]->cipher) { + botan_cipher_destroy(cryspr_cb->aes_sek[0]->cipher); + cryspr_cb->aes_sek[0]->cipher = NULL; + } + if (cryspr_cb->aes_sek[1]->cipher) { + botan_cipher_destroy(cryspr_cb->aes_sek[1]->cipher); + cryspr_cb->aes_sek[1]->cipher = NULL; + } + + return crysprHelper_Close(cryspr_cb); +} + +int crysprBotan_KmPbkdf2( + CRYSPR_cb *cryspr_cb, + char *passwd, /* passphrase */ + size_t passwd_len, /* passphrase len */ + unsigned char *salt, /* salt */ + size_t salt_len, /* salt_len */ + int itr, /* iterations */ + size_t key_len, /* key_len */ + unsigned char *out) /* derived key buffer[key_len]*/ +{ + (void)cryspr_cb; + + if (botan_pwdhash( + "PBKDF2(SHA-1)", + itr, + 0, + 0, + out, + key_len, + passwd, + passwd_len, + salt, + salt_len) != BOTAN_FFI_SUCCESS) { + return -1; + } + + return 0; +} + +int crysprBotan_KmSetKey(CRYSPR_cb *cryspr_cb, bool bWrap, const unsigned char *kek, size_t kek_len) +{ + return crysprBotan_AES_SetKey( + HCRYPT_CTX_MODE_AESCTR, + bWrap, + kek, + kek_len, + CRYSPR_GETKEK(cryspr_cb)); +} + +int crysprBotan_KmWrap(CRYSPR_cb *cryspr_cb, + unsigned char *wrap, + const unsigned char *sek, + unsigned int seklen) +{ + CRYSPR_AESCTX *aes_key = CRYSPR_GETKEK(cryspr_cb); // key encrypting key + + size_t wraplen = seklen + HAICRYPT_WRAPKEY_SIGN_SZ; + int ret; + if ((ret = botan_nist_kw_enc( + get_key_wrap_algo(aes_key->kstr_len), + 0, + sek, + seklen, + aes_key->kstr, + aes_key->kstr_len, + wrap, + &wraplen)) != BOTAN_FFI_SUCCESS) { + return -1; + } + + if (seklen + HAICRYPT_WRAPKEY_SIGN_SZ != wraplen) { + return -1; + } + + return 0; +} + +int crysprBotan_KmUnwrap( + CRYSPR_cb *cryspr_cb, + unsigned char *sek, + const unsigned char *wrap, + unsigned int wraplen) +{ + CRYSPR_AESCTX *aes_key = CRYSPR_GETKEK(cryspr_cb); // key encrypting key + + size_t seklen = wraplen - HAICRYPT_WRAPKEY_SIGN_SZ; + if (botan_nist_kw_dec( + get_key_wrap_algo(aes_key->kstr_len), + 0, + wrap, + wraplen, + aes_key->kstr, + aes_key->kstr_len, + sek, + &seklen) != BOTAN_FFI_SUCCESS) { + return -1; + } + + if (wraplen - HAICRYPT_WRAPKEY_SIGN_SZ != seklen) { + return -1; + } + + return 0; +} + +static CRYSPR_methods crysprBotan_methods; + +CRYSPR_methods *crysprBotan(void) +{ + if (crysprBotan_methods.open) { + return &crysprBotan_methods; + } + + crysprInit(&crysprBotan_methods); + + /* CryptoLib Primitive API */ + crysprBotan_methods.prng = crysprBotan_Prng; + crysprBotan_methods.aes_set_key = crysprBotan_AES_SetKey; + crysprBotan_methods.aes_ctr_cipher = crysprBotan_AES_CtrCipher; + crysprBotan_methods.aes_gcm_cipher = crysprBotan_AES_GCMCipher; + + //--Crypto Session (Top API) + crysprBotan_methods.open = crysprBotan_Open; + crysprBotan_methods.close = crysprBotan_Close; + + //--Keying material (km) encryption + crysprBotan_methods.km_pbkdf2 = crysprBotan_KmPbkdf2; + crysprBotan_methods.km_setkey = crysprBotan_KmSetKey; + crysprBotan_methods.km_wrap = crysprBotan_KmWrap; + crysprBotan_methods.km_unwrap = crysprBotan_KmUnwrap; + + return &crysprBotan_methods; +} + + + diff --git a/haicrypt/cryspr-botan.h b/haicrypt/cryspr-botan.h new file mode 100644 index 000000000..704d29695 --- /dev/null +++ b/haicrypt/cryspr-botan.h @@ -0,0 +1,59 @@ +/* + * SRT - Secure, Reliable, Transport + * Copyright (c) 2019 Haivision Systems Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +/***************************************************************************** +written by + Haivision Systems Inc. + + 2019-06-27 (jdube) + Botan CRYSPR/4SRT (CRYypto Service PRovider for SRT) + +*****************************************************************************/ + +#ifndef CRYSPR_BOTAN_H +#define CRYSPR_BOTAN_H + +#include + +typedef struct botan_aes_context +{ + botan_cipher_t cipher; + unsigned char kstr[32]; + size_t kstr_len; +} botan_aes_context; + +/* Define CRYSPR_HAS_AESCTR to 1 if this CRYSPR has AES CTR cipher mode. +*/ +#define CRYSPR_HAS_AESCTR 1 + +/* Define CRYSPR_HAS_AESGCM to 1 if this CRYSPR has AES GCM cipher mode. +*/ +#define CRYSPR_HAS_AESGCM 1 + +/* Define CRYSPR_HAS_AESKWRAP to 1 if this CRYSPR has AES Key Wrap. +*/ +#define CRYSPR_HAS_AESKWRAP 1 + +/* Define CRYSPR_HAS_PBKDF2 to 1 if this CRYSPR has SHA1-HMAC Password-based Key Derivaion Function 2. +*/ +#define CRYSPR_HAS_PBKDF2 1 + +/* +#define CRYSPR_AESCTX to the CRYSPR specifix AES key context object. +This type reserves room in the CRYPSPR control block for Haicrypt KEK and SEK +It is set from the keystring through CRYSPR_methods.aes_set_key and passed +to CRYSPR_methods.aes_XXX. +*/ +typedef botan_aes_context CRYSPR_AESCTX; /* CRYpto Service PRovider AES key context */ + +struct tag_CRYSPR_methods *crysprBotan(void); + +#endif /* CRYSPR_BOTAN_H */ + diff --git a/haicrypt/cryspr-config.h b/haicrypt/cryspr-config.h index ee4921dbe..d1b9e8137 100644 --- a/haicrypt/cryspr-config.h +++ b/haicrypt/cryspr-config.h @@ -21,6 +21,10 @@ #include "cryspr-mbedtls.h" #define cryspr4SRT() crysprMbedtls() #define CRYSPR_IMPL_DESC "MbedTLS" +#elif defined(USE_BOTAN) +#include "cryspr-botan.h" +#define cryspr4SRT() crysprBotan() +#define CRYSPR_IMPL_DESC "Botan" #else #error Cryspr implementation not selected. Please define USE_* + OPENSSL/GNUTLS/MBEDTLS. #define CRYSPR_IMPL_DESC "No Cipher" diff --git a/haicrypt/filelist-botan.maf b/haicrypt/filelist-botan.maf new file mode 100644 index 000000000..33b89119e --- /dev/null +++ b/haicrypt/filelist-botan.maf @@ -0,0 +1,24 @@ +# HaiCrypt library contents + +PUBLIC HEADERS +haicrypt.h +hcrypt_ctx.h +hcrypt_msg.h + +PRIVATE HEADERS +hcrypt.h +cryspr.h +cryspr-botan.h +haicrypt_log.h + +SOURCES +cryspr.c +cryspr-botan.c +hcrypt.c +hcrypt_ctx_rx.c +hcrypt_ctx_tx.c +hcrypt_rx.c +hcrypt_sa.c +hcrypt_tx.c +hcrypt_xpt_srt.c +haicrypt_log.cpp diff --git a/scripts/FindBotan.cmake b/scripts/FindBotan.cmake new file mode 100644 index 000000000..01930170c --- /dev/null +++ b/scripts/FindBotan.cmake @@ -0,0 +1,142 @@ +## This script was taken from https://github.com/Tectu/botan-cmake and modified slightly for SRT integration. +## +## This module will automagically download the tarball of the specified Botan version and invoke the configure.py +## python script to generate the amalgamation files (botan_all.cpp and botan_all.h). +## +## Usage: +## find_package( +## Botan 3.0.0 +## COMPONENTS +## system_rng +## argon2 +## sha3 +## REQUIRED +## ) +## +## target_link_libraries( +## MyTarget +## PRIVATE +## botan +## ) +## + +cmake_minimum_required(VERSION 3.19) +include(FetchContent) + +# Find python +find_package( + Python + COMPONENTS + Interpreter + REQUIRED +) + +# Assemble version string +set(Botan_VERSION_STRING ${Botan_FIND_VERSION_MAJOR}.${Botan_FIND_VERSION_MINOR}.${Botan_FIND_VERSION_PATCH}) + +# Assemble download URL +set(DOWNLOAD_URL https://github.com/randombit/botan/archive/refs/tags/${Botan_VERSION_STRING}.tar.gz) + +# Just do a dummy download to see whether we can download the tarball +file( + DOWNLOAD + ${DOWNLOAD_URL} + STATUS download_status +) +if (NOT download_status EQUAL 0) + message(FATAL_ERROR "Could not download Botan tarball (status = ${download_status}): ${DOWNLOAD_URL}") +endif() + +# Download the tarball +FetchContent_Declare( + botan_upstream + URL ${DOWNLOAD_URL} + DOWNLOAD_EXTRACT_TIMESTAMP true +) +FetchContent_MakeAvailable(botan_upstream) + +# Heavy lifting by cmake +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Botan DEFAULT_MSG Botan_VERSION_STRING) + +## Function to generate a target named 'TARGET_NAME' with specific Botan modules enabled. +function(botan_generate TARGET_NAME MODULES) + # The last N arguments are considered to be the modules list. + # Here, we collect those in a list and join them with a comma separator ready to be passed to the configure.py script. + foreach(module_index RANGE 1 ${ARGC}-2) + list(APPEND modules_list ${ARGV${module_index}}) + endforeach() + list(JOIN modules_list "," ENABLE_MODULES_LIST) + + # Determine botan compiler ID (--cc parameter of configure.py) + set(BOTAN_COMPILER_ID ${CMAKE_CXX_COMPILER_ID}) + string(TOLOWER ${BOTAN_COMPILER_ID} BOTAN_COMPILER_ID) + if (BOTAN_COMPILER_ID STREQUAL "gnu") + set(BOTAN_COMPILER_ID "gcc") + endif() + + # Run the configure.py script + add_custom_command( + OUTPUT botan_all.cpp botan_all.h + COMMENT "Generating Botan amalgamation files botan_all.cpp and botan_all.h" + COMMAND ${Python_EXECUTABLE} + ${botan_upstream_SOURCE_DIR}/configure.py + --quiet + --cc-bin=${CMAKE_CXX_COMPILER} + --cc=${BOTAN_COMPILER_ID} + --disable-cc-tests + --os=${BOTAN_OS} + --cpu=${BOTAN_CPU} + --disable-shared + --amalgamation + --with-build-dir=botan + --minimized-build + --enable-modules=${ENABLE_MODULES_LIST} + ) + + # Create target + set(TARGET ${TARGET_NAME}) + add_library(${TARGET} STATIC) + target_sources( + ${TARGET} + PUBLIC + ${CMAKE_CURRENT_BINARY_DIR}/botan_all.h + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/botan_all.cpp + ) + target_include_directories( + ${TARGET} + INTERFACE + ${CMAKE_CURRENT_BINARY_DIR} + ) + set_target_properties( + ${TARGET} + PROPERTIES + POSITION_INDEPENDENT_CODE ON + ) + + add_custom_command( + TARGET ${TARGET_NAME} + COMMENT "Copying build.h file" + COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_BINARY_DIR}/botan/build/build.h" + "${CMAKE_CURRENT_BINARY_DIR}/botan/build.h" + ) + + add_custom_command( + TARGET ${TARGET_NAME} + COMMENT "Copying compiler.h file" + COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_BINARY_DIR}/botan/build/include/botan/compiler.h" + "${CMAKE_CURRENT_BINARY_DIR}/botan/compiler.h" + ) + + add_custom_command( + TARGET ${TARGET_NAME} + COMMENT "Copying ffi.h file" + COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_BINARY_DIR}/botan/build/include/botan/ffi.h" + "${CMAKE_CURRENT_BINARY_DIR}/botan/ffi.h" + ) + +endfunction() diff --git a/scripts/build-android/build-android b/scripts/build-android/build-android index b1c7363a9..99438d7f8 100755 --- a/scripts/build-android/build-android +++ b/scripts/build-android/build-android @@ -7,7 +7,7 @@ echo_help() echo " -a Target API level" echo " -t Space-separated list of target architectures" echo " Android supports the following architectures: armeabi-v7a arm64-v8a x86 x86_64" - echo " -e Encryption library to be used. Possible options: openssl (default) mbedtls" + echo " -e Encryption library to be used. Possible options: openssl (default) mbedtls botan" echo " -o OpenSSL version. E.g. 1.1.1l" echo " -m Mbed TLS version. E.g. v2.26.0" echo @@ -56,12 +56,7 @@ unamestr=$(uname -s) if [ "$unamestr" = 'Linux' ]; then HOST_TAG='linux-x86_64' elif [ "$unamestr" = 'Darwin' ]; then - if [ $(uname -p) = 'arm' ]; then - echo "NDK does not currently support ARM64" - exit 128 - else - HOST_TAG='darwin-x86_64' - fi + HOST_TAG='darwin-x86_64' fi # Write files relative to current location @@ -84,6 +79,8 @@ elif [ $ENC_LIB = 'mbedtls' ]; then git -C $BASE_DIR/mbedtls checkout $MBEDTLS_VERSION fi fi +elif [ $ENC_LIB = 'botan' ]; then + echo "Using Botan for encryption." else echo "Unknown encryption library. Possible options: openssl mbedtls" exit 128 diff --git a/scripts/build-android/mksrt b/scripts/build-android/mksrt index a36900768..d30f01bb5 100755 --- a/scripts/build-android/mksrt +++ b/scripts/build-android/mksrt @@ -14,6 +14,19 @@ do esac done +if [ $ARCH_ABI = "armeabi-v7a" ]; then + BOTAN_CONFIGURE_CPU=armv7 + BOTAN_CXX_FLAGS="" +elif [ $ARCH_ABI = "arm64-v8a" ]; then + BOTAN_CONFIGURE_CPU=arm64 + BOTAN_CXX_FLAGS="-march=armv8-a+crypto" +elif [ $ARCH_ABI = "x86" ]; then + BOTAN_CONFIGURE_CPU=x86 + BOTAN_CXX_FLAGS="" +elif [ $ARCH_ABI = "x86_64" ]; then + BOTAN_CONFIGURE_CPU=x86_64 + BOTAN_CXX_FLAGS="" +fi cd $SRC_DIR ./configure --use-enclib=$ENC_LIB \ @@ -23,9 +36,11 @@ cd $SRC_DIR --STATIC_MBEDTLS=FALSE \ --MBEDTLS_INCLUDE_DIR=$INSTALL_DIR/include --MBEDTLS_INCLUDE_DIRS=$INSTALL_DIR/include \ --MBEDTLS_LIBRARIES=$INSTALL_DIR/lib/libmbedtls.so \ +--BOTAN_OS=android \ +--BOTAN_CPU=$BOTAN_CONFIGURE_CPU \ --CMAKE_PREFIX_PATH=$INSTALL_DIR --CMAKE_INSTALL_PREFIX=$INSTALL_DIR --CMAKE_ANDROID_NDK=$NDK_ROOT \ --CMAKE_SYSTEM_NAME=Android --CMAKE_SYSTEM_VERSION=$API_LEVEL --CMAKE_ANDROID_ARCH_ABI=$ARCH_ABI \ ---CMAKE_C_FLAGS="-fPIC" --CMAKE_SHARED_LINKER_FLAGS="-Wl,--build-id" \ +--CMAKE_C_FLAGS="-fPIC" --CMAKE_CXX_FLAGS=$BOTAN_CXX_FLAGS --CMAKE_SHARED_LINKER_FLAGS="-Wl,--build-id" \ --enable-c++11 --enable-stdcxx-sync \ --enable-debug=2 --enable-logging=0 --enable-heavy-logging=0 --enable-apps=0 make diff --git a/scripts/iOS.cmake b/scripts/iOS.cmake index dfb6aeb97..d3ae0e82b 100644 --- a/scripts/iOS.cmake +++ b/scripts/iOS.cmake @@ -166,8 +166,8 @@ set (CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks ) -# only search the iOS sdks, not the remainder of the host filesystem -set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) +# only search the iOS sdks, not the remainder of the host filesystem (except for programs, so that we can still find Python if needed) +set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)