- 概念總覽
- Hash 雜湊函數
- 對稱式加密
- 非對稱式加密
- 三種技術比較
- 實戰應用場景
- 常見問題
- 總結
| 特性 |
Hash 雜湊 |
對稱加密 |
非對稱加密 |
| 轉換方向 |
單向(不可還原) |
雙向可逆 |
雙向可逆 |
| 可逆性 |
❌ 不可逆 |
✅ 可逆 |
✅ 可逆 |
| 金鑰數量 |
無需金鑰 |
1 把(加解密同鑰) |
2 把(公鑰/私鑰) |
| 運算速度 |
快 |
快 |
慢(100-1000x) |
| 輸出長度 |
固定 |
與輸入相關 |
與輸入相關 |
| 主要用途 |
驗證、指紋 |
資料加密 |
金鑰交換、數位簽章 |
| 運作流程 |
明文 → Hash 值 |
明文 ⇄ 密文(同鑰) |
明文 ⇄ 密文(公私鑰) |
| 常見演算法 |
SHA-256、SHA-3、bcrypt、Argon2 |
AES、ChaCha20、3DES |
RSA、ECC、Ed25519 |
Hash(雜湊) 是一種將任意長度的輸入資料,轉換為固定長度輸出的單向函數。
任意長度輸入 Hash 函數 固定長度輸出
───────────── ────────── ─────────────
"Hello" → SHA-256 → 2cf24dba5fb0a30e...(64 字元)
"Hello World" → SHA-256 → a591a6d40bf420404...(64 字元)
1GB 檔案 → SHA-256 → 7d865e959b2466918...(64 字元)
| 特性 |
說明 |
範例 |
| 單向性 |
無法從 Hash 值反推原始資料 |
Hash(明文) → Hash 值 ✅
Hash 值 → 明文 ❌ |
| 確定性 |
相同輸入永遠產生相同輸出 |
Hash("abc") 永遠相同 |
| 雪崩效應 |
輸入微小變化造成輸出巨大差異 |
"abc" vs "abd" 的 Hash 完全不同 |
| 抗碰撞性 |
難以找到兩個不同輸入產生相同輸出 |
很難找到 Hash(A) = Hash(B) 且 A ≠ B |
| 固定長度 |
無論輸入多長,輸出長度固定 |
SHA-256 永遠輸出 256 bits |
echo -n "hello" | sha256sum
echo -n "hallo" | sha256sum
| 項目 |
說明 |
| 全名 |
Message Digest 5 |
| 輸出長度 |
128 bits(32 字元十六進位) |
| 狀態 |
⚠️ 已被破解,不建議用於安全用途 |
| 用途 |
檔案校驗(非安全場景) |
echo -n "hello" | md5sum
| 項目 |
說明 |
| 全名 |
Secure Hash Algorithm 1 |
| 輸出長度 |
160 bits(40 字元十六進位) |
| 狀態 |
⚠️ 2017 年被 Google 實現碰撞攻擊 |
| 用途 |
Git commit ID(歷史原因) |
echo -n "hello" | sha1sum
| 變體 |
輸出長度 |
十六進位字元數 |
安全性 |
| SHA-224 |
224 bits |
56 字元 |
✅ 安全 |
| SHA-256 |
256 bits |
64 字元 |
✅ 推薦 |
| SHA-384 |
384 bits |
96 字元 |
✅ 安全 |
| SHA-512 |
512 bits |
128 字元 |
✅ 最安全 |
echo -n "hello" | sha256sum
echo -n "hello" | sha512sum
| 項目 |
說明 |
| 全名 |
Secure Hash Algorithm 3(Keccak) |
| 特點 |
完全不同於 SHA-2 的設計,更高安全性 |
| 變體 |
SHA3-224, SHA3-256, SHA3-384, SHA3-512 |
| 狀態 |
✅ NIST 標準(2015 年發布) |
echo -n "hello" | openssl dgst -sha3-256
一般 Hash 太快,容易被暴力破解密碼。密碼專用 Hash 特意設計成慢速。
| 項目 |
說明 |
| 特點 |
內建 salt、可調整運算成本(work factor) |
| 輸出格式 |
$2b$成本$salt+hash |
| 推薦用途 |
密碼儲存 |
$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/X4beS6pN8wBMxAnWu
│ │ │
│ │ └── Salt + Hash 值
│ └───── 成本因子(2^12 = 4096 次迭代)
└──────── 演算法版本
| 項目 |
說明 |
| 特點 |
記憶體密集型,抵抗 GPU/ASIC 攻擊 |
| 參數 |
N(CPU 成本)、r(記憶體成本)、p(平行度) |
| 推薦用途 |
密碼儲存、加密貨幣 |
| 項目 |
說明 |
| 特點 |
2015 年密碼雜湊競賽冠軍 |
| 變體 |
Argon2d(抗 GPU)、Argon2i(抗側通道)、Argon2id(混合) |
| 推薦 |
✅ 目前密碼儲存的首選 |
變體比較:
Argon2d - 資料相依,最強抗 GPU,可能有側通道風險
Argon2i - 資料無關,抗側通道攻擊,適合金鑰推導
Argon2id - 混合模式,推薦用於密碼儲存
| 演算法 |
輸出長度 |
速度 |
安全性 |
推薦用途 |
| MD5 |
128 bit |
極快 |
❌ 已破解 |
非安全校驗 |
| SHA-1 |
160 bit |
很快 |
❌ 已破解 |
不建議使用 |
| SHA-256 |
256 bit |
快 |
✅ 安全 |
通用 Hash |
| SHA-512 |
512 bit |
快 |
✅ 安全 |
高安全需求 |
| SHA-3 |
可變 |
中等 |
✅ 最安全 |
未來標準 |
| bcrypt |
184 bit |
慢 |
✅ 安全 |
密碼儲存 |
| scrypt |
可變 |
慢 |
✅ 安全 |
密碼/加密貨幣 |
| Argon2 |
可變 |
慢 |
✅ 最佳 |
密碼儲存首選 |
┌────────────────────────────────────────────────────────────┐
│ Hash 應用場景 │
├────────────────────────────────────────────────────────────┤
│ │
│ 1. 密碼儲存 │
│ ──────── │
│ 使用者密碼 → bcrypt/Argon2 → 儲存 Hash │
│ 登入驗證:輸入密碼 → Hash → 比對儲存的 Hash │
│ │
│ 2. 資料完整性 │
│ ──────────── │
│ 檔案下載驗證:比對 SHA-256 checksum │
│ Git commit:SHA-1 作為 commit ID │
│ │
│ 3. 數位簽章 │
│ ──────── │
│ 訊息 → Hash → 用私鑰加密 Hash → 數位簽章 │
│ │
│ 4. 區塊鏈 │
│ ────── │
│ 交易資料 → Hash → 區塊 → Hash → 鏈結 │
│ │
│ 5. 快取鍵 │
│ ────── │
│ URL/參數 → Hash → 作為快取的 key │
│ │
└────────────────────────────────────────────────────────────┘
對稱式加密使用同一把金鑰進行加密和解密。
加密:明文 + 金鑰 K → 密文
解密:密文 + 金鑰 K → 明文
(加密和解密使用同一把金鑰)
| 優點 |
缺點 |
| ✅ 運算速度快 |
❌ 金鑰分發問題 |
| ✅ 適合大量資料加密 |
❌ 金鑰管理困難 |
| ✅ 實作相對簡單 |
❌ 無法確認身份 |
| 項目 |
說明 |
| 全名 |
Data Encryption Standard |
| 金鑰長度 |
56 bits |
| 區塊大小 |
64 bits |
| 狀態 |
❌ 已被暴力破解,不要使用 |
| 項目 |
說明 |
| 全名 |
Triple DES |
| 金鑰長度 |
112 或 168 bits |
| 原理 |
DES 執行三次(加密→解密→加密) |
| 狀態 |
⚠️ 逐漸被 AES 取代 |
3DES 流程:
明文 → DES 加密(K1) → DES 解密(K2) → DES 加密(K3) → 密文
| 項目 |
說明 |
| 全名 |
Advanced Encryption Standard |
| 金鑰長度 |
128 / 192 / 256 bits |
| 區塊大小 |
128 bits |
| 狀態 |
✅ 目前的業界標準 |
AES 變體:
├── AES-128:10 輪加密,適合一般用途
├── AES-192:12 輪加密,中等安全需求
└── AES-256:14 輪加密,最高安全需求(政府/軍事級)
| 項目 |
說明 |
| 特點 |
串流加密、無需硬體加速也很快 |
| 金鑰長度 |
256 bits |
| 狀態 |
✅ Google 推薦,用於 TLS 1.3 |
| 優勢 |
軟體實作效能優於 AES |
區塊加密需要搭配加密模式來處理超過一個區塊的資料。
明文區塊1 → 加密 → 密文區塊1
明文區塊2 → 加密 → 密文區塊2
明文區塊3 → 加密 → 密文區塊3
問題:相同明文區塊產生相同密文,洩漏資料模式
著名案例:ECB 企鵝
原圖的企鵝輪廓在 ECB 加密後仍可辨識,因為相同顏色區塊加密後相同
IV ──────┐
↓
明文1 → XOR → 加密 → 密文1 ──┐
↓
明文2 ─────→ XOR → 加密 → 密文2 ──┐
↓
明文3 ──────→ XOR → 加密 → 密文3
特點:每個區塊依賴前一個密文,需要 IV(初始向量)
Nonce + Counter1 → 加密 → XOR ← 明文1 → 密文1
Nonce + Counter2 → 加密 → XOR ← 明文2 → 密文2
Nonce + Counter3 → 加密 → XOR ← 明文3 → 密文3
特點:可平行處理、不需要 padding
CTR 模式加密 + 認證標籤(Authentication Tag)
特點:
✅ 同時提供加密和完整性驗證
✅ 可偵測資料被竄改
✅ TLS 1.2/1.3 的預設模式
| 模式 |
平行處理 |
需要 IV |
認證 |
推薦度 |
| ECB |
✅ |
❌ |
❌ |
❌ 不要用 |
| CBC |
❌ |
✅ |
❌ |
⚠️ 可用 |
| CTR |
✅ |
✅ |
❌ |
⚠️ 可用 |
| GCM |
✅ |
✅ |
✅ |
✅ 推薦 |
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
key = AESGCM.generate_key(bit_length=256)
aesgcm = AESGCM(key)
nonce = os.urandom(12)
plaintext = b"Hello, World!"
associated_data = b"header"
ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data)
decrypted = aesgcm.decrypt(nonce, ciphertext, associated_data)
print(decrypted)
openssl enc -aes-256-gcm -salt -in plaintext.txt -out encrypted.bin -pass pass:mypassword
openssl enc -aes-256-gcm -d -in encrypted.bin -out decrypted.txt -pass pass:mypassword
非對稱式加密使用一對金鑰:公鑰(public key)和私鑰(private key)。
公鑰加密 私鑰解密
──────── ────────
明文 ─────────────→ 密文 ─────────────→ 明文
│ │
│ 公鑰(任何人可持有)│ 私鑰(僅持有者可用)
└────────────────────┘
數學關係:
公鑰加密的內容 → 只有對應的私鑰能解密
私鑰簽署的內容 → 任何人可用公鑰驗證
1. 加密通訊(Encryption)
─────────────────────
發送方用「接收方的公鑰」加密
接收方用「自己的私鑰」解密
目的:確保只有接收方能讀取
2. 數位簽章(Digital Signature)
─────────────────────────
發送方用「自己的私鑰」簽署
接收方用「發送方的公鑰」驗證
目的:確認發送方身份、確保內容未被竄改
| 優點 |
缺點 |
| ✅ 解決金鑰分發問題 |
❌ 運算速度慢(比對稱慢 100-1000 倍) |
| ✅ 可實現數位簽章 |
❌ 不適合加密大量資料 |
| ✅ 可驗證身份 |
❌ 金鑰長度需要更長 |
| 項目 |
說明 |
| 全名 |
Rivest-Shamir-Adleman |
| 原理 |
基於大質數分解的困難性 |
| 金鑰長度 |
2048 / 3072 / 4096 bits |
| 用途 |
加密、數位簽章、金鑰交換 |
| 狀態 |
✅ 廣泛使用,但逐漸被 ECC 取代 |
RSA 原理簡化:
1. 選擇兩個大質數 p, q
2. 計算 n = p × q
3. 公鑰 = (n, e)
4. 私鑰 = (n, d)
5. 加密:C = M^e mod n
6. 解密:M = C^d mod n
安全性基於:
已知 n 很難分解回 p 和 q(大數分解問題)
| 項目 |
說明 |
| 全名 |
Elliptic Curve Cryptography |
| 原理 |
基於橢圓曲線離散對數問題 |
| 金鑰長度 |
256 / 384 bits(等效安全性更短) |
| 用途 |
數位簽章(ECDSA)、金鑰交換(ECDH) |
| 狀態 |
✅ 現代標準,逐漸取代 RSA |
ECC vs RSA 金鑰長度對照(等效安全性):
┌──────────────┬──────────────┐
│ ECC 金鑰 │ RSA 金鑰 │
├──────────────┼──────────────┤
│ 256 bits │ 3072 bits │
│ 384 bits │ 7680 bits │
│ 521 bits │ 15360 bits │
└──────────────┴──────────────┘
ECC 優勢:更短的金鑰、更快的運算、更小的憑證
| 曲線名稱 |
位元數 |
說明 |
| P-256 (secp256r1) |
256 |
NIST 標準,廣泛使用 |
| P-384 (secp384r1) |
384 |
更高安全性 |
| P-521 (secp521r1) |
521 |
最高安全性 |
| Curve25519 |
256 |
現代設計,高效能 |
| secp256k1 |
256 |
Bitcoin 使用 |
| 項目 |
說明 |
| 全名 |
Digital Signature Algorithm |
| 用途 |
僅用於數位簽章(不能加密) |
| 狀態 |
⚠️ 逐漸被 ECDSA 取代 |
| 項目 |
說明 |
| 基於 |
Curve25519 橢圓曲線 |
| 特點 |
快速、安全、實作簡單 |
| 用途 |
SSH 金鑰、數位簽章 |
| 狀態 |
✅ 現代推薦選擇 |
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048
)
public_key = private_key.public_key()
message = b"Hello, RSA!"
ciphertext = public_key.encrypt(
message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
plaintext = private_key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
print(plaintext)
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -pubout -out public.pem
openssl ecparam -genkey -name prime256v1 -out ec_private.pem
openssl genpkey -algorithm Ed25519 -out ed25519_private.pem
| 特性 |
Hash 雜湊 |
對稱加密 |
非對稱加密 |
| 目的 |
產生固定長度 Hash 值 |
加密資料保密 |
金鑰交換、身份驗證 |
| 可逆性 |
❌ 單向不可逆 |
✅ 雙向可逆 |
✅ 雙向可逆 |
| 金鑰 |
無需金鑰 |
單一金鑰 |
公鑰 + 私鑰 |
| 速度 |
非常快 |
快 |
慢(100-1000x) |
| 輸出長度 |
固定 |
與輸入相關 |
與輸入相關 |
| 金鑰分發 |
N/A |
需安全通道 |
公鑰可公開 |
| 代表演算法 |
SHA-256, Argon2 |
AES-256 |
RSA, ECC |
需要驗證資料完整性?
├── Yes → Hash(SHA-256)
└── No ↓
需要加密資料?
├── Yes ↓
│ 需要雙方共享秘密?
│ ├── Yes → 對稱加密(AES-GCM)
│ └── No ↓
│ 需要安全交換金鑰?
│ └── Yes → 非對稱加密(RSA/ECC)
└── No ↓
需要數位簽章?
├── Yes → 非對稱加密(ECDSA/Ed25519)
└── No → 可能不需要加密
現實世界通常混合使用這三種技術:
HTTPS/TLS 握手流程:
─────────────────────
1. 非對稱加密:交換對稱金鑰
Client → Server: 用 Server 公鑰加密的對稱金鑰
2. 對稱加密:加密實際資料
Client ⇄ Server: 用對稱金鑰加密的資料
3. Hash + 數位簽章:驗證身份和完整性
Server → Client: 憑證(含公鑰 + CA 簽章)
為什麼混合使用?
├── 非對稱加密:解決金鑰分發問題,但速度慢
├── 對稱加密:高效加密大量資料
└── Hash:確保資料完整性
❌ 錯誤做法:
明文儲存密碼
MD5/SHA-1 儲存密碼
✅ 正確做法:
使用 Argon2id(首選)或 bcrypt
實作:
password = "user_password"
hash = argon2id(password, salt, memory=64MB, iterations=3, parallelism=4)
# 儲存 hash 到資料庫
sha256sum important_file.zip > checksum.txt
sha256sum -c checksum.txt
import hmac
import hashlib
import time
def sign_request(api_key, secret_key, params):
timestamp = str(int(time.time()))
message = f"{api_key}{timestamp}{sorted(params.items())}"
signature = hmac.new(
secret_key.encode(),
message.encode(),
hashlib.sha256
).hexdigest()
return {
'api_key': api_key,
'timestamp': timestamp,
'signature': signature,
**params
}
from cryptography.fernet import Fernet
key = Fernet.generate_key()
cipher = Fernet(key)
sensitive_data = b"credit_card_number"
encrypted = cipher.encrypt(sensitive_data)
decrypted = cipher.decrypt(encrypted)
JWT 結構:
Header.Payload.Signature
Header: {"alg": "RS256", "typ": "JWT"} ← Base64
Payload: {"sub": "user123", "exp": ...} ← Base64
Signature: RS256(Header.Payload, private_key) ← 非對稱簽章
驗證流程:
1. Base64 解碼 Header 和 Payload
2. 用公鑰驗證 Signature
3. 檢查 Payload 中的過期時間
| Hash |
加密 |
| 單向,不可還原 |
雙向,可以解密 |
| 用於驗證、指紋 |
用於保護資料機密性 |
| 輸出固定長度 |
輸出與輸入相關 |
SHA-256 太快了!
假設:
- SHA-256 每秒可計算 10 億次
- 8 位數字密碼:10^8 種組合
- 暴力破解時間:0.1 秒
bcrypt/Argon2 設計為慢速:
- 每秒僅能計算數千次
- 暴力破解時間:數年
Salt = 隨機字串,加在密碼前再 Hash
目的:
1. 防止彩虹表攻擊
2. 相同密碼產生不同 Hash
user1: password123 + salt1 → hash1
user2: password123 + salt2 → hash2
即使密碼相同,Hash 也不同
選擇 ECC:
├── 效能優先(行動裝置、IoT)
├── 頻寬有限
├── 新系統開發
└── TLS 1.3
選擇 RSA:
├── 相容性優先
├── 既有系統維護
└── 特定硬體需求
AES-128:
✅ 對目前技術足夠安全
✅ 效能較好
✅ 一般應用推薦
AES-256:
✅ 更長的安全期限
✅ 抵抗量子計算(理論上)
✅ 政府/軍事/金融級需求
密碼學三劍客:
─────────────
Hash 雜湊 → 產生指紋,驗證完整性
├── 推薦:SHA-256(通用)、Argon2id(密碼)
└── 用途:密碼儲存、檔案校驗、數位簽章輔助
對稱加密 → 高效加密大量資料
├── 推薦:AES-256-GCM
└── 用途:資料加密、磁碟加密、通訊加密
非對稱加密 → 安全金鑰交換、身份驗證
├── 推薦:ECC(新系統)、RSA-2048+(相容性)
└── 用途:金鑰交換、數位簽章、憑證
| 需求 |
推薦方案 |
| 密碼儲存 |
Argon2id |
| 檔案校驗 |
SHA-256 |
| 資料加密 |
AES-256-GCM |
| 金鑰交換 |
ECDH (Curve25519) |
| 數位簽章 |
Ed25519 / ECDSA |
| TLS/HTTPS |
ECC + AES-GCM |
| SSH 金鑰 |
Ed25519 |
✅ 使用成熟、經過驗證的演算法
✅ 使用足夠長的金鑰
✅ 正確使用隨機 IV/Nonce
✅ 使用認證加密(如 GCM)
✅ 安全儲存金鑰
❌ 不要自己發明加密演算法
❌ 不要使用 MD5/SHA-1 於安全用途
❌ 不要使用 ECB 模式
❌ 不要重複使用 IV/Nonce
❌ 不要在程式碼中寫死金鑰
建立日期:2025-12-16
最後更新:2025-12-16