mirror of
https://git.jabber.space/devs/cproof.git
synced 2026-07-24 04:16:21 +00:00
Add OMEMO message encryption and decryption
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
#include <signal/signal_protocol.h>
|
||||
#include <signal/signal_protocol_types.h>
|
||||
#include <sodium.h>
|
||||
#include <gcrypt.h>
|
||||
|
||||
#include "omemo/omemo.h"
|
||||
#include "omemo/crypto.h"
|
||||
|
||||
int
|
||||
@@ -12,10 +14,12 @@ omemo_crypto_init(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (crypto_aead_aes256gcm_is_available() == 0) {
|
||||
if (!gcry_check_version(GCRYPT_VERSION)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -96,41 +100,195 @@ int
|
||||
omemo_encrypt_func(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)
|
||||
{
|
||||
gcry_cipher_hd_t hd;
|
||||
unsigned char *padded_plaintext;
|
||||
unsigned char *ciphertext;
|
||||
unsigned long long ciphertext_len;
|
||||
size_t ciphertext_len;
|
||||
int mode;
|
||||
int algo;
|
||||
uint8_t padding = 0;
|
||||
|
||||
assert(cipher != SG_CIPHER_AES_GCM_NOPADDING);
|
||||
assert(key_len == crypto_aead_aes256gcm_KEYBYTES);
|
||||
assert(iv_len == crypto_aead_aes256gcm_NPUBBYTES);
|
||||
switch (key_len) {
|
||||
case 32:
|
||||
algo = GCRY_CIPHER_AES256;
|
||||
break;
|
||||
default:
|
||||
return OMEMO_ERR_UNSUPPORTED_CRYPTO;
|
||||
}
|
||||
|
||||
ciphertext = malloc(plaintext_len + crypto_aead_aes256gcm_ABYTES);
|
||||
crypto_aead_aes256gcm_encrypt(ciphertext, &ciphertext_len, plaintext, plaintext_len, NULL, 0, NULL, iv, key);
|
||||
switch (cipher) {
|
||||
case SG_CIPHER_AES_CBC_PKCS5:
|
||||
mode = GCRY_CIPHER_MODE_CBC;
|
||||
break;
|
||||
default:
|
||||
return OMEMO_ERR_UNSUPPORTED_CRYPTO;
|
||||
}
|
||||
|
||||
gcry_cipher_open(&hd, algo, mode, GCRY_CIPHER_SECURE);
|
||||
|
||||
gcry_cipher_setkey(hd, key, key_len);
|
||||
|
||||
switch (cipher) {
|
||||
case SG_CIPHER_AES_CBC_PKCS5:
|
||||
gcry_cipher_setiv(hd, iv, iv_len);
|
||||
padding = 16 - (plaintext_len % 16);
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
|
||||
padded_plaintext = malloc(plaintext_len + padding);
|
||||
memcpy(padded_plaintext, plaintext, plaintext_len);
|
||||
memset(padded_plaintext + plaintext_len, padding, padding);
|
||||
|
||||
ciphertext_len = plaintext_len + padding;
|
||||
ciphertext = malloc(ciphertext_len);
|
||||
gcry_cipher_encrypt(hd, ciphertext, ciphertext_len, padded_plaintext, plaintext_len + padding);
|
||||
|
||||
*output = signal_buffer_create(ciphertext, ciphertext_len);
|
||||
free(padded_plaintext);
|
||||
free(ciphertext);
|
||||
|
||||
return 0;
|
||||
gcry_cipher_close(hd);
|
||||
|
||||
return SG_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
omemo_decrypt_func(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 ret = SG_SUCCESS;
|
||||
gcry_cipher_hd_t hd;
|
||||
unsigned char *plaintext;
|
||||
unsigned long long plaintext_len;
|
||||
size_t plaintext_len;
|
||||
int mode;
|
||||
int algo;
|
||||
uint8_t padding = 0;
|
||||
|
||||
assert(cipher != SG_CIPHER_AES_GCM_NOPADDING);
|
||||
assert(key_len == crypto_aead_aes256gcm_KEYBYTES);
|
||||
assert(iv_len == crypto_aead_aes256gcm_NPUBBYTES);
|
||||
|
||||
plaintext = malloc(ciphertext_len - crypto_aead_aes256gcm_ABYTES);
|
||||
if (crypto_aead_aes256gcm_decrypt(plaintext, &plaintext_len, NULL, ciphertext, ciphertext_len, NULL, 0, iv, key) < 0) {
|
||||
free(plaintext);
|
||||
return -1;
|
||||
switch (key_len) {
|
||||
case 32:
|
||||
algo = GCRY_CIPHER_AES256;
|
||||
break;
|
||||
default:
|
||||
return OMEMO_ERR_UNSUPPORTED_CRYPTO;
|
||||
}
|
||||
|
||||
*output = signal_buffer_create(plaintext, plaintext_len);
|
||||
switch (cipher) {
|
||||
case SG_CIPHER_AES_CBC_PKCS5:
|
||||
mode = GCRY_CIPHER_MODE_CBC;
|
||||
break;
|
||||
default:
|
||||
return OMEMO_ERR_UNSUPPORTED_CRYPTO;
|
||||
}
|
||||
|
||||
gcry_cipher_open(&hd, algo, mode, GCRY_CIPHER_SECURE);
|
||||
|
||||
gcry_cipher_setkey(hd, key, key_len);
|
||||
|
||||
switch (cipher) {
|
||||
case SG_CIPHER_AES_CBC_PKCS5:
|
||||
gcry_cipher_setiv(hd, iv, iv_len);
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
|
||||
plaintext_len = ciphertext_len;
|
||||
plaintext = malloc(plaintext_len);
|
||||
gcry_cipher_decrypt(hd, plaintext, plaintext_len, ciphertext, ciphertext_len);
|
||||
|
||||
switch (cipher) {
|
||||
case SG_CIPHER_AES_CBC_PKCS5:
|
||||
padding = plaintext[plaintext_len - 1];
|
||||
break;
|
||||
default:
|
||||
assert(FALSE);
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < padding; i++) {
|
||||
if (plaintext[plaintext_len - 1 - i] != padding) {
|
||||
ret = SG_ERR_UNKNOWN;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
*output = signal_buffer_create(plaintext, plaintext_len - padding);
|
||||
|
||||
out:
|
||||
free(plaintext);
|
||||
|
||||
return 0;
|
||||
gcry_cipher_close(hd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
aes128gcm_encrypt(unsigned char *ciphertext, size_t *ciphertext_len, const unsigned char *const plaintext, size_t plaintext_len, const unsigned char *const iv, const unsigned char *const key)
|
||||
{
|
||||
gcry_error_t res;
|
||||
gcry_cipher_hd_t hd;
|
||||
|
||||
res = gcry_cipher_open(&hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_GCM, GCRY_CIPHER_SECURE);
|
||||
if (res != GPG_ERR_NO_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
res = gcry_cipher_setkey(hd, key, AES128_GCM_KEY_LENGTH);
|
||||
if (res != GPG_ERR_NO_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
res = gcry_cipher_setiv(hd, iv, AES128_GCM_IV_LENGTH);
|
||||
if (res != GPG_ERR_NO_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = gcry_cipher_encrypt(hd, ciphertext, *ciphertext_len, plaintext, plaintext_len);
|
||||
if (res != GPG_ERR_NO_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = gcry_cipher_gettag(hd, ciphertext + plaintext_len, AES128_GCM_TAG_LENGTH);
|
||||
if (res != GPG_ERR_NO_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
gcry_cipher_close(hd);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
aes128gcm_decrypt(unsigned char *plaintext, size_t *plaintext_len, const unsigned char *const ciphertext, size_t ciphertext_len, const unsigned char *const iv, const unsigned char *const key)
|
||||
{
|
||||
gcry_error_t res;
|
||||
gcry_cipher_hd_t hd;
|
||||
|
||||
res = gcry_cipher_open(&hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_GCM, GCRY_CIPHER_SECURE);
|
||||
if (res != GPG_ERR_NO_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = gcry_cipher_setkey(hd, key, AES128_GCM_KEY_LENGTH);
|
||||
if (res != GPG_ERR_NO_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = gcry_cipher_setiv(hd, iv, AES128_GCM_IV_LENGTH);
|
||||
if (res != GPG_ERR_NO_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = gcry_cipher_decrypt(hd, plaintext, *plaintext_len, ciphertext, ciphertext_len);
|
||||
if (res != GPG_ERR_NO_ERROR) {
|
||||
goto out;
|
||||
}
|
||||
//res = gcry_cipher_checktag(hd, ciphertext + ciphertext_len - AES128_GCM_TAG_LENGTH, AES128_GCM_TAG_LENGTH);
|
||||
//if (res != GPG_ERR_NO_ERROR) {
|
||||
// goto out;
|
||||
//}
|
||||
|
||||
out:
|
||||
gcry_cipher_close(hd);
|
||||
return res;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user