混合公钥加密(HPKE)作为现代加密协议的核心,已在TLS 1.3和隐私增强技术中广泛应用,本文将通过三段关键代码示例,逐层拆解HPKE的运行机制,并对比不同模式的安全特性。
HPKE通过分层设计实现高效安全的加密传输,其核心流程分为三个阶段:
使用非对称加密传递对称密钥种子。发送方通过接收方公钥加密生成:
● 临时共享密钥 shared_secret
● 封装结果 enc(包含临时公钥信息)
接收方用私钥解封装获得相同密钥
采用HKDF将共享密钥扩展为三个核心参数:
● key:对称加密密钥(如AES-GCM-256)
● base_nonce:初始计数器
● exporter_secret:扩展密钥
通过salt和info参数增强随机性
使用对称算法(如AES-GCM-256)加密数据
本地密钥生成:

KEM实现:


HPKE 密钥协商:

加解密封装:

模拟 HPKE 的运行逻辑:

运行效果:

导入pyhpke 包:

假设 alice 和 bob 基于 HPKE 进行加密通信,alice为发送方,bob 为接收方,在开始通信前做好数据准备:

生成 bob 接收方的公私钥:

发送方 alice 进行 KEM 生成预共享密钥:

发送方 alice 加密明文数据:

接收方 bob 接收密文并解密:

运行效果:

