【安全算法之SHA1】SHA1摘要运算的C语言源码实现

  • 概述
  • 头文件定义
  • C语言版本的实现源码
  • 测试用例
  • github仓库
  • 更多参考链接

概述

大家都知道摘要算法在安全领域,也是一个特别重要的存在,而SHA1是其中比较常见的一种摘要算法,它的特点就是计算复杂度较低,不等长的数据原文输入,可以得出等长的摘要值,这个值是固定为20字节。正是由于这种特殊性,很多重要的数据完整性校验领域,都可以看到SHA1的影子。
今天给大家带来SHA1的C源码版本实现,欢迎大家深入学习和讨论。

头文件定义

头文件定义如下,主要定义了SHA1的上下文结构体,以及导出的三个API:


#ifndef __SHA1_H__
#define __SHA1_H__#include <stdint.h>#define SHA1_DIGEST_LEN 20           // SHA1 outputs a 20 byte digesttypedef struct _sha1_ctx_t {uint32_t        total[2];       /*!< number of bytes processed  */uint32_t       state[5];       /*!< intermediate digest state  */uint8_t        buffer[64];     /*!< data block being processed */
} sha1_ctx_t;void crypto_sha1_init(sha1_ctx_t *ctx);
void crypto_sha1_update(sha1_ctx_t *ctx, const uint8_t *data, uint32_t len);
void crypto_sha1_final(sha1_ctx_t *ctx, uint8_t *digest);#endif   // __SHA1_H__

C语言版本的实现源码

下面是SHA1的C语言版本实现,主要也是围绕导出的3个API:


