一、引言
在当今数字化时代,信息安全至关重要。消息验证是保障信息完整性和真实性的关键手段之一。HMAC(Hash-based Message Authentication Code,基于哈希的消息认证码)作为一种重要的消息验证技术,在众多领域得到了广泛应用。Python 作为一门功能强大的编程语言,提供了内置的 hmac 模块,方便开发者进行消息验证相关的操作。
二、知识讲解
(一)HMAC 原理概述
1. 定义
HMAC 是一种基于哈希函数和密钥的消息认证码算法。它结合了哈希函数的特性和密钥的安全性,用于验证消息的完整性和真实性。简单来说,HMAC 是通过使用一个密钥和一个哈希函数对消息进行处理,生成一个固定长度的认证码,接收方可以使用相同的密钥和哈希函数对收到的消息进行同样的处理,并将生成的认证码与接收到的认证码进行比较,从而判断消息是否被篡改以及是否来自合法的发送方。
2. 原理
HMAC 的计算过程基于一个基础的哈希函数(如 MD5、SHA-1、SHA-256 等)。其核心思想是将密钥与一个特定的填充值进行组合,然后与消息一起输入到哈希函数中进行计算。具体步骤如下:
- 首先,将密钥进行填充或截断,使其长度与哈希函数所要求的块大小一致。
- 接着,将填充后的密钥与两个固定的填充值(分别为 ipad 和 opad)进行异或操作,得到两个新的值。
- 然后,将其中一个新值与消息拼接后输入到哈希函数中进行计算,得到中间结果。
- 最后,将另一个新值与中间结果再次拼接后输入到哈希函数中进行计算,最终得到 HMAC 值。
通过这种方式,HMAC 利用了密钥的保密性和哈希函数的不可逆性,有效地保证了消息的安全性。
3. 知识图谱
(二)hmac 模块概述
Python 的 hmac 模块实现了 RFC 2104 中描述的 HMAC 算法。该模块允许使用任何具有固定摘要大小的哈希函数,但不支持可扩展输出函数(如 SHAKE - 128 或 SHAKE - 256)。
(三)hmac.new() 函数
1. 功能
用于创建一个新的 HMAC 对象,该对象可用于后续的消息处理和摘要计算。
2. 原型及参数
hmac.new(key, msg=None, digestmod)
- 参数: key:指定密钥,必须是一个 bytes 或 bytearray 对象,它是用于 HMAC 计算的秘密密钥,起到身份验证和保证消息完整性的关键作用。 msg:可选参数,若提供,将会调用 update(msg) 方法,即对传入的消息进行初始处理。可以是 hashlib 所支持的任意类型,在 Python 3.4 版本后支持更广泛的类型。 digestmod:必须参数,为 HMAC 对象所用的摘要名称、摘要构造器或模块。它可以是适用于 hashlib.new() 的任何名称,用于指定具体的哈希算法,如 'sha256' 等,决定了 HMAC 计算所使用的哈希函数。
- 返回值:返回一个新的 hmac 对象。
3. 注意事项
- 在 Python 3.4 版本中,形参 key 可以为 bytes 或 bytearray 对象,形参 msg 可以为 hashlib 所支持的任意类型,形参 digestmod 可以为某种哈希算法的名称。
- 在 Python 3.8 版本中,digestmod 参数变为必须的,并且建议将其作为关键字参数传入,以避免在没有初始 msg 时可能出现的麻烦。
4. 示例代码
import hmac
import hashlib
# 定义密钥和消息
key = b'my_secret_key'
msg = b'Hello, HMAC!'
# 使用 sha256 哈希算法创建 HMAC 对象
h = hmac.new(key, msg, digestmod=hashlib.sha256)
print(h)
(四)hmac.digest() 函数
1. 功能
基于给定密钥 key 和指定的哈希算法 digest,直接返回 msg 的摘要。此函数等价于 HMAC(key, msg, digest).digest(),但使用了优化的 C 或内联实现,对于放入内存的消息能处理得更快。
2. 原型及参数
hmac.digest(key, msg, digest)
- 参数: key、msg 和 digest 具有与 hmac.new() 中相同的含义。key 是密钥,msg 是待处理的消息,digest 是指定的哈希算法名称。
- 返回值:返回消息 msg 的 HMAC 摘要。
3. 注意事项
作为 CPython 的实现细节,优化的 C 实现仅当 digest 为字符串并且是一个 OpenSSL 所支持的摘要算法的名称时才会被使用。
4. 示例代码
import hmac
key = b'my_secret_key'
msg = b'Hello, HMAC!'
digest = 'sha256'
result = hmac.digest(key, msg, digest)
print(result)
(五)HMAC 对象的方法
1. HMAC.update(msg)
(1)功能
用 msg 来更新 hmac 对象。重复调用相当于单次调用并传入所有参数的拼接结果,即 m.update(a); m.update(b) 等价于 m.update(a + b),方便对分块消息进行处理。
(2)原型及参数
HMAC.update(msg)
- 参数:msg,在 Python 3.4 版本后可以为 hashlib 所支持的任何类型,通常为 bytes 或 bytearray 类型的消息数据,用于对 HMAC 对象进行进一步的消息更新处理。
- 返回值:无。
(3)注意事项
在处理大消息时,可以分块调用 update() 方法,提高代码的灵活性和效率。
(4)示例代码
import hmac
import hashlib
key = b'my_secret_key'
msg_part1 = b'Hello, '
msg_part2 = b'HMAC!'
h = hmac.new(key, digestmod=hashlib.sha256)
h.update(msg_part1)
h.update(msg_part2)
print(h.digest())
2. HMAC.digest()
(1)功能
返回当前已传给 update() 方法的字节串数据的摘要。这个字节串数据的长度将与传给构造器的摘要的长度 digest_size 相同。它可以包含非 ASCII 的字节,包括 NUL 字节。
(2)原型及参数
HMAC.digest()
- 参数:无。
- 返回值:返回当前消息的 HMAC 摘要,为 bytes 类型。
(3)注意事项
在验证例程运行期间将 digest() 的输出与外部提供的摘要进行比较时,建议使用 compare_digest() 函数而不是 == 运算符以减少面对定时攻击的弱点。
(4)示例代码
import hmac
import hashlib
key = b'my_secret_key'
msg = b'Hello, HMAC!'
h = hmac.new(key, msg, digestmod=hashlib.sha256)
digest_result = h.digest()
print(digest_result)
3. HMAC.hexdigest()
(1)功能
类似于 digest() 但摘要会以两倍长度字符串的形式返回,其中仅包含十六进制数码。这可以被用于在电子邮件或其他非二进制环境中安全地交换数据值。
(2)原型及参数
HMAC.hexdigest()
- 参数:无。
- 返回值:返回当前消息的 HMAC 摘要的十六进制字符串表示,为 str 类型。
(3)注意事项
在验证例程运行期间将 hexdigest() 的输出与外部提供的摘要进行比较时,建议使用 compare_digest() 函数而不是 == 运算符以减少面对定时攻击的弱点。
(4)示例代码
import hmac
import hashlib
key = b'my_secret_key'
msg = b'Hello, HMAC!'
h = hmac.new(key, msg, digestmod=hashlib.sha256)
hexdigest_result = h.hexdigest()
print(hexdigest_result)
4. HMAC.copy()
(1)功能
返回 hmac 对象的副本(“克隆”)。这可被用来高效地计算共享相同初始子串的数据的摘要。
(2)原型及参数
HMAC.copy()
- 参数:无。
- 返回值:返回一个新的 hmac 对象,是原对象的副本。
(3)示例代码
import hmac
import hashlib
key = b'my_secret_key'
msg = b'Hello, HMAC!'
h = hmac.new(key, msg, digestmod=hashlib.sha256)
h_copy = h.copy()
print(h_copy.digest())
(六)HMAC 对象的属性
1. HMAC.digest_size
(1)功能
以字节表示的结果 HMAC 摘要的大小。不同的哈希算法对应的摘要大小不同,例如 SHA-256 的摘要大小通常为 32 字节。
(2)示例代码
import hmac
import hashlib
key = b'my_secret_key'
msg = b'Hello, HMAC!'
h = hmac.new(key, msg, digestmod=hashlib.sha256)
print(h.digest_size)
2. HMAC.block_size
(1)功能
以字节表示的哈希算法的内部块大小。这是哈希算法在处理数据时的内部块划分大小。
(2)示例代码
import hmac
import hashlib
key = b'my_secret_key'
msg = b'Hello, HMAC!'
h = hmac.new(key, msg, digestmod=hashlib.sha256)
print(h.block_size)
3. HMAC.name
(1)功能
HMAC 的规范名称,总是为小写形式,例如 hmac-md5。用于标识当前 HMAC 对象所使用的哈希算法类型。
(2)示例代码
import hmac
import hashlib
key = b'my_secret_key'
msg = b'Hello, HMAC!'
h = hmac.new(key, msg, digestmod=hashlib.sha256)
print(h.name)
(七)辅助函数 hmac.compare_digest(a, b)
1. 功能
返回 a == b。此函数使用一种经专门设计的方式通过避免基于内容的短路行为来防止定时分析,使得它适合处理密码相关的比较操作,增强安全性。
2. 原型及参数
hmac.compare_digest(a, b)
- 参数: a 和 b 必须为相同的类型:或者是 str (仅限 ASCII 字符,如 HMAC.hexdigest() 的返回值),或者是 bytes-like object。
- 返回值:如果 a 和 b 相等则返回 True,否则返回 False。
3. 注意事项
如果 a 和 b 具有不同的长度,或者如果发生了错误,定时攻击在理论上可以获取有关 a 和 b 的类型和长度信息 — 但不能获取它们的值。在 Python 3.10 版本中,此函数在可能的情况下会在内部使用 OpenSSL 的 CRYPTO_memcmp()。
4. 示例代码
import hmac
import hashlib
key = b'my_secret_key'
msg = b'Hello, HMAC!'
h1 = hmac.new(key, msg, digestmod=hashlib.sha256)
h2 = hmac.new(key, msg, digestmod=hashlib.sha256)
digest1 = h1.digest()
digest2 = h2.digest()
print(hmac.compare_digest(digest1, digest2))
三、应用案例
(一)案例背景
假设我们有一个简单的客户端 - 服务器系统,客户端向服务器发送消息,服务器需要验证消息的完整性和真实性,防止消息在传输过程中被篡改。
(二)代码实现
1. 客户端代码
import hmac
import hashlib
# 服务器和客户端共享的密钥
SECRET_KEY = b'shared_secret_key'
message = b'This is an important message.'
# 创建 HMAC 对象并计算摘要
h = hmac.new(SECRET_KEY, message, digestmod=hashlib.sha256)
digest = h.hexdigest()
# 模拟将消息和摘要发送给服务器
print(f"Sending message: {message.decode()}")
print(f"Sending digest: {digest}")
2. 服务器代码
import hmac
import hashlib
# 服务器和客户端共享的密钥
SECRET_KEY = b'shared_secret_key'
# 模拟接收到的消息和摘要
received_message = b'This is an important message.'
received_digest = 'a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e'
# 计算接收到的消息的摘要
h = hmac.new(SECRET_KEY, received_message, digestmod=hashlib.sha256)
calculated_digest = h.hexdigest()
# 验证摘要
if hmac.compare_digest(calculated_digest, received_digest):
print("Message is valid.")
else:
print("Message is invalid.")
(三)代码解释
- 在客户端,使用共享密钥和消息创建 HMAC 对象,计算消息的摘要(十六进制字符串形式),并将消息和摘要发送给服务器(这里模拟发送)。
- 在服务器端,接收到消息和摘要后,使用相同的共享密钥和消息重新计算摘要,然后使用 hmac.compare_digest() 函数比较计算得到的摘要和接收到的摘要,若相等则消息有效,否则无效。
四、应用扩展
(一)与网络通信结合
在实际的网络应用中,如 HTTP 请求、WebSocket 通信等,可以将 HMAC 用于验证请求的合法性和数据的完整性。例如,在 HTTP 请求头中添加 HMAC 签名,服务器端验证该签名以确保请求未被篡改。
(二)数据存储安全
在存储敏感数据时,可以使用 HMAC 对数据进行签名,存储数据和签名。在读取数据时,重新计算签名并进行验证,确保数据在存储过程中未被篡改。
五、学习路线
(一)基础学习
- 了解 HMAC 的基本原理和概念,熟悉哈希函数的相关知识。
- 学习 Python hmac 模块的基本函数和类,掌握 hmac.new()、HMAC.update()、HMAC.digest() 等方法的使用。
(二)实践操作
- 通过编写简单的示例代码,如上述应用案例,进行消息验证的实践操作,熟悉 hmac 模块在实际场景中的应用。
- 尝试不同的哈希算法(如 SHA-256、SHA-512 等),观察其对 HMAC 计算结果的影响。
(三)深入拓展
- 研究 HMAC 在网络通信、数据存储等实际领域的应用案例,学习如何将其集成到复杂的项目中。
- 探索 HMAC 与其他安全技术的结合使用,如加密算法、数字证书等,提升系统的安全性。
六、学习总结
HMAC 作为一种重要的消息验证技术,在保障信息完整性和真实性方面发挥着关键作用。我们学习了Python hmac 模块的各个函数和类的使用方法,包括 hmac.new()、hmac.digest() 以及 HMAC 对象的各种方法和属性,同时掌握了辅助函数 hmac.compare_digest() 的使用。通过实际的应用案例和扩展,我们了解了 HMAC 在不同场景下的应用方式和重要性。
在学习过程中,我们不仅要掌握 hmac 模块的基本使用,更要理解其背后的原理和安全机制,以便在实际项目中合理、安全地运用该技术。同时,要不断实践和探索,将 HMAC 技术与其他安全技术相结合,提升系统的整体安全性。
持续更新Python编程学习日志与技巧,敬请关注!