# pip install cryptography==36.0.1fromcryptography.hazmat.primitivesimporthashesfromcryptography.hazmat.primitives.asymmetricimportdh# 1. 双方协商使用两个独特的正整数 g 与 p## generator => 即基数 g,通常使用 2, 有时也使用 5## key_size => 模数 p 的长度,通常使用 2048-3072 位(2048 位的安全性正在减弱)params=dh.generate_parameters(generator=2,key_size=2048)param_numbers=params.parameter_numbers()g=param_numbers.g# => 肯定是 2p=param_numbers.p# => 一个 2048 位的整数print(f"{g=}, {p=}")# 2. Alice 生成自己的秘密整数 a 与公开整数 Aalice_priv_key=params.generate_private_key()a=alice_priv_key.private_numbers().xA=alice_priv_key.private_numbers().public_numbers.yprint(f"{a=}")print(f"{A=}")# 3. Bob 生成自己的秘密整数 b 与公开整数 Bbob_priv_key=params.generate_private_key()b=bob_priv_key.private_numbers().xB=bob_priv_key.private_numbers().public_numbers.yprint(f"{b=}")print(f"{B=}")# 4. Alice 与 Bob 公开交换整数 A 跟 B(即各自的公钥)# 5. Alice 使用 a B 与 p 计算出共享密钥## 首先使用 B p g 构造出 bob 的公钥对象(实际上 g 不参与计算)bob_pub_numbers=dh.DHPublicNumbers(B,param_numbers)bob_pub_key=bob_pub_numbers.public_key()## 计算共享密钥alice_shared_key=alice_priv_key.exchange(bob_pub_key)# 6. Bob 使用 b A 与 p 计算出共享密钥## 首先使用 A p g 构造出 alice 的公钥对象(实际上 g 不参与计算)alice_pub_numbers=dh.DHPublicNumbers(A,param_numbers)alice_pub_key=alice_pub_numbers.public_key()## 计算共享密钥bob_shared_key=bob_priv_key.exchange(alice_pub_key)# 两者应该完全相等, Alice 与 Bob 完成第一次密钥交换alice_shared_key==bob_shared_key# 7. Alice 与 Bob 使用 shared_key 进行对称加密通讯
# pip install tinyec # ECC 曲线库fromtinyecimportregistryimportsecretsdefcompress(pubKey):returnhex(pubKey.x)+hex(pubKey.y%2)[2:]curve=registry.get_curve('brainpoolP256r1')alicePrivKey=secrets.randbelow(curve.field.n)alicePubKey=alicePrivKey*curve.gprint("Alice public key:",compress(alicePubKey))bobPrivKey=secrets.randbelow(curve.field.n)bobPubKey=bobPrivKey*curve.gprint("Bob public key:",compress(bobPubKey))print("Now exchange the public keys (e.g. through Internet)")aliceSharedKey=alicePrivKey*bobPubKeyprint("Alice shared key:",compress(aliceSharedKey))bobSharedKey=bobPrivKey*alicePubKeyprint("Bob shared key:",compress(bobSharedKey))print("Equal shared keys:",aliceSharedKey==bobSharedKey)
# pip install cryptography==36.0.1fromcryptography.hazmat.primitivesimporthashesfromcryptography.hazmat.primitives.asymmetricimportdh# 1. 双方协商使用两个独特的正整数 g 与 p## generator => 即基数 g,通常使用 2, 有时也使用 5## key_size => 模数 p 的长度,通常使用 2048-3072 位(2048 位的安全性正在减弱)params=dh.generate_parameters(generator=2,key_size=2048)param_numbers=params.parameter_numbers()g=param_numbers.g# => 肯定是 2p=param_numbers.p# => 一个 2048 位的整数print(f"{g=}, {p=}")# 2. Alice 生成自己的秘密整数 a 与公开整数 Aalice_priv_key=params.generate_private_key()a=alice_priv_key.private_numbers().xA=alice_priv_key.private_numbers().public_numbers.yprint(f"{a=}")print(f"{A=}")# 3. Bob 生成自己的秘密整数 b 与公开整数 Bbob_priv_key=params.generate_private_key()b=bob_priv_key.private_numbers().xB=bob_priv_key.private_numbers().public_numbers.yprint(f"{b=}")print(f"{B=}")# 4. Alice 与 Bob 公开交换整数 A 跟 B(即各自的公钥)# 5. Alice 使用 a B 与 p 计算出共享密钥## 首先使用 B p g 构造出 bob 的公钥对象(实际上 g 不参与计算)bob_pub_numbers=dh.DHPublicNumbers(B,param_numbers)bob_pub_key=bob_pub_numbers.public_key()## 计算共享密钥alice_shared_key=alice_priv_key.exchange(bob_pub_key)# 6. Bob 使用 b A 与 p 计算出共享密钥## 首先使用 A p g 构造出 alice 的公钥对象(实际上 g 不参与计算)alice_pub_numbers=dh.DHPublicNumbers(A,param_numbers)alice_pub_key=alice_pub_numbers.public_key()## 计算共享密钥bob_shared_key=bob_priv_key.exchange(alice_pub_key)# 上面的流程跟经典 DHKE 完全一致,代码也是从前面 Copy 下来的# 但是从这里开始,进入 DHE 协议补充的部分shared_key_1=bob_shared_key# 第一个共享密钥# 7. 假设 Bob 现在要发送消息 M_b_1 给 Alice## 首先 Bob 使用对称加密算法加密消息 M_bM_b_1="Hello Alice, I'm bob~"C_b_1=Encrypt(M_b_1,shared_key_1)# Encrypt 是某种对称加密方案的加密算法,如 AES-256-CTR-HMAC-SHA-256## 然后 Bob 需要生成一个新的公私钥 b_2 与 B_2(注意 g 与 p 两个参数是不变的)bob_priv_key_2=parameters.generate_private_key()b_2=bob_priv_key.private_numbers().xB_2=bob_priv_key.private_numbers().public_numbers.yprint(f"{b_2=}")print(f"{B_2=}")# 8. Bob 将 C_b_1 与 B_2 一起发送给 Alice# 9. Alice 首先解密数据 C_b_1 得到原始消息 M_b_1assertM_b_1==Decrypt(C_b_1,shared_key_1)# Dncrypt 是某种对称加密方案的解密算法,如 AES-256-CTR-HMAC-SHA-256## 然后 Alice 也生成新的公私钥 a_2 与 A_2alice_priv_key_2=parameters.generate_private_key()## Alice 使用 a_2 B_2 与 p 计算出新的共享密钥 shared_key_2bob_pub_numbers_2=dh.DHPublicNumbers(B_2,param_numbers)bob_pub_key_2=bob_pub_numbers_2.public_key()shared_key_2=alice_priv_key_2.exchange(bob_pub_key_2)# 10. Alice 回复 Bob 消息时,使用新共享密钥 shared_key_2 加密消息得到 C_a_1# 然后将密文 C_a_1 与 A_2 一起发送给 Bob# 11. Bob 使用 b_2 A_2 与 p 计算出共享密钥 shared_key_2# 然后再使用 shared_key_2 解密数据# Bob 在下次发送消息时,会生成新的 b_3 与 B_3,将 B_3 随密文一起发送## 依次类推
通过上面的代码描述我们应该能理解到,Alice 与 Bob 每次交换数据,实际上都会生成新的临时共享密钥,公钥密钥在每次数据交换时都会更新。即使攻击者花了很大的代价破解了其中某一个临时共享密钥 shared_key_k(或者该密钥因为某种原因泄漏了),TA 也只能解密出其中某一次数据交换的信息 M_b_k,其他所有的消息仍然是保密的,不受此次攻击(或泄漏)的影响。