Skip to content

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

Open
@DUQIA

Description

@DUQIA

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions