🔐 非对称加密算法
使用公钥和私钥配对,解决密钥分发难题,实现安全通信和数字签名
🔑 RSA
最广泛使用的非对称加密算法,基于大数分解难题。用于加密和数字签名。
🤝 Diffie-Hellman
密钥交换协议,允许双方在不安全信道上协商共享密钥。
🌀 ECC 椭圆曲线
基于椭圆曲线数学理论,相同安全强度下密钥更短,效率更高。
✍️ 数字签名
验证消息完整性和发送者身份,防止抵赖和篡改。
💡 非对称加密核心概念
🔑 双密钥机制
公钥加密,私钥解密;私钥签名,公钥验证
📐 数学基础
大数分解、离散对数、椭圆曲线难题
🔒 安全通信
解决密钥分发问题,实现机密通信
✍️ 数字签名
验证身份和完整性,防止抵赖
⚖️ 对称加密 vs 非对称加密
| 特性 | 对称加密 | 非对称加密 |
|---|---|---|
| 密钥数量 | 1 个共享密钥 | 2 个(公钥 + 私钥) |
| 密钥分发 | 困难,需要安全通道 | 简单,公钥可公开 |
| 计算速度 | 快(适合大数据) | 慢(100-1000 倍) |
| 典型算法 | AES, DES, ChaCha20 | RSA, ECC, DH |
| 适用场景 | 大量数据加密 | 密钥交换、数字签名 |
🔑 1. RSA 算法
算法原理
RSA 以三位发明者 Rivest、Shamir、Adleman 的名字命名,其安全性基于大整数分解的困难性:已知 n = p × q 很难分解出 p 和 q。
密钥生成:
n = p × q(模数)
φ(n) = (p-1) × (q-1)(欧拉函数)
e × d ≡ 1 (mod φ(n))(公钥 e,私钥 d)
加密: C = Mᵉ mod n
解密: M = Cᵈ mod n
n = p × q(模数)
φ(n) = (p-1) × (q-1)(欧拉函数)
e × d ≡ 1 (mod φ(n))(公钥 e,私钥 d)
加密: C = Mᵉ mod n
解密: M = Cᵈ mod n
密钥生成
O(√n)
加密/解密
O(log³n)
安全基础
大数分解
✅ 优点
- 算法成熟,广泛应用
- 同时支持加密和签名
- 实现简单,易于理解
- 标准化程度高
❌ 缺点
- 密钥长度要求长
- 计算速度慢
- 量子计算威胁
- 需要大素数生成
RSA 密钥长度与安全级别
| 密钥长度 | 安全级别 | 预计安全年限 | 推荐使用场景 |
|---|---|---|---|
| 1024 位 | 低 | 已不安全 | 不推荐使用 |
| 2048 位 | 高 | 2030 年 | 当前标准 |
| 3072 位 | 高 | 2035 年 | 长期安全 |
| 4096 位 | 高 | 2040 年后 | 高安全需求 |
代码实现
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.backends import default_backend
# 生成 RSA 密钥对
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
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
)
)
print(f"密文:{ciphertext.hex()[:50]}...")
# 解密
plaintext = private_key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
print(f"明文:{plaintext.decode()}")
# 签名
signature = private_key.sign(
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
# 验证签名
try:
public_key.verify(
signature,
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
print("签名验证成功!")
except Exception as e:
print(f"签名验证失败:{e}")const crypto = require('crypto');
// 生成 RSA 密钥对
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicExponent: 0x10001,
privateKeyEncoding: { type: 'pkcs1', format: 'pem' },
publicKeyEncoding: { type: 'pkcs1', format: 'pem' }
});
// 加密
const message = "Hello, RSA!";
const encrypted = crypto.publicEncrypt(
{ key: publicKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING },
Buffer.from(message)
);
console.log("加密:", encrypted.toString('base64').substring(0, 50) + "...");
// 解密
const decrypted = crypto.privateDecrypt(
{ key: privateKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING },
encrypted
);
console.log("解密:", decrypted.toString('utf8'));
// 签名
const sign = crypto.createSign('SHA256');
sign.update(message);
sign.end();
const signature = sign.sign(privateKey).toString('base64');
console.log("签名:", signature.substring(0, 50) + "...");
// 验证签名
const verify = crypto.createVerify('SHA256');
verify.update(message);
verify.end();
const isValid = verify.verify(publicKey, Buffer.from(signature, 'base64'));
console.log("签名验证:", isValid);package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"fmt"
)
func main() {
// 生成 RSA 密钥对
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
publicKey := &privateKey.PublicKey
// 加密
message := []byte("Hello, RSA!")
ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, message, nil)
if err != nil {
panic(err)
}
fmt.Printf("密文:%s\n", hex.EncodeToString(ciphertext)[:50]+"...")
// 解密
plaintext, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, ciphertext, nil)
if err != nil {
panic(err)
}
fmt.Printf("明文:%s\n", string(plaintext))
// 签名
hashed := sha256.Sum256(message)
signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed[:])
if err != nil {
panic(err)
}
fmt.Printf("签名:%s\n", hex.EncodeToString(signature)[:50]+"...")
// 验证签名
err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, hashed[:], signature)
if err != nil {
fmt.Printf("签名验证失败:%v\n", err)
} else {
fmt.Println("签名验证成功!")
}
// 保存私钥到 PEM
privBytes := x509.MarshalPKCS1PrivateKey(privateKey)
privPEM := pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privBytes,
})
fmt.Printf("\n私钥 PEM:\n%s\n", string(privPEM)[:100]+"...")
}🤝 2. Diffie-Hellman 密钥交换
算法原理
Diffie-Hellman(DH)算法允许双方在不安全信道上协商出一个共享密钥,用于后续的对称加密通信。安全性基于离散对数问题的困难性。
公共参数: 大素数 p,本原根 g
Alice: 选择私钥 a,计算 A = gᵃ mod p
Bob: 选择私钥 b,计算 B = gᵇ mod p
共享密钥: K = gᵃᵇ mod p = Aᵇ mod p = Bᵃ mod p
Alice: 选择私钥 a,计算 A = gᵃ mod p
Bob: 选择私钥 b,计算 B = gᵇ mod p
共享密钥: K = gᵃᵇ mod p = Aᵇ mod p = Bᵃ mod p
🔑 密钥交换过程
1
协商参数
Alice 和 Bob 公开协商 p 和 g
Alice 和 Bob 公开协商 p 和 g
2
生成公私钥
Alice 计算 A = gᵃ mod p
Bob 计算 B = gᵇ mod p
Alice 计算 A = gᵃ mod p
Bob 计算 B = gᵇ mod p
3
交换公钥
Alice 发送 A 给 Bob
Bob 发送 B 给 Alice
Alice 发送 A 给 Bob
Bob 发送 B 给 Alice
4
计算共享密钥
Alice 计算 K = Bᵃ mod p
Bob 计算 K = Aᵇ mod p
Alice 计算 K = Bᵃ mod p
Bob 计算 K = Aᵇ mod p
密钥交换
O(log³n)
安全基础
离散对数
前向安全
支持
代码实现
from cryptography.hazmat.primitives.asymmetric import dh
from cryptography.hazmat.backends import default_backend
# 使用标准 DH 参数(2048 位)
p = int("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC"
"2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
"83655D23DCA3AD961C62F356208552BB9ED529077096966D"
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
"15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
g = 2
# 生成参数
parameters = dh.DHParameterNumbers(p, g)
# Alice 生成密钥对
alice_private = parameters.generate_private_key()
alice_public = alice_private.public_key()
# Bob 生成密钥对
bob_private = parameters.generate_private_key()
bob_public = bob_private.public_key()
# 计算共享密钥
alice_shared = alice_private.exchange(bob_public)
bob_shared = bob_private.exchange(alice_public)
print(f"Alice 共享密钥:{alice_shared.hex()[:50]}...")
print(f"Bob 共享密钥:{bob_shared.hex()[:50]}...")
print(f"密钥匹配:{alice_shared == bob_shared}")package main
import (
"crypto/rand"
"crypto/sha256"
"crypto/subtle"
"encoding/hex"
"fmt"
"math/big"
)
// RFC 3526 2048 位 MODP 组
var (
p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"+
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"+
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"+
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"+
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC"+
"2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"+
"83655D23DCA3AD961C62F356208552BB9ED529077096966D"+
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"+
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"+
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510"+
"15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
g = big.NewInt(2)
)
func generatePrivateKey() *big.Int {
priv, _ := rand.Int(rand.Reader, p)
return priv
}
func computePublicKey(priv *big.Int) *big.Int {
return new(big.Int).Exp(g, priv, p)
}
func computeSharedKey(priv, pub *big.Int) []byte {
shared := new(big.Int).Exp(pub, priv, p)
hash := sha256.Sum256(shared.Bytes())
return hash[:]
}
func main() {
// Alice 生成密钥对
alicePriv := generatePrivateKey()
alicePub := computePublicKey(alicePriv)
// Bob 生成密钥对
bobPriv := generatePrivateKey()
bobPub := computePublicKey(bobPriv)
// 计算共享密钥
aliceShared := computeSharedKey(alicePriv, bobPub)
bobShared := computeSharedKey(bobPriv, alicePub)
fmt.Printf("Alice 共享密钥:%s\n", hex.EncodeToString(aliceShared)[:50]+"...")
fmt.Printf("Bob 共享密钥:%s\n", hex.EncodeToString(bobShared)[:50]+"...")
fmt.Printf("密钥匹配:%v\n", subtle.ConstantTimeCompare(aliceShared, bobShared) == 1)
}🌀 3. ECC 椭圆曲线加密
算法原理
ECC 基于椭圆曲线数学理论,在相同安全强度下,ECC 密钥长度远短于 RSA,计算更快,资源消耗更少。
椭圆曲线方程: y² = x³ + ax + b
密钥生成: 私钥 d(随机数),公钥 Q = d × G
G: 曲线上的基点(公开参数)
安全性: 已知 G 和 Q,很难计算出 d(椭圆曲线离散对数问题)
密钥生成: 私钥 d(随机数),公钥 Q = d × G
G: 曲线上的基点(公开参数)
安全性: 已知 G 和 Q,很难计算出 d(椭圆曲线离散对数问题)
🔑 密钥长度对比
- RSA 2048 位 ≈ ECC 256 位
- RSA 3072 位 ≈ ECC 384 位
- RSA 7680 位 ≈ ECC 512 位
- ECC 密钥短 10-30 倍
⚡ 性能优势
- 计算速度更快
- 内存占用更小
- 带宽需求更低
- 适合移动设备和 IoT
常用椭圆曲线
| 曲线名称 | 密钥长度 | 安全级别 | 应用场景 |
|---|---|---|---|
| secp256k1 | 256 位 | 128 位 | Bitcoin, Ethereum |
| P-256 | 256 位 | 128 位 | TLS, 政府应用 |
| P-384 | 384 位 | 192 位 | 高安全需求 |
| Curve25519 | 255 位 | 128 位 | SSH, Signal 协议 |
代码实现
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.backends import default_backend
# 生成 ECC 密钥对(使用 P-256 曲线)
private_key = ec.generate_private_key(ec.SECP256R1(), default_backend())
public_key = private_key.public_key()
print(f"私钥长度:{private_key.key_size} 位")
print(f"公钥长度:{public_key.key_size} 位")
# ECDH 密钥交换
alice_private = ec.generate_private_key(ec.SECP256R1(), default_backend())
bob_private = ec.generate_private_key(ec.SECP256R1(), default_backend())
alice_shared = alice_private.exchange(ec.ECDH(), bob_private.public_key())
bob_shared = bob_private.exchange(ec.ECDH(), alice_private.public_key())
print(f"\nAlice 共享密钥:{alice_shared.hex()[:50]}...")
print(f"Bob 共享密钥:{bob_shared.hex()[:50]}...")
print(f"密钥匹配:{alice_shared == bob_shared}")
# ECDSA 签名
message = b"Hello, ECC!"
signature = private_key.sign(message, ec.ECDSA(hashes.SHA256()))
print(f"\n签名:{signature.hex()[:50]}...")
# 验证签名
try:
public_key.verify(signature, message, ec.ECDSA(hashes.SHA256()))
print("签名验证成功!")
except Exception as e:
print(f"签名验证失败:{e}")package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"math/big"
)
func main() {
// 生成 ECC 密钥对(使用 P-256 曲线)
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
panic(err)
}
publicKey := &privateKey.PublicKey
fmt.Printf("私钥长度:%d 位\n", privateKey.Params().BitSize)
fmt.Printf("公钥长度:%d 位\n", publicKey.Params().BitSize)
// ECDH 密钥交换
alicePriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
bobPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
aliceShared, _ := alicePriv.Curve.ScalarMult(bobPriv.X, bobPriv.Y, alicePriv.D.Bytes())
bobShared, _ := bobPriv.Curve.ScalarMult(alicePriv.X, alicePriv.Y, bobPriv.D.Bytes())
fmt.Printf("\nAlice 共享密钥:%s\n", hex.EncodeToString(aliceShared.Bytes())[:50]+"...")
fmt.Printf("Bob 共享密钥:%s\n", hex.EncodeToString(bobShared.Bytes())[:50]+"...")
fmt.Printf("密钥匹配:%v\n", aliceShared.Cmp(bobShared) == 0)
// ECDSA 签名
message := []byte("Hello, ECC!")
hashed := sha256.Sum256(message)
r, s, err := ecdsa.Sign(rand.Reader, privateKey, hashed[:])
if err != nil {
panic(err)
}
fmt.Printf("\n签名 r: %s\n", hex.EncodeToString(r.Bytes())[:50]+"...")
fmt.Printf("签名 s: %s\n", hex.EncodeToString(s.Bytes())[:50]+"...")
// 验证签名
valid := ecdsa.Verify(publicKey, hashed[:], r, s)
fmt.Printf("签名验证:%v\n", valid)
// 显示公钥坐标
fmt.Printf("\n公钥坐标:\n X: %s\n Y: %s\n",
publicKey.X.Text(16)[:32], publicKey.Y.Text(16)[:32])
}🌐 常见应用场景
🔒 TLS/SSL 加密
- HTTPS 安全浏览
- 密钥交换(ECDHE)
- 服务器身份验证
- 保护数据传输
📧 PGP/GPG 邮件加密
- 端到端加密
- 数字签名验证
- 密钥信任网络
- 保护隐私通信
₿ 区块链与加密货币
- 比特币地址生成
- 交易签名验证
- 钱包密钥管理
- 智能合约签名
📱 SSH 安全登录
- 远程服务器登录
- 公钥认证
- 密钥交换(Curve25519)
- Git 代码托管
🎯 算法选择指南
- 通用加密签名:RSA 2048/3072(兼容性好)
- 移动设备/IoT:ECC P-256(资源占用小)
- 密钥交换:ECDH 或 X25519(前向安全)
- 区块链应用:secp256k1(比特币标准)
- 高性能需求:Curve25519/Ed25519
- 政府合规:P-256/P-384(NIST 标准)