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

一、实验目的


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

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值