RSA加密,在PHP中加密(phpseclib)和在JavaScript中解密(crypto.contive)



我要做的是在javascript中生成一个密钥对,并在PHP中使用这些密钥对进行加密,然后用JS解密。

我在附加的代码中有两个问题

  1. 它不会从装甲文本块重新加载私钥
  2. 而且它不会解密PHP加密的内容

两者都抛出错误DOMException,而不是有用的错误。

这是我的密码。。。

PHP/JAVASCRIPT

<?php
use phpseclib3CryptPublicKeyLoader;
use phpseclib3CryptRSA;
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()函数中,该函数使用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代码执行加密,并且在上面的代码中应用私钥进行解密。

最新更新