php / php/php-src

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

Ouverte
#15,517 4 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Bug Extension: openssl Status: Needs Triage
Langage dominant
C
Étoiles
40.4k
Forks
8.1k
Merge moyen
2 j 13 h
PR mergées (30 j)
96

Description

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

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Reproduisez le HTML/JavaScript et le PHP fournis dans index.php avec PHP 8.1.29, puis examinez le chiffrement RSA-OAEP et le chemin openssl_private_decrypt en parallèle de l’erreur signalée. Le travail serait considéré comme terminé avec un défaut spécifique à PHP confirmé et un test minimal de php-src, mais l’issue ne mentionne actuellement aucun fichier php-src ni aucun test.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
javascript, php
Domaine
backend, security
Type d'issue
Bug
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
À l'abandon
Clarté
À clarifier
Accessibilité débutants
15/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.