C语言消息摘要函数 SHA-1 算法的实现

news2024/11/24 4:26:17

一、实验目的


(1)加深对消息摘要函数 SHA-1 的理解;
(2)掌握消息摘要函数 SHA-1;
(3)提高编程实践能力。


二、实验内容


(1)按照标准 FIPS-180-2 中 SHA-1 算法,从文件或者屏幕中读取消息,然
后对消息分组,并对最后一个分组进行填充,并对每组通过数据扩充算法扩充到
80 个字,然后执行 SHA-1 算法,并显示输出。
(2)完成填充过程,消息的长度在 1-200 个字符。


三、实验要求


(1)输入待 Hash 消息字符串,编码方式为 ASCII 码。例如程序的默认输入
为 FIPS-180-2 中示例的“abc”, 消息的长度在 1-200 个字符。
(2)按照 SHA-1 算法进行填充,然后 512 比特分组,分为多组,然后对每
组消息进行处理,数据扩充到 80 个字。
(3)输出每一分组中的 W0, W1,W14,W15,W16, W79 (十六进制)

(4)输出最终的消息摘要。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include<stdlib.h>
//cllsse
unsigned H[5] = {0x67452301,0xefcdab89,0x98BADCFE,0x10325476,0xC3D2E1F0};

int blocknum = 1;//第blocknum块
//SHA 函数的结构体
typedef struct SHA1Context
{
	unsigned Length_Low;//消息长度低 32 位
	unsigned Length_High;//消息长度高 32 位
	unsigned char Message_Block[64];// 512bits 的块,总共 64 个字节
	int Message_Block_Index; //512bits 块索引号
	unsigned Message_Digest[5];//初始变量

	int Computed;
	int Corrupted;
} SHA1Context;
//循环左移 bits 位
#define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32 - (bits))))
//赋初值函数
void SHA1Reset(SHA1Context* context)
{
	context->Length_Low = 0;
	context->Length_High = 0;
	context->Message_Block_Index = 0;
	context->Computed = 0;
	context->Corrupted = 0;

	context->Message_Digest[0] = 0x67452301;//初始变量H为160bit数据块。
	context->Message_Digest[1] = 0xEFCDAB89;
	context->Message_Digest[2] = 0x98BADCFE;
	context->Message_Digest[3] = 0x10325476;
	context->Message_Digest[4] = 0xC3D2E1F0;
}
//每 512bits 数据块处理
void SHA1ProcessMessageBlock(SHA1Context* context)
{
	int t;
	int temp;
	unsigned W[80];
	const unsigned K[] =
	{
		0x5A827999,
		0x6ED9EBA1,
		0x8F1BBCDC,
		0xCA62C1D6
	};//常量值kt
	unsigned    A, B, C, D, E;
	for (t = 0; t < 16; t++)//W[t]有四个字节
	{
		W[t] = ((unsigned)context->Message_Block[t * 4]) << 24;//空出后三字节
		W[t] |= ((unsigned)context->Message_Block[t * 4 + 1]) << 16;
		W[t] |= ((unsigned)context->Message_Block[t * 4 + 2]) << 8;
		W[t] |= ((unsigned)context->Message_Block[t * 4 + 3]);
	}
	for (t = 16; t < 80; t++)//将16个32bit字扩充为80个32bit字
	{
		W[t] = SHA1CircularShift(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]);//循环左移一位
	}
	printf("第%d个块:\n", blocknum);
	//0,1,14,15,16,79
	int index[6] = { 0, 1, 14, 15, 16, 79 };
	for (int i = 0; i < sizeof(index)/4; i++) {
		printf("W[%d]=%08x\n", index[i], W[index[i]]);
	}

	A = context->Message_Digest[0];
	B = context->Message_Digest[1];
	C = context->Message_Digest[2];
	D = context->Message_Digest[3];
	E = context->Message_Digest[4];

	for (t = 0; t < 20; t++)//逻辑函数f1=(b&c)|((~b)&d)
	{
		temp = SHA1CircularShift(5, A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
		temp &= 0xFFFFFFFF;
		E = D;
		D = C;
		C = SHA1CircularShift(30, B);
		B = A;
		A = temp;
	}

	for (t = 20; t < 40; t++)//逻辑函数f2=b^c^d
	{
		temp = SHA1CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[1];//压缩函数,T=ROTL5(A)+ft(B,C,D)+E+W[t]+Kt(mod 2^32)
		temp &= 0xFFFFFFFF;//相当于mod 2^32
		E = D;
		D = C;
		C = SHA1CircularShift(30, B);
		B = A;
		A = temp;
	}

	for (t = 40; t < 60; t++)//逻辑函数f3=(b&c)|(b&d)|(c&d)
	{
		temp = SHA1CircularShift(5, A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];//压缩函数
		temp &= 0xFFFFFFFF;
		E = D;
		D = C;
		C = SHA1CircularShift(30, B);
		B = A;
		A = temp;
	}

	for (t = 60; t < 80; t++)//逻辑函数f4=b^c^d
	{
		temp = SHA1CircularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[3];
		temp &= 0xFFFFFFFF;
		E = D;
		D = C;
		C = SHA1CircularShift(30, B);
		B = A;
		A = temp;
	}

	//最后一步H_0(i)=A+H_0(i-1),H_1(i)=B+H_1(i-1)...
	context->Message_Digest[0] = (context->Message_Digest[0] + A) & 0xFFFFFFFF;
	context->Message_Digest[1] = (context->Message_Digest[1] + B) & 0xFFFFFFFF;
	context->Message_Digest[2] = (context->Message_Digest[2] + C) & 0xFFFFFFFF;
	context->Message_Digest[3] = (context->Message_Digest[3] + D) & 0xFFFFFFFF;
	context->Message_Digest[4] = (context->Message_Digest[4] + E) & 0xFFFFFFFF;


	//每处理一块之后,SHAContext 块索引 0
	context->Message_Block_Index = 0;
	blocknum++;
}
//填充函数
void SHA1PadMessage(SHA1Context* context) {//分<56字节和>=56字节两种填充方法
	if (context->Message_Block_Index > 55)//至少448位
	{
		context->Message_Block[context->Message_Block_Index++] = 0x80;//可能会越界,但不影响扩展时这个块填满,下一个块第一个字节就是0x80
		while (context->Message_Block_Index < 64)
		{
			context->Message_Block[context->Message_Block_Index++] = 0;
		}
		SHA1ProcessMessageBlock(context);//并且索引值归0
		while (context->Message_Block_Index < 56)
		{
			context->Message_Block[context->Message_Block_Index++] = 0;
		}
	}
	else
	{
		context->Message_Block[context->Message_Block_Index++] = 0x80;
		while (context->Message_Block_Index < 56)
		{
			context->Message_Block[context->Message_Block_Index++] = 0;
		}
	}
	context->Message_Block[56] = (context->Length_High >> 24) & 0xFF;
	context->Message_Block[57] = (context->Length_High >> 16) & 0xFF;
	context->Message_Block[58] = (context->Length_High >> 8) & 0xFF;
	context->Message_Block[59] = (context->Length_High) & 0xFF;
	context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF;
	context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF;
	context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF;
	context->Message_Block[63] = (context->Length_Low) & 0xFF;
	SHA1ProcessMessageBlock(context);
}
int SHA1Result(SHA1Context* context)
{
	if (context->Corrupted) {
		return 0;
	}
	if (!context->Computed)
	{
		SHA1PadMessage(context);
		context->Computed = 1;
		printf("最终的消息摘要值为:\n");
		for (int i = 0; i < 5; i++) {
			printf("%x ", context->Message_Digest[i]);
		}
	}
	return 1;
}
void SHA1Input(SHA1Context* context, const unsigned char* message_array,
	unsigned length)
{
	if (!length)//如果输入为空就返回
	{
		return;
	}
	if (context->Computed || context->Corrupted)//防止对已经完成的哈希再次进行输入,或者避免在损坏的上下文中继续处理
	{
		context->Corrupted = 1;
		return;
	}
	while (length-- && !context->Corrupted)
	{
		// 每 8bits 的存放
		context->Message_Block[context->Message_Block_Index++] =(*message_array & 0xFF);//只保留最低8位

		context->Length_Low += 8;//位长度
		context->Length_Low &= 0xFFFFFFFF;//低四字节
		if (context->Length_Low == 0)
		{
			context->Length_High++;
			context->Length_High &= 0xFFFFFFFF;
			if (context->Length_High == 0)//高4字节位长度溢出
			{
				context->Corrupted = 1;//已损坏
			}
		}
		if (context->Message_Block_Index == 64)//数组被填满时调用
		{
			SHA1ProcessMessageBlock(context);
		}
		message_array++;//指向下一个字符
	}
}
int main()
{
	SHA1Context sha;
	char input[64];
	
	printf("ASCII string:");
	scanf("%s", input);
	SHA1Reset(&sha);
	SHA1Input(&sha, (const unsigned char*)input, strlen(input));
	SHA1Result(&sha);
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1690998.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

B站pink老师CSS学习(二)

文章目录 一、emmet语法1.快速生成HTML结构语法 二、复合选择器1.什么是复合选择器2.后代选择器3.子选择器4.并集选择器5.伪类选择器6.链接伪类选择器7&#xff1a;focus伪类选择器8.总结 三、元素的显示模式1.什么是元素显示模式2.块元素3.行内元素4.行内块元素5.总结6.元素显…

springboot 配置动态调整profiles-active参数

配置动态调整active参数&#xff1a; 1.bootstrap.yml中&#xff1a; spring:profiles:active: spring.profiles.active #占位符 替换 2.pom.xml中配置&#xff1a; <build><resources><resource><directory>src/main/resources</directory>&…

栈(从数据结构的三要素出发)

文章目录 逻辑结构物理结构顺序栈链栈共享栈 数据的操作顺序栈的基本操作链栈的基本操作共享栈的基本操作 数据结构的应用栈在括号匹配中的应用栈在表达式求值中的应用栈在递归调用中的应用 逻辑结构 栈是只允许在一端进行插入或删除操作的线性表。首先栈是一种线性表&#xf…

数据结构-队列(带图详解)

目录 队列的概念 画图理解队列 代码图理解 代码展示(注意这个队列是单链表的结构实现) Queue.h(队列结构) Queue.c(函数/API实现) main.c(测试文件) 队列的概念 队列&#xff08;Queue&#xff09;是一种基础的数据结构&#xff0c;它遵循先进先出&#xff08;First In …

本地部署Whisper实现语言转文字

文章目录 本地部署Whisper实现语言转文字1.前置条件2.安装chocolatey3.安装ffmpeg4.安装whisper5.测试用例6.命令行用法7.本地硬件受限&#xff0c;借用hugging face资源进行转译 本地部署Whisper实现语言转文字 1.前置条件 环境windows10 64位 2.安装chocolatey 安装chocol…

无人机+飞行服务:无人机飞防服务(打药+施肥+播种)技术详解

无人机飞防服务&#xff0c;结合了先进的无人机技术与农业实践&#xff0c;为现代农业提供了高效、精准的打药、施肥和播种解决方案。以下是对这些技术的详细解析&#xff1a; 一、无人机打药技术 无人机打药技术利用无人机搭载喷雾设备&#xff0c;对农田进行精准施药。通过…

修改vuetify3的开关组件v-switch在inset模式下的大小

<v-switchv-model"model":label"Switch: ${model.toString()}"hide-detailsinset></v-switch><style lang"scss" scoped> .custom-switch {:deep(.v-switch__thumb) {height: 18px !important; /* 设置开关按钮的高度 */width…

编一个自己的万年历

编一个自己的万年历 前阶段突然想查一下某一天是星期几&#xff0c;于是自己编了一个[小程序][https://blog.csdn.net/weixin_41905135/article/details/138972055?spm1001.2014.3001.5501]&#xff0c;但是功能很单一&#xff0c;就是单纯的查是星期几。&#xff08;虽然用网…

解决深度确定问题:使用不相交集合森林

解决深度确定问题&#xff1a;使用不相交集合森林 引言不相交集合森林&#xff08;DSF&#xff09;基础按秩合并与路径压缩深度确定问题的解决方案实现MAKE-TREE修改FIND-SET实现FIND-DEPTH实现GRAFT分析最坏情况运行时间结论参考文献 引言 在计算机科学中&#xff0c;树结构是…

多维数据库创建

多维数据库 小白的数据仓库学习笔记 2024/5/21 上午 文章目录 多维数据库Cube的作用&#xff1a;什么是多维数据库维的级别多维数据分析方法如何构建多维数据集&#xff1f;创建项目创建数据源创建数据源视图创建多维数据集维度表中缺失的值拖拽过去建立维度结构设计类型启动连…

现代C++ 如何使用 Lambda 使代码更具表现力、更容易理解?

使用 Lambda 使代码更具表现力 一、Lambda VS. 仿函数二、总结 一、Lambda VS. 仿函数 Lambda 是 C11 中最引人注目的语言特性之一。它是一个强大的工具&#xff0c;但必须正确使用才能使代码更具表现力&#xff0c;而不是更难理解。 首先&#xff0c;要明确的是&#xff0c;…

【LeetCode】【5】最长回文子串

文章目录 [toc]题目描述样例输入输出与解释样例1样例2 提示Python实现动态规划 个人主页&#xff1a;丷从心 系列专栏&#xff1a;LeetCode 刷题指南&#xff1a;LeetCode刷题指南 题目描述 给一个字符串s&#xff0c;找到s中最长的回文子串 样例输入输出与解释 样例1 输入…

2024电工杯数学建模B题Python代码+结果表数据教学

2024电工杯B题保姆级分析完整思路代码数据教学 B题题目&#xff1a;大学生平衡膳食食谱的优化设计及评价 以下仅展示部分&#xff0c;完整版看文末的文章 import pandas as pd df1 pd.read_excel(附件1&#xff1a;1名男大学生的一日食谱.xlsx) df1# 获取所有工作表名称 e…

派可数据助力制造企业数字化生产管理新能力提升

生产管理是现代企业运营的核心之一&#xff0c;它决定了产品的质量、生产效率和企业的竞争力。在一个日益竞争激烈、市场需求多变的商业环境中&#xff0c;如何高效地组织和管理生产过程成为了企业不容忽视的重要课题。 过去&#xff0c;生产管理可能主要侧重于物理工厂的运作…

Sping源码(八)—registerBeanPostProcessors

序言 之前我们用大量的篇幅介绍过invokeBeanFactoryPostProcessors()方法的执行流程。 而invokeBeanFactoryPostProcessors的主要逻辑就是遍历执行实现了BeanDefinitionRegistryPostProcesso类(主要是针对BeanDefinition的操作)和BeanFactoryPostProcessor(主要针对BeanFacrot…

【C语言】深入理解指针(一)(上)

本篇文章将讲解&#xff1a; &#xff08;1&#xff09;内存和地址 &#xff08;2&#xff09;指针变量和细致 &#xff08;3&#xff09;指针变量类型的意义 一&#xff1a;内存和地址 &#xff08;1&#xff09;内存 在讲内存和地址之前&#xff0c;我们讲一个生活中的…

混合组网VS传统网络:智能硬件混合组网优劣势浅要解析

智能硬件混合组网是一种利用多种通信技术相结合的方法&#xff0c;以实现更灵活、更可靠的网络连接。通过蓝牙、Wi-Fi、LoRa、4G相互之间的不同通讯方式&#xff0c;根据应用场景的不同以及现场实际环境&#xff0c;优选最佳物联网混合组网方案&#xff0c;以达到部署最便捷性价…

618知识狂欢,挑本好书,点亮智慧生活!

618精选编程书单&#xff1a;提升你的代码力 一年一度的618又到啦&#xff01;今年的618就不要乱买啦&#xff0c;衣服买多了会被淘汰&#xff0c;电子产品买多了会过时&#xff0c;零食买多了会增肥&#xff0c;最后怎么看都不划算。可是如果你购买知识&#xff0c;坚持阅读&a…

2024年了, 你还不会使用node.js做压力测试?

前些天刷抖音&#xff0c;看到网传的Java继父&#xff0c;求人攻击压测他的网站&#xff0c;这不得摩拳擦掌。 所以今天来聊聊如何对自己的项目、接口进行压力测试。 压力测试的目的 首先, 绝对不是为了压测、攻击别人的网站为乐。 1、探索线上系统流量承载的极限&#xff…

鲁教版六年级数学下册-笔记

文章目录 第五章 基本平面图形1 线段、射线、直线2 比较线段的长短3 角4 角的比较5 多边形和圆的初步认识第六章 整式的乘除1 同底数幂的乘法2 幂的乘方与积的乘方3 同底数幂的除法4 零指数幂与负整数指数幂5 整式的乘法6 平方差公式7 完全平方公式8 整式的除法 第七章 相交线与…