#include <string.h>
#include "sha1.h"/** 32-bit integer manipulation macros (big endian)*/
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n, b, i)                                              \{                                                                       \(n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | \((uint32_t)(b)[(i) + 2] << 8) | ((uint32_t)(b)[(i) + 3]);     \}
#endif#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n, b, i)                  \{                                           \(b)[(i)]     = (uint8_t)((n) >> 24);    \(b)[(i) + 1] = (uint8_t)((n) >> 16);    \(b)[(i) + 2] = (uint8_t)((n) >> 8);     \(b)[(i) + 3] = (uint8_t)((n));          \}
#endifstatic const uint8_t sha1_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};static void local_sha1_process(sha1_ctx_t *ctx,const uint8_t   data[64])
{uint32_t temp, W[16], A, B, C, D, E;GET_UINT32_BE(W[0], data, 0);GET_UINT32_BE(W[1], data, 4);GET_UINT32_BE(W[2], data, 8);GET_UINT32_BE(W[3], data, 12);GET_UINT32_BE(W[4], data, 16);GET_UINT32_BE(W[5], data, 20);GET_UINT32_BE(W[6], data, 24);GET_UINT32_BE(W[7], data, 28);GET_UINT32_BE(W[8], data, 32);GET_UINT32_BE(W[9], data, 36);GET_UINT32_BE(W[10], data, 40);GET_UINT32_BE(W[11], data, 44);GET_UINT32_BE(W[12], data, 48);GET_UINT32_BE(W[13], data, 52);GET_UINT32_BE(W[14], data, 56);GET_UINT32_BE(W[15], data, 60);#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))#define R(t)                                                             \(temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ \W[t & 0x0F],                                                 \(W[t & 0x0F] = S(temp, 1)))#define P(a, b, c, d, e, x)                \{                                      \e += S(a, 5) + F(b, c, d) + K + x; \b = S(b, 30);                      \}A = ctx->state[0];B = ctx->state[1];C = ctx->state[2];D = ctx->state[3];E = ctx->state[4];#define F(x, y, z) (z ^ (x & (y ^ z)))
#define K 0x5A827999P(A, B, C, D, E, W[0]);P(E, A, B, C, D, W[1]);P(D, E, A, B, C, W[2]);P(C, D, E, A, B, W[3]);P(B, C, D, E, A, W[4]);P(A, B, C, D, E, W[5]);P(E, A, B, C, D, W[6]);P(D, E, A, B, C, W[7]);P(C, D, E, A, B, W[8]);P(B, C, D, E, A, W[9]);P(A, B, C, D, E, W[10]);P(E, A, B, C, D, W[11]);P(D, E, A, B, C, W[12]);P(C, D, E, A, B, W[13]);P(B, C, D, E, A, W[14]);P(A, B, C, D, E, W[15]);P(E, A, B, C, D, R(16));P(D, E, A, B, C, R(17));P(C, D, E, A, B, R(18));P(B, C, D, E, A, R(19));#undef K
#undef F#define F(x, y, z) (x ^ y ^ z)
#define K 0x6ED9EBA1P(A, B, C, D, E, R(20));P(E, A, B, C, D, R(21));P(D, E, A, B, C, R(22));P(C, D, E, A, B, R(23));P(B, C, D, E, A, R(24));P(A, B, C, D, E, R(25));P(E, A, B, C, D, R(26));P(D, E, A, B, C, R(27));P(C, D, E, A, B, R(28));P(B, C, D, E, A, R(29));P(A, B, C, D, E, R(30));P(E, A, B, C, D, R(31));P(D, E, A, B, C, R(32));P(C, D, E, A, B, R(33));P(B, C, D, E, A, R(34));P(A, B, C, D, E, R(35));P(E, A, B, C, D, R(36));P(D, E, A, B, C, R(37));P(C, D, E, A, B, R(38));P(B, C, D, E, A, R(39));#undef K
#undef F#define F(x, y, z) ((x & y) | (z & (x | y)))
#define K 0x8F1BBCDCP(A, B, C, D, E, R(40));P(E, A, B, C, D, R(41));P(D, E, A, B, C, R(42));P(C, D, E, A, B, R(43));P(B, C, D, E, A, R(44));P(A, B, C, D, E, R(45));P(E, A, B, C, D, R(46));P(D, E, A, B, C, R(47));P(C, D, E, A, B, R(48));P(B, C, D, E, A, R(49));P(A, B, C, D, E, R(50));P(E, A, B, C, D, R(51));P(D, E, A, B, C, R(52));P(C, D, E, A, B, R(53));P(B, C, D, E, A, R(54));P(A, B, C, D, E, R(55));P(E, A, B, C, D, R(56));P(D, E, A, B, C, R(57));P(C, D, E, A, B, R(58));P(B, C, D, E, A, R(59));#undef K
#undef F#define F(x, y, z) (x ^ y ^ z)
#define K 0xCA62C1D6P(A, B, C, D, E, R(60));P(E, A, B, C, D, R(61));P(D, E, A, B, C, R(62));P(C, D, E, A, B, R(63));P(B, C, D, E, A, R(64));P(A, B, C, D, E, R(65));P(E, A, B, C, D, R(66));P(D, E, A, B, C, R(67));P(C, D, E, A, B, R(68));P(B, C, D, E, A, R(69));P(A, B, C, D, E, R(70));P(E, A, B, C, D, R(71));P(D, E, A, B, C, R(72));P(C, D, E, A, B, R(73));P(B, C, D, E, A, R(74));P(A, B, C, D, E, R(75));P(E, A, B, C, D, R(76));P(D, E, A, B, C, R(77));P(C, D, E, A, B, R(78));P(B, C, D, E, A, R(79));#undef K
#undef Fctx->state[0] += A;ctx->state[1] += B;ctx->state[2] += C;ctx->state[3] += D;ctx->state[4] += E;
}/** SHA-1 process init*/
void crypto_sha1_init(sha1_ctx_t *ctx)
{memset(ctx, 0, sizeof(sha1_ctx_t));ctx->total[0] = 0;ctx->total[1] = 0;ctx->state[0] = 0x67452301;ctx->state[1] = 0xEFCDAB89;ctx->state[2] = 0x98BADCFE;ctx->state[3] = 0x10325476;ctx->state[4] = 0xC3D2E1F0;
}/** SHA-1 process buffer*/
void crypto_sha1_update(sha1_ctx_t *ctx, const uint8_t *input,uint32_t ilen)
{uint32_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);local_sha1_process(ctx, ctx->buffer);input += fill;ilen -= fill;left = 0;}while (ilen >= 64) {local_sha1_process(ctx, input);input += 64;ilen -= 64;}if (ilen > 0) {memcpy((void *)(ctx->buffer + left), input, ilen);}
}/** SHA-1 final digest*/
void crypto_sha1_final(sha1_ctx_t *ctx, uint8_t *digest)
{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);PUT_UINT32_BE(high, msglen, 0);PUT_UINT32_BE(low, msglen, 4);last = ctx->total[0] & 0x3F;padn = (last < 56) ? (56 - last) : (120 - last);crypto_sha1_update(ctx, sha1_padding, padn);crypto_sha1_update(ctx, msglen, 8);PUT_UINT32_BE(ctx->state[0], digest, 0);PUT_UINT32_BE(ctx->state[1], digest, 4);PUT_UINT32_BE(ctx->state[2], digest, 8);PUT_UINT32_BE(ctx->state[3], digest, 12);PUT_UINT32_BE(ctx->state[4], digest, 16);
}

测试用例

针对SHA1导出的三个接口,我编写了以下测试用例:


