一、原理
SHA-1 是一种数据加密算法,该算法的思想是接收一段明文,然后以不可逆的方式将其转换为一段密文,这也可以简单理解为输入一串二进制代码并将它们转换为长度更短、位数固定的输出序列,即哈希值,也称为消息摘要或消息认证码。 SHA-1算法输入消息的最大长度不超过 2^64 位,得到的输出是一个 160 位的消息摘要。输入以 512 位的数据包进行处理。SHA-1 是不可逆的,具有抗冲突性,并且具有良好的雪崩效应。
- 初始化函数:初始化算法的状态并设置哈希的初始值。在 SHA-1 中,这是 sha1 init 函数的作用。
- 处理块函数:处理输入消息的每个块,执行一系列轮次来更新哈希状态。在 SHA-1 中,这是 sha1 process block 函数的作用。
- 输出函数:在所有块都处理完毕后产生最终的哈希值。在 SHA-1 中,这是 sha1 final 函数的作用。 处理块函数是 SHA-1 算法的核心,它接受每一个 512 位的消息块,并通过一系列轮次更新哈希状态。这个函数的设计包括消息块的分割、轮循操作以及逻辑函数的应用,以确保算法的安全性和性能。 这种结构允许 SHA-1 算法通过迭代应用处理块函数来处理任意长度的消息,同时保持对抗碰撞攻击的性能。在实践中,处理块函数的设计和实现对哈希算法的安全性至关重要。
二、C/C++实现
SHA_1.h
#include <stdlib.h>
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
//SHA-1 哈希上下文结构
typedef struct hash_context
{
uint8_t buffer[64];
uint32_t state[5];
uint32_t total[2];
} hash_context;
// 初始化哈希函数数据和缓冲区
void hash_start(hash_context* ctx);
//更新哈希上下文。input为输入,ilen为输入数据的长度,单位为Bytes
void hash_update(hash_context* ctx, uint8_t* input, size_t ilen);
//完成哈希计算,并输出结果
void hash_finish(hash_context* ctx, uint8_t* output);
SHA_1.cpp
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "SHA_1.h"
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
// SHA-1 相关的宏定义
#define LEFT_ROTATE(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define EP0(x) (LEFT_ROTATE(x, 5) ^ LEFT_ROTATE(x, 14) ^ LEFT_ROTATE(x, 30))
#define EP1(x) (LEFT_ROTATE(x, 3) ^ LEFT_ROTATE(x, 12) ^ LEFT_ROTATE(x, 25))
// 常量 K
static const uint32_t K[] = {
0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6
};
//typedef struct hash_context
//{
// uint8_t buffer[64];
// uint32_t state[5];
// uint32_t total[2];
//} hash_context;
void hash_start(hash_context* ctx)
{
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xC3D2E1F0;
ctx->total[0] = 0;
ctx->total[1] = 0;
}
void process_block(hash_context* ctx, const uint8_t* data)
{
uint32_t w[80];
uint32_t a, b, c, d, e, temp;
int t;
for (t = 0; t < 16; ++t) {
w[t] = (data[t * 4] << 24) | (data[t * 4 + 1] << 16) |
(data[t * 4 + 2] << 8) | (data[t * 4 + 3]);
}
for (t = 16; t < 80; ++t) {
w[t] = LEFT_ROTATE((w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]), 1);
}
a = ctx->state[0];
b = ctx->state[1];
c = ctx->state[2];
d = ctx->state[3];
e = ctx->state[4];
for (t = 0; t < 80; ++t) {
if (t < 20)
temp = CH(b, c, d) + K[0];
else if (t < 40)
temp = MAJ(b, c, d) + K[1];
else if (t < 60)
temp = CH(b, c, d) + K[2];
else
temp = MAJ(b, c, d) + K[3];
temp += LEFT_ROTATE(a, 5) + e + w[t];
e = d;
d = c;
c = LEFT_ROTATE(b, 30);
b = a;
a = temp;
}
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
ctx->state[4] += e;
}
void hash_update(hash_context* ctx, uint8_t* input, size_t ilen)
{
size_t fill;
uint32_t left;
if (ilen == 0)
return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (uint32_t)ilen;
ctx->total[0] &= 0xFFFFFFFF;
if (ctx->total[0] < (uint32_t)ilen)
ctx->total[1]++;
if (left && ilen >= fill) {
memcpy((void*)(ctx->buffer + left), input, fill);
process_block(ctx, ctx->buffer);
input += fill;
ilen -= fill;
left = 0;
}
while (ilen >= 64) {
process_block(ctx, input);
input += 64;
ilen -= 64;
}
if (ilen > 0) {
memcpy((void*)(ctx->buffer + left), input, ilen);
}
}
void hash_finish(hash_context* ctx, uint8_t* output)
{
uint32_t last, padn;
uint32_t high, low;
uint8_t msglen[8];
high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
low = (ctx->total[0] << 3);
msglen[0] = (uint8_t)(high >> 24);
msglen[1] = (uint8_t)(high >> 16);
msglen[2] = (uint8_t)(high >> 8);
msglen[3] = (uint8_t)(high);
msglen[4] = (uint8_t)(low >> 24);
msglen[5] = (uint8_t)(low >> 16);
msglen[6] = (uint8_t)(low >> 8);
msglen[7] = (uint8_t)(low);
last = ctx->total[0] & 0x3F;
padn = (last < 56) ? (56 - last) : (120 - last);
hash_update(ctx, (uint8_t*)"\x80", 1);
hash_update(ctx, (uint8_t*)(msglen + 1), padn - 1);
hash_update(ctx, msglen, 8);
for (int i = 0; i < 5; i++) {
output[i * 4] = (uint8_t)(ctx->state[i] >> 24);
output[i * 4 + 1] = (uint8_t)(ctx->state[i] >> 16);
output[i * 4 + 2] = (uint8_t)(ctx->state[i] >> 8);
output[i * 4 + 3] = (uint8_t)(ctx->state[i]);
}
}
/************************** 宏定义 **************************/
#define DATA_SIZE 1073741824
#define ROUNDS 1
/************************* 函数定义 *************************/
uint8_t data[DATA_SIZE];
int main()
{
hash_context ctx;
uint8_t hash[20];
clock_t start, end;
// 生成随机数据填充到data数组中
for (int i = 0; i < DATA_SIZE; i++)
{
data[i] = rand() & 0xFF;
}
// 开始计时
start = clock();
for (int i = 0; i < ROUNDS; i++)
{
hash_start(&ctx);
hash_update(&ctx, data, DATA_SIZE);
hash_finish(&ctx, hash);
}
// 结束计时
end = clock();
// 计算总运行时间和每秒处理的数据量
double time = (double)(end - start) / CLOCKS_PER_SEC;
double computing_speed = (DATA_SIZE * ROUNDS * (unsigned long long)8 / 1000 / 1000) / time;
printf("运行时间: %f seconds\n", time);
printf("运算速度: %f Mbps\n", computing_speed);
return 0;
}