基于IEEE 802.11的WPA3 SAE密码元素生成KDF函数问题排查
WPA3 SAE KDF函数实现错误排查
我正在依据IEEE 802.11标准用Python实现WPA3 SAE的密码元素生成功能,已经找到SAE测试向量,但KDF函数生成的候选x值与标准不符。目前我的H函数输出正确,KDF函数及H函数代码如下:
import hmac import hashlib from math import ceil def kdf(k: bytes): """ KDF-SHA-256-256 :k: password-seed (H[max(mac_a, mac_b) || min(mac_a, mac_b), password || counter]) :label: ASCII string indetifying the purpose of the keys derived. :context: bit string that provides context to identify the derived key :return: A length-bit derived key """ label = b"SAE Hunting and Pecking" context = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF # Prime number for DH Group 19 length = 256 # Length of the derived key in bits hash_len = 32 * 8 # Length of the digest produced by hash function (in bits) iterations = ceil(length / hash_len) result = b"" for i in range(1, iterations + 1): data = i.to_bytes(2, "big") + label + context + length.to_bytes(2, "big") result = result + H(key=k, data=data) return result[:length] def H(key: bytes, data: bytes): """ :data: message to use :key: key to use """ return hmac.new(key, data, hashlib.sha256).digest()
IEEE标准中的第一组测试向量:
group: 19 Password: ‘thisisreallysecret’ Local MAC address: 7b-88-56-20-2d-8d Peer’s MAC address: e2-47-1c-0a-5a-cb H(e2-47-1c-0a-5a-cb || 7b-88-56-20-2d-8d, thisisreallysecret || 1) 69f69099 83675392 d0a3a882 47ffef20 413ee972 15872942 4415e139 46ecc206 candidate x value: a16729e0 339c38f8 b06e2b83 76d43066 85578354 ab09d848 a0f140ac 825e6a3d
可能的错误点:
- Context参数类型错误:你将Group19的质数定义为整数,但KDF要求context是字节串。需要把这个整数转换成32字节的大端字节串,直接用整数和字节串拼接会触发类型错误,同时也不符合标准要求的比特串格式。
- 结果切片错误:
length定义的是导出密钥的比特数(256比特),但字节串切片是按字节计数的,256比特等于32字节。你当前用result[:length]会取前256个字节,完全超出需求,应该改为result[:32](或result[:length//8])。 - 代码潜在运行错误:原代码中
data = i.to_bytes(2, "big") + label + context + length.to_bytes(2, "big")这一行,因context是整数,实际运行会抛出TypeError: can only concatenate bytes (not "int") to bytes,说明你可能未实际运行这段代码,或运行时的代码与当前版本不一致。
修正后的KDF函数示例:
import hmac import hashlib from math import ceil def kdf(k: bytes): """ KDF-SHA-256-256 :k: password-seed (H[max(mac_a, mac_b) || min(mac_a, mac_b), password || counter]) :return: 256-bit derived key """ label = b"SAE Hunting and Pecking" # 将Group19的质数转换为32字节大端字节串 context = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF context_bytes = context.to_bytes(32, byteorder='big') length_bits = 256 hash_len_bits = 256 # SHA-256输出是256比特 iterations = ceil(length_bits / hash_len_bits) result = b"" for i in range(1, iterations + 1): # 构造KDF输入数据:counter(2字节) || label || context || length(2字节) counter = i.to_bytes(2, byteorder='big') length_bytes = length_bits.to_bytes(2, byteorder='big') data = counter + label + context_bytes + length_bytes result += H(key=k, data=data) # 取前256比特(32字节)作为结果 return result[:length_bits // 8] def H(key: bytes, data: bytes): return hmac.new(key, data, hashlib.sha256).digest()
用测试向量中的k值(即69f6909983675392d0a3a88247ffef20413ee972158729424415e13946ecc206对应的字节串)调用修正后的kdf函数,即可得到标准中的候选x值。
内容的提问来源于stack exchange,提问作者David Richard
相关产品推荐
相关产品推荐

