PHP项目解密文件如何校验密码正确性

wen PHP项目 27

本文目录导读:

PHP项目解密文件如何校验密码正确性

  1. 哈希校验法(推荐)
  2. HMAC验证法
  3. Magic Bytes验证法
  4. 完整示例实现
  5. 安全建议

在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;
}

安全建议

  1. 使用强哈希算法password_hash() + PASSWORD_BCRYPTPASSWORD_ARGON2ID
  2. 防止时序攻击:使用 hash_equals() 进行字符串比较
  3. 添加错误延迟:防止暴力破解
  4. 使用密钥派生函数:如 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(哈希校验法),它既安全又易于实现。

抱歉,评论功能暂时关闭!