PHP 怎么PHP Sodium

wen PHP项目 3

本文目录导读:

PHP 怎么PHP Sodium

  1. 安装与启用
  2. 核心加密功能
  3. 密码哈希
  4. 密钥交换 (X25519)
  5. 消息签名
  6. 高级特性
  7. 最佳实践
  8. 重要注意事项

我来详细介绍 PHP Sodium 扩展(现代加密库)的使用方法。

安装与启用

安装方法

# PHP 7.2+ 默认内置,否则需安装
# Ubuntu/Debian
sudo apt-get install php-sodium
# CentOS/RHEL
sudo yum install php-sodium
# macOS (Homebrew)
brew install php-sodium

检查是否启用

<?php
echo extension_loaded('sodium') ? '已启用' : '未启用';
// 或查看函数是否存在
echo function_exists('sodium_crypto_secretbox') ? '可用' : '不可用';

核心加密功能

对称加密(密钥加密)

<?php
// 加密
function encryptData(string $plaintext): array {
    $key = sodium_crypto_secretbox_keygen(); // 生成密钥
    $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); // 随机数
    $ciphertext = sodium_crypto_secretbox($plaintext, $nonce, $key);
    return [
        'ciphertext' => base64_encode($nonce . $ciphertext),
        'key' => base64_encode($key)
    ];
}
// 解密
function decryptData(string $ciphertext, string $key): string {
    $key = base64_decode($key);
    $decoded = base64_decode($ciphertext);
    $nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
    $cipher = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
    $plaintext = sodium_crypto_secretbox_open($cipher, $nonce, $key);
    if ($plaintext === false) {
        throw new Exception('解密失败');
    }
    return $plaintext;
}
// 使用示例
$data = "敏感信息:密码123";
$encrypted = encryptData($data);
$decrypted = decryptData($encrypted['ciphertext'], $encrypted['key']);
echo "原始数据: $data\n";
echo "加密后: " . $encrypted['ciphertext'] . "\n";
echo "解密后: $decrypted\n";

非对称加密(公钥/私钥)

<?php
// 生成密钥对
function generateKeyPair(): array {
    $keypair = sodium_crypto_box_keypair();
    $publicKey = sodium_crypto_box_publickey($keypair);
    $secretKey = sodium_crypto_box_secretkey($keypair);
    return [
        'keypair' => $keypair,
        'public' => base64_encode($publicKey),
        'secret' => base64_encode($secretKey)
    ];
}
// 加密(使用接收方公钥)
function encryptWithPublicKey(string $message, string $recipientPublicKey, string $senderSecretKey): string {
    $recipientPublic = base64_decode($recipientPublicKey);
    $senderSecret = base64_decode($senderSecretKey);
    // 创建密钥对
    $senderKeypair = sodium_crypto_box_keypair_from_secretkey_and_publickey(
        $senderSecret, 
        $recipientPublic
    );
    $nonce = random_bytes(SODIUM_CRYPTO_BOX_NONCEBYTES);
    $ciphertext = sodium_crypto_box($message, $nonce, $senderKeypair);
    return base64_encode($nonce . $ciphertext);
}
// 解密
function decryptWithPrivateKey(string $encrypted, string $recipientSecretKey, string $senderPublicKey): string {
    $decoded = base64_decode($encrypted);
    $nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_BOX_NONCEBYTES, '8bit');
    $cipher = mb_substr($decoded, SODIUM_CRYPTO_BOX_NONCEBYTES, null, '8bit');
    $recipientSecret = base64_decode($recipientSecretKey);
    $senderPublic = base64_decode($senderPublicKey);
    $recipientKeypair = sodium_crypto_box_keypair_from_secretkey_and_publickey(
        $recipientSecret, 
        $senderPublic
    );
    $plaintext = sodium_crypto_box_open($cipher, $nonce, $recipientKeypair);
    if ($plaintext === false) {
        throw new Exception('解密失败');
    }
    return $plaintext;
}
// 使用示例
$alice = generateKeyPair();
$bob = generateKeyPair();
$message = "Hello Bob, this is Alice!";
$encrypted = encryptWithPublicKey(
    $message, 
    $bob['public'], 
    $alice['secret']
);
$decrypted = decryptWithPrivateKey(
    $encrypted, 
    $bob['secret'], 
    $alice['public']
);
echo "原始消息: $message\n";
echo "加密后: $encrypted\n";
echo "解密后: $decrypted\n";

