🔐 非对称加密算法

使用公钥和私钥配对,解决密钥分发难题,实现安全通信和数字签名

🔑 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
密钥生成
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

🔑 密钥交换过程

1
协商参数
Alice 和 Bob 公开协商 p 和 g
2
生成公私钥
Alice 计算 A = gᵃ mod p
Bob 计算 B = gᵇ mod p
3
交换公钥
Alice 发送 A 给 Bob
Bob 发送 B 给 Alice
4
计算共享密钥
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(椭圆曲线离散对数问题)

🔑 密钥长度对比

  • 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 标准)