I am trying decrypt in a web application (developed with java/servlet) a token encrypted on the client-side with a javascript/JSEncrypt code.
this is the javascript code:
function submit() {
var form = document.querySelector("form");
var plainText = document.querySelector("input[name=ip]").value;
var fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.addEventListener('change', function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onloadend = function (e) {
var privateKey = e.target.result;
var encryptor = new JSEncrypt();
encryptor.setPrivateKey(privateKey);
var encryptedText = encryptor.encrypt(plainText);
const params = new URLSearchParams();
params.append('token', encryptedText);
fetch(form.action, {
method: form.method,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: params
})
.then(response => {
var main = document.querySelector("main");
var p = document.createElement("h1");
p.textContent = response.text();
main.appendChild(p);
//window.location.href = "http://localhost/inbox/home";
})
.catch(error => {
var main = document.querySelector("main");
var p = document.createElement("h1");
p.textContent = error.text();
main.appendChild(p);
});
};
reader.readAsText(file);
});
fileInput.click();
}
this is the java code that is trying to do the decryption:
public class RSADecryptor {
public static String decrypt(byte[] cipherText, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance(RSAKeyGenerator.RSA_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, publicKey);
int keySize = ((RSAKey) publicKey).getModulus().bitLength();
int blockSize = keySize / 8;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
int offset = 0;
while(offset < cipherText.length) {
int length = Math.min(cipherText.length - offset, blockSize);
byte[] block = cipher.doFinal(cipherText, offset, length);
outputStream.write(block, 0, block.length);
offset += blockSize;
}
byte[] decryptedBytes = outputStream.toByteArray();
//byte[] decryptedBytes = cipher.doFinal(cipherext);
return new String(decryptedBytes);
}
}
Anyone can point out what I am doing wrong here?
Both libraries have dedicated functions for signing and verification. For JSEncrypt, see the documentation, sec. How to use this library, 2nd code snippet, for Java, see the Signature
class.
In the case of JSEncrypt, a possible implementation for signing is (using RSASSA-PKCS1-v1_5 as signature algorithm and SHA256 as digest):
var privPkcs8Pem = `-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCYiWw16W1eGdG2
INU24v4EBjir6dYRQ4rhacVhiqOGXvnvC3M7XYMnT1+rTVTJpPrl/KY7OnskOYJj
BQOdV61hh7/uacvfG27xKuBmm5YZOcIcWHWzuMijF9MynmnzeEBVGbUlm5NyMaS4
xNVNnv/c3jagWHXDnygzQgvW6K7HmZ6+ZWCxKa+dpcVtnrG7dApdDbMkMaj+zJvL
1fWDrQYDPWrt3bdewXBHA6LjwyrQfuOvVxlxSuvvo1E/Xi0aW5taZQQi86ltz331
uLGp7pZnhIQPldDhoXSX4TI5rv12LEs9KPKLDiG1e4QkjeDCJAG4uHxEvcGA7LXz
GSAs2y/DAgMBAAECggEAFhYBGjXqv9nK221El0u6+OKHuR3vVhTqr88MpR4ZpZ6X
NLf6iX7K5dm1zKFdT0xj3FdpIEv27DH8LDyGdJ/vJZ8uDftj6VwuWPKwMYXXRV7E
uYL2GT1+UN27FuoIsEKEmhh8pJiH+wcExpC6y8rjrttpRcKZMT0YaSznzEho6ihy
6HtHMkXOI6KO/aZDRbI9n6Sdkul4qWmBAHj1CcKAFAHOaxVzYHpMaIPcZ+Mr++Bw
+m0qyMOlYvXFnUvpgwgL5KQ5id6wLT6WrBOybaHfmtAsVV7/baAxh7urdEHv+zCc
YJHhM/PnFOTzTfkUMDt1pWJyMAZCAygZWesaHtzsiQKBgQDS2RRivF7TekB/Tl+C
nFWF4SR9YNeIKXMywFiyQDD2lPnMwagWjcbCqp9ZjYhv3siAHhsTCbnkSsnQcq40
CxqUxeDmX6PZCTVgWw0Uj6IZmPUVDj9twVWYyv5FF33C5Qwwwdu7DSZaA8Jl+JKv
InMsI6vNdCN6Of94F3pnBu1NawKBgQC5M6kMX+negUUJQPeWEjt4TCvUxqWMUmkx
4ly8XyCOCM6Wt1kmhHN1NYs4+O60cO8x/6JSBq94eiS5otpDBGTL1tRjq3Kvvytg
jOpAlNIhfEBiPABfcwV/+k2fz8uGFZFMIUliDMLAa4wxo3rBbmuSPEsioyQ3dOmV
/GnHELklCQKBgHFOzUC+QCtfsFd5s6QKBX+73RMvvsPimpC0gzXPf0CUEKXzkDQG
nsCwVpAWmjKcQ51uEFirymUft9K4Plujd/ZpXJIQ5YlWBIQyihX5lkAxTcux6249
DpXcyMYyeJgK5QEyvLWJvIl1KbwI2DMbzU70IHh5qDMgBeTwoQvK0i3fAoGBAKQX
nLmlJd8KpHNth7EFGIIe41sUYsvwnNohGU+h7YNLVFf/vdK92lrIhUGGdmGUCqs/
N7/7wm85sd5053QnqXNeNjLVTrle5X0XfdqYwZH/uEARr7bif8YDrdFiWI7F/0X3
3EAu1EOPRtkYYwSN5GveVigrakRkpy5IRiSlsZWZAoGAM3y4tYRbOVCmp4Z419gQ
/9HlEgRjBaGnDQRcDEFqcLtIm1C6mygdjP+wCkDNwVoszSbsgdRMuoZ2ReD6gFRv
bBZM7lHICA5tPaARgGgeKomUZnozTxgVH7FMxax+BJPrI/dpXcX0fCNinAJo48l0
GOHy1iLgxKUEEli3j6hchjU=
-----END PRIVATE KEY-----`
var sign = new JSEncrypt()
// key import
sign.setPrivateKey(privPkcs8Pem)
// signing
var message = 'The quick brown fox jumps over the lazy dog'
var signature = sign.sign(message, CryptoJS.SHA256, 'sha256')
console.log(signature) // E888/KGgC0Zgw8/1Ojd5wxMI/0KmuzhP+YYoBawSb7w6EGRvPf0SXSYfZeiiiEDMFKchb9k6lH4M/Foi++y2Lvuaqd8ZA+/fv1uiAhzwAzBsNolPWIxN3K1yO9kc+d0YZCDaEz7abasDOubppd6cNnyIgZnEwd3JjSoqs+zWayKxYGb1CqbhXVNKWoRgwkPqzs1pw0kcZsAuTBa0uZ/hAYIdaQh7X7n/ZjNXCddZ2iHQJExtPNquay80pfL1HVA0FlX1QM1smw3OP/hj7DSYswhayr98pKIPZeLtrbzOBrpLfk/nF/YBIEj+1KQH5ZD9wjK7q4ulaF6uy03rAZ5eaQ==
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsencrypt/3.3.2/jsencrypt.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
A possible Java counterpart for verification is:
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
...
String pubX509Pem = """
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmIlsNeltXhnRtiDVNuL+
BAY4q+nWEUOK4WnFYYqjhl757wtzO12DJ09fq01UyaT65fymOzp7JDmCYwUDnVet
YYe/7mnL3xtu8SrgZpuWGTnCHFh1s7jIoxfTMp5p83hAVRm1JZuTcjGkuMTVTZ7/
3N42oFh1w58oM0IL1uiux5mevmVgsSmvnaXFbZ6xu3QKXQ2zJDGo/syby9X1g60G
Az1q7d23XsFwRwOi48Mq0H7jr1cZcUrr76NRP14tGlubWmUEIvOpbc999bixqe6W
Z4SED5XQ4aF0l+EyOa79dixLPSjyiw4htXuEJI3gwiQBuLh8RL3BgOy18xkgLNsv
wwIDAQAB
-----END PUBLIC KEY-----""";
// key import
String pubX509DerB64 = pubX509Pem.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "").replace("\n", "");
byte[] pubX509Der = Base64.getDecoder().decode(pubX509DerB64);
KeyFactory kf = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pubX509Der);
PublicKey pubKey = (RSAPublicKey) kf.generatePublic(keySpec);
// verification
byte[] message = "The quick brown fox jumps over the lazy dog".getBytes(StandardCharsets.UTF_8);
byte[] signature = Base64.getDecoder().decode("E888/KGgC0Zgw8/1Ojd5wxMI/0KmuzhP+YYoBawSb7w6EGRvPf0SXSYfZeiiiEDMFKchb9k6lH4M/Foi++y2Lvuaqd8ZA+/fv1uiAhzwAzBsNolPWIxN3K1yO9kc+d0YZCDaEz7abasDOubppd6cNnyIgZnEwd3JjSoqs+zWayKxYGb1CqbhXVNKWoRgwkPqzs1pw0kcZsAuTBa0uZ/hAYIdaQh7X7n/ZjNXCddZ2iHQJExtPNquay80pfL1HVA0FlX1QM1smw3OP/hj7DSYswhayr98pKIPZeLtrbzOBrpLfk/nF/YBIEj+1KQH5ZD9wjK7q4ulaF6uy03rAZ5eaQ==");
Signature verifier = Signature.getInstance("SHA256withRSA");
verifier.initVerify(pubKey);
verifier.update(message);
boolean result = verifier.verify(signature);
System.out.println(result); // true