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

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)输出最终的消息摘要。

www.zeeklog.com  - C语言消息摘要函数 SHA-1 算法的实现
#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;
}

Read more

JavaScript for 循环

JavaScript for 循环

JavaScript for 循环 * * JavaScript for 循环 在JavaScript中,for循环是一种常用的迭代语句,它允许我们执行一段代码块指定的次数。for循环的语法结构清晰,易于理解,是处理数组、列表或任何需要重复执行操作的场景中的强大工具。 for循环的基本语法 JavaScript的for循环的基本语法如下: for (initialization; condition; final expression) { // code block to be executed } * initialization:初始化循环变量。这通常在循环开始前只执行一次。 * condition:这是一个条件表达式,每次循环迭代前都会检查。如果表达式的结果为true,则执行循环体。如果为false,则跳出循环。 * final expression:在每次循环迭代结束时执行的表达式。通常用于更新循环变量。 * code block:在每次满足condition时执行的代码块。 示例 下面是一个简单的for循环示例,用于打印数字

By Ne0inhk
python画图 四大常用绘图 Matplotlib Seaborn Plotly Bokeh 十四个源代码绘图示例 折线图 正弦曲线折线图 散点图 柱状图 饼图 热力图 箱线图 面积图 极坐标图 蜘

python画图 四大常用绘图 Matplotlib Seaborn Plotly Bokeh 十四个源代码绘图示例 折线图 正弦曲线折线图 散点图 柱状图 饼图 热力图 箱线图 面积图 极坐标图 蜘

python画图 * * * * * python画图 Python是一种功能强大的编程语言,其广泛的应用领域包括但不限于数据分析、机器学习、网络开发等。在数据可视化方面,Python同样有着出色的表现。利用Python的绘图库,我们可以轻松地创建各种图形,以便更好地理解和分析数据。 Python四大常用绘图库 1. Matplotlib 这是Python中最流行的绘图库之一,它提供了大量的绘图工具和函数,用于创建静态、动态、交互式的可视化图表。Matplotlib不仅功能强大,而且灵活性极高,可以满足各种复杂的绘图需求。无论是简单的折线图、柱状图,还是复杂的散点图、热力图,Matplotlib都能轻松应对。 2. Seaborn 基于Matplotlib的一个数据可视化库,提供了更高级别的接口,使得绘制各种统计图形变得更加简单。Seaborn内置了多种常见的统计绘图方法,如分布图、相关图、成对图等,能够快速地帮助用户分析和展示数据。 3. Plotly 一个交互式的绘图库,可以创建具有丰富交互功能的图表,支持在线和离线使用。Pl

By Ne0inhk
JavaScript while 循环

JavaScript while 循环

JavaScript while 循环 * JavaScript while 循环 在JavaScript中,while循环是一种基本的控制流语句,它允许代码块在给定条件为真的情况下重复执行。while循环的语法非常直观,使得开发者能够轻松地构建需要重复执行的任务。 while 循环的基本语法 while循环的基本语法如下: while (condition) { // code block to be executed } 在这里,condition是一个表达式,只要它的值为真(truthy),循环就会继续执行。如果condition的值为假(falsy),则循环停止,程序继续执行循环之后的代码。 while循环的基本语法如上文所述,它包含一个条件表达式和一个代码块。只要条件表达式的结果为真,代码块就会不断重复执行。这种机制使得while循环成为处理需要重复执行的任务的理想选择。 示例1:使用while循环打印数字 下面是一个使用while循环打印从1到5的数字的示例: let i = 1; while (i <= 5) { cons

By Ne0inhk
kylin入门教程(开源分布式分析引擎下载解压启动安装与配置 创建项目定义模型 构建Cube执行查询 优化 SQL接口扩展 监控与警告 实战演练与案例分析 数据设计与构建 查询分析 社区资源与生态)

kylin入门教程(开源分布式分析引擎下载解压启动安装与配置 创建项目定义模型 构建Cube执行查询 优化 SQL接口扩展 监控与警告 实战演练与案例分析 数据设计与构建 查询分析 社区资源与生态)

kylin入门教程(开源分布式分析引擎下载解压启动安装与配置 创建项目定义模型 构建Cube执行查询 优化 SQL接口扩展 监控与警告 实战演练与案例分析 数据设计与构建 查询分析 社区资源与生态) * * * * * * kylin入门教程 Kylin是一个开源的分布式分析引擎,它提供了Hadoop/Spark之上的SQL接口及多维分析(OLAP)能力以支持超大规模数据,最初由eBay Inc. 开发并贡献到开源社区。Kylin通过预计算的方式,将多维分析查询转化为bitmap进行存储,从而极大地提高了查询速度。本教程将详细介绍Kylin的入门知识,包括安装、配置、使用以及常见问题解决方法。 一、安装与配置 1. kylin环境准备 在搭建Apache Kylin环境之前,需要确保已满足一系列的前提条件。Apache Kylin是一个开源的分布式分析引擎,提供Hadoop/Spark之上的SQL接口及多维分析(OLAP)能力以支持超大规模数据,最初由eBay Inc. 开发并贡献到开源社区。它能够提供SQL接口和多维分析(OLAP)

By Ne0inhk