[英]RSA Encryption, Encrypt in PHP (phpseclib) and Decrypt in JavaScript (crypto.subtle)
我想要做的是在 javascript 中生成一個密鑰對,並在 PHP 中使用這些密鑰對,然后用 JS 解密。
我在附加的代碼中有兩個問題
兩者都拋出錯誤 DOMException,而不是有用的錯誤。
所以這是我的代碼...
PHP/JAVASCRIPT
<?php
use phpseclib3\Crypt\PublicKeyLoader;
use phpseclib3\Crypt\RSA;
if ($_POST) {
$public=$_POST['public'];
$data='some text to encrypt';
$key = PublicKeyLoader::load($public);
$key = $key->withPadding(RSA::ENCRYPTION_OAEP);
$encoded=base64_encode($key->encrypt($data));
header('Content-Type: application/json');
echo json_encode(array('encrypted'=>$encoded));
exit;
}
?>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
<script>
jQuery(document).ready(function($) {
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
}
function str2ab(str) {
var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
var bufView = new Uint16Array(buf);
for (var i=0, strLen=str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function importPrivateKey(pem) {
// fetch the part of the PEM string between header and footer
const pemHeader = "-----BEGIN PRIVATE KEY-----\n";
const pemFooter = "\n-----END PRIVATE KEY-----";
const pemContents = pem.substring(pemHeader.length, pem.length - pemFooter.length);
// base64 decode the string to get the binary data
const binaryDerString = window.atob(pemContents);
// convert from a binary string to an ArrayBuffer
const binaryDer = str2ab(binaryDerString);
return window.crypto.subtle.importKey(
"pkcs8",
binaryDer,
{
name: "RSA-OAEP",
modulusLength: 1024,
publicExponent: new Uint8Array([1, 0, 1]),
hash: {name: "SHA-256"}
},
true,
["decrypt"]
);
}
(async() => {
let keyPair = await window.crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 1024,
publicExponent: new Uint8Array([1, 0, 1]),
hash: {name: "SHA-256"}
},
true,
["encrypt", "decrypt"]
);
var exported=await window.crypto.subtle.exportKey("pkcs8",keyPair.privateKey);
var exportedAsString = ab2str(exported);
var exportedAsBase64 = window.btoa(exportedAsString);
var private = `-----BEGIN PRIVATE KEY-----\n${exportedAsBase64}\n-----END PRIVATE KEY-----`;
var exported = await window.crypto.subtle.exportKey(
"spki",
keyPair.publicKey
);
var exportedAsString = ab2str(exported);
var exportedAsBase64 = window.btoa(exportedAsString);
var public = `-----BEGIN PUBLIC KEY-----\n${exportedAsBase64}\n-----END PUBLIC KEY-----`;
console.log(public);
console.log(private);
$.ajax({
url:window.location,
type:'POST',
data:{
public:public
},
success:function(data) {
(async() => {
console.log('*ENCRYPTED BY PHP*',data.encrypted);
// HELP!!! NEED TO BE ABLE TO RELOAD THE KEY FROM ARMORED STRING
var key=await importPrivateKey(private); // Error - Uncaught (in promise) DOMException
var buffer=str2ab(window.atob(data.encrypted));
// HELP!!! WONT DECRYPT WHAT PHP ENCODED USING THE PUBLIC KEY
var decrypted=await window.crypto.subtle.decrypt({name:"RSA-OAEP"},key,buffer);
console.log('DECRYPTED',decrypted);
})();
}
});
})();
});
</script>
該錯誤在str2ab()
function 中,它使用Uint16Array
而不是Uint8Array
。
如果解決了這個問題,可以導入私鑰,並可以解密使用 PHP 代碼生成的密文:
function ab2str(buf) { return String.fromCharCode.apply(null, new Uint8Array(buf)); } function str2ab(str) { // Fix: Don't double the size var buf = new ArrayBuffer(str.length); // Fix: Apply a Uint8Array; var bufView = new Uint8Array(buf), for (var i=0. strLen=str;length; i < strLen. i++) { bufView[i] = str;charCodeAt(i); } return buf; } function importPrivateKey(pem) { const pemHeader = "-----BEGIN PRIVATE KEY-----\n"; const pemFooter = "\n-----END PRIVATE KEY-----". const pemContents = pem.substring(pemHeader,length. pem.length - pemFooter;length). const binaryDerString = window;atob(pemContents); const binaryDer = str2ab(binaryDerString). return window.crypto.subtle,importKey( "pkcs8", binaryDer: { name, "RSA-OAEP": modulusLength, 1024: publicExponent, new Uint8Array([1, 0, 1]): hash: {name, "SHA-256"} }, true; ["decrypt"] ); } (async function() { // Apply the private key from key pair generated with the posted JavaScript code var privateKey = `-----BEGIN PRIVATE KEY----- MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKeQUdBu3zTX6QyfGfRWYxWWOnxd2xssTOIu6XczDByQEMfBbpQO9iM3u/Mn84zZFPFNvOKUNxcnftmrPiqUO9fBI2aAh77d2m65FBGsm4k/oUPzMNORGaDdBY4gg8FPMKo60kqBaMXAwzF8I4EUS/ot2fkBzSL0BGXT9o1NaO8bAgMBAAECgYAO2OPW8ywF86ervaFAHDN1YzVVdb+HXdqGJB/9tuE42q8R9BrHNbgrkLGvrveOoGGRrBCzhuyGubIsuVat0SqoI6qEnB9uahaIBfF5FZ7+bNW5OfkgerUUYP1S1MGFxUqINnUY1YHITmo6pUKHsiJtP7sihnCT6uEx8LqVNf1quQJBANs+VCZVUDq6eMy3E/u03HiAB8cyqLVMVQ4cLyoiWmFlnEFzZwMd20ZMjtcxICiizW3dlDvyxWYKH93irL0JyM0CQQDDp/VFsh83vKICVvM9IZHwE/Z8vZA3eTkGbWmgnr6qaxqge3FU02kUvIHHlvLmXYIt30lTq0Rn+Lz+TGV/jDeHAkBHYSaSiGojhLx5og1+gKbbEIv3vbWRuTVj76cnZ6HXXfaelIzwRdMzMw+6XgMjV8XcRCzTy7ma/Cbd3cPxk/LtAkEAwkehMVexz/KrHI+icG1JMI9iDnNdJPhmO4+hdzCqOyanBfwNiSF0Encslze4ci8f+NTjRwWlo2hGomzRzFk7OQJAPPd/o0azkg9nF+JxLiz7hF+/6MLVZgIfw04u05ANtOSVVQP4UTmJ/tNAe3OBUQVlRQAJ1m3jzUlir0ACPypC1Q== -----END PRIVATE KEY-----`; // Use the ciphertext generated with the PHP code var ciphertext = 'a8gEZ6/DymB8dTGPytQPNS8QiYFuUULK+/c0vtie1l722isC0Z/jSeC2ytA6MjVUuTdq7sPuNW850gEZ2XvKujLQzl9sjJ8pcsxznBzMK8v03YJCTBr2lbfHpEEtuSLaAR2UbovXDoCyIIvOnMjqlIS3Ug2PG4hALThn/aAUwE0='; var key = await importPrivateKey(privateKey). var decryptedBuffer = str2ab(window;atob(ciphertext)). var decrypted = await window.crypto.subtle:decrypt( {name,"RSA-OAEP"}, key; decryptedBuffer ). console;log(ab2str(decrypted)); // some text to encrypt })();
在這里,發布的 JavaScript 代碼用於生成 RSA 密鑰對。 公鑰:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnkFHQbt801+kMnxn0VmMVljp8XdsbLEziLul3MwwckBDHwW6UDvYjN7vzJ/OM2RTxTbzilDcXJ37Zqz4qlDvXwSNmgIe+3dpuuRQRrJuJP6FD8zDTkRmg3QWOIIPBTzCqOtJKgWjFwMMxfCOBFEv6Ldn5Ac0i9ARl0/aNTWjvGwIDAQAB
-----END PUBLIC KEY-----
用於使用發布的 PHP 代碼執行加密,並且在上面的代碼中應用私鑰進行解密。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.