EDIT 1
In the decryptFile method, the decrypt part will not output anything..
let decrypted = CryptoJS.AES.decrypt(e.target.result, CryptoJS.enc.Utf8.parse(key), {
iv: CryptoJS.enc.Utf8.parse(iv),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
EDIT 2 The link that has been given in the comments section partially solves the problem. It does encrypt and decrypt cross platform, but it is rather slow due to PBKDF2 with SHA256 hashing. I cannot find a way to only use the AES part and not the PKBDF2 part.
ORIGINAL TEXT
I am using the same key and IV for both the Java and Javascript version. I cannot decrypt a file in Javascript that has been encrypted in Java, nor can I decrypt a file in Java that has been encrypted in Javascript. I need those two to be compatible with eachother, but I cannot figure out how I am trying to decrypt a file in Javascript that was previously encrypted in Java. I have succesfully implemented decrypting and encrypting text between the two, but when I would like to for example decrypt a file that is encrypted in Java, it just won't work.
Encrypt / decrypt a file in Java:
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Test {
private SecretKey secretKey;
private IvParameterSpec ivParameterSpec;
private String key = "ThisIsMyGreatKey";
private byte[] ivKey = "ABCDEFGHabcdefgh".getBytes();
public static void main(String[] args) {
try {
new Test().run();
} catch (Exception e) {
e.printStackTrace();
}
}
private void run() {
ivParameterSpec = new IvParameterSpec(ivKey);
secretKey = new SecretKeySpec(key.getBytes(), "AES");
encryptOrDecryptFile(Cipher.ENCRYPT_MODE,
new File("src/cactus.jpg"), new File("src/cactus-encrypted.jpg"));
}
private void encryptOrDecryptFile(int mode, File inputFile, File outputFile) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(mode, secretKey, ivParameterSpec);
// Read input
byte[] input = new byte[(int) inputFile.length()];
FileInputStream inputStream = new FileInputStream(inputFile);
inputStream.read(input);
// Encrypt and write to output
byte[] output = cipher.doFinal(input);
FileOutputStream outputStream = new FileOutputStream(outputFile);
outputStream.write(output);
inputStream.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Encrypt / decrypt in Javascript
<input type="file" id="file-input" onchange="handleFile(this)">
<button onclick="useEncryptionForFile()" id="encrypt-file">Encrypt File</button>
<button onclick="useDecryptionForFile()" id="decrypt-file">Decrypt File</button>
<textarea id="output"></textarea>
<img id="example">
<script>
let key = "ThisIsMyGreatKey";
let iv = "ABCDEFGHabcdefgh";
let useEncryption, useDecryption;
let input = document.getElementById("file-input");
let output = document.getElementById("output");
let example = document.getElementById("example");
function handleFile(element) {
if (element.files && element.files[0]) {
let file = element.files[0];
if (useDecryption) {
decryptFile(file);
} else {
encryptFile(file);
}
}
}
function encryptFile(file) {
let reader = new FileReader();
reader.onload = function (e) {
let encrypted = CryptoJS.AES.encrypt(e.target.result, CryptoJS.enc.Utf8.parse(key), {
iv: CryptoJS.enc.Utf8.parse(iv),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
output.textContent = encrypted;
let a = document.createElement("a");
a.setAttribute('href', 'data:application/octet-stream,' + encrypted);
a.setAttribute('download', file.name + '.encrypted');
a.click();
};
reader.readAsDataURL(file);
}
function decryptFile(file) {
let reader = new FileReader();
reader.onload = function (e) {
let decrypted = CryptoJS.AES.decrypt(e.target.result, CryptoJS.enc.Utf8.parse(key), {
iv: CryptoJS.enc.Utf8.parse(iv),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
// Decrypted is emtpy
output.textContent = decrypted;
// Desperate try to get something working
example.src = "data:image/png;base64," + btoa(decrypted);
let a = document.createElement("a");
a.setAttribute('href', decrypted);
a.setAttribute('download', file.name.replace('encrypted', 'decrypted'));
a.click();
};
reader.readAsText(file);
}
function useEncryptionForFile() {
document.getElementById("encrypt-file").style.backgroundColor = "#757575";
document.getElementById("decrypt-file").style.backgroundColor = "#FFFFFF";
useEncryption = true;
useDecryption = false;
}
function useDecryptionForFile() {
document.getElementById("encrypt-file").style.backgroundColor = "#FFFFFF";
document.getElementById("decrypt-file").style.backgroundColor = "#757575";
useDecryption = true;
useEncryption = false;
}
</script>
I also made a Fiddle in case you'd like that more :), and the Java source can be downloaded here.
In the Java source I used a cactus.jpg as file, but any file could be used :). The cactus can be found here.
How can I decrypt the file that has been encrypted in Java? I have tried converting the blob contents to String, retrieving the data as ArrayBuffer and convert it to String, receive it as text and pass it to the decryption method, but nothing seems to work.
The library I am using in Javascript is CryptoJS, and in Java the standard Crypto libraries.
I found other similar (1,2) questions. However, I think they differ too much, as the answer of those questions does not concern this issue, but rather a small mistake.
If I've forgotten any data, please tell me.