本類別展示一種基於「密鑰字元位移替換表」的對稱加密演算法。特點:
$ralphabet(含大小寫字母、數字、符號)$alphabet,方便循環位移$alphabet 中對應一個位移後的替換表$ralphabet 位置 → 對應密鑰位移表的字元$ralphabet 原字元<?php
$ralphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 !,.:;?~@#$%^&*()_+-=][}{/><\'"';
$alphabet = $ralphabet . $ralphabet;
class Crypto {
public function encrypt(string $password, string $plaintext): string {
$tables = $this->buildTables($password);
$plen = strlen($plaintext);
$klen = count($tables);
$cipher = '';
for ($i = 0, $k = 0; $i < $plen; $i++, $k = ($k + 1) % $klen) {
$pos = strpos($ralphabet, $plaintext[$i]);
if ($pos !== false) {
$cipher .= $tables[$k][$pos];
} else {
// 不在字元表內的字元保留原樣(或拋出異常)
$cipher .= $plaintext[$i];
}
}
return $cipher;
}
public function decrypt(string $password, string $ciphertext): string {
$tables = $this->buildTables($password);
$clen = strlen($ciphertext);
$klen = count($tables);
$plain = '';
for ($i = 0, $k = 0; $i < $clen; $i++, $k = ($k + 1) % $klen) {
$pos = strpos($tables[$k], $ciphertext[$i]);
if ($pos !== false) {
$plain .= $ralphabet[$pos];
} else {
$plain .= $ciphertext[$i];
}
}
return $plain;
}
// 產生密鑰對應的位移替換表陣列
private function buildTables(string $password): array {
$tables = [];
$rlen = strlen($ralphabet);
for ($i = 0; $i < strlen($password); $i++) {
$ch = $password[$i];
$pos = strpos($alphabet, $ch);
if ($pos !== false) {
$tables[] = substr($alphabet, $pos, $rlen);
}
}
return $tables ?: [$ralphabet]; // 至少有一個表
}
// 除錯用:輸出替換表 HTML 表格
public function printTable(string $password): void {
$tables = $this->buildTables($password);
echo '<table border="1" cellpadding="3" cellspacing="0">';
echo '<tr><th>Pos</th>';
for ($j = 0; $j < strlen($ralphabet); $j++) {
echo '<th>' . htmlspecialchars($ralphabet[$j]) . '</th>';
}
echo '</tr>';
foreach ($tables as $idx => $table) {
echo '<tr><td>' . ($idx + 1) . '</td>';
for ($j = 0; $j < strlen($table); $j++) {
echo '<td>' . htmlspecialchars($table[$j]) . '</td>';
}
echo '</tr>';
}
echo '</table>';
}
}
// 簡易測試表單
$crypto = new Crypto();
$mode = $_POST['mode'] ?? 'encrypt';
$password = $_POST['password'] ?? 'secret';
$input = $_POST['input'] ?? '';
if ($mode === 'encrypt') {
$output = $crypto->encrypt($password, $input);
$action = 'decrypt';
$btn = '解密';
} else {
$output = $crypto->decrypt($password, $input);
$action = 'encrypt';
$btn = '加密';
}
?>
<!DOCTYPE html>
<html lang="zh-TW">
<head><meta charset="UTF-8"><title>Crypto Demo</title></head>
<body>
<h2>自訂加密/解密示範</h2>
<form method="post">
<input type="hidden" name="mode" value="<?= $action ?>">
<label>密鑰: <input type="text" name="password" value="<?= htmlspecialchars($password) ?>" size="20"></label><br><br>
<label><?= $mode === 'encrypt' ? '明文' : '密文' ?>:<br>
<textarea name="input" rows="5" cols="60"><?= htmlspecialchars($input) ?></textarea></label><br>
<button type="submit"><?= $btn ?></button>
</form>
<hr>
<label>結果:<br>
<textarea rows="5" cols="60" readonly><?= htmlspecialchars($output) ?></textarea></label>
<hr>
<h3>替換表</h3>
<?php $crypto->printTable($password); ?>
</body>
</html>
| 問題 | 影響 | 改進建議 |
|---|---|---|
| 無完整性驗證 (MAC) | 密文被竄改後解密不會報錯 | 加密後附加 HMAC-SHA256,解密前驗證 |
| 金鑰衍生弱 | 直接使用密碼字元,熵值低 | 使用 PBKDF2 / Argon2 衍生金鑰 |
| ECB 模式特性 | 相同明文區塊產生相同密文,洩漏模式 | 引入 IV (Initialization Vector) 改為 CBC/GCM 模式 |
| 字元表固定 | 已知明文攻擊容易破解 | 使用標準加密庫 (OpenSSL、libsodium) |