HPKE运行的几种模式
模式 | 核心参数 | 安全强度 | 适用场景 |
|---|---|---|---|
Base模式 | 仅接收方公钥 | ★★★☆ | 内部服务通信 |
PSK模式 | + 预共享密钥psk | ★★★★ | IoT设备认证 |
Auth模式 | + 发送方私钥sks | ★★★★☆ | 跨服务认证 |
PSK+Auth | psk+sks双参数 | ★★★★★ | 军事/政府通信 |
● Base模式(基本模式):
○ 发送方:只需要接收方的公钥(pkr)和信息(info,可选)
○ 接收方:需要封装后的临时公钥(enc)、接收方的私钥(skr)和相同的信息(info)
○ 安全强度:提供前向安全性,但不提供发送方认证
● PSK模式(预共享密钥模式):
○ 发送方:除了Base模式的参数外,还需要预共享密钥(psk)和预共享密钥标识(psk_id)
○ 接收方:同样需要enc, skr, info,以及相同的psk和psk_id
○ 安全强度:除了前向安全性,还通过预共享密钥提供了双向认证(双方都知道PSK),防止未知方发起通信
● Auth模式(身份验证模式):
○ 发送方:需要接收方的公钥(pkr)、信息(info,可选)以及发送方的私钥(sks)用于身份验证
○ 接收方:需要enc, skr, info,以及发送方的公钥(pks)用于验证发送方身份
○ 安全强度:提供发送方身份认证,确保接收方知道消息的来源
● Auth_PSK模式(认证+预共享密钥模式):
○ 发送方:需要pkr, info, psk, psk_id, 以及发送方的私钥(sks)
○ 接收方:需要enc, skr, info, psk, psk_id, 以及发送方的公钥(pks)
○ 安全强度:同时提供发送方身份认证和预共享密钥认证,安全强度最高
安全配置建议 :
• 敏感数据 :优先选择Auth或PSK+Auth模式
• 性能敏感场景 :Base模式+P-256曲线(比P-521快3倍)
• 密钥轮换 :通过info字段绑定密钥版本(如info=b"v2_key")
# 假设 alice 和 bob 需要使用 HPKE 方式进行加密通信,通信的内容就是 plaintext
# 假设 alice 是发送方(sender),bob 是接收方(recipient)
plaintext ="Hello, HPKE! 这是一段用于测试 HPKE 的代码,用于理解 HPKE 的运算流程!".encode()
print(f'plain:{plaintext.decode()}')
print(f'plain hash:{hashlib.sha256(plaintext).hexdigest()}')
# 定义HPKE所需的附加信息
aead_info =b"HPKE AEAD INFO"
psk =b"HPKE PSK DATA"
psk_id =b"HPKE PSK ID"
aad_tag =b"HPKE AEAD TAG"
# 分割线
print('########################')
# 分割线
# 生成Bob的公私钥对
# Bob的公钥是公开的,Alice可以获取到
bob_ec_private_key , bob_ec_public_key = generate_key_pair()
# 生成 alice 的公钥
alice_ec_private_key , alice_ec_pubic_key = generate_key_pair()
alice_public_key_for_auth = KEMKey.from_pem(alice_ec_pubic_key.public_bytes(
encoding = serialization.Encoding.PEM ,
format= serialization.PublicFormat.SubjectPublicKeyInfo ,
))
alice_private_key_for_auth = KEMKey.from_pem(alice_ec_private_key.private_bytes(
encoding = serialization.Encoding.PEM ,
format= serialization.PrivateFormat.PKCS8 ,
encryption_algorithm = serialization.NoEncryption(),
))
# Alice和Bob约定的密钥规格
# 使用KEM_P521_HKDF_SHA512作为KEM算法
# 使用HKDF_SHA512作为KDF算法
# 使用AES256_GCM作为AEAD算法
alice_cipher_suite = CipherSuite.new(
kem_id = KEMId.DHKEM_P521_HKDF_SHA512 ,
kdf_id = KDFId.HKDF_SHA512 ,
aead_id = AEADId.AES256_GCM ,
)
# Alice解析Bob的公钥
# 将Bob的公钥转换为PEM格式,并从中提取出KEMKey对象
peer_public_key_from_bob = KEMKey.from_pem(bob_ec_public_key.public_bytes(
encoding = serialization.Encoding.PEM ,
format= serialization.PublicFormat.SubjectPublicKeyInfo ,
))
# Alice基于Bob的公钥生成临时公钥和加密上下文
# KEM阶段:Alice使用Bob的公钥生成一个共享密钥
# 返回临时公钥字节和发送者上下文
alice_tmp_enc_public_key_bytes , alice_sender = alice_cipher_suite.create_sender_context(
pkr = peer_public_key_from_bob ,
info = aead_info ,
psk = psk ,
psk_id = psk_id ,
sks = alice_private_key_for_auth ,# 发送者使用私钥做身份验证
)
print(f'alice_tmp_enc_public_key hash:{hashlib.sha256(alice_tmp_enc_public_key_bytes).hexdigest()}')
print(f'alice_tmp_enc_public_key_bytes length:{len(alice_tmp_enc_public_key_bytes)}')
# 发送方Alice加密数据
# AEAD阶段:Alice使用生成的上下文对明文进行加密
ciphertext = alice_sender.seal(pt = plaintext , aad = aad_tag)
print(f'ciphertext hash:{hashlib.sha256(ciphertext).hexdigest()}')
# 分割线
print('########################')
# 分割线
# Bob配置相同的CipherSuite
bob_cipher_suite = CipherSuite.new(
kem_id = KEMId.DHKEM_P521_HKDF_SHA512 ,
kdf_id = KDFId.HKDF_SHA512 ,
aead_id = AEADId.AES256_GCM ,
)
# Bob解析自己的私钥
# 将Bob的私钥转换为PEM格式,并从中提取出KEMKey对象
bob_private_key = KEMKey.from_pem(bob_ec_private_key.private_bytes(
encoding = serialization.Encoding.PEM ,
format= serialization.PrivateFormat.PKCS8 ,
encryption_algorithm = serialization.NoEncryption(),
))
# Bob创建接收者上下文
# KEM阶段:Bob使用自己的私钥和Alice的临时公钥生成共享密钥
# 返回接收者上下文
bob_as_receiver = bob_cipher_suite.create_recipient_context(
enc = alice_tmp_enc_public_key_bytes ,
skr = bob_private_key ,
info = aead_info ,
psk = psk ,
psk_id = psk_id ,
pks = alice_public_key_for_auth ,# 发送者的公钥
)
# 接收方Bob解密数据
# AEAD阶段:Bob使用生成的上下文对密文进行解密
decrypted = bob_as_receiver.open(ciphertext , aad = aad_tag)
print(f'decrypted hash:{hashlib.sha256(decrypted).hexdigest()}')
print(f'decrypted: {decrypted.decode()}')
print('解密成功:', decrypted == plaintext)最核心的参数变化为:


运行效果:

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。