椭圆曲线Diffie-Hellman密钥交换(ECDH)

椭圆曲线Diffie-Hellman密钥交换(ECDH)

椭圆曲线密码:https://www.cnblogs.com/luminescence/p/18932875

1. 椭圆曲线基础

1.1 椭圆曲线方程

椭圆曲线由以下方程定义:

y² = x³ + ax + b (mod p)

其中:

  • ab是曲线参数
  • p是一个大素数
  • 所有运算都在模p下进行

1.2 椭圆曲线上的点

Point类表示椭圆曲线上的点:

class Point:
    def __init__(self, x: int = None, y: int = None):
        self.x = x
        self.y = y
    
    def is_infinity(self) -> bool:
        return self.x is None and self.y is None

特殊点无穷远点表示群运算的单位元

2. 椭圆曲线运算

2.1 点加法

椭圆曲线上的点加法运算遵循以下规则:

  1. 单位元:P + ∞ = P
  2. 逆元:P + (-P) = ∞
  3. 点加倍:P + P = 2P
  4. 不同点相加:P + Q = R
    代码实现:
def add(self, p1: Point, p2: Point) -> Point:
    if p1.is_infinity():
        return p2
    if p2.is_infinity():
        return p1
    
    # P + (-P) = 无穷远点
    if p1.x == p2.x and p1.y != p2.y:
        return self.infinity
    
    # 点加倍 P + P
    if p1 == p2:
        if p1.y == 0:
            return self.infinity
        numerator = (3 * p1.x * p1.x + self.a) % self.p
        denominator = (2 * p1.y) % self.p
        lam = (numerator * self.mod_inverse(denominator, self.p)) % self.p
    else:
        # P + Q
        numerator = (p2.y - p1.y) % self.p
        denominator = (p2.x - p1.x) % self.p
        lam = (numerator * self.mod_inverse(denominator, self.p)) % self.p
    
    x3 = (lam * lam - p1.x - p2.x) % self.p
    y3 = (lam * (p1.x - x3) - p1.y) % self.p
    
    return Point(x3, y3)

2.2 标量乘法

标量乘法k*P使用"双倍-加"算法实现:

def multiply(self, k: int, point: Point) -> Point:
    if k == 0:
        return self.infinity
    if k < 0:
        raise ValueError("k 必须为正整数")
    
    result = self.infinity
    addend = point
    
    while k:
        if k & 1:
            result = self.add(result, addend)
        addend = self.add(addend, addend)
        k >>= 1
    
    return result

3. ECDH密钥交换协议

3.1 协议步骤

  1. 双方约定使用相同的椭圆曲线参数和基点G
  2. Alice生成私钥a,计算公钥A = a*G
  3. Bob生成私钥b,计算公钥B = b*G
  4. Alice计算共享密钥S = a*B
  5. Bob计算共享密钥S = b*A
  6. 由于aB = a(bG) = b(aG) = bA,双方得到相同的共享密钥

3.2 实现

class ECDH:
    def __init__(self, curve: EllipticCurve, base_point: Point):
        self.curve = curve
        self.base_point = base_point
        if not curve.is_on_curve(base_point):
            raise ValueError("基点不在曲线上")
    
    def generate_private_key(self, bits: int = 256) -> int:
        """生成私钥"""
        return secrets.randbelow(2**bits - 1) + 1
    
    def compute_public_key(self, private_key: int) -> Point:
        """计算公钥"""
        return self.curve.multiply(private_key, self.base_point)
    
    def compute_shared_secret(self, private_key: int, peer_public_key: Point) -> bytes:
        """计算共享密钥"""
        shared_point = self.curve.multiply(private_key, peer_public_key)
        if shared_point.is_infinity():
            raise ValueError("共享密钥计算失败")
        shared_bytes = shared_point.x.to_bytes((shared_point.x.bit_length() + 7) // 8, 'big')
        return hashlib.sha256(shared_bytes).digest()

4.中间人攻击

MITM

中间人攻击利用未认证的公钥交换过程:
攻击者拦截通信双方(Alice 和 Bob)的公钥交换
攻击者用自己的公钥替换双方接收到的公钥
通信双方与攻击者分别建立共享密钥
攻击者可解密、篡改和重新加密所有通信

攻击过程

class MITM:
    """
    MITM 拦截双方的公钥并用自己的公钥替换,从而与双方分别建立共享密钥
    """
    def __init__(self, ecdh: ECDH):
        self.ecdh = ecdh
        self.priv = ecdh.generate_private_key()
        self.pub = ecdh.compute_public_key(self.priv)

    def intercept_replace(self, original_pub: Point) -> Point:
        """拦截并返回 MITM 的公钥,用以替换原始公钥。"""
        return self.pub

    def compute_shared_with(self, peer_public: Point) -> bytes:
        """使用 MITM 的私钥与真实对端公钥计算共享密钥(供 MITM 自身使用)。"""
        return self.ecdh.compute_shared_secret(self.priv, peer_public)
if __name__ == "__main__":

    mitm = MITM(ecdh)

    # MITM 在 Alice->Bob 的通道上拦截并替换 Alice 的公钥
    bob_received_pub = mitm.intercept_replace(alice_public)

    # MITM 在 Bob->Alice 的通道上拦截并替换 Bob 的公钥
    alice_received_pub = mitm.intercept_replace(bob_public)

    # Alice 和 Bob 使用被替换后的公钥计算共享密钥(实际上各自与 MITM 建立了共享密钥)
    alice_shared_mitm = ecdh.compute_shared_secret(alice_private, alice_received_pub)
    bob_shared_mitm = ecdh.compute_shared_secret(bob_private, bob_received_pub)

    # MITM 使用自己的私钥与真实的 Alice/Bob 公钥分别计算共享密钥
    mitm_secret_with_alice = mitm.compute_shared_with(alice_public)
    mitm_secret_with_bob = mitm.compute_shared_with(bob_public)

    print("--- 含中间人(MITM)攻击示例 ---")
    print(f"MITM 公钥: {mitm.pub}")
    print(f"Alice 看到的(被替换后)公钥: {alice_received_pub}")
    print(f"Bob   看到的(被替换后)公钥: {bob_received_pub}")
    print(f"Alice 计算得到的共享密钥 (与 MITM): {alice_shared_mitm.hex()}")
    print(f"MITM 与 Alice 的共享密钥:{mitm_secret_with_alice.hex()}")
    print(f"Bob   计算得到的共享密钥 (与 MITM): {bob_shared_mitm.hex()}")
    print(f"MITM 与 Bob 的共享密钥:{mitm_secret_with_bob.hex()}")

    print(f"Alice 的共享密钥 == MITM 与 Alice 的密钥:{alice_shared_mitm == mitm_secret_with_alice}")
    print(f"Bob 的共享密钥   == MITM 与 Bob 的密钥:{bob_shared_mitm == mitm_secret_with_bob}")
    print(f"Alice 的共享密钥 == Bob 的共享密钥:{alice_shared_mitm == bob_shared_mitm}")
	
posted @ 2025-11-20 10:47  lumiere_cloud  阅读(30)  评论(0)    收藏  举报