#include <stdio.h>
#include <string.h>#include "sha1.h"
#include "convert.h"int log_hexdump(const char *title, const unsigned char *data, int len)
{char str[160], octet[10];int ofs, i, k, d;const unsigned char *buf = (const unsigned char *)data;const char dimm[] = "+------------------------------------------------------------------------------+";printf("%s (%d bytes):\r\n", title, len);printf("%s\r\n", dimm);printf("| Offset  : 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F   0123456789ABCDEF |\r\n");printf("%s\r\n", dimm);for (ofs = 0; ofs < (int)len; ofs += 16) {d = snprintf( str, sizeof(str), "| %08X: ", ofs );for (i = 0; i < 16; i++) {if ((i + ofs) < (int)len) {snprintf( octet, sizeof(octet), "%02X ", buf[ofs + i] );} else {snprintf( octet, sizeof(octet), "   " );}d += snprintf( &str[d], sizeof(str) - d, "%s", octet );}d += snprintf( &str[d], sizeof(str) - d, "  " );k = d;for (i = 0; i < 16; i++) {if ((i + ofs) < (int)len) {str[k++] = (0x20 <= (buf[ofs + i]) &&  (buf[ofs + i]) <= 0x7E) ? buf[ofs + i] : '.';} else {str[k++] = ' ';}}str[k] = '\0';printf("%s |\r\n", str);}printf("%s\r\n", dimm);return 0;
}int main(int argc, const char *argv[])
{const char *data = "C1D0F8FB4958670DBA40AB1F3752EF0D";const char *digest_exp_str = "B36BFDB04A31F6C55E0D592B8F2D3219FBC2424D";uint8_t digest_calc[SHA1_DIGEST_LEN];uint8_t digest_exp_hex[SHA1_DIGEST_LEN];sha1_ctx_t ctx;const char *p_calc = data;uint8_t data_bytes[128];uint16_t len_bytes;char data_str[128];if (argc > 1) {p_calc = argv[1];}utils_hex_string_2_bytes(data, data_bytes, &len_bytes);log_hexdump("data_bytes", data_bytes, len_bytes);utils_bytes_2_hex_string(data_bytes, len_bytes, data_str);printf("data_str: %s\n", data_str);if (!strcmp(data, data_str)) {printf("hex string - bytes convert OK\n");} else {printf("hex string - bytes convert FAIL\n");}crypto_sha1_init(&ctx);crypto_sha1_update(&ctx, (uint8_t *)p_calc, strlen(p_calc));crypto_sha1_final(&ctx, digest_calc);utils_hex_string_2_bytes(digest_exp_str, digest_exp_hex, &len_bytes);if (len_bytes == sizeof(digest_calc) && !memcmp(digest_calc, digest_exp_hex, sizeof(digest_calc))) {printf("SHA1 digest test OK\n");log_hexdump("digest_calc", digest_calc, sizeof(digest_calc));} else {log_hexdump("digest_calc", digest_calc, sizeof(digest_calc));log_hexdump("digest_exp", digest_exp_hex, sizeof(digest_exp_hex));printf("SHA1 digest test FAIL\n");}return 0;
}

测试用例比较简单,就是对字符串C1D0F8FB4958670DBA40AB1F3752EF0D进行SHA1运算,期望的摘要结果的hexstring是B36BFDB04A31F6C55E0D592B8F2D3219FBC2424D,这个期望值是用算法工具算出来的。
先用API接口算出摘要值,再与期望值比较,这里有个hexstringtobyte的转换,如果比较一致则表示API计算OK;反之,接口计算失败。
同时,也欢迎大家设计提供更多的测试案例代码。

github仓库

以上代码和测试用例,及编译运行等,可以参考我的github仓库,有详细的流程介绍,欢迎大家交流讨论。如果有帮助到你的话,记得帮忙点亮一颗星哦。

更多参考链接

[1] 【安全算法的github仓库】
[2] 【安全算法之概述】一文带你简要了解常见常用的安全算法
[3] 【安全算法之base64】base64加解密的C语言源码实现
[4] 【安全算法之MD5】MD5摘要运算的C语言源码实现
[5] 【安全算法之SHA1】SHA1摘要运算的C语言源码实现
[6] 【安全算法之SHA224】SHA224摘要运算的C语言源码实现
[7] 【安全算法之SHA256】SHA256摘要运算的C语言源码实现
[8] 【安全算法之SHA384】SHA384摘要运算的C语言源码实现
[9] 【安全算法之SHA512】SHA512摘要运算的C语言源码实现

