1. 概要
ECC英文全称"Ellipse Curve Cryptography"
与传统的基于大质数因子分解困难性的加密方法不同,ECC通过椭圆曲线方程式性质产生密钥。ECC164位的密钥产生一个安全级,相当于RSA 1024位密钥提供的保密强度,而且计算量较小,处理速度更快,存储空间和传输带宽占用较少。目前我国居民二代身份证正在使用 256 位的椭圆曲线密码,虚拟货币比特币也选择ECC作为加密算法。
ECC = 椭圆曲线密码学
它是一种 公钥密码算法,和 RSA 一样用于加密、签名、密钥交换,但 ECC 更"轻量"、更安全、速度更快。
一句话总结:
👉 用更小的密钥实现同等甚至更高的安全性
2. ECC的几何动作
ECC的基本动作:点加 & 点倍乘(核心)
ECC 的计算不是加减乘除,而是:
- 点加( P + Q )
- 点倍乘( kP )
这是椭圆曲线上的几何动作。
2.1 点加( P + Q )
步骤简单但很巧妙:
(1) 两点 P 和 Q 在曲线上
都是真实的 (x, y)
(2) 画一条直线连接 P 到 Q
(3) 这条直线会在曲线上再撞一个点,叫 R′
这是 ECC 的几何性质:直线总会与曲线交三次。
(4) 把 R′ 沿 x 轴翻转 → 得到 R
这个 R 就是:
R=P+Q

2.2 点倍乘( kP )
点倍乘就是:
kP=P+P+P+...(加 k 次)

3. ECC 的私钥、公钥怎么来的?
非常简单:
🔐 私钥 = 任意一个 256 位的随机数 d
例如:
d = 0xC8F1A93D...
🔓 公钥 = 点倍乘计算得到:
Q=dG
其中:
- G是椭圆曲线固定基点
- 通过点倍乘可算出 Q
3.1 为什么 ECC 安全?(关键细节)
关键原因就 1 个:
✨ 椭圆曲线离散对数问题( ECDLP )难到爆炸
已知:
- G
- Q = dG
求 d → 不可能。
因为:
- d 是 256 位随机数
- 暴力破解需要 2²⁵⁶ 次
- 相当于 10⁷⁷ 次
这数字比银河系里的原子还多。所有攻击都无法反推出私钥。
4. ECC常见用途
- 🔐 密钥交换 ECDH
- 🪪 数字签名 ECDSA
- 🔒 加密 ECIES
4.1 密钥交换 ECDH
ECDH 完整流程
假设 Alice 和 Bob 想建立安全通信。
Step 1 :选择公共参数(公开)
- 椭圆曲线 E(比如 secp256r1)
- 基点 G
任何人都能看到这些参数。
Step 2 :双方生成自己的私钥与公钥
Alice :
- 私钥:a(随机大整数)
- 公钥:A = aG
Bob :
- 私钥:b(随机大整数)
- 公钥:B = bG
私钥 不能泄露
公钥 可以公开
Step 3 :交换公钥 A 与 B
Alice → Bob:发送 A
Bob → Alice:发送 B
⚠ 过程中不需要加密,因为公钥泄露也没问题。
Step 4 :双方计算共享密钥
Alice 计算:
K=aB=a(bG)=abG
Bob 计算:
K=bA=b(aG)=abG
结果完全一致!
4.2 数字签名 ECDSA


4.2.1 曲线阶 n
曲线阶 n = 把点 G 不断相加,最终回到起点所需要的次数。
🧸 更直观的比喻
想象你站在一个圆圈上,有一个"起点":
你每走一步,就是"加一次 G"(G 就是一种"固定的走法")。
不断走:
G
2G
3G
4G
...
终于,有一天你绕了一圈,又回到起点:
nG = 起点
➜ 这个"绕一圈所需要的步数"就叫 曲线阶 n。
4.2.2 举个例子
签名


验签






4.3 加密 ECIES
ECIES 属于"混合加密"(Hybrid Encryption):
- 使用椭圆曲线 Diffie--Hellman ( ECDH ) 协商密钥
- 发送方用自己的临时私钥和接收方的长期公钥计算共享密钥
- 从共享密钥中导出对称密钥
- 使用 KDF(Key Derivation Function)
- 用对称密钥(比如 AES )加密消息
- 使用 MAC (如 HMAC )保证完整性和防篡改
🔵 步骤 1 :接收方提供自己的 ECC 公钥
发送方需要接收方的公钥:
receiverPublicKey
它仅用于生成共享密钥。
📌 它不需要保密,可公开。
🔵 步骤 2 :发送方生成 " 临时密钥对 "
发送方生成:
ephemeralPrivateKey
ephemeralPublicKey
这个临时密钥只为"这一次加密服务"。
📌 为什么需要临时密钥?
- 提供 前向安全性( Forward Secrecy )
- 即使长期密钥被泄露,过去的消息仍无法解密
🔵 步骤 3 :使用 ECDH 计算共享秘密 Shared Secret
ECDH 的本质就是:
"你的私钥 × 对方的公钥 = 一个只有你们能算出的点"
发送方计算:
sharedSecret = ECDH(ephemeralPrivateKey, receiverPublicKey)
注意:
- 这是一个"大数字"或"点"
- 它本身不能直接拿来加密
🔵 步骤 4 :使用 KDF 从 Shared Secret 派生两把密钥
使用 HKDF / ANSI KDF 进行派生:
(k_enc, k_mac) = KDF(sharedSecret)
📌 为什么要 KDF?
SharedSecret 本身不均匀、也不适合作为 AES 密钥。
KDF 可以把它"拉伸成":
- k_enc:对称加密密钥
- k_mac:认证用密钥
📌 为什么是两把?
因为:
- 一个负责加密
- 另一个负责认证
- 不能混用(否则不安全)
🔵 步骤 5 :用 k_enc 加密明文,得到密文
ciphertext = Encrypt(k_enc, plaintext)
通常使用:
- AES-CTR / AES-GCM
- 或 ChaCha20
🔵 步骤 6 :使用 k_mac 生成消息认证码( MAC )
tag = HMAC(k_mac, ciphertext)
作用:
- 确保数据没有被修改
- 接收方可以发现篡改
这一步是 ECIES 能"防止密文被动或主动攻击"的核心。
🔵 步骤 7 :发送方把三个东西发过去
发送方发送:
ephemeralPublicKey
ciphertext
tag
📌 为什么要发送临时公钥?
接收方需要它才能复现 sharedSecret。
🟧 接收方的 4 个步骤
🔵 步骤 8 :接收方使用自己的私钥 + 临时公钥重建 Shared Secret
接收方计算:
sharedSecret = ECDH(receiverPrivateKey, ephemeralPublicKey)
数学上保证这和发送方算的一样。
这叫做 密钥一致性( Key Agreement )。
🔵 步骤 9 :使用同样的 KDF 派生 k_enc 和 k_mac
接收方执行:
(k_enc, k_mac) = KDF(sharedSecret)
因为 KDF 和输入都一样,所以输出也一样。
🔵 步骤 10 :验证消息完整性(使用 tag )
接收方计算:
tag' = HMAC(k_mac, ciphertext)
并比较:
tag' == tag ?
如果不一致:
❌ 密文被篡改
❌ 或密钥不匹配
❌ 或攻击者伪造数据
此时必须丢弃消息。
🔵 步骤 11 :使用 k_enc 解密密文,得到明文
plaintext = Decrypt(k_enc, ciphertext)
只有在 MAC 验证成功后才进行。