在 PHP 中模拟 WebCrypto RSA-OAEP 加密
simulate WebCrypto RSA-OAEP encryption in PHP
我们有一个服务器正在使用 RSA-OAEP 从客户端接收数据。
我无法访问服务器,检查结果的唯一方法是发送请求并检查其回复。
我已经能够使用 WebCrypto 发送正确的请求,但我没有成功使用 php。
我为 JS 使用的代码:
var DataToEncrypt = 'abcd';
var pemEncodedKey = `-----BEGIN PUBLIC KEY-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END PUBLIC KEY-----`;
let encryptionKey;
function str2ab(str) {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function importPublicKey(pem) {
const pemHeader = "-----BEGIN PUBLIC KEY-----";
const pemFooter = "-----END PUBLIC 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(
"spki",
binaryDer,
{
name: "RSA-OAEP",
hash: "SHA-256"
},
true,
["encrypt"]
);
}
function getMessageEncoding() {
const enc = new TextEncoder();
return enc.encode(DataToEncrypt);
}
async function encryptMessage() {
const encoded = getMessageEncoding();
const ciphertext = await window.crypto.subtle.encrypt(
{
name: "RSA-OAEP"
},
encryptionKey,
encoded
);
var decoder = new TextDecoder('utf8');
var b64encoded = btoa(String.fromCharCode.apply(null, new Uint8Array(ciphertext)));
document.getElementById('crypt').value = b64encoded;
}
document.getElementById('import').addEventListener("click", async () => {
encryptionKey = await importPublicKey(pemEncodedKey);
});
document.getElementById('encrypt').addEventListener("click", function(){
encryptMessage();
});
这是我的 php 函数(使用 phpseclib):
function encrypt($data) {
$key = '-----BEGIN PUBLIC KEY-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END PUBLIC KEY-----';
$rsa = new Crypt_RSA();
$rsa->setHash('sha256');
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_OAEP);
$rsa->loadKey($key); // public key
$crypted = $rsa->encrypt($data);
return base64_encode($crypted);
}
echo encrypt('abcd');
我尝试了这两种方法结果向服务器发送请求,正如我之前提到的,只有 js 代码有效,php 输出没有按预期工作。
我尝试用我生成的一对 public/private 密钥用 js 加密一些东西并用 php (phpseclib) 解密它并且成功了。
之后,我尝试将我的 public 键重新格式化为每行 64 个字符(它像 js 中的那样在一行中)并同时使用 setHash('sha256') 和 setMGFHash ('sha256') 现在我的 php 功能正常了。
新 php 功能:
function encrypt($data)
{
$key = '-----BEGIN PUBLIC KEY-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXX
-----END PUBLIC KEY-----';
$rsa = new Crypt_RSA();
$rsa->setHash('sha256');
$rsa->setMGFHash('sha256');
$lk = $rsa->loadKey($key); // public key
$crypted = $rsa->encrypt($data);
return base64_encode($crypted);
}
我们有一个服务器正在使用 RSA-OAEP 从客户端接收数据。
我无法访问服务器,检查结果的唯一方法是发送请求并检查其回复。
我已经能够使用 WebCrypto 发送正确的请求,但我没有成功使用 php。
我为 JS 使用的代码:
var DataToEncrypt = 'abcd';
var pemEncodedKey = `-----BEGIN PUBLIC KEY-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END PUBLIC KEY-----`;
let encryptionKey;
function str2ab(str) {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function importPublicKey(pem) {
const pemHeader = "-----BEGIN PUBLIC KEY-----";
const pemFooter = "-----END PUBLIC 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(
"spki",
binaryDer,
{
name: "RSA-OAEP",
hash: "SHA-256"
},
true,
["encrypt"]
);
}
function getMessageEncoding() {
const enc = new TextEncoder();
return enc.encode(DataToEncrypt);
}
async function encryptMessage() {
const encoded = getMessageEncoding();
const ciphertext = await window.crypto.subtle.encrypt(
{
name: "RSA-OAEP"
},
encryptionKey,
encoded
);
var decoder = new TextDecoder('utf8');
var b64encoded = btoa(String.fromCharCode.apply(null, new Uint8Array(ciphertext)));
document.getElementById('crypt').value = b64encoded;
}
document.getElementById('import').addEventListener("click", async () => {
encryptionKey = await importPublicKey(pemEncodedKey);
});
document.getElementById('encrypt').addEventListener("click", function(){
encryptMessage();
});
这是我的 php 函数(使用 phpseclib):
function encrypt($data) {
$key = '-----BEGIN PUBLIC KEY-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END PUBLIC KEY-----';
$rsa = new Crypt_RSA();
$rsa->setHash('sha256');
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_OAEP);
$rsa->loadKey($key); // public key
$crypted = $rsa->encrypt($data);
return base64_encode($crypted);
}
echo encrypt('abcd');
我尝试了这两种方法结果向服务器发送请求,正如我之前提到的,只有 js 代码有效,php 输出没有按预期工作。
我尝试用我生成的一对 public/private 密钥用 js 加密一些东西并用 php (phpseclib) 解密它并且成功了。
之后,我尝试将我的 public 键重新格式化为每行 64 个字符(它像 js 中的那样在一行中)并同时使用 setHash('sha256') 和 setMGFHash ('sha256') 现在我的 php 功能正常了。
新 php 功能:
function encrypt($data)
{
$key = '-----BEGIN PUBLIC KEY-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXX
-----END PUBLIC KEY-----';
$rsa = new Crypt_RSA();
$rsa->setHash('sha256');
$rsa->setMGFHash('sha256');
$lk = $rsa->loadKey($key); // public key
$crypted = $rsa->encrypt($data);
return base64_encode($crypted);
}