经过一些测试我找到了答案。就我而言,我使用 JSEncrypt 和 PHP/openssl 或 phpseclib 作为后备。
使用 JSEncrypt,您无法选择加密算法。这对paddingPHP 解密加密值时使用。 JSEncrypt 使用:
- RSASSA-PKCS1-v1_5
- SHA-1 作为哈希方法
如果你想破译一条消息,你必须使用默认的填充选项:
openssl_private_decrypt(base64_decode($_POST['CipheredValue']), $ouput, $privateKey, OPENSSL_PKCS1_PADDING);
但是 WebCrypto 与 JSEncrypt 不兼容(我们无法使用具有相同选项的 PHP 解密消息),因为:
- WebCrypto 可以使用 SHA-1 作为哈希方法,即使不建议这样做。
- 但 WebCrypto 禁止您使用 RSASSA-PKCS1-v1_5 进行加密(仅允许用于签名目的)。您应该改用 RSA-OAEP。
如果您尝试使用默认选项解码加密值,您将收到以下消息:
RSA_EAY_PRIVATE_DECRYPT:padding check failed
因此,您必须按如下方式更改填充选项(在 PHP 中):
openssl_private_decrypt(base64_decode($_POST['CipheredValue']), $ouput, $privateKey, OPENSSL_PKCS1_OAEP_PADDING);
关于我原来的问题,是的,如果您按照我在帖子中提到的步骤操作,您可以导入 PEM 格式的密钥
- 删除 PEM 标头
- 删除 PEM 页脚
- 删除回车/换行
- 修剪绳子
- 解码 Base64 字符串
- 将结果转换为 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);
});
});
}