Optionally use OpenSSL or LibreSSL instead of bundled crypto-algorithms
crypto-algorithms "have no resistence to side-channel attacks and should not be used in contexts that need cryptographically secure implementations" (see lib/crypto-algorithms/README.md), so using OpenSSL or LibreSSL is preferable. This does solve https://github.com/matrix-org/olm/issues/3 for some platforms, without breaking other platforms without these libraries (like web). Signed-off-by: Lukas Lihotzki <lukas@lihotzki.de>
This commit is contained in:
parent
797183f27f
commit
c7039f5e99
3 changed files with 328 additions and 2 deletions
|
@ -4,6 +4,8 @@ project(olm VERSION 3.2.8 LANGUAGES CXX C)
|
||||||
|
|
||||||
option(OLM_TESTS "Build tests" ON)
|
option(OLM_TESTS "Build tests" ON)
|
||||||
option(BUILD_SHARED_LIBS "Build as a shared library" ON)
|
option(BUILD_SHARED_LIBS "Build as a shared library" ON)
|
||||||
|
option(OLM_USE_OPENSSL "Use OpenSSL instead of bundled crypto-algorithms" OFF)
|
||||||
|
option(OLM_USE_LIBRESSL "Use LibreSSL instead of bundled crypto-algorithms" OFF)
|
||||||
|
|
||||||
add_definitions(-DOLMLIB_VERSION_MAJOR=${PROJECT_VERSION_MAJOR})
|
add_definitions(-DOLMLIB_VERSION_MAJOR=${PROJECT_VERSION_MAJOR})
|
||||||
add_definitions(-DOLMLIB_VERSION_MINOR=${PROJECT_VERSION_MINOR})
|
add_definitions(-DOLMLIB_VERSION_MINOR=${PROJECT_VERSION_MINOR})
|
||||||
|
@ -47,11 +49,23 @@ add_library(olm
|
||||||
src/outbound_group_session.c
|
src/outbound_group_session.c
|
||||||
src/pickle_encoding.c
|
src/pickle_encoding.c
|
||||||
|
|
||||||
lib/crypto-algorithms/aes.c
|
|
||||||
lib/crypto-algorithms/sha256.c
|
|
||||||
lib/curve25519-donna/curve25519-donna.c)
|
lib/curve25519-donna/curve25519-donna.c)
|
||||||
add_library(Olm::Olm ALIAS olm)
|
add_library(Olm::Olm ALIAS olm)
|
||||||
|
|
||||||
|
if(OLM_USE_OPENSSL)
|
||||||
|
find_package(OpenSSL REQUIRED)
|
||||||
|
target_link_libraries(olm OpenSSL::Crypto)
|
||||||
|
target_compile_definitions(olm PRIVATE OLM_USE_OPENSSL)
|
||||||
|
elseif(OLM_USE_LIBRESSL)
|
||||||
|
find_package(LibreSSL REQUIRED)
|
||||||
|
target_link_libraries(olm LibreSSL::Crypto)
|
||||||
|
target_compile_definitions(olm PRIVATE OLM_USE_LIBRESSL)
|
||||||
|
else()
|
||||||
|
target_sources(olm PRIVATE
|
||||||
|
lib/crypto-algorithms/aes.c
|
||||||
|
lib/crypto-algorithms/sha256.c)
|
||||||
|
endif()
|
||||||
|
|
||||||
# restrict the exported symbols
|
# restrict the exported symbols
|
||||||
include(GenerateExportHeader)
|
include(GenerateExportHeader)
|
||||||
generate_export_header(olm
|
generate_export_header(olm
|
||||||
|
|
227
cmake/FindLibreSSL.cmake
Normal file
227
cmake/FindLibreSSL.cmake
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
#[=======================================================================[
|
||||||
|
|
||||||
|
Copyright (c) 2019 John Norrbin <jlnorrbin@johnex.se>
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
FindLibreSSL
|
||||||
|
------------
|
||||||
|
|
||||||
|
Find the LibreSSL encryption library.
|
||||||
|
|
||||||
|
Optional Components
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This module supports two optional components: SSL and TLS. Both
|
||||||
|
components have associated imported targets, as described below.
|
||||||
|
|
||||||
|
Imported Targets
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This module defines the following imported targets:
|
||||||
|
|
||||||
|
LibreSSL::Crypto
|
||||||
|
The LibreSSL crypto library, if found.
|
||||||
|
|
||||||
|
LibreSSL::SSL
|
||||||
|
The LibreSSL ssl library, if found. Requires and includes LibreSSL::Crypto automatically.
|
||||||
|
|
||||||
|
LibreSSL::TLS
|
||||||
|
The LibreSSL tls library, if found. Requires and includes LibreSSL::SSL and LibreSSL::Crypto automatically.
|
||||||
|
|
||||||
|
Result Variables
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This module will set the following variables in your project:
|
||||||
|
|
||||||
|
LIBRESSL_FOUND
|
||||||
|
System has the LibreSSL library. If no components are requested it only requires the crypto library.
|
||||||
|
LIBRESSL_INCLUDE_DIR
|
||||||
|
The LibreSSL include directory.
|
||||||
|
LIBRESSL_CRYPTO_LIBRARY
|
||||||
|
The LibreSSL crypto library.
|
||||||
|
LIBRESSL_SSL_LIBRARY
|
||||||
|
The LibreSSL SSL library.
|
||||||
|
LIBRESSL_TLS_LIBRARY
|
||||||
|
The LibreSSL TLS library.
|
||||||
|
LIBRESSL_LIBRARIES
|
||||||
|
All LibreSSL libraries.
|
||||||
|
LIBRESSL_VERSION
|
||||||
|
This is set to $major.$minor.$revision (e.g. 2.6.8).
|
||||||
|
|
||||||
|
Hints
|
||||||
|
^^^^^
|
||||||
|
|
||||||
|
Set LIBRESSL_ROOT_DIR to the root directory of an LibreSSL installation.
|
||||||
|
|
||||||
|
]=======================================================================]
|
||||||
|
|
||||||
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
|
||||||
|
# Set Hints
|
||||||
|
set(_LIBRESSL_ROOT_HINTS
|
||||||
|
${LIBRESSL_ROOT_DIR}
|
||||||
|
ENV LIBRESSL_ROOT_DIR
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set Paths
|
||||||
|
if (WIN32)
|
||||||
|
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
|
||||||
|
set(_LIBRESSL_ROOT_PATHS
|
||||||
|
"${_programfiles}/LibreSSL"
|
||||||
|
)
|
||||||
|
unset(_programfiles)
|
||||||
|
else()
|
||||||
|
set(_LIBRESSL_ROOT_PATHS
|
||||||
|
"/usr/local/"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Combine
|
||||||
|
set(_LIBRESSL_ROOT_HINTS_AND_PATHS
|
||||||
|
HINTS ${_LIBRESSL_ROOT_HINTS}
|
||||||
|
PATHS ${_LIBRESSL_ROOT_PATHS}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Find Include Path
|
||||||
|
find_path(LIBRESSL_INCLUDE_DIR
|
||||||
|
NAMES
|
||||||
|
tls.h
|
||||||
|
${_LIBRESSL_ROOT_HINTS_AND_PATHS}
|
||||||
|
PATH_SUFFIXES
|
||||||
|
include
|
||||||
|
)
|
||||||
|
|
||||||
|
# Find Crypto Library
|
||||||
|
find_library(LIBRESSL_CRYPTO_LIBRARY
|
||||||
|
NAMES
|
||||||
|
libcrypto
|
||||||
|
crypto
|
||||||
|
NAMES_PER_DIR
|
||||||
|
${_LIBRESSL_ROOT_HINTS_AND_PATHS}
|
||||||
|
PATH_SUFFIXES
|
||||||
|
lib
|
||||||
|
)
|
||||||
|
|
||||||
|
# Find SSL Library
|
||||||
|
find_library(LIBRESSL_SSL_LIBRARY
|
||||||
|
NAMES
|
||||||
|
libssl
|
||||||
|
ssl
|
||||||
|
NAMES_PER_DIR
|
||||||
|
${_LIBRESSL_ROOT_HINTS_AND_PATHS}
|
||||||
|
PATH_SUFFIXES
|
||||||
|
lib
|
||||||
|
)
|
||||||
|
|
||||||
|
# Find TLS Library
|
||||||
|
find_library(LIBRESSL_TLS_LIBRARY
|
||||||
|
NAMES
|
||||||
|
libtls
|
||||||
|
tls
|
||||||
|
NAMES_PER_DIR
|
||||||
|
${_LIBRESSL_ROOT_HINTS_AND_PATHS}
|
||||||
|
PATH_SUFFIXES
|
||||||
|
lib
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set Libraries
|
||||||
|
set(LIBRESSL_LIBRARIES ${LIBRESSL_CRYPTO_LIBRARY} ${LIBRESSL_SSL_LIBRARY} ${LIBRESSL_TLS_LIBRARY})
|
||||||
|
|
||||||
|
# Mark Variables As Advanced
|
||||||
|
mark_as_advanced(LIBRESSL_INCLUDE_DIR LIBRESSL_LIBRARIES LIBRESSL_CRYPTO_LIBRARY LIBRESSL_SSL_LIBRARY LIBRESSL_TLS_LIBRARY)
|
||||||
|
|
||||||
|
# Find Version File
|
||||||
|
if(LIBRESSL_INCLUDE_DIR AND EXISTS "${LIBRESSL_INCLUDE_DIR}/openssl/opensslv.h")
|
||||||
|
|
||||||
|
# Get Version From File
|
||||||
|
file(STRINGS "${LIBRESSL_INCLUDE_DIR}/openssl/opensslv.h" OPENSSLV.H REGEX "#define LIBRESSL_VERSION_TEXT[ ]+\".*\"")
|
||||||
|
|
||||||
|
# Match Version String
|
||||||
|
string(REGEX REPLACE ".*\".*([0-9]+)\\.([0-9]+)\\.([0-9]+)\"" "\\1;\\2;\\3" LIBRESSL_VERSION_LIST "${OPENSSLV.H}")
|
||||||
|
|
||||||
|
# Split Parts
|
||||||
|
list(GET LIBRESSL_VERSION_LIST 0 LIBRESSL_VERSION_MAJOR)
|
||||||
|
list(GET LIBRESSL_VERSION_LIST 1 LIBRESSL_VERSION_MINOR)
|
||||||
|
list(GET LIBRESSL_VERSION_LIST 2 LIBRESSL_VERSION_REVISION)
|
||||||
|
|
||||||
|
# Set Version String
|
||||||
|
set(LIBRESSL_VERSION "${LIBRESSL_VERSION_MAJOR}.${LIBRESSL_VERSION_MINOR}.${LIBRESSL_VERSION_REVISION}")
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Set Find Package Arguments
|
||||||
|
find_package_handle_standard_args(LibreSSL
|
||||||
|
REQUIRED_VARS
|
||||||
|
LIBRESSL_CRYPTO_LIBRARY
|
||||||
|
LIBRESSL_INCLUDE_DIR
|
||||||
|
VERSION_VAR
|
||||||
|
LIBRESSL_VERSION
|
||||||
|
HANDLE_COMPONENTS
|
||||||
|
FAIL_MESSAGE
|
||||||
|
"Could NOT find LibreSSL, try setting the path to LibreSSL using the LIBRESSL_ROOT_DIR environment variable"
|
||||||
|
)
|
||||||
|
|
||||||
|
# LibreSSL Found
|
||||||
|
if(LIBRESSL_FOUND)
|
||||||
|
|
||||||
|
# Set LibreSSL::Crypto
|
||||||
|
if(NOT TARGET LibreSSL::Crypto AND EXISTS "${LIBRESSL_CRYPTO_LIBRARY}")
|
||||||
|
|
||||||
|
# Add Library
|
||||||
|
add_library(LibreSSL::Crypto UNKNOWN IMPORTED)
|
||||||
|
|
||||||
|
# Set Properties
|
||||||
|
set_target_properties(
|
||||||
|
LibreSSL::Crypto
|
||||||
|
PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${LIBRESSL_INCLUDE_DIR}"
|
||||||
|
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||||
|
IMPORTED_LOCATION "${LIBRESSL_CRYPTO_LIBRARY}"
|
||||||
|
)
|
||||||
|
|
||||||
|
endif() # LibreSSL::Crypto
|
||||||
|
|
||||||
|
# Set LibreSSL::SSL
|
||||||
|
if(NOT TARGET LibreSSL::SSL AND EXISTS "${LIBRESSL_SSL_LIBRARY}")
|
||||||
|
|
||||||
|
# Add Library
|
||||||
|
add_library(LibreSSL::SSL UNKNOWN IMPORTED)
|
||||||
|
|
||||||
|
# Set Properties
|
||||||
|
set_target_properties(
|
||||||
|
LibreSSL::SSL
|
||||||
|
PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${LIBRESSL_INCLUDE_DIR}"
|
||||||
|
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||||
|
IMPORTED_LOCATION "${LIBRESSL_SSL_LIBRARY}"
|
||||||
|
INTERFACE_LINK_LIBRARIES LibreSSL::Crypto
|
||||||
|
)
|
||||||
|
|
||||||
|
endif() # LibreSSL::SSL
|
||||||
|
|
||||||
|
# Set LibreSSL::TLS
|
||||||
|
if(NOT TARGET LibreSSL::TLS AND EXISTS "${LIBRESSL_TLS_LIBRARY}")
|
||||||
|
add_library(LibreSSL::TLS UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(
|
||||||
|
LibreSSL::TLS
|
||||||
|
PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${LIBRESSL_INCLUDE_DIR}"
|
||||||
|
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||||
|
IMPORTED_LOCATION "${LIBRESSL_TLS_LIBRARY}"
|
||||||
|
INTERFACE_LINK_LIBRARIES LibreSSL::SSL
|
||||||
|
)
|
||||||
|
|
||||||
|
endif() # LibreSSL::TLS
|
||||||
|
|
||||||
|
endif(LIBRESSL_FOUND)
|
|
@ -17,12 +17,23 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#if defined(OLM_USE_OPENSSL) || defined(OLM_USE_LIBRESSL)
|
||||||
|
#include <openssl/crypto.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/hmac.h>
|
||||||
|
#ifdef OLM_USE_OPENSSL
|
||||||
|
#include <openssl/kdf.h>
|
||||||
|
#else
|
||||||
|
#include <openssl/hkdf.h>
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
#include "crypto-algorithms/aes.h"
|
#include "crypto-algorithms/aes.h"
|
||||||
#include "crypto-algorithms/sha256.h"
|
#include "crypto-algorithms/sha256.h"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "ed25519/src/ed25519.h"
|
#include "ed25519/src/ed25519.h"
|
||||||
#include "curve25519-donna.h"
|
#include "curve25519-donna.h"
|
||||||
|
@ -37,6 +48,8 @@ static const std::size_t SHA256_BLOCK_LENGTH = 64;
|
||||||
static const std::uint8_t HKDF_DEFAULT_SALT[32] = {};
|
static const std::uint8_t HKDF_DEFAULT_SALT[32] = {};
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(OLM_USE_OPENSSL) && !defined(OLM_USE_LIBRESSL)
|
||||||
|
|
||||||
template<std::size_t block_size>
|
template<std::size_t block_size>
|
||||||
inline static void xor_block(
|
inline static void xor_block(
|
||||||
std::uint8_t * block,
|
std::uint8_t * block,
|
||||||
|
@ -98,6 +111,20 @@ inline static void hmac_sha256_final(
|
||||||
olm::unset(o_pad);
|
olm::unset(o_pad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static T checked(T val) {
|
||||||
|
if (!val) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void _olm_crypto_curve25519_generate_key(
|
void _olm_crypto_curve25519_generate_key(
|
||||||
|
@ -176,6 +203,14 @@ void _olm_crypto_aes_encrypt_cbc(
|
||||||
std::uint8_t const * input, std::size_t input_length,
|
std::uint8_t const * input, std::size_t input_length,
|
||||||
std::uint8_t * output
|
std::uint8_t * output
|
||||||
) {
|
) {
|
||||||
|
#if defined(OLM_USE_OPENSSL) || defined(OLM_USE_LIBRESSL)
|
||||||
|
EVP_CIPHER_CTX* ctx = checked(EVP_CIPHER_CTX_new());
|
||||||
|
checked(EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key->key, iv->iv));
|
||||||
|
int output_length[2];
|
||||||
|
checked(EVP_EncryptUpdate(ctx, output, &output_length[0], input, input_length));
|
||||||
|
checked(EVP_EncryptFinal_ex(ctx, output + output_length[0], &output_length[1]));
|
||||||
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
|
#else
|
||||||
std::uint32_t key_schedule[AES_KEY_SCHEDULE_LENGTH];
|
std::uint32_t key_schedule[AES_KEY_SCHEDULE_LENGTH];
|
||||||
::aes_key_setup(key->key, key_schedule, AES_KEY_BITS);
|
::aes_key_setup(key->key, key_schedule, AES_KEY_BITS);
|
||||||
std::uint8_t input_block[AES_BLOCK_LENGTH];
|
std::uint8_t input_block[AES_BLOCK_LENGTH];
|
||||||
|
@ -198,6 +233,7 @@ void _olm_crypto_aes_encrypt_cbc(
|
||||||
::aes_encrypt(input_block, output, key_schedule, AES_KEY_BITS);
|
::aes_encrypt(input_block, output, key_schedule, AES_KEY_BITS);
|
||||||
olm::unset(key_schedule);
|
olm::unset(key_schedule);
|
||||||
olm::unset(input_block);
|
olm::unset(input_block);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -207,6 +243,15 @@ std::size_t _olm_crypto_aes_decrypt_cbc(
|
||||||
std::uint8_t const * input, std::size_t input_length,
|
std::uint8_t const * input, std::size_t input_length,
|
||||||
std::uint8_t * output
|
std::uint8_t * output
|
||||||
) {
|
) {
|
||||||
|
#if defined(OLM_USE_OPENSSL) || defined(OLM_USE_LIBRESSL)
|
||||||
|
EVP_CIPHER_CTX* ctx = checked(EVP_CIPHER_CTX_new());
|
||||||
|
checked(EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key->key, iv->iv));
|
||||||
|
int output_length[2];
|
||||||
|
checked(EVP_DecryptUpdate(ctx, output, &output_length[0], input, input_length));
|
||||||
|
checked(EVP_DecryptFinal_ex(ctx, output + output_length[0], &output_length[1]));
|
||||||
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
|
return output_length[0] + output_length[1];
|
||||||
|
#else
|
||||||
std::uint32_t key_schedule[AES_KEY_SCHEDULE_LENGTH];
|
std::uint32_t key_schedule[AES_KEY_SCHEDULE_LENGTH];
|
||||||
::aes_key_setup(key->key, key_schedule, AES_KEY_BITS);
|
::aes_key_setup(key->key, key_schedule, AES_KEY_BITS);
|
||||||
std::uint8_t block1[AES_BLOCK_LENGTH];
|
std::uint8_t block1[AES_BLOCK_LENGTH];
|
||||||
|
@ -223,6 +268,7 @@ std::size_t _olm_crypto_aes_decrypt_cbc(
|
||||||
olm::unset(block2);
|
olm::unset(block2);
|
||||||
std::size_t padding = output[input_length - 1];
|
std::size_t padding = output[input_length - 1];
|
||||||
return (padding > input_length) ? std::size_t(-1) : (input_length - padding);
|
return (padding > input_length) ? std::size_t(-1) : (input_length - padding);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -230,11 +276,15 @@ void _olm_crypto_sha256(
|
||||||
std::uint8_t const * input, std::size_t input_length,
|
std::uint8_t const * input, std::size_t input_length,
|
||||||
std::uint8_t * output
|
std::uint8_t * output
|
||||||
) {
|
) {
|
||||||
|
#if defined(OLM_USE_OPENSSL) || defined(OLM_USE_LIBRESSL)
|
||||||
|
checked(EVP_Digest(input, input_length, output, nullptr, EVP_sha256(), nullptr));
|
||||||
|
#else
|
||||||
::SHA256_CTX context;
|
::SHA256_CTX context;
|
||||||
::sha256_init(&context);
|
::sha256_init(&context);
|
||||||
::sha256_update(&context, input, input_length);
|
::sha256_update(&context, input, input_length);
|
||||||
::sha256_final(&context, output);
|
::sha256_final(&context, output);
|
||||||
olm::unset(context);
|
olm::unset(context);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -243,6 +293,9 @@ void _olm_crypto_hmac_sha256(
|
||||||
std::uint8_t const * input, std::size_t input_length,
|
std::uint8_t const * input, std::size_t input_length,
|
||||||
std::uint8_t * output
|
std::uint8_t * output
|
||||||
) {
|
) {
|
||||||
|
#if defined(OLM_USE_OPENSSL) || defined(OLM_USE_LIBRESSL)
|
||||||
|
checked(HMAC(EVP_sha256(), key, key_length, input, input_length, output, nullptr));
|
||||||
|
#else
|
||||||
std::uint8_t hmac_key[SHA256_BLOCK_LENGTH];
|
std::uint8_t hmac_key[SHA256_BLOCK_LENGTH];
|
||||||
::SHA256_CTX context;
|
::SHA256_CTX context;
|
||||||
hmac_sha256_key(key, key_length, hmac_key);
|
hmac_sha256_key(key, key_length, hmac_key);
|
||||||
|
@ -251,6 +304,7 @@ void _olm_crypto_hmac_sha256(
|
||||||
hmac_sha256_final(&context, hmac_key, output);
|
hmac_sha256_final(&context, hmac_key, output);
|
||||||
olm::unset(hmac_key);
|
olm::unset(hmac_key);
|
||||||
olm::unset(context);
|
olm::unset(context);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -260,6 +314,36 @@ void _olm_crypto_hkdf_sha256(
|
||||||
std::uint8_t const * info, std::size_t info_length,
|
std::uint8_t const * info, std::size_t info_length,
|
||||||
std::uint8_t * output, std::size_t output_length
|
std::uint8_t * output, std::size_t output_length
|
||||||
) {
|
) {
|
||||||
|
#ifdef OLM_USE_OPENSSL
|
||||||
|
EVP_PKEY_CTX *pctx = checked(EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL));
|
||||||
|
checked(EVP_PKEY_derive_init(pctx));
|
||||||
|
checked(EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()));
|
||||||
|
|
||||||
|
if (input_length) {
|
||||||
|
checked(EVP_PKEY_CTX_set1_hkdf_key(pctx, input, input_length));
|
||||||
|
} else {
|
||||||
|
/* OpenSSL HKDF doesn't directly support zero-length keys:
|
||||||
|
* https://github.com/openssl/openssl/issues/8531
|
||||||
|
* Do the extract step manually with HMAC and use HKDF only for expand */
|
||||||
|
uint8_t intermediate[SHA256_OUTPUT_LENGTH];
|
||||||
|
checked(HMAC(EVP_sha256(), nullptr, 0, salt, salt_length, intermediate, nullptr));
|
||||||
|
checked(EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY));
|
||||||
|
checked(EVP_PKEY_CTX_set1_hkdf_key(pctx, intermediate, sizeof(intermediate)));
|
||||||
|
}
|
||||||
|
|
||||||
|
checked(EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, salt_length));
|
||||||
|
checked(EVP_PKEY_CTX_add1_hkdf_info(pctx, info, info_length));
|
||||||
|
checked(EVP_PKEY_derive(pctx, output, &output_length));
|
||||||
|
EVP_PKEY_CTX_free(pctx);
|
||||||
|
#elif defined(OLM_USE_LIBRESSL)
|
||||||
|
if (salt_length == 0) {
|
||||||
|
/* LibreSSL HKDF rejects nullptr salt, even if salt_length is 0.
|
||||||
|
* salt needs to be set to something else. */
|
||||||
|
salt = (const uint8_t*)"";
|
||||||
|
}
|
||||||
|
checked(HKDF(output, output_length, EVP_sha256(), input, input_length,
|
||||||
|
salt, salt_length, info, info_length));
|
||||||
|
#else
|
||||||
::SHA256_CTX context;
|
::SHA256_CTX context;
|
||||||
std::uint8_t hmac_key[SHA256_BLOCK_LENGTH];
|
std::uint8_t hmac_key[SHA256_BLOCK_LENGTH];
|
||||||
std::uint8_t step_result[SHA256_OUTPUT_LENGTH];
|
std::uint8_t step_result[SHA256_OUTPUT_LENGTH];
|
||||||
|
@ -296,4 +380,5 @@ void _olm_crypto_hkdf_sha256(
|
||||||
olm::unset(context);
|
olm::unset(context);
|
||||||
olm::unset(hmac_key);
|
olm::unset(hmac_key);
|
||||||
olm::unset(step_result);
|
olm::unset(step_result);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue