本文目录导读:

在PHP项目中,解密文件并校验密码正确性的常见方法有以下几种:
哈希校验法(推荐)
加密过程
// 加密文件时
$password = 'user_password';
$hashed_password = password_hash($password, PASSWORD_BCRYPT);
$file_data = file_get_contents('original.txt');
$encrypted_data = openssl_encrypt(
$file_data,
'aes-256-cbc',
$password,
0,
$iv
);
// 存储:$hashed_password + $iv + $encrypted_data
file_put_contents('encrypted.dat', $hashed_password . '::' . base64_encode($iv) . '::' . base64_encode($encrypted_data));
解密校验
function decryptFile($file_path, $password) {
$data = file_get_contents($file_path);
list($stored_hash, $iv_b64, $data_b64) = explode('::', $data);
// 验证密码
if (!password_verify($password, $stored_hash)) {
return false; // 密码错误
}
$iv = base64_decode($iv_b64);
$encrypted_data = base64_decode($data_b64);
// 解密
$decrypted = openssl_decrypt(
$encrypted_data,
'aes-256-cbc',
$password,
0,
$iv
);
return $decrypted;
}
HMAC验证法
function encryptWithHMAC($data, $password) {
$iv = openssl_random_pseudo_bytes(16);
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $password, 0, $iv);
// 生成HMAC用于验证
$hmac = hash_hmac('sha256', $encrypted, $password);
// 存储:HMAC + IV + 加密数据
return $hmac . '::' . base64_encode($iv) . '::' . base64_encode($encrypted);
}
function decryptWithHMAC($file_data, $password) {
list($stored_hmac, $iv_b64, $data_b64) = explode('::', $file_data);
$iv = base64_decode($iv_b64);
$encrypted_data = base64_decode($data_b64);
// 验证HMAC
$computed_hmac = hash_hmac('sha256', $encrypted_data, $password);
if (!hash_equals($stored_hmac, $computed_hmac)) {
return false; // 密码错误
}
return openssl_decrypt($encrypted_data, 'aes-256-cbc', $password, 0, $iv);
}
Magic Bytes验证法
function encryptWithMagicBytes($data, $password) {
// 加密前添加特定标记
$magic = 'VALID';
$data_with_magic = $magic . $data;
$iv = openssl_random_pseudo_bytes(16);
$encrypted = openssl_encrypt($data_with_magic, 'aes-256-cbc', $password, 0, $iv);
return base64_encode($iv) . '::' . base64_encode($encrypted);
}
function decryptCheckMagic($file_data, $password) {
list($iv_b64, $data_b64) = explode('::', $file_data);
$iv = base64_decode($iv_b64);
$encrypted_data = base64_decode($data_b64);
$decrypted = openssl_decrypt($encrypted_data, 'aes-256-cbc', $password, 0, $iv);
// 检查magic bytes
if (substr($decrypted, 0, 5) !== 'VALID') {
return false; // 密码错误或数据损坏
}
return substr($decrypted, 5); // 移除magic bytes
}
完整示例实现
class FileCrypto {
private $cipher = 'aes-256-cbc';
public function encryptFile($input_file, $output_file, $password) {
$data = file_get_contents($input_file);
if ($data === false) {
throw new Exception("无法读取输入文件");
}
// 生成IV
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($this->cipher));
// 加密
$encrypted = openssl_encrypt($data, $this->cipher, $password, 0, $iv);
// 存储格式:密码哈希::IV(base64)::加密数据(base64)::文件大小
$hash = password_hash($password, PASSWORD_DEFAULT);
$stored = json_encode([
'hash' => $hash,
'iv' => base64_encode($iv),
'data' => base64_encode($encrypted),
'size' => strlen($data),
'time' => time()
]);
return file_put_contents($output_file, $stored) !== false;
}
public function decryptFile($input_file, $password) {
$stored = file_get_contents($input_file);
if ($stored === false) {
throw new Exception("无法读取加密文件");
}
$info = json_decode($stored, true);
if (!$info) {
throw new Exception("文件格式错误");
}
// 验证密码
if (!password_verify($password, $info['hash'])) {
return false; // 密码错误
}
$iv = base64_decode($info['iv']);
$encrypted = base64_decode($info['data']);
$decrypted = openssl_decrypt($encrypted, $this->cipher, $password, 0, $iv);
// 验证解密后数据大小
if (strlen($decrypted) !== $info['size']) {
return false; // 数据可能损坏
}
return $decrypted;
}
}
// 使用示例
$crypto = new FileCrypto();
// 加密
$crypto->encryptFile('original.txt', 'encrypted.dat', 'user_password123');
// 解密并验证
$decrypted = $crypto->decryptFile('encrypted.dat', 'user_password123');
if ($decrypted === false) {
echo "密码错误!";
} else {
echo "解密成功,内容:\n" . $decrypted;
}
安全建议
- 使用强哈希算法:
password_hash()+PASSWORD_BCRYPT或PASSWORD_ARGON2ID - 防止时序攻击:使用
hash_equals()进行字符串比较 - 添加错误延迟:防止暴力破解
- 使用密钥派生函数:如 PBKDF2 或 Argon2
// 使用Argon2(PHP 7.2+)
$options = [
'memory_cost' => 1<<17, // 128MB
'time_cost' => 4,
'threads' => 3
];
$hash = password_hash($password, PASSWORD_ARGON2ID, $options);
// 添加登录延迟
usleep(500000); // 0.5秒延迟
if (!password_verify($password, $stored_hash)) {
// 密码错误处理
}
推荐使用 方法1(哈希校验法),它既安全又易于实现。