密码哈希

<?php
// 哈希密码
function hashPassword(string $password): string {
    $hash = sodium_crypto_pwhash_str(
        $password,
        SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE,  // 计算开销
        SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE   // 内存限制
    );
    return $hash;
}
// 验证密码
function verifyPassword(string $password, string $hash): bool {
    return sodium_crypto_pwhash_str_verify($hash, $password);
}
// 使用示例
$password = "MySecurePassword123!";
$hash = hashPassword($password);
echo "密码哈希: $hash\n";
echo "验证结果: " . (verifyPassword("MySecurePassword123!", $hash) ? '正确' : '错误') . "\n";
echo "错误密码验证: " . (verifyPassword("wrong", $hash) ? '正确' : '错误') . "\n";

密钥交换 (X25519)

<?php
// 生成密钥对
function generateX25519KeyPair(): array {
    $keypair = sodium_crypto_kx_keypair();
    $publicKey = sodium_crypto_kx_publickey($keypair);
    $secretKey = sodium_crypto_kx_secretkey($keypair);
    return [
        'keypair' => $keypair,
        'public' => base64_encode($publicKey),
        'secret' => base64_encode($secretKey)
    ];
}
// 客户端计算共享密钥
function clientSessionKeys(string $clientKeypair, string $serverPublicKey): array {
    $serverPublic = base64_decode($serverPublicKey);
    $keys = sodium_crypto_kx_client_session_keys($clientKeypair, $serverPublic);
    return [
        'rx_key' => base64_encode($keys[0]), // 接收密钥
        'tx_key' => base64_encode($keys[1])  // 发送密钥
    ];
}
// 服务端计算共享密钥
function serverSessionKeys(string $serverKeypair, string $clientPublicKey): array {
    $clientPublic = base64_decode($clientPublicKey);
    $keys = sodium_crypto_kx_server_session_keys($serverKeypair, $clientPublic);
    return [
        'rx_key' => base64_encode($keys[0]),
        'tx_key' => base64_encode($keys[1])
    ];
}

消息签名

<?php
// 生成签名密钥对
function generateSignKeyPair(): array {
    $keypair = sodium_crypto_sign_keypair();
    $publicKey = sodium_crypto_sign_publickey($keypair);
    $secretKey = sodium_crypto_sign_secretkey($keypair);
    return [
        'keypair' => $keypair,
        'public' => base64_encode($publicKey),
        'secret' => base64_encode($secretKey)
    ];
}
// 签名消息
function signMessage(string $message, string $secretKey): string {
    $secret = base64_decode($secretKey);
    $signed = sodium_crypto_sign($message, $secret);
    return base64_encode($signed);
}
// 验证签名
function verifySignature(string $signedMessage, string $publicKey): string|false {
    $signed = base64_decode($signedMessage);
    $public = base64_decode($publicKey);
    $message = sodium_crypto_sign_open($signed, $public);
    return $message;
}
// 使用示例
$keys = generateSignKeyPair();
$message = "重要合同内容";
$signed = signMessage($message, $keys['secret']);
$verified = verifySignature($signed, $keys['public']);
echo "签名消息: $signed\n";
echo "验证结果: " . ($verified !== false ? $verified : '签名无效') . "\n";

高级特性

常量时间比较(防时序攻击)

