專案需生成「授權碼」,包含到期時間等敏感資訊,寫入授權文件。客戶端讀取文件,用唯一金鑰解密驗證。早期嘗試 Base64+MD5+反轉等簡易混淆,極易破解。正確做法:採用業界標準對稱加密算法(AES/DES),金鑰管理得當。
| 算法 | 金鑰長度 | 區塊大小 | 推薦模式 | 備註 |
|---|---|---|---|---|
| AES-256-CBC | 32 bytes | 16 bytes | CBC/GCM | 現代首選,硬體加速廣泛支援 |
| AES-128-CBC | 16 bytes | 16 bytes | CBC/GCM | 安全性足夠大多數場景 |
| DES-EDE3-CBC (3DES) | 24 bytes | 8 bytes | CBC | 已棄用,僅相容舊系統 |
| DES-CBC | 8 bytes | 8 bytes | CBC | 極不安全,禁止新專案使用 |
<?php
class LicenseCrypto {
private string $cipher = 'AES-256-CBC';
private int $keyLen;
private int $ivLen;
private string $masterKey; // 32 bytes 原始金鑰或高熵密碼
public function __construct(string $masterKey) {
$this->keyLen = openssl_cipher_iv_length($this->cipher); // 32
$this->ivLen = openssl_cipher_iv_length($this->cipher); // 16
// 若傳入非 32 bytes,使用 PBKDF2 派生
$this->masterKey = strlen($masterKey) === $this->keyLen
? $masterKey
: hash_pbkdf2('sha256', $masterKey, '', 200000, $this->keyLen, true);
}
/** 生成授權碼(加密) */
public function encrypt(array $payload): string {
$plaintext = json_encode($payload, JSON_UNESCAPED_UNICODE);
$iv = random_bytes($this->ivLen);
$ciphertext = openssl_encrypt($plaintext, $this->cipher, $this->masterKey, OPENSSL_RAW_DATA, $iv);
if ($ciphertext === false) {
throw new \RuntimeException('加密失敗: ' . openssl_error_string());
}
// 格式:IV(16) + Ciphertext + HMAC(可選)
return base64_encode($iv . $ciphertext);
}
/** 驗證授權碼(解密) */
public function decrypt(string $license): array {
$data = base64_decode($license, true);
if ($data === false || strlen($data) < $this->ivLen) {
throw new \InvalidArgumentException('授權碼格式錯誤');
}
$iv = substr($data, 0, $this->ivLen);
$ciphertext = substr($data, $this->ivLen);
$plaintext = openssl_decrypt($ciphertext, $this->cipher, $this->masterKey, OPENSSL_RAW_DATA, $iv);
if ($plaintext === false) {
throw new \RuntimeException('解密失敗:金鑰錯誤或資料已損壞');
}
$payload = json_decode($plaintext, true);
if (!is_array($payload)) {
throw new \RuntimeException('授權碼內容格式錯誤');
}
return $payload;
}
}
// 使用範例
$crypto = new LicenseCrypto('your-32-byte-master-secret-key-123'); // 實際應從環境變數/密碼管理器讀取
// 生成授權:有效期至 2025-12-31
$license = $crypto->encrypt([
'product' => 'SuperApp',
'expires' => '2025-12-31 23:59:59',
'features' => ['pro', 'api', 'multi-user'],
]);
file_put_contents('/path/to/license.dat', $license);
// 客戶端驗證
try {
$payload = $crypto->decrypt(file_get_contents('/path/to/license.dat'));
if (strtotime($payload['expires']) < time()) {
die('授權已過期');
}
echo "授權有效:{$payload['product']} - " . implode(', ', $payload['features']);
} catch (\Throwable $e) {
die('授權驗證失敗:' . $e->getMessage());
}
?>
PHP 7.1+ 支援 GCM 模式,內建認證標籤(Tag),防範密文竄改:
public function encryptAEAD(array $payload): string {
$plaintext = json_encode($payload);
$iv = random_bytes(12); // GCM 建議 12 bytes IV
$tag = '';
$ciphertext = openssl_encrypt($plaintext, 'AES-256-GCM', $this->masterKey, OPENSSL_RAW_DATA, $iv, $tag, '', 16);
// 格式:IV(12) + Tag(16) + Ciphertext
return base64_encode($iv . $tag . $ciphertext);
}
public function decryptAEAD(string $license): array {
$data = base64_decode($license, true);
if (strlen($data) < 28) throw new \InvalidArgumentException('格式錯誤');
$iv = substr($data, 0, 12);
$tag = substr($data, 12, 16);
$ciphertext = substr($data, 28);
$plaintext = openssl_decrypt($ciphertext, 'AES-256-GCM', $this->masterKey, OPENSSL_RAW_DATA, $iv, $tag);
// ... 後續同 CBC
}
使用 OpenSSL 的 AES-256-CBC/GCM 搭配 PBKDF2 金鑰派生、隨機 IV、Base64 封裝,能快速構建安全可靠的授權碼系統。核心在於:算法標準化、金鑰與數據分離、完整性驗證、金鑰全生命週期管理。