Replace OpenSSL with GCrypt
This commit is contained in:
parent
e3b69538ba
commit
a0b2a66ef0
|
@ -16,8 +16,8 @@ Install
|
|||
* GTK (≥ 3.22)
|
||||
* GPGME (For the OpenPGP plugin)
|
||||
* libgee-0.8 (≥ 0.10)
|
||||
* libgcrypt (For the OMEMO plugin)
|
||||
* libnotify
|
||||
* OpenSSL (For the OMEMO plugin)
|
||||
* SQLite3
|
||||
|
||||
Build
|
||||
|
|
57
cmake/FindGCrypt.cmake
Normal file
57
cmake/FindGCrypt.cmake
Normal file
|
@ -0,0 +1,57 @@
|
|||
set(GCrypt_PKG_CONFIG_NAME gcrypt)
|
||||
|
||||
find_program(GCrypt_CONFIG_EXECUTABLE NAMES libgcrypt-config)
|
||||
mark_as_advanced(GCrypt_CONFIG_EXECUTABLE)
|
||||
find_program(GCrypt_SH_EXECUTABLE NAMES sh)
|
||||
mark_as_advanced(GCrypt_SH_EXECUTABLE)
|
||||
|
||||
|
||||
if(GCrypt_CONFIG_EXECUTABLE)
|
||||
macro(gcrypt_config_fail errcode)
|
||||
if(${errcode})
|
||||
message(FATAL_ERROR "Error invoking libgcrypt-config: ${errcode}")
|
||||
endif(${errcode})
|
||||
endmacro(gcrypt_config_fail)
|
||||
file(TO_NATIVE_PATH "${GCrypt_CONFIG_EXECUTABLE}" GCrypt_CONFIG_EXECUTABLE)
|
||||
file(TO_NATIVE_PATH "${GCrypt_SH_EXECUTABLE}" GCrypt_SH_EXECUTABLE)
|
||||
|
||||
execute_process(COMMAND "${GCrypt_SH_EXECUTABLE}" "${GCrypt_CONFIG_EXECUTABLE}" --version
|
||||
OUTPUT_VARIABLE GCrypt_VERSION
|
||||
RESULT_VARIABLE ERRCODE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
gcrypt_config_fail(${ERRCODE})
|
||||
|
||||
execute_process(COMMAND "${GCrypt_SH_EXECUTABLE}" "${GCrypt_CONFIG_EXECUTABLE}" --api-version
|
||||
OUTPUT_VARIABLE GCrypt_API_VERSION
|
||||
RESULT_VARIABLE ERRCODE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
gcrypt_config_fail(${ERRCODE})
|
||||
|
||||
execute_process(COMMAND "${GCrypt_SH_EXECUTABLE}" "${GCrypt_CONFIG_EXECUTABLE}" --cflags
|
||||
OUTPUT_VARIABLE GCrypt_CFLAGS
|
||||
RESULT_VARIABLE ERRCODE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
gcrypt_config_fail(${ERRCODE})
|
||||
|
||||
execute_process(COMMAND "${GCrypt_SH_EXECUTABLE}" "${GCrypt_CONFIG_EXECUTABLE}" --libs
|
||||
OUTPUT_VARIABLE GCrypt_LDFLAGS
|
||||
RESULT_VARIABLE ERRCODE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
gcrypt_config_fail(${ERRCODE})
|
||||
|
||||
string(REGEX REPLACE "^(.* |)-l([^ ]*gcrypt[^ ]*)( .*|)$" "\\2" GCrypt_LIBRARY "${GCrypt_LDFLAGS}")
|
||||
string(REGEX REPLACE "^(.* |)-L([^ ]*)( .*|)$" "\\2" GCrypt_LIBRARY_DIRS "${GCrypt_LDFLAGS}")
|
||||
find_library(LIB_NAME_GCrypt ${GCrypt_LIBRARY} HINTS ${GCrypt_LIBRARY_DIRS})
|
||||
set(GCrypt_LIBRARY ${LIB_NAME_GCrypt})
|
||||
|
||||
if(NOT TARGET gcrypt)
|
||||
add_library(gcrypt INTERFACE IMPORTED)
|
||||
set_property(TARGET gcrypt PROPERTY INTERFACE_LINK_LIBRARIES "${GCrypt_LDFLAGS}")
|
||||
set_property(TARGET gcrypt PROPERTY INTERFACE_COMPILE_OPTIONS "${GCrypt_CFLAGS}")
|
||||
endif(NOT TARGET gcrypt)
|
||||
endif(GCrypt_CONFIG_EXECUTABLE)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(GCrypt
|
||||
REQUIRED_VARS GCrypt_LIBRARY
|
||||
VERSION_VAR GCrypt_VERSION)
|
|
@ -2,23 +2,42 @@ set(GPGME_PKG_CONFIG_NAME gpgme)
|
|||
|
||||
find_program(GPGME_CONFIG_EXECUTABLE NAMES gpgme-config)
|
||||
mark_as_advanced(GPGME_CONFIG_EXECUTABLE)
|
||||
find_program(GPGME_SH_EXECUTABLE NAMES sh)
|
||||
mark_as_advanced(GPGME_SH_EXECUTABLE)
|
||||
|
||||
|
||||
if(GPGME_CONFIG_EXECUTABLE)
|
||||
execute_process(COMMAND ${GPGME_CONFIG_EXECUTABLE} --version
|
||||
macro(gpgme_config_fail errcode)
|
||||
if(${errcode})
|
||||
message(FATAL_ERROR "Error invoking gpgme-config: ${errcode}")
|
||||
endif(${errcode})
|
||||
endmacro(gpgme_config_fail)
|
||||
file(TO_NATIVE_PATH "${GPGME_CONFIG_EXECUTABLE}" GPGME_CONFIG_EXECUTABLE)
|
||||
file(TO_NATIVE_PATH "${GPGME_SH_EXECUTABLE}" GPGME_SH_EXECUTABLE)
|
||||
|
||||
execute_process(COMMAND "${GPGME_SH_EXECUTABLE}" "${GPGME_CONFIG_EXECUTABLE}" --version
|
||||
OUTPUT_VARIABLE GPGME_VERSION
|
||||
RESULT_VARIABLE ERRCODE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
gpgme_config_fail(${ERRCODE})
|
||||
|
||||
execute_process(COMMAND ${GPGME_CONFIG_EXECUTABLE} --api-version
|
||||
execute_process(COMMAND "${GPGME_SH_EXECUTABLE}" "${GPGME_CONFIG_EXECUTABLE}" --api-version
|
||||
OUTPUT_VARIABLE GPGME_API_VERSION
|
||||
RESULT_VARIABLE ERRCODE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
gpgme_config_fail(${ERRCODE})
|
||||
|
||||
execute_process(COMMAND ${GPGME_CONFIG_EXECUTABLE} --cflags
|
||||
execute_process(COMMAND "${GPGME_SH_EXECUTABLE}" "${GPGME_CONFIG_EXECUTABLE}" --cflags
|
||||
OUTPUT_VARIABLE GPGME_CFLAGS
|
||||
RESULT_VARIABLE ERRCODE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
gpgme_config_fail(${ERRCODE})
|
||||
|
||||
execute_process(COMMAND ${GPGME_CONFIG_EXECUTABLE} --libs
|
||||
execute_process(COMMAND "${GPGME_SH_EXECUTABLE}" "${GPGME_CONFIG_EXECUTABLE}" --libs
|
||||
OUTPUT_VARIABLE GPGME_LDFLAGS
|
||||
RESULT_VARIABLE ERRCODE
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
gpgme_config_fail(${ERRCODE})
|
||||
|
||||
string(REGEX REPLACE "^(.* |)-l([^ ]*gpgme[^ ]*)( .*|)$" "\\2" GPGME_LIBRARY "${GPGME_LDFLAGS}")
|
||||
string(REGEX REPLACE "^(.* |)-L([^ ]*)( .*|)$" "\\2" GPGME_LIBRARY_DIRS "${GPGME_LDFLAGS}")
|
||||
|
|
|
@ -52,6 +52,7 @@ mark_as_advanced(VALA_EXECUTABLE)
|
|||
|
||||
# Determine the valac version
|
||||
if(VALA_EXECUTABLE)
|
||||
file(TO_NATIVE_PATH "${VALA_EXECUTABLE}" VALA_EXECUTABLE)
|
||||
execute_process(COMMAND ${VALA_EXECUTABLE} "--version"
|
||||
OUTPUT_VARIABLE VALA_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
|
|
@ -44,7 +44,7 @@ BuildRequires: pkgconfig(gtk+-3.0) >= 3.22
|
|||
BuildRequires: pkgconfig(gee-0.8) >= 0.10
|
||||
BuildRequires: pkgconfig(libnotify)
|
||||
BuildRequires: pkgconfig(sqlite3)
|
||||
BuildRequires: pkgconfig(openssl)
|
||||
BuildRequires: libgcrypt-devel
|
||||
BuildRequires: gpgme-devel
|
||||
Requires: hicolor-icon-theme
|
||||
Requires: %{name}-libs%{?_isa} = %{version}-%{release}
|
||||
|
|
|
@ -3,7 +3,7 @@ set_property(TARGET curve25519 PROPERTY POSITION_INDEPENDENT_CODE ON)
|
|||
set_property(TARGET protobuf-c PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET signal-protocol-c PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(GCrypt REQUIRED)
|
||||
find_packages(SIGNAL_PROTOCOL_PACKAGES REQUIRED
|
||||
Gee
|
||||
GLib
|
||||
|
@ -34,7 +34,7 @@ set(CFLAGS ${VALA_CFLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}/libsignal-protocol-c/src
|
|||
add_definitions(${CFLAGS})
|
||||
add_library(signal-protocol-vala ${SIGNAL_PROTOCOL_VALA_C} ${CMAKE_CURRENT_SOURCE_DIR}/src/signal_helper.c)
|
||||
add_dependencies(signal-protocol-vala signal-protocol-c)
|
||||
target_link_libraries(signal-protocol-vala ${SIGNAL_PROTOCOL_PACKAGES} ${OPENSSL_CRYPTO_LIBRARY} signal-protocol-c m)
|
||||
target_link_libraries(signal-protocol-vala ${SIGNAL_PROTOCOL_PACKAGES} gcrypt signal-protocol-c m)
|
||||
set_property(TARGET signal-protocol-vala PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(SIGNAL_PROTOCOL_C_HEADERS
|
||||
|
@ -102,7 +102,7 @@ DEPENDS
|
|||
${C_HEADERS_TARGET}
|
||||
)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
if(BUILD_TESTS)
|
||||
vala_precompile(SIGNAL_TEST_VALA_C
|
||||
SOURCES
|
||||
"tests/common.vala"
|
||||
|
@ -112,7 +112,7 @@ if(BUILD_TESTING)
|
|||
"tests/hkdf.vala"
|
||||
"tests/session_builder.vala"
|
||||
CUSTOM_VAPIS
|
||||
${CMAKE_BINARY_DIR}/exports/signal-protocol-vala-internal.vapi
|
||||
${CMAKE_BINARY_DIR}/exports/signal-protocol-vala_internal.vapi
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vapi/signal-protocol-public.vapi
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vapi/signal-protocol-native.vapi
|
||||
PACKAGES
|
||||
|
@ -123,4 +123,4 @@ if(BUILD_TESTING)
|
|||
add_executable(signal-protocol-vala-test ${SIGNAL_TEST_VALA_C})
|
||||
add_dependencies(signal-protocol-vala-test signal-protocol-vala signal-protocol-vapi)
|
||||
target_link_libraries(signal-protocol-vala-test signal-protocol-vala ${SIGNAL_PROTOCOL_PACKAGES})
|
||||
endif(BUILD_TESTING)
|
||||
endif(BUILD_TESTS)
|
|
@ -1,25 +1,7 @@
|
|||
#include <signal_helper.h>
|
||||
#include <signal_protocol_internal.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
signal_type_base* signal_type_ref_vapi(signal_type_base* instance) {
|
||||
if (instance->ref_count > 100 || instance->ref_count < 1)
|
||||
printf("REF %x -> %d\n", instance, instance->ref_count+1);
|
||||
signal_type_ref(instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
signal_type_base* signal_type_unref_vapi(signal_type_base* instance) {
|
||||
if (instance->ref_count > 100 || instance->ref_count < 0)
|
||||
printf("UNREF %x -> %d\n", instance, instance->ref_count-1);
|
||||
signal_type_unref(instance);
|
||||
return 0;
|
||||
}
|
||||
#include <gcrypt.h>
|
||||
|
||||
signal_protocol_address* signal_protocol_address_new() {
|
||||
signal_protocol_address* address = malloc(sizeof(signal_protocol_address));
|
||||
|
@ -68,199 +50,136 @@ session_signed_pre_key* session_signed_pre_key_new(uint32_t id, uint64_t timesta
|
|||
|
||||
|
||||
|
||||
int signal_vala_random_generator(uint8_t *data, size_t len, void *user_data)
|
||||
{
|
||||
if(RAND_bytes(data, len)) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return SG_ERR_UNKNOWN;
|
||||
}
|
||||
int signal_vala_random_generator(uint8_t *data, size_t len, void *user_data) {
|
||||
gcry_randomize(data, len, GCRY_STRONG_RANDOM);
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
int signal_vala_hmac_sha256_init(void **hmac_context, const uint8_t *key, size_t key_len, void *user_data)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100001L
|
||||
HMAC_CTX *ctx = HMAC_CTX_new();
|
||||
#else
|
||||
HMAC_CTX *ctx = malloc(sizeof(HMAC_CTX));
|
||||
if(!ctx) {
|
||||
return SG_ERR_NOMEM;
|
||||
int signal_vala_hmac_sha256_init(void **hmac_context, const uint8_t *key, size_t key_len, void *user_data) {
|
||||
gcry_mac_hd_t* ctx = malloc(sizeof(gcry_mac_hd_t));
|
||||
if (!ctx) return SG_ERR_NOMEM;
|
||||
|
||||
if (gcry_mac_open(ctx, GCRY_MAC_HMAC_SHA256, 0, 0)) {
|
||||
free(ctx);
|
||||
return SG_ERR_UNKNOWN;
|
||||
}
|
||||
HMAC_CTX_init(ctx);
|
||||
#endif
|
||||
|
||||
if (gcry_mac_setkey(*ctx, key, key_len)) {
|
||||
free(ctx);
|
||||
return SG_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
*hmac_context = ctx;
|
||||
|
||||
if(HMAC_Init_ex(ctx, key, key_len, EVP_sha256(), 0) != 1) {
|
||||
return SG_ERR_UNKNOWN;
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
int signal_vala_hmac_sha256_update(void *hmac_context, const uint8_t *data, size_t data_len, void *user_data) {
|
||||
gcry_mac_hd_t* *ctx = hmac_context;
|
||||
|
||||
if (gcry_mac_write(*ctx, data, data_len)) return SG_ERR_UNKNOWN;
|
||||
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
int signal_vala_hmac_sha256_update(void *hmac_context, const uint8_t *data, size_t data_len, void *user_data)
|
||||
{
|
||||
HMAC_CTX *ctx = hmac_context;
|
||||
int result = HMAC_Update(ctx, data, data_len);
|
||||
int signal_vala_hmac_sha256_final(void *hmac_context, signal_buffer **output, void *user_data) {
|
||||
unsigned int len = gcry_mac_get_algo_maclen(GCRY_MAC_HMAC_SHA256);
|
||||
unsigned char md[len];
|
||||
gcry_mac_hd_t* ctx = hmac_context;
|
||||
|
||||
return (result == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
int signal_vala_hmac_sha256_final(void *hmac_context, signal_buffer **output, void *user_data)
|
||||
{
|
||||
int result = 0;
|
||||
unsigned char md[EVP_MAX_MD_SIZE];
|
||||
unsigned int len = 0;
|
||||
HMAC_CTX *ctx = hmac_context;
|
||||
|
||||
if(HMAC_Final(ctx, md, &len) != 1) {
|
||||
return SG_ERR_UNKNOWN;
|
||||
}
|
||||
if (gcry_mac_read(*ctx, md, &len)) return SG_ERR_UNKNOWN;
|
||||
|
||||
signal_buffer *output_buffer = signal_buffer_create(md, len);
|
||||
if(!output_buffer) {
|
||||
result = SG_ERR_NOMEM;
|
||||
goto complete;
|
||||
}
|
||||
if (!output_buffer) return SG_ERR_NOMEM;
|
||||
|
||||
*output = output_buffer;
|
||||
|
||||
complete:
|
||||
return result;
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
void signal_vala_hmac_sha256_cleanup(void *hmac_context, void *user_data)
|
||||
{
|
||||
if(hmac_context) {
|
||||
HMAC_CTX *ctx = hmac_context;
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100001L
|
||||
HMAC_CTX_free(ctx);
|
||||
#else
|
||||
HMAC_CTX_cleanup(ctx);
|
||||
free(ctx);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
const EVP_CIPHER *aes_cipher(int cipher, size_t key_len)
|
||||
{
|
||||
if(cipher == SG_CIPHER_AES_CBC_PKCS5) {
|
||||
if(key_len == 16) {
|
||||
return EVP_aes_128_cbc();
|
||||
}
|
||||
else if(key_len == 24) {
|
||||
return EVP_aes_192_cbc();
|
||||
}
|
||||
else if(key_len == 32) {
|
||||
return EVP_aes_256_cbc();
|
||||
}
|
||||
}
|
||||
else if(cipher == SG_CIPHER_AES_CTR_NOPADDING) {
|
||||
if(key_len == 16) {
|
||||
return EVP_aes_128_ctr();
|
||||
}
|
||||
else if(key_len == 24) {
|
||||
return EVP_aes_192_ctr();
|
||||
}
|
||||
else if(key_len == 32) {
|
||||
return EVP_aes_256_ctr();
|
||||
}
|
||||
}
|
||||
else if (cipher == SG_CIPHER_AES_GCM_NOPADDING) {
|
||||
if(key_len == 16) {
|
||||
return EVP_aes_128_gcm();
|
||||
}
|
||||
else if(key_len == 24) {
|
||||
return EVP_aes_192_gcm();
|
||||
}
|
||||
else if(key_len == 32) {
|
||||
return EVP_aes_256_gcm();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int signal_vala_sha512_digest_init(void **digest_context, void *user_data)
|
||||
{
|
||||
int result = 0;
|
||||
EVP_MD_CTX *ctx;
|
||||
|
||||
ctx = EVP_MD_CTX_create();
|
||||
if(!ctx) {
|
||||
result = SG_ERR_NOMEM;
|
||||
goto complete;
|
||||
}
|
||||
|
||||
result = EVP_DigestInit_ex(ctx, EVP_sha512(), 0);
|
||||
if(result == 1) {
|
||||
result = SG_SUCCESS;
|
||||
}
|
||||
else {
|
||||
result = SG_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
complete:
|
||||
if(result < 0) {
|
||||
void signal_vala_hmac_sha256_cleanup(void *hmac_context, void *user_data) {
|
||||
gcry_mac_hd_t* ctx = hmac_context;
|
||||
if (ctx) {
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
gcry_mac_close(*ctx);
|
||||
free(ctx);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
int signal_vala_sha512_digest_init(void **digest_context, void *user_data) {
|
||||
gcry_md_hd_t* ctx = malloc(sizeof(gcry_mac_hd_t));
|
||||
if (!ctx) return SG_ERR_NOMEM;
|
||||
|
||||
if (gcry_md_open(ctx, GCRY_MD_SHA512, 0)) {
|
||||
free(ctx);
|
||||
return SG_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
*digest_context = ctx;
|
||||
}
|
||||
return result;
|
||||
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
int signal_vala_sha512_digest_update(void *digest_context, const uint8_t *data, size_t data_len, void *user_data)
|
||||
{
|
||||
EVP_MD_CTX *ctx = digest_context;
|
||||
int signal_vala_sha512_digest_update(void *digest_context, const uint8_t *data, size_t data_len, void *user_data) {
|
||||
gcry_md_hd_t* ctx = digest_context;
|
||||
|
||||
int result = EVP_DigestUpdate(ctx, data, data_len);
|
||||
gcry_md_write(*ctx, data, data_len);
|
||||
|
||||
return (result == 1) ? SG_SUCCESS : SG_ERR_UNKNOWN;
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
int signal_vala_sha512_digest_final(void *digest_context, signal_buffer **output, void *user_data)
|
||||
{
|
||||
int result = 0;
|
||||
unsigned char md[EVP_MAX_MD_SIZE];
|
||||
unsigned int len = 0;
|
||||
EVP_MD_CTX *ctx = digest_context;
|
||||
int signal_vala_sha512_digest_final(void *digest_context, signal_buffer **output, void *user_data) {
|
||||
unsigned int len = gcry_md_get_algo_dlen(GCRY_MD_SHA512);
|
||||
gcry_md_hd_t* ctx = digest_context;
|
||||
|
||||
result = EVP_DigestFinal_ex(ctx, md, &len);
|
||||
if(result == 1) {
|
||||
result = SG_SUCCESS;
|
||||
}
|
||||
else {
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
unsigned char* md = gcry_md_read(*ctx, GCRY_MD_SHA512);
|
||||
if (!md) return SG_ERR_UNKNOWN;
|
||||
|
||||
result = EVP_DigestInit_ex(ctx, EVP_sha512(), 0);
|
||||
if(result == 1) {
|
||||
result = SG_SUCCESS;
|
||||
}
|
||||
else {
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
gcry_md_reset(*ctx);
|
||||
|
||||
signal_buffer *output_buffer = signal_buffer_create(md, len);
|
||||
if(!output_buffer) {
|
||||
result = SG_ERR_NOMEM;
|
||||
goto complete;
|
||||
}
|
||||
if (!output_buffer) return SG_ERR_NOMEM;
|
||||
|
||||
*output = output_buffer;
|
||||
|
||||
complete:
|
||||
return result;
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
void signal_vala_sha512_digest_cleanup(void *digest_context, void *user_data)
|
||||
{
|
||||
EVP_MD_CTX *ctx = digest_context;
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
void signal_vala_sha512_digest_cleanup(void *digest_context, void *user_data) {
|
||||
gcry_md_hd_t* ctx = digest_context;
|
||||
if (ctx) {
|
||||
gcry_md_close(*ctx);
|
||||
free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
const int aes_cipher(int cipher, size_t key_len, int* algo, int* mode) {
|
||||
switch (key_len) {
|
||||
case 16:
|
||||
*algo = GCRY_CIPHER_AES128;
|
||||
break;
|
||||
case 24:
|
||||
*algo = GCRY_CIPHER_AES192;
|
||||
break;
|
||||
case 32:
|
||||
*algo = GCRY_CIPHER_AES256;
|
||||
break;
|
||||
default:
|
||||
return SG_ERR_UNKNOWN;
|
||||
}
|
||||
switch (cipher) {
|
||||
case SG_CIPHER_AES_CBC_PKCS5:
|
||||
*mode = GCRY_CIPHER_MODE_CBC;
|
||||
break;
|
||||
case SG_CIPHER_AES_CTR_NOPADDING:
|
||||
*mode = GCRY_CIPHER_MODE_CTR;
|
||||
break;
|
||||
case SG_CIPHER_AES_GCM_NOPADDING:
|
||||
*mode = GCRY_CIPHER_MODE_GCM;
|
||||
break;
|
||||
default:
|
||||
return SG_ERR_UNKNOWN;
|
||||
}
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
int signal_vala_encrypt(signal_buffer **output,
|
||||
|
@ -268,114 +187,59 @@ int signal_vala_encrypt(signal_buffer **output,
|
|||
const uint8_t *key, size_t key_len,
|
||||
const uint8_t *iv, size_t iv_len,
|
||||
const uint8_t *plaintext, size_t plaintext_len,
|
||||
void *user_data)
|
||||
{
|
||||
int result = 0;
|
||||
uint8_t *out_buf = 0;
|
||||
void *user_data) {
|
||||
int algo, mode;
|
||||
if (aes_cipher(cipher, key_len, &algo, &mode)) return SG_ERR_UNKNOWN;
|
||||
|
||||
const EVP_CIPHER *evp_cipher = aes_cipher(cipher, key_len);
|
||||
if(!evp_cipher) {
|
||||
fprintf(stderr, "invalid AES mode or key size: %zu\n", key_len);
|
||||
if (iv_len != 16) return SG_ERR_UNKNOWN;
|
||||
|
||||
gcry_cipher_hd_t ctx = {0};
|
||||
|
||||
if (gcry_cipher_open(&ctx, algo, mode, 0)) return SG_ERR_UNKNOWN;
|
||||
|
||||
goto no_error;
|
||||
error:
|
||||
gcry_cipher_close(ctx);
|
||||
return SG_ERR_UNKNOWN;
|
||||
no_error:
|
||||
|
||||
if (gcry_cipher_setkey(ctx, key, key_len)) goto error;
|
||||
|
||||
uint8_t tag_len = 0, pad_len = 0;
|
||||
switch (cipher) {
|
||||
case SG_CIPHER_AES_CBC_PKCS5:
|
||||
if (gcry_cipher_setiv(ctx, iv, iv_len)) goto error;
|
||||
pad_len = 16 - (plaintext_len % 16);
|
||||
if (pad_len == 0) pad_len = 16;
|
||||
break;
|
||||
case SG_CIPHER_AES_CTR_NOPADDING:
|
||||
if (gcry_cipher_setctr(ctx, iv, iv_len)) goto error;
|
||||
break;
|
||||
case SG_CIPHER_AES_GCM_NOPADDING:
|
||||
if (gcry_cipher_setiv(ctx, iv, iv_len)) goto error;
|
||||
tag_len = 16;
|
||||
break;
|
||||
default:
|
||||
return SG_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
if(iv_len != 16) {
|
||||
fprintf(stderr, "invalid AES IV size: %zu\n", iv_len);
|
||||
return SG_ERR_UNKNOWN;
|
||||
size_t padded_len = plaintext_len + pad_len;
|
||||
uint8_t padded[padded_len];
|
||||
memset(padded + plaintext_len, pad_len, pad_len);
|
||||
memcpy(padded, plaintext, plaintext_len);
|
||||
|
||||
uint8_t out_buf[padded_len + tag_len];
|
||||
|
||||
if (gcry_cipher_encrypt(ctx, out_buf, padded_len, padded, padded_len)) goto error;
|
||||
|
||||
if (tag_len > 0) {
|
||||
if (gcry_cipher_gettag(ctx, out_buf + padded_len, tag_len)) goto error;
|
||||
}
|
||||
|
||||
if(plaintext_len > INT_MAX - EVP_CIPHER_block_size(evp_cipher)) {
|
||||
fprintf(stderr, "invalid plaintext length: %zu\n", plaintext_len);
|
||||
return SG_ERR_UNKNOWN;
|
||||
}
|
||||
*output = signal_buffer_create(out_buf, padded_len + tag_len);
|
||||
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||
|
||||
int buf_extra = 0;
|
||||
|
||||
if(cipher == SG_CIPHER_AES_GCM_NOPADDING) {
|
||||
// In GCM mode we use the last 16 bytes as auth tag
|
||||
buf_extra += 16;
|
||||
|
||||
result = EVP_EncryptInit_ex(ctx, evp_cipher, NULL, NULL, NULL);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot initialize cipher\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
|
||||
result = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot set iv size\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
|
||||
result = EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot set key/iv\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
} else {
|
||||
result = EVP_EncryptInit_ex(ctx, evp_cipher, 0, key, iv);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot initialize cipher\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
}
|
||||
|
||||
if(cipher == SG_CIPHER_AES_CTR_NOPADDING || cipher == SG_CIPHER_AES_GCM_NOPADDING) {
|
||||
result = EVP_CIPHER_CTX_set_padding(ctx, 0);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot set padding\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
}
|
||||
|
||||
out_buf = malloc(sizeof(uint8_t) * (plaintext_len + EVP_CIPHER_block_size(evp_cipher) + buf_extra));
|
||||
if(!out_buf) {
|
||||
fprintf(stderr, "cannot allocate output buffer\n");
|
||||
result = SG_ERR_NOMEM;
|
||||
goto complete;
|
||||
}
|
||||
|
||||
int out_len = 0;
|
||||
result = EVP_EncryptUpdate(ctx,
|
||||
out_buf, &out_len, plaintext, plaintext_len);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot encrypt plaintext\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
|
||||
int final_len = 0;
|
||||
result = EVP_EncryptFinal_ex(ctx, out_buf + out_len, &final_len);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot finish encrypting plaintext\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
|
||||
if(cipher == SG_CIPHER_AES_GCM_NOPADDING) {
|
||||
result = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, out_buf + (out_len + final_len));
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot get tag\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
}
|
||||
|
||||
*output = signal_buffer_create(out_buf, out_len + final_len + buf_extra);
|
||||
|
||||
complete:
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
if(out_buf) {
|
||||
free(out_buf);
|
||||
}
|
||||
return result;
|
||||
gcry_cipher_close(ctx);
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
int signal_vala_decrypt(signal_buffer **output,
|
||||
|
@ -383,112 +247,61 @@ int signal_vala_decrypt(signal_buffer **output,
|
|||
const uint8_t *key, size_t key_len,
|
||||
const uint8_t *iv, size_t iv_len,
|
||||
const uint8_t *ciphertext, size_t ciphertext_len,
|
||||
void *user_data)
|
||||
{
|
||||
int result = 0;
|
||||
uint8_t *out_buf = 0;
|
||||
void *user_data) {
|
||||
int algo, mode;
|
||||
if (aes_cipher(cipher, key_len, &algo, &mode)) return SG_ERR_UNKNOWN;
|
||||
|
||||
const EVP_CIPHER *evp_cipher = aes_cipher(cipher, key_len);
|
||||
if(!evp_cipher) {
|
||||
fprintf(stderr, "invalid AES mode or key size: %zu\n", key_len);
|
||||
return SG_ERR_INVAL;
|
||||
}
|
||||
if (iv_len != 16) return SG_ERR_UNKNOWN;
|
||||
|
||||
if(iv_len != 16) {
|
||||
fprintf(stderr, "invalid AES IV size: %zu\n", iv_len);
|
||||
return SG_ERR_INVAL;
|
||||
}
|
||||
gcry_cipher_hd_t ctx = {0};
|
||||
|
||||
if(ciphertext_len > INT_MAX - EVP_CIPHER_block_size(evp_cipher)) {
|
||||
fprintf(stderr, "invalid ciphertext length: %zu\n", ciphertext_len);
|
||||
if (gcry_cipher_open(&ctx, algo, mode, 0)) return SG_ERR_UNKNOWN;
|
||||
|
||||
goto no_error;
|
||||
error:
|
||||
gcry_cipher_close(ctx);
|
||||
return SG_ERR_UNKNOWN;
|
||||
no_error:
|
||||
|
||||
if (gcry_cipher_setkey(ctx, key, key_len)) goto error;
|
||||
|
||||
uint8_t tag_len = 0, pkcs_pad = FALSE;
|
||||
switch (cipher) {
|
||||
case SG_CIPHER_AES_CBC_PKCS5:
|
||||
if (gcry_cipher_setiv(ctx, iv, iv_len)) goto error;
|
||||
pkcs_pad = TRUE;
|
||||
break;
|
||||
case SG_CIPHER_AES_CTR_NOPADDING:
|
||||
if (gcry_cipher_setctr(ctx, iv, iv_len)) goto error;
|
||||
break;
|
||||
case SG_CIPHER_AES_GCM_NOPADDING:
|
||||
if (gcry_cipher_setiv(ctx, iv, iv_len)) goto error;
|
||||
if (ciphertext_len < 16) goto error;
|
||||
tag_len = 16;
|
||||
break;
|
||||
default:
|
||||
return SG_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||
size_t padded_len = ciphertext_len - tag_len;
|
||||
uint8_t out_buf[padded_len];
|
||||
|
||||
if(cipher == SG_CIPHER_AES_GCM_NOPADDING) {
|
||||
// In GCM mode we use the last 16 bytes as auth tag
|
||||
ciphertext_len -= 16;
|
||||
if (gcry_cipher_decrypt(ctx, out_buf, padded_len, ciphertext, padded_len)) goto error;
|
||||
|
||||
result = EVP_DecryptInit_ex(ctx, evp_cipher, NULL, NULL, NULL);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot initialize cipher\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
if (tag_len > 0) {
|
||||
if (gcry_cipher_checktag(ctx, ciphertext + padded_len, tag_len)) goto error;
|
||||
}
|
||||
|
||||
result = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot set iv size\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
|
||||
result = EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot set key/iv\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
if (pkcs_pad) {
|
||||
uint8_t pad_len = out_buf[padded_len - 1];
|
||||
if (pad_len > 16) goto error;
|
||||
*output = signal_buffer_create(out_buf, padded_len - pad_len);
|
||||
} else {
|
||||
result = EVP_DecryptInit_ex(ctx, evp_cipher, 0, key, iv);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot initialize cipher\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
*output = signal_buffer_create(out_buf, padded_len);
|
||||
}
|
||||
|
||||
if(cipher == SG_CIPHER_AES_CTR_NOPADDING || cipher == SG_CIPHER_AES_GCM_NOPADDING) {
|
||||
result = EVP_CIPHER_CTX_set_padding(ctx, 0);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot set padding\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
}
|
||||
|
||||
out_buf = malloc(sizeof(uint8_t) * (ciphertext_len + EVP_CIPHER_block_size(evp_cipher)));
|
||||
if(!out_buf) {
|
||||
fprintf(stderr, "cannot allocate output buffer\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
|
||||
int out_len = 0;
|
||||
result = EVP_DecryptUpdate(ctx,
|
||||
out_buf, &out_len, ciphertext, ciphertext_len);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot decrypt ciphertext\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
|
||||
if(cipher == SG_CIPHER_AES_GCM_NOPADDING) {
|
||||
result = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, (uint8_t*)ciphertext + ciphertext_len);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot set tag\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
}
|
||||
|
||||
int final_len = 0;
|
||||
result = EVP_DecryptFinal_ex(ctx, out_buf + out_len, &final_len);
|
||||
if(!result) {
|
||||
fprintf(stderr, "cannot finish decrypting ciphertexts\n");
|
||||
result = SG_ERR_UNKNOWN;
|
||||
goto complete;
|
||||
}
|
||||
|
||||
*output = signal_buffer_create(out_buf, out_len + final_len);
|
||||
|
||||
complete:
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
if(out_buf) {
|
||||
free(out_buf);
|
||||
}
|
||||
return result;
|
||||
gcry_cipher_close(ctx);
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
void setup_signal_vala_crypto_provider(signal_context *context)
|
||||
|
|
|
@ -51,12 +51,8 @@ namespace Signal {
|
|||
}
|
||||
|
||||
[Compact]
|
||||
[CCode (cname = "signal_type_base", ref_function="signal_type_ref_vapi", unref_function="signal_type_unref_vapi", cheader_filename="signal_protocol_types.h,signal_helper.h")]
|
||||
[CCode (cname = "signal_type_base", ref_function="signal_type_ref", ref_function_void=true, unref_function="signal_type_unref", cheader_filename="signal_protocol_types.h,signal_helper.h")]
|
||||
public class TypeBase {
|
||||
[CCode (cname = "signal_type_ref_vapi")]
|
||||
public TypeBase ref();
|
||||
[CCode (cname = "signal_type_unref_vapi")]
|
||||
public TypeBase unref(void* what);
|
||||
}
|
||||
|
||||
[Compact]
|
||||
|
|
Loading…
Reference in a new issue