aboutsummaryrefslogtreecommitdiff
path: root/plugins/omemo/src
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/omemo/src')
-rw-r--r--plugins/omemo/src/file_transfer/file_decryptor.vala2
-rw-r--r--plugins/omemo/src/file_transfer/file_encryptor.vala6
-rw-r--r--plugins/omemo/src/jingle/jet_omemo.vala8
-rw-r--r--plugins/omemo/src/logic/encrypt.vala6
-rw-r--r--plugins/omemo/src/native/context.vala6
-rw-r--r--plugins/omemo/src/native/helper.c265
-rw-r--r--plugins/omemo/src/native/helper.h1
-rw-r--r--plugins/omemo/src/native/helper_gcrypt.c257
-rw-r--r--plugins/omemo/src/native/helper_openssl.c313
-rw-r--r--plugins/omemo/src/native/store.vala2
10 files changed, 583 insertions, 283 deletions
diff --git a/plugins/omemo/src/file_transfer/file_decryptor.vala b/plugins/omemo/src/file_transfer/file_decryptor.vala
index 80303789..ff96b4a3 100644
--- a/plugins/omemo/src/file_transfer/file_decryptor.vala
+++ b/plugins/omemo/src/file_transfer/file_decryptor.vala
@@ -59,7 +59,7 @@ public class OmemoFileDecryptor : FileDecryptor, Object {
file_transfer.encryption = Encryption.OMEMO;
debug("Decrypting file %s from %s", file_transfer.file_name, file_transfer.server_file_name);
- SymmetricCipher cipher = new SymmetricCipher("AES-GCM");
+ SymmetricCipherDecryption cipher = create_symmetric_cipher_decryption("AES-GCM");
cipher.set_key(key);
cipher.set_iv(iv);
return new ConverterInputStream(encrypted_stream, new SymmetricCipherDecrypter((owned) cipher, 16));
diff --git a/plugins/omemo/src/file_transfer/file_encryptor.vala b/plugins/omemo/src/file_transfer/file_encryptor.vala
index 58be7ef1..1aed752f 100644
--- a/plugins/omemo/src/file_transfer/file_encryptor.vala
+++ b/plugins/omemo/src/file_transfer/file_encryptor.vala
@@ -27,11 +27,11 @@ public class OmemoFileEncryptor : Dino.FileEncryptor, Object {
try {
//Create a key and use it to encrypt the file
uint8[] iv = new uint8[IV_SIZE];
- Plugin.get_context().randomize(iv);
+ Crypto.randomize(iv);
uint8[] key = new uint8[KEY_SIZE];
- Plugin.get_context().randomize(key);
+ Crypto.randomize(key);
- SymmetricCipher cipher = new SymmetricCipher("AES-GCM");
+ SymmetricCipherEncryption cipher = create_symmetric_cipher_encryption("AES-GCM");
cipher.set_key(key);
cipher.set_iv(iv);
diff --git a/plugins/omemo/src/jingle/jet_omemo.vala b/plugins/omemo/src/jingle/jet_omemo.vala
index 2c364625..b1a27e15 100644
--- a/plugins/omemo/src/jingle/jet_omemo.vala
+++ b/plugins/omemo/src/jingle/jet_omemo.vala
@@ -93,19 +93,19 @@ public class AesGcmCipher : Jet.Cipher, Object {
}
public Jet.TransportSecret generate_random_secret() {
uint8[] iv = new uint8[default_iv_size];
- Omemo.Plugin.get_context().randomize(iv);
+ Crypto.randomize(iv);
uint8[] key = new uint8[key_size];
- Omemo.Plugin.get_context().randomize(key);
+ Crypto.randomize(key);
return new Jet.TransportSecret(key, iv);
}
public InputStream wrap_input_stream(InputStream input, Jet.TransportSecret secret) requires (secret.transport_key.length == key_size) {
- SymmetricCipher cipher = new SymmetricCipher("AES-GCM");
+ SymmetricCipherDecryption cipher = create_symmetric_cipher_decryption("AES-GCM");
cipher.set_key(secret.transport_key);
cipher.set_iv(secret.initialization_vector);
return new ConverterInputStream(input, new SymmetricCipherDecrypter((owned) cipher, 16));
}
public OutputStream wrap_output_stream(OutputStream output, Jet.TransportSecret secret) requires (secret.transport_key.length == key_size) {
- Crypto.SymmetricCipher cipher = new SymmetricCipher("AES-GCM");
+ SymmetricCipherEncryption cipher = create_symmetric_cipher_encryption("AES-GCM");
cipher.set_key(secret.transport_key);
cipher.set_iv(secret.initialization_vector);
return new ConverterOutputStream(output, new SymmetricCipherEncrypter((owned) cipher, 16));
diff --git a/plugins/omemo/src/logic/encrypt.vala b/plugins/omemo/src/logic/encrypt.vala
index e5d11c69..94203ac9 100644
--- a/plugins/omemo/src/logic/encrypt.vala
+++ b/plugins/omemo/src/logic/encrypt.vala
@@ -26,9 +26,9 @@ namespace Dino.Plugins.Omemo {
//Create a key and use it to encrypt the message
uint8[] key = new uint8[KEY_SIZE];
- Plugin.get_context().randomize(key);
+ Crypto.randomize(key);
uint8[] iv = new uint8[IV_SIZE];
- Plugin.get_context().randomize(iv);
+ Crypto.randomize(iv);
uint8[] aes_encrypt_result = aes_encrypt(Cipher.AES_GCM_NOPADDING, key, iv, plaintext.data);
uint8[] ciphertext = aes_encrypt_result[0:aes_encrypt_result.length - 16];
@@ -128,4 +128,4 @@ namespace Dino.Plugins.Omemo {
encryption_data.add_device_key(device_id, device_key.serialized, device_key.type == CiphertextType.PREKEY);
}
}
-} \ No newline at end of file
+}
diff --git a/plugins/omemo/src/native/context.vala b/plugins/omemo/src/native/context.vala
index b1f5945b..29a96bc1 100644
--- a/plugins/omemo/src/native/context.vala
+++ b/plugins/omemo/src/native/context.vala
@@ -1,7 +1,7 @@
namespace Omemo {
public class Context {
- internal NativeContext native_context;
+ public NativeContext native_context;
private RecMutex mutex = RecMutex();
static void locking_function_lock(void* user_data) {
@@ -29,10 +29,6 @@ public class Context {
return new Store(this);
}
- public void randomize(uint8[] data) throws Error {
- throw_by_code(native_random(data));
- }
-
public SignedPreKeyRecord generate_signed_pre_key(IdentityKeyPair identity_key_pair, int32 id, uint64 timestamp = 0) throws Error {
if (timestamp == 0) timestamp = new DateTime.now_utc().to_unix();
SignedPreKeyRecord res;
diff --git a/plugins/omemo/src/native/helper.c b/plugins/omemo/src/native/helper.c
index 2d808cde..020e39d0 100644
--- a/plugins/omemo/src/native/helper.c
+++ b/plugins/omemo/src/native/helper.c
@@ -1,7 +1,5 @@
#include "helper.h"
-#include <gcrypt.h>
-
signal_type_base* signal_type_ref_vapi(void* instance) {
g_return_val_if_fail(instance != NULL, NULL);
signal_type_ref(instance);
@@ -64,266 +62,3 @@ void signal_protocol_address_set_device_id(signal_protocol_address* self, int32_
self->device_id = device_id;
}
-int signal_vala_randomize(uint8_t *data, size_t len) {
- gcry_randomize(data, len, GCRY_STRONG_RANDOM);
- return SG_SUCCESS;
-}
-
-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) {
- 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;
- }
-
- if (gcry_mac_setkey(*ctx, key, key_len)) {
- free(ctx);
- return SG_ERR_UNKNOWN;
- }
-
- *hmac_context = ctx;
-
- return SG_SUCCESS;
-}
-
-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_final(void *hmac_context, signal_buffer **output, void *user_data) {
- size_t len = gcry_mac_get_algo_maclen(GCRY_MAC_HMAC_SHA256);
- uint8_t md[len];
- gcry_mac_hd_t* ctx = hmac_context;
-
- if (gcry_mac_read(*ctx, md, &len)) return SG_ERR_UNKNOWN;
-
- signal_buffer *output_buffer = signal_buffer_create(md, len);
- if (!output_buffer) return SG_ERR_NOMEM;
-
- *output = output_buffer;
-
- return SG_SUCCESS;
-}
-
-void signal_vala_hmac_sha256_cleanup(void *hmac_context, void *user_data) {
- gcry_mac_hd_t* ctx = hmac_context;
- if (ctx) {
- gcry_mac_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,
- int cipher,
- 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 algo, mode, error_code = SG_ERR_UNKNOWN;
- if (aes_cipher(cipher, key_len, &algo, &mode)) return SG_ERR_INVAL;
-
- gcry_cipher_hd_t ctx = {0};
-
- if (gcry_cipher_open(&ctx, algo, mode, 0)) return SG_ERR_NOMEM;
-
- signal_buffer* padded = 0;
- signal_buffer* out_buf = 0;
- goto no_error;
-error:
- gcry_cipher_close(ctx);
- if (padded != 0) {
- signal_buffer_bzero_free(padded);
- }
- if (out_buf != 0) {
- signal_buffer_free(out_buf);
- }
- return error_code;
-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;
- }
-
- size_t padded_len = plaintext_len + pad_len;
- padded = signal_buffer_alloc(padded_len);
- if (padded == 0) {
- error_code = SG_ERR_NOMEM;
- goto error;
- }
-
- memset(signal_buffer_data(padded) + plaintext_len, pad_len, pad_len);
- memcpy(signal_buffer_data(padded), plaintext, plaintext_len);
-
- out_buf = signal_buffer_alloc(padded_len + tag_len);
- if (out_buf == 0) {
- error_code = SG_ERR_NOMEM;
- goto error;
- }
-
- if (gcry_cipher_encrypt(ctx, signal_buffer_data(out_buf), padded_len, signal_buffer_data(padded), padded_len)) goto error;
-
- if (tag_len > 0) {
- if (gcry_cipher_gettag(ctx, signal_buffer_data(out_buf) + padded_len, tag_len)) goto error;
- }
-
- *output = out_buf;
- out_buf = 0;
-
- signal_buffer_bzero_free(padded);
- padded = 0;
-
- gcry_cipher_close(ctx);
- return SG_SUCCESS;
-}
-
-int signal_vala_decrypt(signal_buffer **output,
- int cipher,
- 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 algo, mode, error_code = SG_ERR_UNKNOWN;
- *output = 0;
- if (aes_cipher(cipher, key_len, &algo, &mode)) return SG_ERR_INVAL;
- if (ciphertext_len == 0) return SG_ERR_INVAL;
-
- gcry_cipher_hd_t ctx = {0};
-
- if (gcry_cipher_open(&ctx, algo, mode, 0)) return SG_ERR_NOMEM;
-
- signal_buffer* out_buf = 0;
- goto no_error;
-error:
- gcry_cipher_close(ctx);
- if (out_buf != 0) {
- signal_buffer_bzero_free(out_buf);
- }
- return error_code;
-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:
- goto error;
- }
-
- size_t padded_len = ciphertext_len - tag_len;
- out_buf = signal_buffer_alloc(padded_len);
- if (out_buf == 0) {
- error_code = SG_ERR_NOMEM;
- goto error;
- }
-
- if (gcry_cipher_decrypt(ctx, signal_buffer_data(out_buf), signal_buffer_len(out_buf), ciphertext, padded_len)) goto error;
-
- if (tag_len > 0) {
- if (gcry_cipher_checktag(ctx, ciphertext + padded_len, tag_len)) goto error;
- }
-
- if (pkcs_pad) {
- uint8_t pad_len = signal_buffer_data(out_buf)[padded_len - 1];
- if (pad_len > 16 || pad_len > padded_len) goto error;
- *output = signal_buffer_create(signal_buffer_data(out_buf), padded_len - pad_len);
- signal_buffer_bzero_free(out_buf);
- out_buf = 0;
- } else {
- *output = out_buf;
- out_buf = 0;
- }
-
- gcry_cipher_close(ctx);
- return SG_SUCCESS;
-}
-
-void setup_signal_vala_crypto_provider(signal_context *context)
-{
- gcry_check_version(NULL);
-
- signal_crypto_provider provider = {
- .random_func = signal_vala_random_generator,
- .hmac_sha256_init_func = signal_vala_hmac_sha256_init,
- .hmac_sha256_update_func = signal_vala_hmac_sha256_update,
- .hmac_sha256_final_func = signal_vala_hmac_sha256_final,
- .hmac_sha256_cleanup_func = signal_vala_hmac_sha256_cleanup,
- .sha512_digest_init_func = NULL,
- .sha512_digest_update_func = NULL,
- .sha512_digest_final_func = NULL,
- .sha512_digest_cleanup_func = NULL,
- .encrypt_func = signal_vala_encrypt,
- .decrypt_func = signal_vala_decrypt,
- .user_data = 0
- };
-
- signal_context_set_crypto_provider(context, &provider);
-}
diff --git a/plugins/omemo/src/native/helper.h b/plugins/omemo/src/native/helper.h
index 3cc21d8a..cbbe220f 100644
--- a/plugins/omemo/src/native/helper.h
+++ b/plugins/omemo/src/native/helper.h
@@ -17,7 +17,6 @@ gchar* signal_protocol_address_get_name(signal_protocol_address* self);
void signal_protocol_address_set_device_id(signal_protocol_address* self, int32_t device_id);
int32_t signal_protocol_address_get_device_id(signal_protocol_address* self);
-int signal_vala_randomize(uint8_t *data, size_t len);
int signal_vala_random_generator(uint8_t *data, size_t len, void *user_data);
int signal_vala_hmac_sha256_init(void **hmac_context, const uint8_t *key, size_t key_len, void *user_data);
int signal_vala_hmac_sha256_update(void *hmac_context, const uint8_t *data, size_t data_len, void *user_data);
diff --git a/plugins/omemo/src/native/helper_gcrypt.c b/plugins/omemo/src/native/helper_gcrypt.c
new file mode 100644
index 00000000..a6921bca
--- /dev/null
+++ b/plugins/omemo/src/native/helper_gcrypt.c
@@ -0,0 +1,257 @@
+#include "helper.h"
+#include <gcrypt.h>
+
+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) {
+ 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;
+ }
+
+ if (gcry_mac_setkey(*ctx, key, key_len)) {
+ free(ctx);
+ return SG_ERR_UNKNOWN;
+ }
+
+ *hmac_context = ctx;
+
+ return SG_SUCCESS;
+}
+
+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_final(void *hmac_context, signal_buffer **output, void *user_data) {
+ size_t len = gcry_mac_get_algo_maclen(GCRY_MAC_HMAC_SHA256);
+ uint8_t md[len];
+ gcry_mac_hd_t* ctx = hmac_context;
+
+ if (gcry_mac_read(*ctx, md, &len)) return SG_ERR_UNKNOWN;
+
+ signal_buffer *output_buffer = signal_buffer_create(md, len);
+ if (!output_buffer) return SG_ERR_NOMEM;
+
+ *output = output_buffer;
+
+ return SG_SUCCESS;
+}
+
+void signal_vala_hmac_sha256_cleanup(void *hmac_context, void *user_data) {
+ gcry_mac_hd_t* ctx = hmac_context;
+ if (ctx) {
+ gcry_mac_close(*ctx);
+ free(ctx);
+ }
+}
+
+static 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,
+ int cipher,
+ 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 algo, mode, error_code = SG_ERR_UNKNOWN;
+ if (aes_cipher(cipher, key_len, &algo, &mode)) return SG_ERR_INVAL;
+
+ gcry_cipher_hd_t ctx = {0};
+
+ if (gcry_cipher_open(&ctx, algo, mode, 0)) return SG_ERR_NOMEM;
+
+ signal_buffer* padded = 0;
+ signal_buffer* out_buf = 0;
+ goto no_error;
+error:
+ gcry_cipher_close(ctx);
+ if (padded != 0) {
+ signal_buffer_bzero_free(padded);
+ }
+ if (out_buf != 0) {
+ signal_buffer_free(out_buf);
+ }
+ return error_code;
+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;
+ }
+
+ size_t padded_len = plaintext_len + pad_len;
+ padded = signal_buffer_alloc(padded_len);
+ if (padded == 0) {
+ error_code = SG_ERR_NOMEM;
+ goto error;
+ }
+
+ memset(signal_buffer_data(padded) + plaintext_len, pad_len, pad_len);
+ memcpy(signal_buffer_data(padded), plaintext, plaintext_len);
+
+ out_buf = signal_buffer_alloc(padded_len + tag_len);
+ if (out_buf == 0) {
+ error_code = SG_ERR_NOMEM;
+ goto error;
+ }
+
+ if (gcry_cipher_encrypt(ctx, signal_buffer_data(out_buf), padded_len, signal_buffer_data(padded), padded_len)) goto error;
+
+ if (tag_len > 0) {
+ if (gcry_cipher_gettag(ctx, signal_buffer_data(out_buf) + padded_len, tag_len)) goto error;
+ }
+
+ *output = out_buf;
+ out_buf = 0;
+
+ signal_buffer_bzero_free(padded);
+ padded = 0;
+
+ gcry_cipher_close(ctx);
+ return SG_SUCCESS;
+}
+
+int signal_vala_decrypt(signal_buffer **output,
+ int cipher,
+ 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 algo, mode, error_code = SG_ERR_UNKNOWN;
+ *output = 0;
+ if (aes_cipher(cipher, key_len, &algo, &mode)) return SG_ERR_INVAL;
+ if (ciphertext_len == 0) return SG_ERR_INVAL;
+
+ gcry_cipher_hd_t ctx = {0};
+
+ if (gcry_cipher_open(&ctx, algo, mode, 0)) return SG_ERR_NOMEM;
+
+ signal_buffer* out_buf = 0;
+ goto no_error;
+error:
+ gcry_cipher_close(ctx);
+ if (out_buf != 0) {
+ signal_buffer_bzero_free(out_buf);
+ }
+ return error_code;
+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:
+ goto error;
+ }
+
+ size_t padded_len = ciphertext_len - tag_len;
+ out_buf = signal_buffer_alloc(padded_len);
+ if (out_buf == 0) {
+ error_code = SG_ERR_NOMEM;
+ goto error;
+ }
+
+ if (gcry_cipher_decrypt(ctx, signal_buffer_data(out_buf), signal_buffer_len(out_buf), ciphertext, padded_len)) goto error;
+
+ if (tag_len > 0) {
+ if (gcry_cipher_checktag(ctx, ciphertext + padded_len, tag_len)) goto error;
+ }
+
+ if (pkcs_pad) {
+ uint8_t pad_len = signal_buffer_data(out_buf)[padded_len - 1];
+ if (pad_len > 16 || pad_len > padded_len) goto error;
+ *output = signal_buffer_create(signal_buffer_data(out_buf), padded_len - pad_len);
+ signal_buffer_bzero_free(out_buf);
+ out_buf = 0;
+ } else {
+ *output = out_buf;
+ out_buf = 0;
+ }
+
+ gcry_cipher_close(ctx);
+ return SG_SUCCESS;
+}
+
+void setup_signal_vala_crypto_provider(signal_context *context) {
+ gcry_check_version(NULL);
+
+ signal_crypto_provider provider = {
+ .random_func = signal_vala_random_generator,
+ .hmac_sha256_init_func = signal_vala_hmac_sha256_init,
+ .hmac_sha256_update_func = signal_vala_hmac_sha256_update,
+ .hmac_sha256_final_func = signal_vala_hmac_sha256_final,
+ .hmac_sha256_cleanup_func = signal_vala_hmac_sha256_cleanup,
+ .encrypt_func = signal_vala_encrypt,
+ .decrypt_func = signal_vala_decrypt,
+ .user_data = 0
+ };
+
+ signal_context_set_crypto_provider(context, &provider);
+}
+
diff --git a/plugins/omemo/src/native/helper_openssl.c b/plugins/omemo/src/native/helper_openssl.c
new file mode 100644
index 00000000..a0020971
--- /dev/null
+++ b/plugins/omemo/src/native/helper_openssl.c
@@ -0,0 +1,313 @@
+#include "helper.h"
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+
+int signal_vala_random_generator(uint8_t *data, size_t len, void *user_data) {
+ return RAND_bytes(data, len) == 1 ? SG_SUCCESS : SG_ERR_UNKNOWN;
+}
+
+struct SIGNAL_VALA_HMAC_CTX {
+ EVP_PKEY *pkey;
+ EVP_MD_CTX *ctx;
+};
+
+int signal_vala_hmac_sha256_init(void **hmac_context, const uint8_t *key, size_t key_len, void *user_data) {
+ EVP_PKEY *pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, key, key_len);
+ if (!pkey) {
+ return SG_ERR_NOMEM;
+ }
+ EVP_MD_CTX *ctx = EVP_MD_CTX_new();
+ if (!ctx) {
+ EVP_PKEY_free(pkey);
+ return SG_ERR_NOMEM;
+ }
+ if (EVP_DigestSignInit(ctx, NULL, EVP_sha256(), NULL, pkey) != 1) {
+ EVP_MD_CTX_free(ctx);
+ EVP_PKEY_free(pkey);
+ return SG_ERR_UNKNOWN;
+ }
+
+ struct SIGNAL_VALA_HMAC_CTX *hmac_ctx = malloc(sizeof(*hmac_ctx));
+ hmac_ctx->pkey = pkey;
+ hmac_ctx->ctx = ctx;
+ *hmac_context = hmac_ctx;
+
+ return SG_SUCCESS;
+}
+
+int signal_vala_hmac_sha256_update(void *hmac_context, const uint8_t *data, size_t data_len, void *user_data) {
+ struct SIGNAL_VALA_HMAC_CTX *hmac_ctx = hmac_context;
+ if (EVP_DigestSignUpdate(hmac_ctx->ctx, data, data_len) != 1) {
+ return SG_ERR_UNKNOWN;
+ }
+ return SG_SUCCESS;
+}
+
+int signal_vala_hmac_sha256_final(void *hmac_context, signal_buffer **output, void *user_data) {
+ size_t len;
+ struct SIGNAL_VALA_HMAC_CTX *hmac_ctx = hmac_context;
+ if (EVP_DigestSignFinal(hmac_ctx->ctx, NULL, &len) != 1) {
+ return SG_ERR_UNKNOWN;
+ }
+ signal_buffer *output_buffer = signal_buffer_alloc(len);
+ if (!output_buffer) {
+ return SG_ERR_NOMEM;
+ }
+ size_t another_len = len;
+ if (EVP_DigestSignFinal(hmac_ctx->ctx, signal_buffer_data(output_buffer), &another_len) != 1) {
+ signal_buffer_free(output_buffer);
+ return SG_ERR_UNKNOWN;
+ }
+ if (another_len != len) {
+ signal_buffer_free(output_buffer);
+ return SG_ERR_UNKNOWN;
+ }
+ *output = output_buffer;
+ return SG_SUCCESS;
+}
+
+void signal_vala_hmac_sha256_cleanup(void *hmac_context, void *user_data) {
+ struct SIGNAL_VALA_HMAC_CTX *hmac_ctx = hmac_context;
+ if (hmac_ctx) {
+ EVP_MD_CTX_free(hmac_ctx->ctx);
+ EVP_PKEY_free(hmac_ctx->pkey);
+ free(hmac_ctx);
+ }
+}
+
+static const EVP_CIPHER *aes_cipher(int cipher, size_t key_len) {
+ switch (cipher) {
+ case SG_CIPHER_AES_CBC_PKCS5:
+ switch (key_len) {
+ case 16: return EVP_aes_128_cbc();
+ case 24: return EVP_aes_192_cbc();
+ case 32: return EVP_aes_256_cbc();
+ }
+ break;
+ case SG_CIPHER_AES_CTR_NOPADDING:
+ switch (key_len) {
+ case 16: return EVP_aes_128_ctr();
+ case 24: return EVP_aes_192_ctr();
+ case 32: return EVP_aes_256_ctr();
+ }
+ break;
+ case SG_CIPHER_AES_GCM_NOPADDING:
+ switch (key_len) {
+ case 16: return EVP_aes_128_gcm();
+ case 24: return EVP_aes_192_gcm();
+ case 32: return EVP_aes_256_gcm();
+ }
+ break;
+
+ }
+ return NULL;
+}
+
+int signal_vala_encrypt(signal_buffer **output,
+ int cipher,
+ 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 = NULL;
+ 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 (plaintext_len > INT_MAX - EVP_CIPHER_block_size(evp_cipher)) {
+ // fprintf(stderr, "invalid plaintext length: %zu\n", plaintext_len);
+ return SG_ERR_UNKNOWN;
+ }
+ 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;
+
+ if (EVP_EncryptInit_ex(ctx, evp_cipher, NULL, NULL, NULL) != 1) {
+ // fprintf(stderr, "cannot initialize cipher\n");
+ result = SG_ERR_UNKNOWN;
+ goto complete;
+ }
+
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL) != 1) {
+ // fprintf(stderr, "cannot set iv size\n");
+ result = SG_ERR_UNKNOWN;
+ goto complete;
+ }
+
+ if (EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv) != 1) {
+ // fprintf(stderr, "cannot set key/iv\n");
+ result = SG_ERR_UNKNOWN;
+ goto complete;
+ }
+ } else {
+ // TODO: set ivlen?
+ if (EVP_EncryptInit_ex(ctx, evp_cipher, 0, key, iv) != 1) {
+ // 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) {
+ if (EVP_CIPHER_CTX_set_padding(ctx, 0) != 1) {
+ // fprintf(stderr, "cannot set padding\n");
+ result = SG_ERR_UNKNOWN;
+ goto complete;
+ }
+ }
+
+ out_buf = malloc(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;
+ if (EVP_EncryptUpdate(ctx, out_buf, &out_len, plaintext, plaintext_len) != 1) {
+ // fprintf(stderr, "cannot encrypt plaintext\n");
+ result = SG_ERR_UNKNOWN;
+ goto complete;
+ }
+
+ int final_len = 0;
+ if (EVP_EncryptFinal_ex(ctx, out_buf + out_len, &final_len) != 1) {
+ // fprintf(stderr, "cannot finish encrypting plaintext\n");
+ result = SG_ERR_UNKNOWN;
+ goto complete;
+ }
+
+ if (cipher == SG_CIPHER_AES_GCM_NOPADDING) {
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, out_buf + out_len + final_len) != 1) {
+ // 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;
+}
+
+int signal_vala_decrypt(signal_buffer **output,
+ int cipher,
+ 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 = NULL;
+ 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 (ciphertext_len > INT_MAX - EVP_CIPHER_block_size(evp_cipher)) {
+ // fprintf(stderr, "invalid ciphertext length: %zu\n", ciphertext_len);
+ return SG_ERR_UNKNOWN;
+ }
+
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+
+ if (cipher == SG_CIPHER_AES_GCM_NOPADDING) {
+ // In GCM mode we use the last 16 bytes as auth tag
+ ciphertext_len -= 16;
+
+ if (EVP_DecryptInit_ex(ctx, evp_cipher, NULL, NULL, NULL) != 1) {
+ // fprintf(stderr, "cannot initialize cipher\n");
+ result = SG_ERR_UNKNOWN;
+ goto complete;
+ }
+
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL) != 1) {
+ // fprintf(stderr, "cannot set iv size\n");
+ result = SG_ERR_UNKNOWN;
+ goto complete;
+ }
+
+ if (EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv) != 1) {
+ // fprintf(stderr, "cannot set key/iv\n");
+ result = SG_ERR_UNKNOWN;
+ goto complete;
+ }
+ } else {
+ // TODO: set ivlen?
+ if (EVP_DecryptInit_ex(ctx, evp_cipher, 0, key, iv) != 1) {
+ // 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) {
+ if (EVP_CIPHER_CTX_set_padding(ctx, 0) != 1) {
+ // fprintf(stderr, "cannot set padding\n");
+ result = SG_ERR_UNKNOWN;
+ goto complete;
+ }
+ }
+
+ out_buf = malloc(ciphertext_len + EVP_CIPHER_block_size(evp_cipher));
+ if (!out_buf) {
+ // fprintf(stderr, "cannot allocate output buffer\n");
+ result = SG_ERR_NOMEM;
+ goto complete;
+ }
+
+ int out_len = 0;
+ if (EVP_DecryptUpdate(ctx, out_buf, &out_len, ciphertext, ciphertext_len) != 1) {
+ // fprintf(stderr, "cannot decrypt ciphertext\n");
+ result = SG_ERR_UNKNOWN;
+ goto complete;
+ }
+
+ if (cipher == SG_CIPHER_AES_GCM_NOPADDING) {
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, (void *)(ciphertext + ciphertext_len)) != 1) {
+ // fprintf(stderr, "cannot set tag\n");
+ result = SG_ERR_UNKNOWN;
+ goto complete;
+ }
+ }
+
+ int final_len = 0;
+ if (EVP_DecryptFinal_ex(ctx, out_buf + out_len, &final_len) != 1) {
+ // 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;
+}
+
+void setup_signal_vala_crypto_provider(signal_context *context) {
+ signal_crypto_provider provider = {
+ .random_func = signal_vala_random_generator,
+ .hmac_sha256_init_func = signal_vala_hmac_sha256_init,
+ .hmac_sha256_update_func = signal_vala_hmac_sha256_update,
+ .hmac_sha256_final_func = signal_vala_hmac_sha256_final,
+ .hmac_sha256_cleanup_func = signal_vala_hmac_sha256_cleanup,
+ .encrypt_func = signal_vala_encrypt,
+ .decrypt_func = signal_vala_decrypt,
+ .user_data = 0
+ };
+
+ signal_context_set_crypto_provider(context, &provider);
+}
diff --git a/plugins/omemo/src/native/store.vala b/plugins/omemo/src/native/store.vala
index b1861d93..12f22f83 100644
--- a/plugins/omemo/src/native/store.vala
+++ b/plugins/omemo/src/native/store.vala
@@ -107,7 +107,7 @@ public class Store : Object {
public PreKeyStore pre_key_store { get; set; default = new SimplePreKeyStore(); }
public SignedPreKeyStore signed_pre_key_store { get; set; default = new SimpleSignedPreKeyStore(); }
public uint32 local_registration_id { get { return identity_key_store.local_registration_id; } }
- internal NativeStoreContext native_context {get { return native_store_context_; }}
+ public NativeStoreContext native_context {get { return native_store_context_; }}
private NativeStoreContext native_store_context_;
static int iks_get_identity_key_pair(out Buffer public_data, out Buffer private_data, void* user_data) {