本文目录导读:

我来详细介绍 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 扩展来确保最佳安全性。