Skip to content

SHA-1(Secure Hash Algorithm 1)

SHA-1(Secure Hash Algorithm 1)是一种密码学哈希函数,由美国国家安全局(NSA)设计并由美国国家标准与技术研究院(NIST)发布。它于1993年首次推出,是SHA家族中最早的成员之一,生成一个160位(20字节)的哈希值。

SHA-1的特点

  • 固定长度输出:无论输入数据的长度如何,SHA-1总是生成160位(20字节)的哈希值。
  • 输入长度不限:可以处理任意长度的数据输入。
  • 广泛应用:SHA-1曾广泛应用于数字签名、证书、加密协议(如SSL/TLS)、版本控制系统(如Git)等领域。

SHA-1的工作原理

SHA-1算法主要包括以下几个步骤:

  1. 消息填充:将输入数据扩展到一个比特长度为64比特的整数倍的长度,并在数据末尾附加一个1比特的“1”,然后是若干个“0”,最后附加一个64比特的数,用于表示原始消息的长度。

  2. 初始化缓冲区:SHA-1使用五个32位寄存器(A、B、C、D、E)作为缓冲区,初始值为特定的常量。

  3. 处理消息块:将消息分成512比特的块,每块依次进行80轮的复杂操作。在每一轮中,使用逻辑函数、非线性函数、位操作和常量,将消息块与缓冲区中的数据进行混合。

  4. 生成哈希值:所有消息块处理完成后,缓冲区中的内容被连接起来,生成160位的哈希值。

安全性问题

尽管SHA-1曾是一个广泛应用的哈希算法,但随着时间的推移,研究人员发现了它的安全性问题:

  • 碰撞攻击:在2005年,研究人员首次展示了SHA-1存在实际的碰撞攻击漏洞,即可以找到两个不同的输入产生相同的哈希值。2017年,Google首次展示了一个实际的SHA-1碰撞攻击。
  • 不推荐使用:由于这些安全性问题,SHA-1已被认为不再安全。在现代加密和数据验证应用中,SHA-1不再推荐使用,尤其是在需要高安全性的场合,通常建议使用更安全的SHA-256或SHA-3等算法。

应用和现状

  • 历史应用:SHA-1在过去的很多应用中得到了广泛使用,包括HTTPS、PGP、SSH等加密协议,以及Git等版本控制系统。
  • 逐渐淘汰:由于其安全性问题,许多系统和协议已经逐步淘汰SHA-1,改用更安全的哈希算法。

C语言实现

