IEEE 802.11 KDF实现疑问:Perl整数转字节的字节序与有效位
问题背景
我正尝试实现IEEE 802.11中的密钥派生函数(KDF),其伪代码如下:
result ← ""
iterations ← ⌈Length / Hashlen⌉
do i = 1 to iterations
result ← result ‖ HMAC-Hash(K, i ‖ Label ‖ Context ‖ Length)
od
return first Length bits of result, and irretrievably delete the other bitswhere
i 和 Length 被编码为16位无符号整数,采用9.2.2节的位序约定
K、Label和Context 是位串,采用9.2.2节的位序约定
Hashlen是Hash生成的摘要长度(比特位)
9.2.2节的位序说明:
在图示中,字段内所有位从0到k编号,字段长度为k+1位。长度超过1位的数字字段中,位按有效位递增顺序排列,即编号最小的位有效位最低。字段内的字节边界可通过字段位编号模8得到。长度超过1字节的数字字段中,字节按有效位递增顺序排列(从编号最小的位到最大的位)。长度超过1字节的字段中的字节按包含编号最小位的字节到包含编号最大位的字节的顺序发送到物理层。
我用Perl编写了实现代码,但对字节序和有效位概念存疑,未得到预期结果,希望确认对无符号整数编码的理解及pack()用法是否正确。代码如下:
sub kdf { my ($self, $K, $Hash, $Context, $Length) = @_; my $Label = "Pairwise key expansion"; my $Hashlen; my $result = ""; my $LengthBytes = pack("S", $Length); my $iBytes; if ($Hash eq "SHA_256") { $Hashlen = 256; for (my $i = 1; $i <= ceil($Length / $Hashlen); $i++) { $iBytes = pack("S", $i); $result .= hmac_sha256($K, $iBytes . $Label . $Context . $LengthBytes); } return substr($result, 0, $Length / 8); } }
核心问题
当$Length设为384时,printf("%v02X", $LengthBytes)的输出应为01.80、80.01,还是其他结果?
解答
1. 解读IEEE 802.11 9.2.2节的字节序要求
根据9.2.2节的描述,多字节数字字段的编码规则是小端序:
- 位编号0对应最低有效位(LSB)
- 字节排列顺序为:包含最低有效位的字节(低8位)在前,包含最高有效位的字节(高8位)在后
2. 计算384的正确字节编码
384的十六进制表示为0x180,拆分两个字节:
- 低8位(对应位0-7):
0x80 - 高8位(对应位8-15):
0x01
按照小端序排列,字节序列应为0x80 followed by 0x01,因此printf("%v02X", $LengthBytes)的正确输出是80.01。
3. Perl pack()用法修正
你的代码中使用pack("S", $Length)采用的是主机字节序(可能是大端或小端,取决于运行环境),无法保证符合IEEE 802.11的标准要求。应改用小端序的pack格式符v(无符号短整型,小端序):
my $LengthBytes = pack("v", $Length); my $iBytes = pack("v", $i);
这样无论主机字节序是什么,都能生成符合标准的小端字节序列。
内容的提问来源于stack exchange,提问作者miken32

