php / php/php-src

Help, I use crypto asymmetric encryption symmetric key, passed to PHP there is an error!

未关闭
#15,517 4 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 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

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 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

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。