我正在用 python 开发 SSL 解码器,但我在 HMAC 验证方面遇到了一些问题:
我已经提取了所有与 key 环相关的 Material (客户端 IV、MAC、 key 和服务器 IV、MAC、 key )。 当我收到第一条 Application_Data 消息 (0x17) 时,我能够对其进行解密,但无法验证消息的完整性。
在 RFC 2246 ( https://www.ietf.org/rfc/rfc2246.txt ) 上,告诉:
The MAC is generated as:
HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type + TLSCompressed.version + TLSCompressed.length + TLSCompressed.fragment));
where "+" denotes concatenation.
seq_num The sequence number for this record.
hash The hashing algorithm specified by SecurityParameters.mac_algorithm.
以此为例:
Chosen cipher_suite is TLS_RSA_WITH_AES_256_CBC_SHA256
client_mac = "some random stuff"
message_type = 0x17
message_version = 0x0303
encrypted_message_length = 1184 (IV|Message|MAC|Offset)
decrypted_message_length = 1122 (removing IV, MAC and offset)
message = "some message of length 1122"
- client_mac 是从 keyring_material 中提取的
- message_type是0x17,因为作为Application_data消息类型,正确的值应该是0x17
- 消息版本为 0x0303,因为它是 TLS 1.2
- 消息长度为1122,去掉前面的IV,offset和MAC验证,消息,得到最终长度为1122
- seq_number 为 1,因为它是第一条消息
HMAC_SHA256计算,在python中,如下:
import hashlib
import hmac
hmac.new(<client_mac>,label+message,hashlib.sha256).digest()
我的问题是,如何计算标签? 正如RFC提到的,“+”表示连接,但是连接什么
- 十六进制值转换为字符串
- “1”+“17”+“0303”+“462”
- INT 值转换为字符串
- “1”+“23”+“771”+“1122”
另外要提的是,TLSCompressed.version 意味着:
- 0x0303
- 771
- “1.2”
- “12”
- “TLS 1.2”
在这个邮件列表 ( http://www.ietf.org/mail-archive/web/tls/current/msg14357.html ) 中,我发现了对 MAC 值的假定说明,
MAC(MAC_write_key, seq_num + TLSCipherText.type + TLSCipherText.version + length of ENC(content + padding + padding_length) + IV + ENC(content + padding + padding_length));
where the length is encoded as two bytes in the usual way.
但这对我来说毫无意义,因为重新编码解密值以检查计算 MAC 是没有用的。从最后一行 “其中长度以通常方式编码为两个字节”,这是否意味着我应该使用
struct.pack("!H",length)
然后删除“\x”并使用这个值?或者我应该用 HEX 编码这个值然后连接它吗?
我有点迷茫,因为 RFC 并不清楚应该如何使用值。
我一直在尝试几种组合(甚至是暴力破解),但都没有奏效,我希望你能为我指明方向。
最佳答案
好吧,经过一番挖掘,我设法解决了这个问题。
RFC 5246,第 6.2.3.1 节(https://www.rfc-editor.org/rfc/rfc5246#section-6.2.3.1)
The MAC is generated as:
MAC(MAC_write_key, seq_num + TLSCompressed.type + TLSCompressed.version + TLSCompressed.length + TLSCompressed.fragment);
where "+" denotes concatenation.
但它没有指出数据大小,无论是表示格式(十六进制,字符串...)。
每个字段的表示方式如下:
序号:
- 描述:一个整数计数器,从 0 开始,每接收或发送一帧都会递增。对于 TCP session ,必须使用两个 seq_numbers,一个用于服务器,另一个用于客户端,每次发送一个帧时递增。
- 表示:此值必须表示为 Unsigned Long Long 8 个字节
- 表示示例:
struct.pack("!Q",seq_num)
TLSCompressed.type
- 描述:该字段是从 TLS 记录层(加密的负载)中提取的。例如,如果它是一个应用程序数据帧,我们必须使用 0x17。
- 表示:此值必须表示为 Signed Char,占 2 个字节。
- 表示示例:
struct.pack("!b",TLSCompressed.type)
TLSCompressed.version
- 描述:该字段也是从 TLS 记录层(加密的负载)中提取的。例如,如果使用 TLS 1.2 传输帧,我们必须使用它的十六进制表示形式 0x0303。
- 表示:此值必须表示为 Unsigned Short,2 个字节。
- 表示示例:
struct.pack("!H",TLSCompressed.version)
TLSCompressed.length
- 说明:该字段表示解密负载的实际长度。
- 表示:此值必须表示为 Unsigned Short,2 个字节。
- 表示示例:
struct.pack("!H",TLSCompressed.length)
TLSCompressed.fragment
- 说明:此字段**是实际的解密有效负载。
- 表示:该值必须表示为字符串
作为一个 python 示例,HMAC 散列对于我们之前的示例如下:
hmac_digest = hmac.new(mac_secret,'',digestmod=hashlib.sha256)
hmac_digest.update(struct.pack('!QbHH',seq_num,TLSCompressed.type,TLSCompressed.version, len(decrypted)))
hmac_digest.update(decrypted)
hmac_digest.digest()
关于python - TLS MAC 消息验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31009358/