<?php
// 安全的比较函数
function secureCompare(string $known, string $user): bool {
    return sodium_memcmp($known, $user) === 0;
}
// 使用示例
$storedHash = '已知的哈希值';
$userInput = '用户输入';
if (secureCompare($storedHash, $userInput)) {
    echo "匹配成功";
} else {
    echo "匹配失败";
}

生成安全随机数

<?php
// 生成安全的随机字节
function generateRandomBytes(int $length): string {
    return random_bytes($length);
}
// 生成安全的十六进制字符串
function generateHexString(int $length = 32): string {
    return bin2hex(random_bytes($length));
}
// 生成安全的整数
function secureRandomInt(int $min, int $max): int {
    return random_int($min, $max);
}
echo "随机字节: " . base64_encode(generateRandomBytes(16)) . "\n";
echo "十六进制: " . generateHexString() . "\n";
echo "随机整数: " . secureRandomInt(1, 100) . "\n";

最佳实践

<?php
class SecureEncryption {
    private string $key;
    public function __construct() {
        // 从安全存储加载密钥
        $this->key = $this->loadKey();
    }
    public function encrypt(string $data): string {
        $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
        $ciphertext = sodium_crypto_secretbox($data, $nonce, $this->key);
        return base64_encode($nonce . $ciphertext);
    }
    public function decrypt(string $encrypted): string {
        $decoded = base64_decode($encrypted);
        if ($decoded === false || mb_strlen($decoded, '8bit') < SODIUM_CRYPTO_SECRETBOX_NONCEBYTES) {
            throw new InvalidArgumentException('无效的加密数据');
        }
        $nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
        $ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
        $plaintext = sodium_crypto_secretbox_open($ciphertext, $nonce, $this->key);
        if ($plaintext === false) {
            throw new RuntimeException('解密失败,数据可能被篡改');
        }
        // 安全擦除敏感数据
        sodium_memzero($ciphertext);
        return $plaintext;
    }
    private function loadKey(): string {
        // 从环境变量或安全存储加载密钥
        $key = getenv('ENCRYPTION_KEY');
        if ($key === false || strlen(base64_decode($key)) !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
            throw new RuntimeException('无效的加密密钥');
        }
        return base64_decode($key);
    }
    // 生成新密钥
    public static function generateKey(): string {
        return base64_encode(sodium_crypto_secretbox_keygen());
    }
}
// 使用示例
try {
    $crypto = new SecureEncryption();
    $encrypted = $crypto->encrypt("敏感数据");
    $decrypted = $crypto->decrypt($encrypted);
    echo "加密: $encrypted\n";
    echo "解密: $decrypted\n";
} catch (Exception $e) {
    echo "错误: " . $e->getMessage() . "\n";
}

重要注意事项

安全警告

<?php
// ❌ 不要使用过时的加密方式
// $encrypted = mcrypt_encrypt(...); // 已废弃
// ✅ 使用 Sodium 进行加密
// $encrypted = sodium_crypto_secretbox(...);
// ❌ 不要使用 MD5 或 SHA1 哈希密码
// $hash = md5($password);
// ✅ 使用 Sodium 的密码哈希
// $hash = sodium_crypto_pwhash_str($password);
// ❌ 不要使用简单的比较
// if ($input === $hash) { }
// ✅ 使用常量时间比较
// if (sodium_memcmp($hash, $input) === 0) { }

性能优化

<?php
// 对于频繁加密操作,重用密钥
$key = sodium_crypto_secretbox_keygen();
// 批量加密
$dataArray = ['item1', 'item2', 'item3'];
$encrypted = [];
foreach ($dataArray as $item) {
    $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
    $encrypted[] = base64_encode($nonce . sodium_crypto_secretbox($item, $nonce, $key));
}
// 清理敏感数据
sodium_memzero($key);

Sodium 是现代 PHP 应用中推荐使用的加密库,提供了安全、高效的加密功能,始终使用最新版本的 PHP 和 Sodium 扩展来确保最佳安全性。

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