Support new 12-byte IV format and legacy 16-byte IV format

This commit is contained in:
Travis Burtrum 2017-08-07 00:26:43 -04:00
parent 7c8281d7e5
commit 7ce7d25ada
2 changed files with 26 additions and 13 deletions

View File

@ -1,7 +1,9 @@
# ImageDownloader # ImageDownloader
When [Conversations](https://conversations.im) uploads an encrypted image with [XEP-0363: HTTP Upload](http://xmpp.org/extensions/xep-0363.html) it appends the encryption key as an anchor to the URL. When [Conversations](https://conversations.im) uploads an encrypted image with [XEP-0363: HTTP Upload](http://xmpp.org/extensions/xep-0363.html) it appends the encryption key as an anchor to the URL.
The anchor is made of 96 characters which represent 48 bytes in HEX. The first 16 bytes are the IV the last 32 bytes are the key. There are now [2 formats for anchors](https://github.com/siacs/Conversations/issues/2578).
*LEGACY FORMAT*: The anchor is made of 96 characters which represent 48 bytes in HEX. The first 16 bytes are the IV the last 32 bytes are the key.
*CURRENT FORMAT*: The anchor is made of 88 characters which represent 44 bytes in HEX. The first 12 bytes are the IV the last 32 bytes are the key.
The encryption mode is ```aes-256-gcm```. The authentication tag of 16 bytes is appended to the file. The encryption mode is ```aes-256-gcm```. The authentication tag of 16 bytes is appended to the file.

View File

@ -3,13 +3,14 @@
#include <unistd.h> #include <unistd.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#define TAG_IV_LENGTH 16 #define TAG_LENGTH 16
#define BYTES_PER_READ 32 * 1024 // 32kb #define BYTES_PER_READ 32 * 1024 // 32kb
#define INITIAL_BUFFER_SIZE 256 * 1024 // 256kb, must be at least 2*BYTES_PER_READ #define INITIAL_BUFFER_SIZE 256 * 1024 // 256kb, must be at least 2*BYTES_PER_READ
void hex2string(char *src, unsigned char **dst_p) unsigned int hex2string(char *src, unsigned char **dst_p)
{ {
*dst_p = malloc(strlen(src)/2); unsigned int byte_length = strlen(src)/2;
*dst_p = malloc(byte_length);
unsigned char *dst = *dst_p; unsigned char *dst = *dst_p;
unsigned char *end = dst + (strlen(src)/2); unsigned char *end = dst + (strlen(src)/2);
unsigned int u; unsigned int u;
@ -18,6 +19,7 @@ void hex2string(char *src, unsigned char **dst_p)
*dst++ = u; *dst++ = u;
src += 2; src += 2;
} }
return byte_length;
} }
int main(int argc, char **argv) int main(int argc, char **argv)
@ -35,7 +37,16 @@ int main(int argc, char **argv)
if (argc > 2 && strcmp("enc", argv[2]) == 0) if (argc > 2 && strcmp("enc", argv[2]) == 0)
decrypt = 0; decrypt = 0;
hex2string(argv[1], &gcm_ivkey); unsigned int byte_length = hex2string(argv[1], &gcm_ivkey);
unsigned int iv_length;
if(byte_length == 48) {
iv_length = 16;
} else if(byte_length == 44) {
iv_length = 12;
} else {
fprintf(stderr, "Invalid key length %d only 44 or 48 bytes supported\n", byte_length);
return 1;
}
gcm_ct = malloc(total_size); gcm_ct = malloc(total_size);
@ -53,9 +64,9 @@ int main(int argc, char **argv)
} }
if(decrypt) if(decrypt)
actual_size -= TAG_IV_LENGTH; actual_size -= TAG_LENGTH;
gcm_pt = malloc(decrypt ? actual_size : (actual_size + TAG_IV_LENGTH)); gcm_pt = malloc(decrypt ? actual_size : (actual_size + TAG_LENGTH));
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
@ -66,14 +77,14 @@ int main(int argc, char **argv)
EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
/* Set IV length, omit for 96 bits */ /* Set IV length, omit for 96 bits */
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, TAG_IV_LENGTH, NULL); EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_length, NULL);
if(decrypt) { if(decrypt) {
/* Specify key and IV */ /* Specify key and IV */
EVP_DecryptInit_ex(ctx, NULL, NULL, gcm_ivkey + TAG_IV_LENGTH, gcm_ivkey); EVP_DecryptInit_ex(ctx, NULL, NULL, gcm_ivkey + iv_length, gcm_ivkey);
/* Set expected tag value. */ /* Set expected tag value. */
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, TAG_IV_LENGTH, gcm_ct + actual_size); EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, TAG_LENGTH, gcm_ct + actual_size);
/* Decrypt plaintext */ /* Decrypt plaintext */
EVP_DecryptUpdate(ctx, gcm_pt, &outlen, gcm_ct, actual_size); EVP_DecryptUpdate(ctx, gcm_pt, &outlen, gcm_ct, actual_size);
@ -82,7 +93,7 @@ int main(int argc, char **argv)
rv = EVP_DecryptFinal_ex(ctx, gcm_pt, &final_outlen); rv = EVP_DecryptFinal_ex(ctx, gcm_pt, &final_outlen);
} else { } else {
/* Specify key and IV */ /* Specify key and IV */
EVP_EncryptInit_ex(ctx, NULL, NULL, gcm_ivkey + TAG_IV_LENGTH, gcm_ivkey); EVP_EncryptInit_ex(ctx, NULL, NULL, gcm_ivkey + iv_length, gcm_ivkey);
/* Encrypt plaintext */ /* Encrypt plaintext */
EVP_EncryptUpdate(ctx, gcm_pt, &outlen, gcm_ct, actual_size); EVP_EncryptUpdate(ctx, gcm_pt, &outlen, gcm_ct, actual_size);
@ -91,7 +102,7 @@ int main(int argc, char **argv)
rv = EVP_EncryptFinal_ex(ctx, gcm_pt, &final_outlen); rv = EVP_EncryptFinal_ex(ctx, gcm_pt, &final_outlen);
/* Get expected tag value. */ /* Get expected tag value. */
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAG_IV_LENGTH, gcm_pt + actual_size); EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAG_LENGTH, gcm_pt + actual_size);
} }
EVP_CIPHER_CTX_free(ctx); EVP_CIPHER_CTX_free(ctx);
@ -100,7 +111,7 @@ int main(int argc, char **argv)
if (rv > 0) { if (rv > 0) {
// success! // success!
fwrite(gcm_pt, 1, decrypt ? outlen : (outlen + TAG_IV_LENGTH), stdout); fwrite(gcm_pt, 1, decrypt ? outlen : (outlen + TAG_LENGTH), stdout);
free(gcm_pt); free(gcm_pt);
return 0; return 0;
} else { } else {