//
// Created by shug on 2024/8/24.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
typedef struct {
uint32_t state[5]; // ABCDE五个状态变量
uint32_t count[2]; // 计数器,表示已经处理的位数
uint8_t buffer[64]; // 输入缓冲区
} SHA1_CTX;
void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]);
void SHA1_Init(SHA1_CTX *context);
void SHA1_Update(SHA1_CTX *context, const uint8_t *data, uint32_t len);
void SHA1_Final(uint8_t digest[20], SHA1_CTX *context);
void SHA1_Encode(uint8_t *output, uint32_t *input, uint32_t len);
void SHA1_Decode(uint32_t *output, const uint8_t *input, uint32_t len);
void SHA1_memcpy(uint8_t *output, const uint8_t *input, uint32_t len);
void SHA1_memset(uint8_t *output, int value, uint32_t len);
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
#define F0(b, c, d) ((b & c) | (~b & d))
#define F1(b, c, d) (b ^ c ^ d)
#define F2(b, c, d) ((b & c) | (b & d) | (c & d))
#define FF0(a, b, c, d, e, w) { \
e += ROTATE_LEFT(a, 5) + F0(b, c, d) + w + 0x5A827999; \
b = ROTATE_LEFT(b, 30); \
}
#define FF1(a, b, c, d, e, w) { \
e += ROTATE_LEFT(a, 5) + F1(b, c, d) + w + 0x6ED9EBA1; \
b = ROTATE_LEFT(b, 30); \
}
#define FF2(a, b, c, d, e, w) { \
e += ROTATE_LEFT(a, 5) + F2(b, c, d) + w + 0x8F1BBCDC; \
b = ROTATE_LEFT(b, 30); \
}
#define FF3(a, b, c, d, e, w) { \
e += ROTATE_LEFT(a, 5) + F1(b, c, d) + w + 0xCA62C1D6; \
b = ROTATE_LEFT(b, 30); \
}
// 初始化SHA1上下文
void SHA1_Init(SHA1_CTX *context) {
context->count[0] = context->count[1] = 0;
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
context->state[4] = 0xC3D2E1F0;
}
// 更新SHA1上下文
void SHA1_Update(SHA1_CTX *context, const uint8_t *data, uint32_t len) {
uint32_t i, j;
j = (context->count[0] >> 3) & 63;
if ((context->count[0] += len << 3) < (len << 3)) {
context->count[1]++;
}
context->count[1] += (len >> 29);
if ((j + len) > 63) {
SHA1_memcpy(&context->buffer[j], data, (i = 64 - j));
SHA1_Transform(context->state, context->buffer);
for (; i + 63 < len; i += 64) {
SHA1_Transform(context->state, &data[i]);
}
j = 0;
} else {
i = 0;
}
SHA1_memcpy(&context->buffer[j], &data[i], len - i);
}
// 最终生成SHA1哈希值
void SHA1_Final(uint8_t digest[20], SHA1_CTX *context) {
uint8_t finalcount[8];
uint32_t i;
for (i = 0; i < 8; i++) {
finalcount[i] = (uint8_t)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255);
}
SHA1_Update(context, (uint8_t *)"\200", 1);
while ((context->count[0] & 504) != 448) {
SHA1_Update(context, (uint8_t *)"\0", 1);
}
SHA1_Update(context, finalcount, 8);
SHA1_Encode(digest, context->state, 20);
SHA1_memset((uint8_t *)context, 0, sizeof(*context));
}
// SHA1的核心变换函数
void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]) {
uint32_t a, b, c, d, e, t, w[80];
SHA1_Decode(w, buffer, 64);
for (t = 16; t < 80; t++) {
w[t] = ROTATE_LEFT(w[t-3] ^ w[t-8] ^ w[t-14] ^ w[t-16], 1);
}
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
for (t = 0; t < 20; t++) {
FF0(a, b, c, d, e, w[t]);
t++;
FF0(e, a, b, c, d, w[t]);
t++;
FF0(d, e, a, b, c, w[t]);
t++;
FF0(c, d, e, a, b, w[t]);
t++;
FF0(b, c, d, e, a, w[t]);
}
for (; t < 40; t++) {
FF1(a, b, c, d, e, w[t]);
t++;
FF1(e, a, b, c, d, w[t]);
t++;
FF1(d, e, a, b, c, w[t]);
t++;
FF1(c, d, e, a, b, w[t]);
t++;
FF1(b, c, d, e, a, w[t]);
}
for (; t < 60; t++) {
FF2(a, b, c, d, e, w[t]);
t++;
FF2(e, a, b, c, d, w[t]);
t++;
FF2(d, e, a, b, c, w[t]);
t++;
FF2(c, d, e, a, b, w[t]);
t++;
FF2(b, c, d, e, a, w[t]);
}
for (; t < 80; t++) {
FF3(a, b, c, d, e, w[t]);
t++;
FF3(e, a, b, c, d, w[t]);
t++;
FF3(d, e, a, b, c, w[t]);
t++;
FF3(c, d, e, a, b, w[t]);
t++;
FF3(b, c, d, e, a, w[t]);
}
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
SHA1_memset((uint8_t *)w, 0, sizeof(w));
}
// 编码,将32位整数转换为字节序列
void SHA1_Encode(uint8_t *output, uint32_t *input, uint32_t len) {
uint32_t i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (uint8_t)((input[i] >> 24) & 0xff);
output[j + 1] = (uint8_t)((input[i] >> 16) & 0xff);
output[j + 2] = (uint8_t)((input[i] >> 8) & 0xff);
output[j + 3] = (uint8_t)(input[i] & 0xff);
}
}
// 解码,将字节序列转换为32位整数
void SHA1_Decode(uint32_t *output, const uint8_t *input, uint32_t len) {
uint32_t i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[i] = ((uint32_t)input[j] << 24) |
((uint32_t)input[j + 1] << 16) |
((uint32_t)input[j + 2] << 8) |
((uint32_t)input[j + 3]);
}
}
// 内存拷贝
void SHA1_memcpy(uint8_t *output, const uint8_t *input, uint32_t len) {
uint32_t i;
for (i = 0; i < len; i++) {
output[i] = input[i];
}
}
// 内存设置
void SHA1_memset(uint8_t *output, int value, uint32_t len) {
uint32_t i;
for (i = 0; i < len; i++) {
output[i] = (uint8_t)value;
}
}
// 打印哈希值
void SHA1_Print(uint8_t digest[20]) {
for (int i = 0; i < 20; i++) {
printf("%02x", digest[i]);
}
printf("\n");
}
int main(int argc, char *argv[]) {
SHA1_CTX context;
uint8_t digest[20];
uint8_t *string = (uint8_t *)"hello world";
SHA1_Init(&context);
SHA1_Update(&context, string, strlen((char *)string));
SHA1_Final(digest, &context);
printf("SHA1 (\"%s\") = ", string);
SHA1_Print(digest);
return 0;
}