我的 PHP 代码解密过程中遇到问题

问题描述 投票:0回答:1

我是 PHP 新手,正在编写 PHP 和 MYSQL 代码,该代码将加密的患者数据存储在 mysql 数据库中,然后在需要时检索它并将其显示给用户。 现在我有 2 个文件,第一个是我加密数据的地方

<?php

require_once "config.php";
require_once "session.php";

try {
    if ($_SERVER["REQUEST_METHOD"] == "POST") {
        if (isset($_SESSION["userid"])) {
            $Patient_Number = $_SESSION["userid"];
            $Date = $_POST["date"];
            
            $encryptionKey = 'random_64_character_hexadecimal_key'; 

            $Systolic_BP = bin2hex(openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-cbc"))) . ':' . bin2hex(openssl_encrypt($_POST["sys"], "aes-256-cbc", hex2bin($encryptionKey), 0, $iv, $tag));
            $Diastolic_BP = bin2hex(openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-cbc"))) . ':' . bin2hex(openssl_encrypt($_POST["dia"], "aes-256-cbc", hex2bin($encryptionKey), 0, $iv, $tag));
            $Respiratory_Rate = bin2hex(openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-cbc"))) . ':' . bin2hex(openssl_encrypt($_POST["rr"], "aes-256-cbc", hex2bin($encryptionKey), 0, $iv, $tag));
            $Capillary_Refill = bin2hex(openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-cbc"))) . ':' . bin2hex(openssl_encrypt($_POST["cr"], "aes-256-cbc", hex2bin($encryptionKey), 0, $iv, $tag));
            $Body_Temp = bin2hex(openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-cbc"))) . ':' . bin2hex(openssl_encrypt($_POST["temp"], "aes-256-cbc", hex2bin($encryptionKey), 0, $iv, $tag));
            $Weight = bin2hex(openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-cbc"))) . ':' . bin2hex(openssl_encrypt($_POST["weight"], "aes-256-cbc", hex2bin($encryptionKey), 0, $iv, $tag));
            $Pulse_Rate = bin2hex(openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-cbc"))) . ':' . bin2hex(openssl_encrypt($_POST["pulse"], "aes-256-cbc", hex2bin($encryptionKey), 0, $iv, $tag));
            $Doctor_Name = bin2hex(openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-cbc"))) . ':' . bin2hex(openssl_encrypt($_POST["dn"], "aes-256-cbc", hex2bin($encryptionKey), 0, $iv, $tag));
            $Symptoms = bin2hex(openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-cbc"))) . ':' . bin2hex(openssl_encrypt($_POST["symptoms"], "aes-256-cbc", hex2bin($encryptionKey), 0, $iv, $tag));
            $Diagnosis = bin2hex(openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-cbc"))) . ':' . bin2hex(openssl_encrypt($_POST["diagnosis"], "aes-256-cbc", hex2bin($encryptionKey), 0, $iv, $tag));
            $Medication = bin2hex(openssl_random_pseudo_bytes(openssl_cipher_iv_length("aes-256-cbc"))) . ':' . bin2hex(openssl_encrypt($_POST["medication"], "aes-256-cbc", hex2bin($encryptionKey), 0, $iv, $tag));

            $error = "";

            $insertQuery = $db->prepare("INSERT INTO medical_records (Date, Symptoms, Systolic_BP, Diastolic_BP, Respiratory_Rate, Capillary_Refill, Body_Temp, Weight, Pulse_Rate, Diagnosis, Medication, Doctor_Name, Patient_Number) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); ");

            if ($insertQuery === false) {
                throw new Exception('Error preparing query: ' . $db->error);
            }

            $insertQuery->bind_param("ssssssssssssi", $Date, $Symptoms, $Systolic_BP, $Diastolic_BP, $Respiratory_Rate, $Capillary_Refill, $Body_Temp, $Weight, $Pulse_Rate, $Diagnosis, $Medication, $Doctor_Name, $Patient_Number);

            $result = $insertQuery->execute();

            if ($result) {
                echo "Query executed successfully.";
                $error .= '<p class="success">Your registration was successful!</p>';
                header("Location: welcome.php");
                exit;
            } else {
                $error .= '<p class="error">Something went wrong! ' . $insertQuery->error . '</p>';
            }

            $insertQuery->close();
            mysqli_close($db);
        } else {
            echo "Patient_Number is not set in the session";
        }
    }
} catch (Exception $e) {
    echo "Caught exception: " . $e->getMessage();
}
?>


第二个文件是我解密数据并以表格格式打印的地方。

<?php
require_once "config.php";
require_once "session.php";

if (!isset($_SESSION["userid"]) || empty($_SESSION["userid"])) {
    header("location: login.php");
    exit;
}

$Patient_Number = $_SESSION["userid"];

$user = [];
if (isset($_SESSION["user"])) {
    $user = $_SESSION["user"];
}

$encryptionKey = 'same_random_64_character_hexadecimal_key_used_during_encryption';

if ($_SERVER["REQUEST_METHOD"] == "GET" && isset($_GET["Case_Number"])) {
    $caseNumber = $_GET["Case_Number"];

    $query = $db->prepare("SELECT * FROM medical_records WHERE Patient_Number = ? AND Case_Number = ?");
    $query->bind_param("ii", $Patient_Number, $caseNumber);
    $query->execute();

    $result = $query->get_result();

    if (!$result) {
        echo "Error: " . $query->error;
        exit;
    }

    if ($result->num_rows > 0) {
        // Fetch the row as an associative array
        $row = $result->fetch_array(MYSQLI_ASSOC);

        // Decrypt the encrypted values
        $decryptedRow = [];
        foreach ($row as $key => $value) {
            if (in_array($key, ['Case_Number', 'Date', 'Patient_Number'])) {
                $decryptedRow[$key] = $value;
                continue;
            }

            // Checking if the value is empty before decryption
            if (!empty($value)) {

                // Separating IV and encrypted value
                $parts = explode(':', $value, 2);
                
                // Checking if the array has at least two elements
                if (count($parts) >= 2) {

                    // Extracting IV and encrypted value
                    list($iv, $encryptedValue) = $parts;
        
                    // Checking IV length
                    $expectedIvLength = openssl_cipher_iv_length("aes-256-cbc");
        
                    if (strlen($iv) === $expectedIvLength * 2) {

                        // Converting hexadecimal IV to binary
                        $ivBinary = hex2bin($iv);
        
                        // Checking if IV conversion was successful
                        if ($ivBinary === false) {
                            echo "Invalid IV format for key: $key\n";
                        } else {

                            $decryptedValue = openssl_decrypt(hex2bin($encryptedValue), 'aes-256-cbc', hex2bin($encryptionKey), 0, $ivBinary);
                            var_dump($decryptedValue);
        
                            // Checking if decryption was successful
                            if ($decryptedValue === false) {
                                echo "Decryption failed for key: $key\n";
                                echo "Error: " . openssl_error_string() . "\n";
                            } else {
                                // Decryption successful, store the decrypted value
                                $decryptedRow[$key] = $decryptedValue;
                            }
                        }
                    } else {
                        echo "Invalid IV length for key: $key\n";
                    }
                } else {
                    // Handling the case where there are not enough parts in the array
                    echo "Invalid format for encrypted value: $value\n";
                }
            } else {
                $decryptedRow[$key] = $value;
            }
        }

        // Displaying decrypted values in a table
        echo "<table border='1'>";
        foreach ($decryptedRow as $key => $value) {
            echo "<tr>";
            echo "<td><strong>$key</strong>";
            echo "<td>$value</td>";
            echo "</tr>";
        }
        echo "</table>";
    } else {
        echo "Report not found.";
    }

    $query->close();
    mysqli_close($db);
} else {
    echo "Invalid request.";
}
?>

现在我面临的问题是,由于某种原因,在解密期间 openssl_decrypt() 函数返回 false;我不确定问题是什么。

我收到的错误是:

密钥解密失败:症状错误:错误:1C800064:提供程序例程::错误解密布尔(假)密钥解密失败:Systolic_BP错误:错误:1C800064:提供程序例程::错误解密布尔(假)密钥解密失败: Diastolic_BP 错误:错误:1C800064:提供程序例程::解密错误 bool(假) 密钥解密失败:Respiratory_Rate 错误:错误:1C800064:提供程序例程::解密错误布尔(假) 密钥解密失败:Capillary_Refill 错误:错误:1C800064 : 提供程序例程:: 错误解密 bool(false) 密钥解密失败:Body_Temp 错误:错误:1C800064:提供程序例程::错误解密 bool(false) 密钥解密失败:权重错误:错误:1C800064:提供程序例程::错误解密布尔(假)密钥解密失败:Pulse_Rate错误:错误:1C800064:提供程序例程::错误解密布尔(假)密钥解密失败:诊断错误:错误:1C800064:提供程序例程::错误解密布尔(假)解密密钥失败:药物错误:错误:1C800064:提供程序例程::解密错误 bool(假) 密钥解密失败:Doctor_Name 错误:错误:1C800064:提供程序例程::解密错误

供您参考,加密数据以以下格式存储

iv:加密数据

例如:

86f8589c55d009da3f46e039a1ee1218:2f5066596e5648414b5150633173516c4448593136513d3d

php mysql encryption openssl
1个回答
0
投票

您使用了大量重复的代码,这是一个巨大的危险信号,您应该封装该逻辑,通常作为函数或方法。

正如评论中所述,您正在生成一个随机 IV,但没有使用它,至少据我所知。

我已经采用了您提供的代码(大部分按原样),并将其转换为加密和解密函数。我并不是说这些都是完美的,但应该能让你进步一点。我们生成一个 IV,在加密中使用它,并将其标记到字符串的前面。我也不太喜欢密码算法的制作方法,但它展示了如何抽象它,至少在某种程度上是这样。作为常数或类似值可能更好。

function encryptString(string $s, string $cipher_algo = "aes-256-cbc"): string
{
    // Not a big fan, but I'm just trying to keep things simple
    global $encryptionKey;

    if (!$ivLength = openssl_cipher_iv_length($cipher_algo)) {
        throw new Exception('Could not determine IV length');
    }

    if (!$iv = openssl_random_pseudo_bytes($ivLength)) {
        throw new Exception('Could not generate IV');
    }

    if (!$encrypted = openssl_encrypt($s, $cipher_algo, hex2bin($encryptionKey), iv: $iv)) {
        throw new Exception('Could not encrypt');
    }

    return sprintf(
        "%s:%s",
        bin2hex($iv),
        bin2hex($encrypted),
    );
}

function decryptString(string $s, string $cipher_algo = "aes-256-cbc"): string
{
    // Not a big fan, but I'm just trying to keep things simple
    global $encryptionKey;

    if (!str_contains($s, ':')) {
        throw new Exception('The provided string does not match the expected format');
    }

    [$iv, $encrypted] = explode(':', $s);

    if (!$decrypted = openssl_decrypt(hex2bin($encrypted), $cipher_algo, hex2bin($encryptionKey), iv: hex2bin($iv),)) {
        throw new Exception('Could not decrypt');
    }

    return $decrypted;
}

然后下面的代码展示了它的使用。密钥显然应该生成一次并安全存储。非常具体地说,将其正确存储在代码文件中会带来潜在的麻烦,因此请务必研究安全存储的方法。

// This would obviously be generated once and stored somewhere safe
$encryptionKey = bin2hex(openssl_random_pseudo_bytes(64));

$encrypted = encryptString('something');
$decrypted = decryptString($encrypted);

echo $encrypted, PHP_EOL, $decrypted, PHP_EOL;

OUTPUT:
960e4b3057968c90c7eef79cdeaaa124:32457554366e325771657479572f7656374e706a58773d3d
something

© www.soinside.com 2019 - 2024. All rights reserved.