diff --git a/README.md b/README.md index 7c1c724..5c0f9b3 100644 --- a/README.md +++ b/README.md @@ -3,25 +3,10 @@ When [Conversations](https://conversations.im) uploads an encrypted image with [ 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. -The encryption mode is ```aes-gcm```. The authentcation 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. -This Java project provides sample code on how to download and dercypt a file. Output is to stdout. Redirect to file or pipe to image viewer. +This C project provides sample code on how to decrypt a file. Output is to stdout. Redirect to file or pipe to image viewer. -Compile with ```mvn package``` +Compile with ```gcc aesgcm.c -lcrypto -o aesgcm```, openbrowser.sh also tries to compile it if the executable not already exist. -Find a compiled version [here](https://gultsch.de/ImageDownloader-0.1.jar) - -Usage: ```java -jar ImageDownloader.jar http://host.tld/path/to/file.jpg#theivandkey``` - -If you change your browser in gajim to something like this script it will automatically open image links in your image viewer if you click on them. -``` -#!/bin/bash -URL=$1 -BROWSER=firefox -JAVA=/usr/lib/jvm/java-8-openjdk/bin/java -IMAGE_DOWNLOADER=/home/daniel/Projects/ImageDownloader/t -if [ ${URL: -97:1} == "#" ]; then - $JAVA -jar $IMAGE_DOWNLOADER $URL | feh -. - -else - $BROWSER $URL -``` +Set openbrowser.sh as your browser in gajim or another XMPP client to automatically decrypt http uploads encrypted with OMEMO or PGP with Conversations. diff --git a/aesgcm.c b/aesgcm.c new file mode 100644 index 0000000..9228887 --- /dev/null +++ b/aesgcm.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include + +#define BYTES_PER_READ 32 * 1024 // 32kb +#define INITIAL_BUFFER_SIZE 256 * 1024 // 256kb, must be at least 2*BYTES_PER_READ + +void hex2string(char *src, unsigned char **dst_p) +{ + *dst_p = malloc(strlen(src)/2); + unsigned char *dst = *dst_p; + unsigned char *end = dst + (strlen(src)/2); + unsigned int u; + + while (dst < end && sscanf(src, "%2x", &u) == 1) { + *dst++ = u; + src += 2; + } +} + +int main(int argc, char **argv) +{ + unsigned char *gcm_ivkey, *gcm_ct, *gcm_pt; + int outlen, rv, final_outlen; + size_t read, actual_size = 0, total_size = INITIAL_BUFFER_SIZE; + + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + return 1; + } + + hex2string(argv[1], &gcm_ivkey); + + gcm_ct = malloc(total_size); + + while ((read = fread(gcm_ct + actual_size, 1, BYTES_PER_READ, stdin)) > 0) { + actual_size += read; + if ((actual_size + BYTES_PER_READ) > total_size) { + total_size = total_size * 1.5; + gcm_ct = realloc(gcm_ct,total_size); + } + } + + if (actual_size < 32) { + fprintf(stderr, "File too small for decryption\n"); + return 1; + } + + actual_size -= 16; + + gcm_pt = malloc(actual_size); + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + + /* Select cipher */ + EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); + + /* Set IV length, omit for 96 bits */ + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL); + + /* Specify key and IV */ + EVP_DecryptInit_ex(ctx, NULL, NULL, gcm_ivkey+16, gcm_ivkey); + + /* Decrypt plaintext */ + EVP_DecryptUpdate(ctx, gcm_pt, &outlen, gcm_ct, actual_size); + + /* Set expected tag value. */ + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, gcm_ct + actual_size); + + /* Finalise: note get no output for GCM */ + rv = EVP_DecryptFinal_ex(ctx, gcm_pt, &final_outlen); + + EVP_CIPHER_CTX_free(ctx); + free(gcm_ivkey); + free(gcm_ct); + + if (rv > 0) { + // success! + fwrite(gcm_pt, 1, outlen, stdout); + free(gcm_pt); + return 0; + } else { + fprintf(stderr, "File integrity check failed\n"); + free(gcm_pt); + return 1; + } +} + +// compile with: gcc aesgcm.c -lcrypto -o aesgcm diff --git a/openbrowser.sh b/openbrowser.sh index dd2de92..21c3976 100755 --- a/openbrowser.sh +++ b/openbrowser.sh @@ -1,10 +1,15 @@ #!/bin/bash +set -e URL=$1 BROWSER=firefox -JAVA=/usr/lib/jvm/java-8-openjdk/bin/java -IMAGE_DOWNLOADER=/home/daniel/Projects/ImageDownloader/target/ImageDownloader-0.1.jar -if [ ${URL: -97:1} == "#" ]; then - $JAVA -jar $IMAGE_DOWNLOADER $URL | feh -. - +AES_GCM="$(dirname $(readlink -f $0))/aesgcm" +if [ ${URL: -97:1} == "#" ] +then + [ -e "$AES_GCM" ] || gcc "$(dirname $(readlink -f $0))/aesgcm.c" -lcrypto -o "$AES_GCM" + curl "$URL" | "$AES_GCM" "${URL: -96}" | feh -. - +elif echo $URL | grep -i '\.pgp$' +then + curl "$URL" | gpg2 -d | feh -. - else $BROWSER $URL fi