【HMAC加密算法介绍】

文章目录

  • 前言
  • [一、什么是 HMAC?](#一、什么是 HMAC?)
  • [二、HMAC 的数学构造与工作流程](#二、HMAC 的数学构造与工作流程)
  • [三、为什么 HMAC 安全?](#三、为什么 HMAC 安全?)
  • 四、常见用法场景
  • 五、示例
    • [示例 1 --- Python(标准库)](#示例 1 — Python(标准库))
    • [示例 2 --- Java(使用 javax.crypto)](#示例 2 — Java(使用 javax.crypto))
    • [示例 3 --- Node.js(crypto)](#示例 3 — Node.js(crypto))
  • 总结

前言

随着网络服务与分布式系统的广泛应用,服务之间交换的数据需要保证完整性认证。HMAC(Hash-based Message Authentication Code,基于哈希的消息认证码)在实际工程中被大量使用来验证消息未被篡改并确认消息来自持有密钥的一方。


一、什么是 HMAC?

HMAC 是一种基于公认哈希函数(如 SHA-256SHA-1SHA-512)的消息认证码(MAC)。其目标是通过一个对称密钥对任意长度的消息生成固定长度的标签(MAC),接收方使用相同密钥重新计算 MAC 并比较,从而确认消息完整性与来源。

关键点:

  • 提供认证完整性 ,但不提供保密
  • 安全性依赖于底层哈希函数的碰撞/伪随机性质和密钥的秘密性与长度。
  • 广泛用于 API 签名、TLS 中的某些模式、JWT 的签名(HMAC-SHA256)等。

二、HMAC 的数学构造与工作流程

HMAC 的标准构造(伪代码):

复制代码
HMAC(K, m) = H( (K' ⊕ opad) || H( (K' ⊕ ipad) || m ) )

其中:

  • H 是底层哈希函数(如 SHA-256)。
  • K 是原始密钥。
  • K' 是被处理后的密钥:如果 len(K) > block_size,则 K' = H(K);否则 K' = K 填充到 block_size(用 0x00 填充)。
  • block_size 是哈希函数的块大小(对于 SHA-256 为 64 字节)。
  • ipad = 0x36 重复 block_size 次,opad = 0x5c 重复 block_size 次。
  • || 表示连接(concatenate)。
  • 表示按字节异或(XOR)。

流程分两步哈希(inner,outer):

  1. inner = H( (K' XOR ipad) || message )
  2. outer = H( (K' XOR opad) || inner )
    返回 outer 作为最终 MAC。

这样做的设计目的包括:利用哈希函数的压缩性质,同时避免对密钥直接暴露给哈希内部结构,增加对密钥长度变化与扩展攻击的抵抗。


三、为什么 HMAC 安全?

  1. 安全性来源:假设底层哈希函数是伪随机函数/抗碰撞的,HMAC 的安全性可以证明为难以伪造 MAC 的。
  2. 密钥长度:密钥应至少与哈希输出长度相当(例如对 SHA-256 至少 256 位),并应由高熵随机源生成。过短或易猜测的密钥会削弱安全性。
  3. 不要把 HMAC 当成加密:HMAC 不隐藏消息内容,仅验证。若需要保密,请同时使用加密(如 AES-GCM)。
  4. 比较时防止时序攻击 :比较 MAC 时应使用常数时间比较(例如 Python 的 hmac.compare_digest),不要使用普通 ==
  5. 选择合适哈希 :避免使用已知弱点的哈希(例如 SHA-1 的碰撞问题),优先使用 SHA-256SHA-384SHA-512 等。
  6. 密钥管理:密钥应定期轮换并安全存储(例如 KMS、硬件 HSM)。不要把密钥硬编码在源码或日志中。
  7. 消息边界与格式:签名数据格式必须严格定义(例如包含时间戳、请求方法、URL、Body 等),否则存在签名绕过风险。

四、常见用法场景

  • API 请求签名(客户端用密钥签名请求,服务端验证)
  • Cookie/Session 防篡改(签名 Cookie 内容)
  • 简单消息完整性检验(不保密)
  • 与 TLS/SSL 内部构造结合用于 MAC(历史上用到 HMAC)

五、示例

下面给出 Python、Java、Node.js 的 HMAC 使用示例,随后提供一个完整实战:使用 HMAC 对 Flask API 请求进行签名与验证。

示例 1 --- Python(标准库)

要点说明:使用 hmachashlib,并用 hmac.compare_digest 做常数时间比较。

python 复制代码
# hmac_example.py
import hmac
import hashlib
import base64

def hmac_sha256_base64(key: bytes, message: bytes) -> str:
    mac = hmac.new(key, message, hashlib.sha256).digest()
    return base64.b64encode(mac).decode('ascii')

if __name__ == "__main__":
    key = b'supersecretkey123456'   # 实际使用中应更长、更随机
    message = b'important message'
    signature_b64 = hmac_sha256_base64(key, message)
    print("Base64 HMAC-SHA256:", signature_b64)

解释

  • hmac.new(key, message, hashlib.sha256).digest() 计算原始 MAC(二进制)。
  • 结果用 Base64 编码便于放入 HTTP 头或 URL 中。

比较示例(验证):

python 复制代码
def verify_hmac(key: bytes, message: bytes, signature_b64: str) -> bool:
    expected = base64.b64encode(hmac.new(key, message, hashlib.sha256).digest()).decode('ascii')
    # 使用常数时间比较避免时序攻击
    return hmac.compare_digest(expected, signature_b64)

示例 2 --- Java(使用 javax.crypto)

java 复制代码
// HmacExample.java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class HmacExample {
    public static String hmacSha256Base64(String key, String message) throws Exception {
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
        sha256_HMAC.init(secret_key);
        byte[] mac_data = sha256_HMAC.doFinal(message.getBytes("UTF-8"));
        return Base64.getEncoder().encodeToString(mac_data);
    }

    public static void main(String[] args) throws Exception {
        String key = "supersecretkey123456";
        String msg = "important message";
        System.out.println(hmacSha256Base64(key, msg));
    }
}

注意 :Java 的 Mac 已在底层实现了 HMAC 的标准构造。

示例 3 --- Node.js(crypto)

javascript 复制代码
// hmac_example.js
const crypto = require('crypto');

function hmacSha256Base64(key, message) {
  return crypto.createHmac('sha256', key).update(message).digest('base64');
}

const key = 'supersecretkey123456';
const message = 'important message';
console.log(hmacSha256Base64(key, message));

总结

HMAC 是一种简单、实用且经证明安全的消息认证机制,适用于绝大多数需要消息完整性与认证的场景。正确使用 HMAC 的要点包括选择合适的哈希函数与密钥长度、使用常数时间比较防止时序攻击、在签名中包含时间戳或 nonce 防止重放,并严格一致地定义被签名的数据格式。

相关推荐
进击的荆棘2 小时前
优选算法——模拟
java·开发语言·算法·模拟
仰泳的熊猫2 小时前
题目2086:蓝桥杯算法提高VIP-最长公共子序列
数据结构·c++·算法·蓝桥杯·动态规划
请你喝好果汁6412 小时前
ML-线性回归(Linear Regression)
算法·回归·线性回归
Figo_Cheung2 小时前
Figo《量子几何学:从希尔伯特空间到全息时空的统一理论体系》(十一)——量子计算几何算法的设计与实现
算法·几何学·量子计算
0 0 02 小时前
CCF-CSP 36-2 梦境巡查(dream)【C++】考点:前缀和
开发语言·c++·算法
VALENIAN瓦伦尼安教学设备2 小时前
便携式蒸汽阀门漏气检测仪作用
人工智能·嵌入式硬件·算法
plus4s2 小时前
3月11日(进阶3)
算法
We་ct2 小时前
LeetCode 39. 组合总和:DFS回溯解法详解
前端·算法·leetcode·typescript·深度优先·个人开发·回溯
小杍随笔2 小时前
【Rust中所有符号的作用及使用场景详解】
java·算法·rust