Ho trovato una risposta dopo alcuni test. Nel mio caso, ho usato JSEncrypt con PHP/openssl o phpseclib come fallback.
Con JSEncrypt, non è possibile scegliere l'algoritmo di crittografia. E questo ha un impatto sul riempimento utilizzato quando PHP decifra il valore crittografato. JSEncrypt usa:
- RSASSA-PKCS1-v1_5
- SHA-1 come metodo di hash
Se si vuole decifrare un messaggio, è necessario utilizzare l'opzione padding di default:
openssl_private_decrypt(base64_decode($_POST['CipheredValue']), $ouput, $privateKey, OPENSSL_PKCS1_PADDING);
Ma WebCrypto non è compatibile con JSEncrypt (non siamo in grado di decifrare il messaggio con PHP con le stesse opzioni), in quanto:
- WebCrypto può utilizzare SHA-1 come metodo hash, anche se non è raccomandato.
- Ma WebCrypto vieta di utilizzare RSASSA-PKCS1-v1_5 a scopo di crittografia (è consentito solo per scopi di firma). Dovresti invece usare RSA-OAEP.
Se si tenta di decodificare il valore cifrato con le opzioni di default, si otterrà questo messaggio:
RSA_EAY_PRIVATE_DECRYPT:padding check failed
Quindi, è necessario modificare l'opzione imbottitura come segue (in PHP):
openssl_private_decrypt(base64_decode($_POST['CipheredValue']), $ouput, $privateKey, OPENSSL_PKCS1_OAEP_PADDING);
per quanto riguarda la mia domanda iniziale, sì, si può importare una chiave in formato PEM, se si seguono i passi che ho menzionate nelle post
- rimuovere l'intestazione PEM
- Rimuovere thePEM footer
- Rimuovere CR/LF
- stringa Trim
- Decodifica la stringa Base64
- convertire il risultato di un codice completo ArrayBuffer
:
var crypto = window.crypto || window.msCrypto;
var encryptAlgorithm = {
name: "RSA-OAEP",
hash: {
name: "SHA-1"
}
};
function arrayBufferToBase64String(arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer)
var byteString = '';
for (var i=0; i<byteArray.byteLength; i++) {
byteString += String.fromCharCode(byteArray[i]);
}
return btoa(byteString);
}
function base64StringToArrayBuffer(b64str) {
var byteStr = atob(b64str);
var bytes = new Uint8Array(byteStr.length);
for (var i = 0; i < byteStr.length; i++) {
bytes[i] = byteStr.charCodeAt(i);
}
return bytes.buffer;
}
function textToArrayBuffer(str) {
var buf = unescape(encodeURIComponent(str)); // 2 bytes for each char
var bufView = new Uint8Array(buf.length);
for (var i=0; i < buf.length; i++) {
bufView[i] = buf.charCodeAt(i);
}
return bufView;
}
function convertPemToBinary(pem) {
var lines = pem.split('\n');
var encoded = '';
for(var i = 0;i < lines.length;i++){
if (lines[i].trim().length > 0 &&
lines[i].indexOf('-BEGIN RSA PRIVATE KEY-') < 0 &&
lines[i].indexOf('-BEGIN RSA PUBLIC KEY-') < 0 &&
lines[i].indexOf('-BEGIN PUBLIC KEY-') < 0 &&
lines[i].indexOf('-END PUBLIC KEY-') < 0 &&
lines[i].indexOf('-END RSA PRIVATE KEY-') < 0 &&
lines[i].indexOf('-END RSA PUBLIC KEY-') < 0) {
encoded += lines[i].trim();
}
}
return base64StringToArrayBuffer(encoded);
}
function importPublicKey(pemKey) {
return new Promise(function(resolve) {
var importer = crypto.subtle.importKey("spki", convertPemToBinary(pemKey), encryptAlgorithm, false, ["encrypt"]);
importer.then(function(key) {
resolve(key);
});
});
}
if (crypto.subtle) {
start = new Date().getTime();
importPublicKey($('#pubkey').val()).then(function(key) {
crypto.subtle.encrypt(encryptAlgorithm, key, textToArrayBuffer($('#txtClear').val())).then(function(cipheredData) {
cipheredValue = arrayBufferToBase64String(cipheredData);
console.log(cipheredValue);
});
});
}
Non dovresti Base64-decodificare il Prima i dati PEM? – robertklep
Se decodifico i dati e poi li converto in un ArrayBuffer ottengo una DOMException –