aboutsummaryrefslogtreecommitdiff
path: root/libdino/src/crypto/gnu
diff options
context:
space:
mode:
authorMarvin W <git@larma.de>2026-10-04 14:42:16 +0200
committerMarvin W <git@larma.de>2026-10-23 16:59:59 +0200
commitdba577f39c489b9db29960f2bf5cc78ac4f29d7b (patch)
treea8354c9fc328c1442d5e8c5c2adec4b428c92f44 /libdino/src/crypto/gnu
parent2413442905e31f34cb0f77c9167003b3725760fe (diff)
Move OMEMO, OpenPGP and RTP plugins into main/libdino
Diffstat (limited to 'libdino/src/crypto/gnu')
-rw-r--r--libdino/src/crypto/gnu/omemo.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/libdino/src/crypto/gnu/omemo.c b/libdino/src/crypto/gnu/omemo.c
new file mode 100644
index 00000000..765e3d79
--- /dev/null
+++ b/libdino/src/crypto/gnu/omemo.c
@@ -0,0 +1,257 @@
+#include "../omemo/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);
+}
+