/* Decrypt XMPP OMEMO Media sharing encrypted AES-GCM-256 files Copyright (C) 2024 DiffieHellman This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include /* it's unclear when AES-256-GCM support was added, but around 2008 sounds about right */ #define NEED_LIBGCRYPT_VERSION "1.3.0" void init_gcrypt() { if (!gcry_check_version (NEED_LIBGCRYPT_VERSION)) { fprintf(stderr, "libgcrypt is too old (need %s, have %s)\n", NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL)); exit(2); } /* disable secure memory (encryption key is one off and in insecure memory anyway) */ gcry_control(GCRYCTL_DISABLE_SECMEM, 0); /* initialization has completed */ gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); } int main(int argc, char *argv[]) { init_gcrypt(); if (argc != 3){fprintf(stderr, "Usage: %s \n", argv[0]); exit(1);} if (strlen(argv[2]) != 88){fprintf(stderr, "Hex encoded iv+key should be 88 bytes long\n"); exit(1);} uint8_t iv[12]; uint8_t key[32]; /* decode ASCII encoded hex */ for (int i = 0, j = 0; i < sizeof(iv); ++i, j += 2){sscanf(argv[2]+j, "%2hhx", &iv[i]);} for (int i = 0, j = 24; i < sizeof(key); ++i, j += 2){sscanf(argv[2]+j, "%2hhx", &key[i]);} /* cipher handle */ gcry_cipher_hd_t handle; /* open the cipher in AES-256-GCM mode */ gcry_cipher_open(&handle, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_GCM, 0); gcry_cipher_setkey(handle, key, sizeof(key)); /* iv can only be set after setting key */ gcry_cipher_setiv(handle, iv, sizeof(iv)); int fd = open(argv[1], O_RDWR); if (fd == -1){fprintf(stderr,"Could not open file: %s\n", strerror(errno)); exit(1);} /* get filesize */ struct stat sb; fstat(fd, &sb); /* read the whole file into stack (files are very unlikely to be more than a few MiB in size) */ char buffer[sb.st_size]; if (read(fd, buffer, sb.st_size) != sb.st_size){fprintf(stderr,"Reading file failed!\n"); exit(1);} /* the next call to gcry_cipher_decrypt will be the last one */ gcry_cipher_final(handle); /* decrypt in place */ gcry_cipher_decrypt(handle, buffer, sb.st_size, NULL, 0); gcry_cipher_close(handle); /* seek to the start of file to overwrite */ lseek(fd, 0, SEEK_SET); if (write(fd, buffer, sb.st_size) != sb.st_size){fprintf(stderr,"Writing file failed!\n"); exit(1);} close(fd); return 0; }