The following code takes a file from user and encrypts it. The user later can retrieve the same file and decrypt it. The problem is; this code works well with the text-based files (.txt, .c, .py, etc) and the output of the decryption is the same as the input of the encryption. However, when I use an .PNG image, the output is corrupted and the image is not showing.
I tried checking the image code with a text editor and I can see a difference in encoding, but I'm not sure at which stage it was produced. Any help would be appreciated. BTW - I tried also jpeg files but it's the same issue.
Encryption Code:
function uploadFile() {
var file = fileupload.files[0];
var reader = new FileReader();
var key = document.getElementById("enc_key").value; //to get encryption key
var fileEnc = null;
reader.onload = function() {
var wordArray = CryptoJS.lib.WordArray.create(reader.result);
console.log("before: " + wordArray);
var encrypted = CryptoJS.AES.encrypt(wordArray, key);
downloadStringAsFile("encr", encrypted);
console.log("after [from encryption]: " + encrypted);
var fileEnc = new Blob([encrypted]);
encryptAndUpload(fileEnc);
reader.readAsArrayBuffer(file);
}
Decryption Code:
async function decryptAndDownload_Unzipped(index) {
// Some code to get the file_url from the server...
https.get(file_url, function(res) {
var data = [], dataLen = 0;
res.on('data', function(chunk) {
data.push(chunk);
dataLen += chunk.length;
}).on('end', function() {
var buf = Buffer.alloc(dataLen);
for (var i = 0, len = data.length, pos = 0; i < len; i++) {
data[i].copy(buf, pos);
pos += data[i].length;
}
dec_file = "";
for(var i = 0; i < data[0].length; i++){
dec_file += String.fromCharCode(data[0][i]);
}
var decrypted = (CryptoJS.AES.decrypt(dec_file, key)).toString(CryptoJS.enc.Latin1);
var sampleBytes = new Int8Array(8192);
var saveByteArray = (function () {
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
return function (decrypted, name) {
var blob = new Blob(decrypted, {type: "octet/stream"}),
url = window.URL.createObjectURL(blob);
a.href = url;
a.download = name;
a.click();
window.URL.revokeObjectURL(url);
};
}());
saveByteArray([decrypted], 'example.png');
});
});
}
The issue was here:
var decrypted = (CryptoJS.AES.decrypt(dec_file, key)).toString(CryptoJS.enc.Latin1);
There was no need to convert the decryption resutls to string. And I also needed to convert the output to Uint8Array type.
I used this function from [this question][1]:
var arrayOfWords = wordArray.hasOwnProperty("words") ? wordArray.words : [];
var length = wordArray.hasOwnProperty("sigBytes") ? wordArray.sigBytes : arrayOfWords.length * 4;
var uInt8Array = new Uint8Array(length), index=0, word, i;
for (i=0; i<length; i++) {
word = arrayOfWords[i];
uInt8Array[index++] = word >> 24;
uInt8Array[index++] = (word >> 16) & 0xff;
uInt8Array[index++] = (word >> 8) & 0xff;
uInt8Array[index++] = word & 0xff;
}
return uInt8Array;
}```
Then I converted the decryption results to Uint8Array then downloaded the file and it works perfectly.
```var decrypted = CryptoJS.AES.decrypt(dec_file, key);```
```var dec_results = convertWordArrayToUint8Array(decrypted);```
[1]: https://stackoverflow.com/questions/60520526/aes-encryption-and-decryption-of-files-using-crypto-js