SHA-256简介
SHA-256 是 **SHA-2(Secure Hash Algorithm 2)**家族中的一种哈希算法,由美国国家安全局设计,并于 2001 年发布。它能够将任意长度的数据映射为一个固定长度256 位,即 32 字节的哈希值,通常以 64 个十六进制字符的形式表示。SHA-256 被广泛用于数据完整性验证、数字签名、区块链等领。
SHA-256 的特点
- 固定输出长度 :
- SHA-256 生成的哈希值始终是 256 位(32 字节)。
- 不可逆性 :
- 从哈希值无法反推出原始数据。
- 雪崩效应 :
- 输入数据的微小变化会导致输出哈希值的巨大变化。
- 抗碰撞性 :
- 设计上极难找到两个不同的输入生成相同的哈希值。
- 高效性 :
- 计算速度快,适合处理大量数据。
- 安全性 :
- 目前尚未发现有效的攻击方法,被广泛认为是安全的。
SHA-256 的应用场景
- 数据完整性验证 :
- 通过比较文件的 SHA-256 值,可以验证文件是否被篡改。
- 数字签名 :
- 用于生成数据的唯一标识,确保数据的真实性和完整性。
- 区块链 :
- 比特币和其他加密货币使用 SHA-256 进行区块哈希计算。
- 密码存储 :
- 用于存储用户密码的哈希值(通常与盐值结合使用)。
- 证书和密钥 :
- 用于生成 SSL/TLS 证书和密钥。
SHA-256 的工作原理
SHA-256 的计算过程可以分为以下几个步骤:
1. 填充数据
- 将输入数据的长度填充至 512 位(64 字节)的倍数。
- 填充方式:在数据末尾添加一个
1
,然后添加若干个0
,最后添加一个 64 位的整数,表示原始数据的长度。
2. 初始化哈希值
-
SHA-256 使用 8 个 32 位的状态变量(A, B, C, D, E, F, G, H),初始值为以下常量:
iniA = 0x6A09E667 B = 0xBB67AE85 C = 0x3C6EF372 D = 0xA54FF53A E = 0x510E527F F = 0x9B05688C G = 0x1F83D9AB H = 0x5BE0CD19
3. 分块处理
- 将填充后的数据分割成若干个 512 位(64 字节)的块。
- 对每个块进行 64 轮处理。
4. 64 轮变换
- 每轮使用以下非线性函数和常量:
- Ch :
Ch(x, y, z) = (x & y) ^ (~x & z)
- Maj :
Maj(x, y, z) = (x & y) ^ (x & z) ^ (y & z)
- Σ0 :
Σ0(x) = (x >>> 2) ^ (x >>> 13) ^ (x >>> 22)
- Σ1 :
Σ1(x) = (x >>> 6) ^ (x >>> 11) ^ (x >>> 25)
- 常量表:使用 64 个预定义的常量值。
- Ch :
5. 更新哈希值
- 每轮处理后,更新状态变量(A, B, C, D, E, F, G, H)。
6. 输出哈希值
- 将最终的 8 个状态变量(A, B, C, D, E, F, G, H)按大端序拼接,生成 256 位的哈希值。
SHA-256 的伪代码
以下是 SHA-256 算法的简化伪代码:
plaintext
Input: 数据 data
Output: 256 位的哈希值
1. 填充数据:
- 在 data 末尾添加 1 和若干个 0,使其长度 ≡ 448 mod 512
- 在末尾添加 64 位的原始数据长度
2. 初始化哈希值:
A = 0x6A09E667
B = 0xBB67AE85
C = 0x3C6EF372
D = 0xA54FF53A
E = 0x510E527F
F = 0x9B05688C
G = 0x1F83D9AB
H = 0x5BE0CD19
3. 对每个 512 位块进行处理:
- 将块分割为 16 个 32 位字
- 扩展为 64 个 32 位字
- 进行 64 轮变换
4. 输出哈希值:
- 将 A, B, C, D, E, F, G, H 按大端序拼接
- 转换为 64 个十六进制字符
SHA-256 的代码实现
以下是 SHA-256 的 C 语言实现的核心部分:
c
#include <stdio.h>
#include <string.h>
#include <stdint.h>
// SHA-256 状态变量
typedef struct {
uint32_t state[8]; // A, B, C, D, E, F, G, H
uint8_t buffer[64]; // 缓冲区
uint64_t length; // 数据长度
} SHA256_CTX;
// 初始化 SHA-256 上下文
void SHA256_Init(SHA256_CTX *ctx) {
ctx->state[0] = 0x6A09E667;
ctx->state[1] = 0xBB67AE85;
ctx->state[2] = 0x3C6EF372;
ctx->state[3] = 0xA54FF53A;
ctx->state[4] = 0x510E527F;
ctx->state[5] = 0x9B05688C;
ctx->state[6] = 0x1F83D9AB;
ctx->state[7] = 0x5BE0CD19;
ctx->length = 0;
}
// 更新 SHA-256 上下文
void SHA256_Update(SHA256_CTX *ctx, const uint8_t *data, size_t len) {
// 处理数据块
}
// 生成最终的 SHA-256 哈希值
void SHA256_Final(SHA256_CTX *ctx, uint8_t digest[32]) {
// 填充数据并生成哈希值
}
// 计算数据的 SHA-256 值
void SHA256(const uint8_t *data, size_t len, uint8_t digest[32]) {
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, data, len);
SHA256_Final(&ctx, digest);
}
SHA-256 的优缺点
优点:
- 安全性高:抗碰撞性强,尚未发现有效的攻击方法。
- 固定输出长度:便于存储和比较。
- 高效性:计算速度快,适合处理大量数据。
缺点:
- 计算资源消耗较大:相比 MD5,SHA-256 的计算开销更大。
- 不适合密码存储:虽然安全,但通常需要与盐值结合使用。
以下是 MD5 和 SHA-256 的对比表格:
特性 | MD5 | SHA-256 |
---|---|---|
全称 | Message Digest Algorithm 5 | Secure Hash Algorithm 256-bit |
设计者 | Ronald Rivest | 美国国家安全局(NSA) |
发布时间 | 1991 | 2001 |
输出长度 | 128 位(16 字节) | 256 位(32 字节) |
哈希值表示 | 32 个十六进制字符 | 64 个十六进制字符 |
不可逆性 | 是 | 是 |
雪崩效应 | 是 | 是 |
抗碰撞性 | 弱(存在碰撞风险) | 强(尚未发现有效碰撞攻击) |
计算速度 | 快 | 较慢(比 MD5 慢) |
安全性 | 不安全(已被证明存在碰撞漏洞) | 安全(目前无有效攻击方法) |
应用场景 | 文件校验、数据去重(不推荐用于安全场景) | 文件校验、数字签名、区块链、密码存储 |
填充方式 | 填充至 448 位(56 字节)的倍数 | 填充至 512 位(64 字节)的倍数 |
状态变量 | 4 个(A, B, C, D) | 8 个(A, B, C, D, E, F, G, H) |
处理轮数 | 4 轮(每轮 16 次操作) | 64 轮 |
非线性函数 | F, G, H, I | Ch, Maj, Σ0, Σ1 |
常量表 | 无 | 64 个预定义常量 |
初始值 | A=0x67452301, B=0xEFCDAB89, C=0x98BADCFE, D=0x10325476 | A=0x6A09E667, B=0xBB67AE85, C=0x3C6EF372, D=0xA54FF53A, E=0x510E527F, F=0x9B05688C, G=0x1F83D9AB, H=0x5BE0CD19 |
推荐使用场景 | 非安全性场景(如文件校验) | 安全性要求高的场景(如数字签名、区块链) |
- MD5:计算速度快,但安全性不足,已被证明存在碰撞漏洞,不推荐用于安全性要求高的场景。
- SHA-256:安全性高,抗碰撞性强,是目前广泛使用的哈希算法,适合安全性要求高的场景。