SHA-1算法的原理与C/C++实现

一、原理

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;
}

三、运行结果

  • 9
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是SHA-1算法的C语言实现,包含了初始化、填充、转换和输出四个步骤: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #define SHA1_BLOCK_SIZE 20 // SHA-1 functions #define SHA1_ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) #define SHA1_ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) #define SHA1_CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) #define SHA1_MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) #define SHA1_E0(x) (SHA1_ROTRIGHT(x, 2) ^ SHA1_ROTRIGHT(x, 13) ^ SHA1_ROTRIGHT(x, 22)) #define SHA1_E1(x) (SHA1_ROTRIGHT(x, 6) ^ SHA1_ROTRIGHT(x, 11) ^ SHA1_ROTRIGHT(x, 25)) #define SHA1_F0(x) (SHA1_ROTRIGHT(x, 7) ^ SHA1_ROTRIGHT(x, 18) ^ ((x) >> 3)) #define SHA1_F1(x) (SHA1_ROTRIGHT(x, 17) ^ SHA1_ROTRIGHT(x, 19) ^ ((x) >> 10)) void sha1_transform(uint32_t *state, const uint8_t *buffer) { uint32_t a, b, c, d, e, temp; uint32_t w[80]; int i; // Copy buffer to work array for (i = 0; i < 16; i++) { w[i] = ((uint32_t)buffer[i * 4]) << 24; w[i] |= ((uint32_t)buffer[i * 4 + 1]) << 16; w[i] |= ((uint32_t)buffer[i * 4 + 2]) << 8; w[i] |= ((uint32_t)buffer[i * 4 + 3]); } for (i = 16; i < 80; i++) { w[i] = SHA1_ROTLEFT(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1); } a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; for (i = 0; i < 20; i++) { temp = SHA1_ROTLEFT(a, 5) + SHA1_CH(b, c, d) + e + w[i] + 0x5a827999; e = d; d = c; c = SHA1_ROTLEFT(b, 30); b = a; a = temp; } for (i = 20; i < 40; i++) { temp = SHA1_ROTLEFT(a, 5) + SHA1_MAJ(b, c, d) + e + w[i] + 0x6ed9eba1; e = d; d = c; c = SHA1_ROTLEFT(b, 30); b = a; a = temp; } for (i = 40; i < 60; i++) { temp = SHA1_ROTLEFT(a, 5) + SHA1_CH(b, c, d) + e + w[i] + 0x8f1bbcdc; e = d; d = c; c = SHA1_ROTLEFT(b, 30); b = a; a = temp; } for (i = 60; i < 80; i++) { temp = SHA1_ROTLEFT(a, 5) + SHA1_MAJ(b, c, d) + e + w[i] + 0xca62c1d6; e = d; d = c; c = SHA1_ROTLEFT(b, 30); b = a; a = temp; } state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; } void sha1_init(uint32_t *state) { state[0] = 0x67452301; state[1] = 0xefcdab89; state[2] = 0x98badcfe; state[3] = 0x10325476; state[4] = 0xc3d2e1f0; } void sha1_pad(uint8_t *buffer, int len) { int i; buffer[len] = 0x80; for (i = len + 1; i % 64 != 56; i++) { buffer[i] = 0x00; } len *= 8; buffer[i++] = (len >> 56) & 0xff; buffer[i++] = (len >> 48) & 0xff; buffer[i++] = (len >> 40) & 0xff; buffer[i++] = (len >> 32) & 0xff; buffer[i++] = (len >> 24) & 0xff; buffer[i++] = (len >> 16) & 0xff; buffer[i++] = (len >> 8) & 0xff; buffer[i++] = len & 0xff; } void sha1_digest(const uint32_t *state, uint8_t *hash) { int i; for (i = 0; i < 5; i++) { hash[i * 4] = (state[i] >> 24) & 0xff; hash[i * 4 + 1] = (state[i] >> 16) & 0xff; hash[i * 4 + 2] = (state[i] >> 8) & 0xff; hash[i * 4 + 3] = state[i] & 0xff; } } void sha1(const uint8_t *data, int len, uint8_t *hash) { uint32_t state[5]; uint8_t buffer[64]; int i; sha1_init(state); for (i = 0; i < len / 64; i++) { memcpy(buffer, data + i * 64, 64); sha1_transform(state, buffer); } memcpy(buffer, data + i * 64, len % 64); sha1_pad(buffer, len % 64); sha1_transform(state, buffer); sha1_digest(state, hash); } int main() { uint8_t data[] = "hello world"; uint8_t hash[SHA1_BLOCK_SIZE]; sha1(data, strlen((char*)data), hash); printf("SHA1 hash of \"%s\": ", data); for (int i = 0; i < SHA1_BLOCK_SIZE; i++) { printf("%02x", hash[i]); } printf("\n"); return 0; } ``` 在这个实现中,`sha1()`函数接受一个输入数据和长度,以及一个输出缓冲区,将计算出的SHA-1摘要存储在缓冲区中。主函数演示了如何使用该函数计算数据的SHA-1摘要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是巴巴布莱特呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值