引言:什么是哈希算法?
哈希算法(Hash Algorithm)是一种将任意长度的输入数据转换为固定长度输出的加密函数,其输出结果称为哈希值或消息摘要。一个优秀的哈希算法应具备以下特性:
- 单向性:从哈希值无法反推原始数据
- 抗碰撞性:很难找到两个不同的输入产生相同的哈希值
- 雪崩效应:输入的微小变化会导致哈希值的巨大变化
- 高效性:计算过程快速高效
哈希算法在信息安全领域扮演着至关重要的角色,广泛应用于数据完整性校验、数字签名、密码存储、数据去重等场景。本文将带您回顾哈希算法的发展历程,从 MD5 到 SHA3,解析其技术原理与实现细节。
一、MD5:曾经的王者
MD5(Message-Digest Algorithm 5)由罗纳德・李维斯特(Ronald Rivest)于 1992 年设计,是 MD 系列算法的第五个版本。它产生 128 位(16 字节)的哈希值,通常以 32 个十六进制字符表示。
MD5 的工作原理
MD5 算法的处理过程分为以下几个步骤:
- 数据填充:将输入数据填充至长度为 448 mod 512,然后附加 64 位的原始数据长度
- 初始化缓冲区:使用 4 个 32 位寄存器 (A、B、C、D) 存储中间结果
- 处理 512 位数据块:对每个 512 位的数据块执行 4 轮共 64 步的处理
- 输出结果:将 4 个寄存器的值连接起来,形成 128 位的哈希值
MD5 的代码实现(基于 openHiTLS)
从 openHiTLS 的源码中,我们可以看到 MD5 的核心实现:
c
// 初始化MD5上下文
void md5_init(md5_ctx *ctx)
{
ctx->h[0] = 0x67452301;
ctx->h[1] = 0xefcdab89;
ctx->h[2] = 0x98badcfe;
ctx->h[3] = 0x10325476;
ctx->nblocks = 0;
ctx->num = 0;
}
// MD5压缩函数,处理一个512位的数据块
void md5_compress(md5_ctx *ctx, const uint8_t *data)
{
uint32_t a, b, c, d, x[16];
int i;
// 将输入数据转换为32位字
for (i = 0; i < 16; i++) {
x[i] = GET_UINT32_LE(data + i * 4);
}
a = ctx->h[0];
b = ctx->h[1];
c = ctx->h[2];
d = ctx->h[3];
// 第一轮处理
F(a, b, c, d, x[0], 7, 0xd76aa478);
F(d, a, b, c, x[1], 12, 0xe8c7b756);
// ... 省略其他步骤 ...
// 第四轮处理
H(a, b, c, d, x[1], 9, 0xf47d5dea);
H(d, a, b, c, x[6], 14, 0x769a09da);
// ... 省略其他步骤 ...
// 更新哈希值
ctx->h[0] += a;
ctx->h[1] += b;
ctx->h[2] += c;
ctx->h[3] += d;
}
MD5 的安全性
MD5 曾经被广泛使用,但随着密码学研究的深入,其安全性逐渐受到质疑:
- 2004 年,王小云教授团队首次提出了 MD5 的碰撞攻击方法
- 2008 年,研究者成功构造了两个不同的可执行文件,其 MD5 哈希值相同
- 目前,MD5 已被证明存在严重的安全漏洞,不适合用于任何安全相关的场景
二、SHA-1:SHA 家族的开端
SHA(Secure Hash Algorithm)系列算法由美国国家安全局(NSA)设计,作为联邦信息处理标准(FIPS)发布。SHA-1 于 1995 年发布,产生 160 位的哈希值。
SHA-1 的工作原理
SHA-1 的处理过程与 MD5 类似,但更为复杂:
- 数据填充:将输入数据填充至长度为 448 mod 512,然后附加 64 位的原始数据长度
- 初始化缓冲区:使用 5 个 32 位寄存器 (H0-H4) 存储中间结果
- 处理 512 位数据块:对每个 512 位的数据块执行 80 步的处理
- 输出结果:将 5 个寄存器的值连接起来,形成 160 位的哈希值
SHA-1 的代码实现(基于 openHiTLS)
c
// 初始化SHA-1上下文
void sha1_init(sha1_ctx *ctx)
{
ctx->h[0] = 0x67452301;
ctx->h[1] = 0xefcdab89;
ctx->h[2] = 0x98badcfe;
ctx->h[3] = 0x10325476;
ctx->h[4] = 0xc3d2e1f0;
ctx->nblocks = 0;
ctx->num = 0;
}
// SHA-1压缩函数
void sha1_compress(sha1_ctx *ctx, const uint8_t *data)
{
uint32_t a, b, c, d, e, t, w[80];
int i;
// 扩展512位数据到80个32位字
for (i = 0; i < 16; i++) {
w[i] = GET_UINT32_BE(data + i * 4);
}
for (; i < 80; i++) {
w[i] = ROTL32(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1);
}
a = ctx->h[0];
b = ctx->h[1];
c = ctx->h[2];
d = ctx->h[3];
e = ctx->h[4];
// 80步处理
for (i = 0; i < 20; i++) {
t = ROTL32(a, 5) + ((b & c) | (~b & d)) + e + w[i] + 0x5a827999;
e = d;
d = c;
c = ROTL32(b, 30);
b = a;
a = t;
}
// ... 省略其他三轮处理 ...
// 更新哈希值
ctx->h[0] += a;
ctx->h[1] += b;
ctx->h[2] += c;
ctx->h[3] += d;
ctx->h[4] += e;
}
SHA-1 的安全性
SHA-1 的安全性也随着时间的推移受到挑战:
- 2005 年,研究人员发现了 SHA-1 的碰撞攻击方法
- 2017 年,Google 与 CWI 合作成功进行了 SHA-1 碰撞攻击的实际演示
- 目前,SHA-1 已被建议停止使用,主流浏览器已不再接受使用 SHA-1 签名的证书
三、SHA-2:更安全的选择
SHA-2 是 SHA 家族的第二个版本,于 2001 年发布,包括 SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224 和 SHA-512/256 等多个变体。其中,SHA-256 和 SHA-512 是最常用的两个版本。
SHA-256 的工作原理
SHA-256 产生 256 位的哈希值,其处理过程如下:
- 数据填充:将输入数据填充至长度为 448 mod 512,然后附加 64 位的原始数据长度
- 初始化缓冲区:使用 8 个 32 位寄存器 (a-h) 存储中间结果,初始值来源于前 8 个质数的平方根的小数部分
- 处理 512 位数据块:对每个 512 位的数据块执行 64 步的处理
- 输出结果:将 8 个寄存器的值连接起来,形成 256 位的哈希值
SHA-256 的代码实现(基于 openHiTLS)
c
// 初始化SHA-256上下文
void sha256_init(sha256_ctx *ctx)
{
ctx->h[0] = 0x6a09e667;
ctx->h[1] = 0xbb67ae85;
ctx->h[2] = 0x3c6ef372;
ctx->h[3] = 0xa54ff53a;
ctx->h[4] = 0x510e527f;
ctx->h[5] = 0x9b05688c;
ctx->h[6] = 0x1f83d9ab;
ctx->h[7] = 0x5be0cd19;
ctx->nblocks = 0;
ctx->num = 0;
}
// SHA-256压缩函数
void sha256_compress(sha256_ctx *ctx, const uint8_t *data)
{
uint32_t a, b, c, d, e, f, g, h, t1, t2, w[64];
int i;
// 扩展512位数据到64个32位字
for (i = 0; i < 16; i++) {
w[i] = GET_UINT32_BE(data + i * 4);
}
for (; i < 64; i++) {
w[i] = SIGMA1(w[i-2]) + w[i-7] + SIGMA0(w[i-15]) + w[i-16];
}
a = ctx->h[0];
b = ctx->h[1];
c = ctx->h[2];
d = ctx->h[3];
e = ctx->h[4];
f = ctx->h[5];
g = ctx->h[6];
h = ctx->h[7];
// 64步处理
for (i = 0; i < 64; i++) {
t1 = h + SIGMA1(e) + CH(e, f, g) + sha256_k[i] + w[i];
t2 = SIGMA0(a) + MAJ(a, b, c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
// 更新哈希值
ctx->h[0] += a;
ctx->h[1] += b;
ctx->h[2] += c;
ctx->h[3] += d;
ctx->h[4] += e;
ctx->h[5] += f;
ctx->h[6] += g;
ctx->h[7] += h;
}
SHA-512 简介
SHA-512 是 SHA-2 家族中的另一个重要成员,产生 512 位的哈希值,其处理过程与 SHA-256 类似,但:
- 使用 64 位寄存器而非 32 位
- 处理 1024 位数据块而非 512 位
- 执行 80 步处理而非 64 步
- 初始哈希值来源于前 8 个质数的立方根的小数部分
SHA-512 提供了更高的安全性,但计算成本也更高,适合对安全性要求极高的场景。
四、SHA-3:全新的设计理念
SHA-3 是美国国家标准与技术研究院(NIST)于 2015 年发布的最新一代哈希算法标准,它基于完全不同的设计理念 —— 海绵结构(Sponge Construction)。
SHA-3 的工作原理
SHA-3 采用海绵结构,其工作过程分为以下几个阶段:
- 初始化:初始化一个状态矩阵
- 吸收阶段:将输入数据分块,依次与状态矩阵进行异或操作,并应用置换函数
- 挤压阶段:从状态矩阵中提取输出数据,直到获得所需长度的哈希值
这种结构与 MD5、SHA-1 和 SHA-2 所采用的 Merkle-Damgård 结构有本质区别,提供了更好的安全性证明。
SHA-3 的代码实现(基于 openHiTLS)
c
// SHA-3初始化函数
void sha3_init(sha3_ctx *ctx, size_t mdlen)
{
memset(ctx->state, 0, sizeof(ctx->state));
ctx->mdlen = mdlen;
ctx->rate = 200 - 2 * mdlen; /* 对于SHA3-256,rate=1088,capacity=512 */
ctx->left = 0;
}
// 吸收数据
void sha3_update(sha3_ctx *ctx, const uint8_t *data, size_t len)
{
size_t i, j;
if (ctx->left) {
j = (len < ctx->rate - ctx->left) ? len : ctx->rate - ctx->left;
memcpy(ctx->buf + ctx->left, data, j);
ctx->left += j;
data += j;
len -= j;
if (ctx->left == ctx->rate) {
sha3_keccakf(ctx->state);
ctx->left = 0;
}
}
while (len >= ctx->rate) {
for (i = 0; i < ctx->rate; i++) {
ctx->state[i] ^= data[i];
}
sha3_keccakf(ctx->state);
data += ctx->rate;
len -= ctx->rate;
}
if (len) {
memcpy(ctx->buf, data, len);
ctx->left = len;
}
}
// 挤压出结果
void sha3_final(uint8_t *md, sha3_ctx *ctx)
{
size_t i;
ctx->buf[ctx->left++] = 0x06;
memset(ctx->buf + ctx->left, 0, ctx->rate - ctx->left);
ctx->buf[ctx->rate - 1] |= 0x80;
for (i = 0; i < ctx->rate; i++) {
ctx->state[i] ^= ctx->buf[i];
}
sha3_keccakf(ctx->state);
memcpy(md, ctx->state, ctx->mdlen);
}
SHA-3 家族包括 SHA3-224、SHA3-256、SHA3-384、SHA3-512 以及 SHAKE128 和 SHAKE256 可扩展输出函数。
五、哈希算法的应用场景
哈希算法在计算机科学和信息安全领域有广泛应用:
- 数据完整性校验:通过比较文件的哈希值,验证文件是否被篡改或损坏
- 密码存储:存储密码的哈希值而非明文,提高安全性
- 数字签名:与非对称加密结合,用于验证数据的来源和完整性
- 数据去重:通过哈希值快速识别重复数据,节省存储空间
- 区块链技术:作为区块链的核心技术,用于链接区块和保证数据不可篡改
六、哈希算法的安全性比较
| 算法 | 哈希值长度 | 安全性状态 | 推荐使用场景 |
|---|---|---|---|
| MD5 | 128 位 | 已被破解,不安全 | 仅用于兼容性,不用于安全场景 |
| SHA-1 | 160 位 | 已被破解,不安全 | 逐步淘汰,仅用于兼容性 |
| SHA-256 | 256 位 | 安全 | 大多数安全场景的首选 |
| SHA-512 | 512 位 | 安全 | 高安全性要求的场景 |
| SHA3-256 | 256 位 | 安全 | 对算法多样性有要求的场景 |
| SHA3-512 | 512 位 | 安全 | 最高安全性要求的场景 |
七、未来展望
随着量子计算技术的发展,传统哈希算法可能面临新的挑战。研究人员正在积极探索抗量子哈希算法,以应对未来量子计算机可能带来的威胁。
同时,哈希算法的应用场景也在不断扩展,从传统的信息安全领域向分布式系统、云计算、大数据等领域渗透,成为现代信息技术的基础组件。
结论
哈希算法从 MD5 到 SHA3 的演进历程,反映了密码学研究的不断深入和信息安全需求的持续提升。每一代算法都在前一代的基础上进行改进,提高安全性和效率。
在实际应用中,我们应根据具体场景选择合适的哈希算法,避免使用已被证明不安全的 MD5 和 SHA-1,优先选择 SHA-256 或 SHA-3 等更安全的算法。
随着技术的发展,哈希算法将继续演进,为信息社会的安全提供更加坚实的基础保障。了解哈希算法的原理和发展历程,对于每一位信息技术从业者都具有重要意义。
openHiTLS旨在打造算法先进、性能卓越、高效敏捷、安全可靠的密码套件,通过轻量级、可剪裁的软件技术架构满足各行业不同场景的多样化要求,让密码技术应用更简单,同时探索后量子等先进算法创新实践,构建密码前沿技术底座!
项目地址:https://gitcode.com/openHiTLS/openhitls

13万+

被折叠的 条评论
为什么被折叠?