【安全算法之SHA1】SHA1摘要运算的C语言源码实现相关推荐

  1. 【安全算法之SHA512】SHA512摘要运算的C语言源码实现

    [安全算法之SHA512]SHA512摘要运算的C语言源码实现 概述 头文件定义 C语言版本的实现源码 测试用例 github仓库 更多参考链接 概述 大家都知道摘要算法在安全领域,也是一个特别重要的 ...

  2. 【安全算法之DES】DES算法(支持ECB/CBC模式)的C语言源码实现

    [安全算法之DES]DES算法(支持ECB/CBC模式)的C语言源码实现 概述 头文件定义 C语言版本的实现源码 数据分组模式:ECB模式和CBC模式 测试用例 github仓库 更多参考链接 概述 ...

  3. 【安全算法之base64】base64加解密的C语言源码实现

    最近,有项目中需要用到base64的加解密,所以用C语言实现了一遍,测试效果还不错,代码量和RAM消耗都比较低,可以提供给大家参考下. #include <stdbool.h> #incl ...

  4. 【优化布局】基于matlab免疫算法求解充电站最优布局【含Matlab源码 2539期】

    ⛄一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[生产调度]基于matlab免疫算法求解生产调度零等待问题[含Matlab源码 1178期] 点击上面蓝色字体,直接付费下载,即可. 获取 ...

  5. 【单目标优化求解】基于matlab增强型黑猩猩优化器算法求解单目标优化问题【含Matlab源码 2013期】

    ⛄一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[单目标优化求解]基于matlab增强型黑猩猩优化器算法求解单目标优化问题[含Matlab源码 2013期] 点击上面蓝色字体,直接付费下 ...

  6. 【Matlab电力负荷预测】模拟退火算法结合狮群算法优化Elman神经网络电力负荷预测【含源码 1454期】

    一.代码运行视频(哔哩哔哩) [Matlab电力负荷预测]模拟退火算法结合狮群算法优化Elman神经网络电力负荷预测[含源码 1454期] 二.matlab版本及参考文献 1 matlab版本 201 ...

  7. 【Matlab路径规划】蚁群算法机器人大规模栅格地图最短路径规划【含源码 1860期】

    一.代码运行视频(哔哩哔哩) [Matlab路径规划]蚁群算法机器人大规模栅格地图最短路径规划[含源码 1860期] 二.蚁群算法及栅格地图简介 随着机器人技术在诸多领域的应用, 如机器人协作焊接.灾 ...

  8. 【微电网优化】基于matlab粒子群算法求解综合能源系统优化问题【含Matlab源码 1969期】

    一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[微电网优化]基于matlab粒子群算法求解综合能源系统优化问题[含Matlab源码 1969期] 点击上面蓝色字体,直接付费下载,即可. ...

  9. 【优化算法】基于matlab量子粒子群算法求解单目标优化问题【含Matlab源码 2203期】

    ⛄一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[优化算法]基于matlab量子粒子群算法求解单目标优化问题[含Matlab源码 2203期] 点击上面蓝色字体,直接付费下载,即可. 获 ...

最新文章

  1. android arcgis 绘制圆_ArcGIS For Android 定位绘图工具 [中心点,误差圆]
  2. OS / Linux / epoll 各种事件解析
  3. Linux表空间扩容,linux下oracle表空间导致磁盘空间不足
  4. mysql update 联合更新_Mysql update多表联合更新的方法小结
  5. 排序算法之归并排序(JAVA)
  6. c# 操作 Excel
  7. 【北京迅为】i.MX6ULL终结者Linux RS232/485驱动实验RS232驱动
  8. Protel 99SE安装向导
  9. QGIS的部分使用流程
  10. IDEA:Windows 下载安装 IDEA 详细教程
  11. pdf在线免费去水印 以及图片去水印 方法
  12. 暴风影音下载|暴风影音播放器下载
  13. 微软账号登陆不上_登录微软账号的Windows电脑如何远程?
  14. dell服务器报错信息,DELL 服务器LED屏报错信息 2012版
  15. 记账的目的和好处是什么
  16. 2022最新!自动驾驶、计算机视觉和AI公司汇总
  17. 黑苹果亮度调节 小太阳
  18. 贝叶斯优化: 一种更好的超参数调优方式
  19. 随手记note(记事簿)
  20. 【SqlServer】T-SQL的简介及基本用法

热门文章

  1. 堪称「神器」的电脑软件
  2. 花火4G聚合路由器无线网络支持5G户外直播应急通讯工作
  3. Rational 最新软件试用下载地址
  4. Flutter 动态化新知识
  5. python 返回函数 变量_你如何设置一个变量等于由python函数返回的值
  6. SkeyeVSS将安防网络摄像机进行类似于萤石云、乐橙云等模式的互联网视频云直播的几种方案
  7. 删除Management Data Warehouse (MDW) job失败
  8. 安卓使用http下载文件
  9. Php 波场离线签名 Tron离线签名
  10. Win10禁用IME解决方案