Help, I use crypto asymmetric encryption symmetric key, passed to PHP there is an error!
未关闭
还没有人认领这个 Issue。
Bug
Extension: openssl
Status: Needs Triage
- 主要语言
- C
- 星标
- 40.4k
- 派生
- 8.2k
- 平均合并
- 2 天 13 小时
- 30 天内合并 PR
- 96
描述
Description
It has been confirmed that:
- PHP 8.1.29
- The private key matches the public key
- Data transfer is complete
- Base64 encoding used for transmission
js:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>test</title>
</head>
<form id="login_form" method="post" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF'], ENT_QUOTES); ?>">
<body>
<div class="container">
<input type="text" name="ad_name" id="ad_name" maxlength="20" size="20" required autofocus><br>
<input type="password" name="ad_pass" id="pass" maxlength="20" size="20" autocomplete="off" required><br>
<input type="hidden" id="encryptedData" name="encryptedData">
<input type="submit" id="submit" value="submit">
</div>
</body>
</form>
<script>
// 数据处理
async function sendEncryptedMessage(data) {
try {
const key = await generateKey();
const rawKey = await exportKey(key);
console.log('密钥:', key);
console.log('原始密钥:', rawKey);
// 公钥接收
const publicKeyBase64 = "<?php echo $publickey_base64; ?>";
const publicKeyPem = atob(publicKeyBase64);
// 公钥加密
const publicKeyArrayBuffer = pemToArrayBuffer(publicKeyPem);
const encrypted = await asymmetricEncrypt(rawKey, publicKeyArrayBuffer);
return {encrypted: encrypted};
} catch (error) {
console.error('数据处理失败:', error);
}
}
// 表单提交
document.getElementById('login_form').addEventListener('submit', async function(event) {
event.preventDefault(); // 阻止明文提交
const formData = new FormData(this);
const data = {};
formData.forEach((value, key) => {
data[key] = value;
});
const encryptedData = await sendEncryptedMessage(JSON.stringify(data));
document.getElementById('encryptedData').value = JSON.stringify(encryptedData);
HTMLFormElement.prototype.submit.call(this); // 确保正确调用表单的 submit 方法
});
// 生成AES-GCM对称密钥。
async function generateKey() {
try {
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
return key;
} catch (error) {
console.error('密钥生成失败:', error);
}
}
// 导出密钥为原始格式
async function exportKey(key) {
try {
const exportedKey = await crypto.subtle.exportKey('raw', key);
return new Uint8Array(exportedKey);
} catch (error) {
console.error('密钥导出失败:', error);
}
}
// 将PEM格式的公钥转换为ArrayBuffer
function pemToArrayBuffer(pem) {
const b64Lines = pem.replace(/-----[^-]+-----/g, "").replace(/\s+/g, "");
const b64 = atob(b64Lines);
const buffer = new ArrayBuffer(b64.length);
const view = new Uint8Array(buffer);
for (let i = 0; i < b64.length; i++) {
view[i] = b64.charCodeAt(i);
}
return buffer;
}
// ArrayBuffer转换为Base64
function arrayBufferToBase64(buffer) {
let binary = '';
const bytes = new Uint8Array(buffer);
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
// 公钥加密
async function asymmetricEncrypt(data, publicKey) {
try {
const keyObject = await crypto.subtle.importKey(
'spki',
publicKey,
{ name: 'RSA-OAEP', hash: 'SHA-256' },
false,
['encrypt']
);
const encrypted = await crypto.subtle.encrypt({ name: 'RSA-OAEP' }, keyObject, new TextEncoder().encode(data));
const base64String = arrayBufferToBase64(encrypted);
return base64String;
} catch (error) {
console.error('公钥加密失败:', error);
}
}
</script>
</html>
PHP:
<?php
session_start();
// 如果会话中没有RSA密钥对,则生成新的密钥对
if (!isset($_SESSION['private_key']) || !isset($_SESSION['public_key'])) {
// 生成 RSA 密钥对
$config = array(
'digest_alg' => 'sha256',
'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
);
$res = openssl_pkey_new($config);
// 获取私钥和公钥
openssl_pkey_export($res, $privateKey);
$publicKey = openssl_pkey_get_details($res)['key'];
// 将密钥对存储在会话中
$_SESSION['private_key'] = $privateKey;
$_SESSION['public_key'] = $publicKey;
}
// 从会话中获取私钥和公钥
$privateKey = $_SESSION['private_key'];
$publicKey = $_SESSION['public_key'];
$publickey_base64 = base64_encode($publicKey); // base64编码传送
// 私钥解密
function decryptWithPrivateKey($encryptedKeyBase64, $privateKeyPem) {
$encryptedKey = base64_decode($encryptedKeyBase64);
// 将PEM格式的私钥转换为OpenSSL可用的格式
$privateKey = openssl_pkey_get_private($privateKeyPem);
echo 'Base64解码后的加密密钥: ' . bin2hex($encryptedKey) . PHP_EOL;
if (!$privateKey) {
throw new Exception('加载私钥失败');
} else {
echo '私钥加载成功' . PHP_EOL;
}
// 使用私钥解密AES-GCM密钥
$decryptedKey = '';
$result = openssl_private_decrypt($encryptedKey, $decryptedKey, $privateKey, OPENSSL_PKCS1_OAEP_PADDING); // OPENSSL_PKCS1_OAEP_PADDING OPENSSL_NO_PADDING
if (!$result) {
throw new Exception('解密失败: ' . openssl_error_string());
}
// 打印解密后的AES-GCM密钥
echo "解密后的AES-GCM密钥: " . bin2hex($decryptedKey);
return $decryptedKey;
}
// 消息接收
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$hashedPassword = json_decode($_POST['encryptedData'], true);
echo 'cryptoBase64:' . PHP_EOL . bin2hex(base64_decode($hashedPassword['encrypted'])) . PHP_EOL;
// 私钥解密
$decryptedKey = decryptWithPrivateKey($hashedPassword['encrypted'], $privateKey);
};
?>
error:
Fatal error: Uncaught Exception: 解密失败: error:0200009F:rsa routines::pkcs decoding error in /home/runner/GigaLowestTransversal/index.php:44 Stack trace: #0 /home/runner/GigaLowestTransversal/index.php(57): decryptWithPrivateKey('MibsVVKMmL1uN9w...', '-----BEGIN PRIV...') #1 {main} thrown in /home/runner/GigaLowestTransversal/index.php on line 44
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
使用 PHP 8.1.29 在 index.php 中重现所提供的 HTML/JavaScript 和 PHP,然后结合报告的错误检查 RSA-OAEP 加密和 openssl_private_decrypt 路径。完成的要求是确认存在 PHP 特有的缺陷,并提供一个最小的 php-src 测试,但当前 issue 没有指定任何 php-src 文件或测试。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- javascript, php
- 领域
- backend, security
- Issue 类型
- 缺陷
- 难度
- 5/5
- 预计耗时
- 一周以上
- 活跃度
- 停滞
- 描述清晰度
- 需要澄清
- 新手友好度
- 15/100