I'm new to PHP and I'm working on a PHP and MYSQL code, which will store encrypted Patient Data in a mysql database, and then when required will retrieve it and display it to the user. Right now I have 2 files, first one is where I am encrypting the data
<?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();
}
?>
The second file is where I am decrypting the data and printing it in a tabular format.
<?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.";
}
?>
Now the problem I'm facing is, for some reason during decryption openssl_decrypt() function is returning false; and I am not sure what is the problem.
The error I am getting is:
Decryption failed for key: Symptoms Error: error:1C800064:Provider routines::bad decrypt bool(false) Decryption failed for key: Systolic_BP Error: error:1C800064:Provider routines::bad decrypt bool(false) Decryption failed for key: Diastolic_BP Error: error:1C800064:Provider routines::bad decrypt bool(false) Decryption failed for key: Respiratory_Rate Error: error:1C800064:Provider routines::bad decrypt bool(false) Decryption failed for key: Capillary_Refill Error: error:1C800064:Provider routines::bad decrypt bool(false) Decryption failed for key: Body_Temp Error: error:1C800064:Provider routines::bad decrypt bool(false) Decryption failed for key: Weight Error: error:1C800064:Provider routines::bad decrypt bool(false) Decryption failed for key: Pulse_Rate Error: error:1C800064:Provider routines::bad decrypt bool(false) Decryption failed for key: Diagnosis Error: error:1C800064:Provider routines::bad decrypt bool(false) Decryption failed for key: Medication Error: error:1C800064:Provider routines::bad decrypt bool(false) Decryption failed for key: Doctor_Name Error: error:1C800064:Provider routines::bad decrypt
For your reference, the encrypted data is stored in the following format
iv : encrypted_data
for Example:
86f8589c55d009da3f46e039a1ee1218:2f5066596e5648414b5150633173516c4448593136513d3d
You are using a lot of repeated code, which is a giant red flag that you should encapsulate that logic, usually as a function or method.
As noted in the comment, you are generating a random IV but not using it, at least as far as I can tell.
I've taken your provided code, mostly as-is, and converted it into encrypt and decrypt functions. I'm not saying these are perfect, but should get you going a bit. We generate an IV, use that in the encryption, and tag it onto the front of the string. I'm also not a big fan of how I did the cipher algorithm, but it shows how it can be abstracted, at least to a point. Probably better as a constant or similar.
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;
}
Then the following code shows using it. The key is obviously something that should be generated once and stored securely. Very specifically, storing it right in a code file is asking for potential trouble, so make sure to look into ways to store if securely.
// 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