本文基于Redis 2.8.19
导读
SHA-1算法是第一代“安全散列算法”的缩写,其本质就是一个Hash算法。SHA系列标准主要用于生成消息摘要(摘要经加密后成为数字签名),曾被认为是MD5算法的后继者。如今SHA家族已经出现了5个算法。Redis使用的是SHA-1,它能将一个最大2^64比特的消息,转换成一串160位的消息摘要,并能保证任何两组不同的消息产生的消息摘要是不同的。虽然SHA1于早年间也传出了破解之道,但作为SHA家族的第一代算法,对我们仍然很具有学习价值和指导意义。
SHA-1算法的详细内容可以参考官方的RFC:http://www.ietf.org/rfc/rfc3174.txt
Redis的sha1.c文件实现了这一算法,但该文件源码实际上是出自Valgrind项目的/tests/sha1_test.c文件(可以看出开源的强大之处:取之于民,用之于民)。它包含四个函数:
- SHA1Init
- SHA1Update
- SHA1Transform
- SHA1Final
SHA1算法流程概述
sha-1算法大致分为5步:
- 附加填充位
- 附加长度
- 初始化散列缓冲区
- 计算信息摘要
- 输出/返回
附加填充位、长度
理论基础
给消息
附加填充位使其模512与448同余(M%512 == 448)。即使满足了条件也要填充512位(比特)。填充过程是这样的:先补一位1,后面一律补0,直至满足条件。因此至少填充1位,最多填充512位。
因为我们存储的时候是以字节为单位存储的,所以我们的消息的长度(单位:位)一定是8的倍数。而我们填充的时候也一定是8位,8位的来填充。也即不可能只填充一个二进制位,至少是8个二进制位(一个字节)。因此最少填充1个字节,最多填充64个字节(64*8=512)。
在附加填充位完成之后,还要
附加长度,即附加64位数据来存储原始消息的长度。因为在附加填充位完成之后,消息长度(单位:位)是512与448同余,而此时再附加64位之后,消息长度就变成了512的整数倍。
最后我们开始计算消息摘要的时候,就是每512位为一组开始计算的。
SHA_CTX结构
SHA_CTX 结构在头文件sha1.h中定义:
typedef struct {
u_int32_t state[5];
u_int32_t count[2];
unsigned char buffer[64];
} SHA1_CTX;
它有三个成员,其含义如下:
成员 | 类型 | 说明 |
---|---|---|
buffer | unsigned char[64] | 512(64×8)比特(位)的消息块(由原始消息经处理得出) |
state | u_int32_t[5] | 160(5×32)比特的消息摘要(即SHA-1算法要得出的) |
count | u_int32_t[2] | 储存消息的长度(单位:比特) |
SHA1Final
SHA1Final()是整个算法的入口与出口。该函数通过调用该文件内其他函数完成了SHA-1算法的整个流程。它的声明如下:
void SHA1Final(unsigned char digest[20], SHA1_CTX* context);