背景:在Visual Studio项目中使用OpenSSL库:
1. 环境准备
1.1 openssl编译或者安装后,获得的库文件(.lib)和头文件(.h)
1.2 VS2012
要点:编译出来的lib是32位的话,将VS的环境配置为x86;引用的lib是64位的话,将VS环境配置为X64.
创建X64平台方案,如图所示:
创建X86平台方案,如图所示:
2. 项目配置
2.1包含目录设置:
打开项目属性 -> VC++ 目录 -> 包含目录 -> 编辑 -> 添加你的OpenSSL头文件路径和库文件路径
2.2 附加依赖项和附加库目录设置:
打开项目属性 -> 链接器 -> 输入 -> 附加依赖项 -> 编辑 -> 添加libssl.lib和libcrypto.lib(以及其他需要的库)。
3. 实例
背景知识:在做SHA256计算之前,我们需要知道HASH计算的逻辑。
SHA256是一种密码散列函数,属于SHA-2(安全散列算法 2)家族,是SHA-1的后继者,SHA 256算法的主要过程包括预处理、主循环以及输出处理。
在预处理阶段,首先将原始数据以512位为一组进行分组,如果原始数据的位数不是512的倍数,则需要在原始数据的末尾填充若干个0,使其长度是512的倍数,并在其后附加一个64位的原始数据长度值。
接着进行64轮迭代运算,每轮迭代运算会对16个32位字进行一系列位运算,这些位运算主要包括循环右移、异或、与、或、非、加等。最后,将64轮迭代运算的结果进行拼接,得到一个256位的哈希值,即SHA256摘要。
使用openssl计算SHA256,主要有两种方案:
方案一,单次计算
使用API unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md) 做单次计算。
使用该方案计算SHA256,只允许输入一次数据const unsigned char *d,计算出来的SHA256的值存储到MD指针中。
方案二,多次计算
使用组合API SHA256_Init(SHA256_CTX *c) + SHA256_Update(SHA256_CTX *c,const void *data, size_t len) + SHA256_Final(unsigned char *md, SHA256_CTX *c) 做多次计算。
使用该方案计算SHA256,允许多次使用SHA256_Update传递被计算数据,理论来说被计算数据没有极限。
SHA256_Init(SHA256_CTX *c)
函数的作用主要是用于初始化一个SHA256_CTX结构体。在SHA-256算法的实现中,SHA256_CTX结构体用于保存SHA-256计算的状态。通过调用SHA256_Init函数,可以对这个结构体进行初始化,为后续的计算过程做准备。
SHA256_Update(SHA256_CTX *c, const void *data, size_t len)
函数在SHA-256哈希算法的计算过程中起到了关键的作用。该函数的主要功能是将输入的数据块添加到SHA256的计算上下文中,以更新当前的哈希值。
具体来说,参数 SHA256_CTX *c
是一个指向SHA256上下文的指针,这个上下文在SHA256_Init函数中已经被初始化,并包含了计算哈希值所需的所有状态信息。参数 const void *data
是一个指向要添加的数据的指针,这些数据可以是任意长度的字节序列。参数 size_t len
表示数据的长度。
SHA256_Update函数会按照SHA-256算法的规定,对输入的数据进行处理,并更新SHA256上下文中的状态。这样,随着数据的不断输入,SHA256的哈希值也会不断更新。
最后,当所有的数据都处理完毕后,可以通过调用SHA256_Final函数来获取最终的哈希值。这个函数会将SHA256上下文中的最终状态转换为固定长度的哈希值输出。
因此,SHA256_Update函数在SHA-256哈希计算中起到了“逐步更新”的作用,使得我们可以分块处理大量的数据,而不需要一次性将所有数据加载到内存中。这对于处理大文件或流式数据非常有用。
SHA256_Final(unsigned char *md, SHA256_CTX *c)
函数在SHA-256哈希计算中扮演着关键角色。这个函数的主要作用是完成SHA-256哈希计算,并将最终的哈希值存储在指定的缓冲区中。
参数unsigned char *md
是一个指向存储哈希结果的缓冲区的指针,该缓冲区的大小应足够大,以存储生成的256位(32字节)哈希值。参数SHA256_CTX *c
是一个指向SHA256_CTX结构体的指针,该结构体包含了哈希计算过程中所需的所有状态信息,包括中间结果。
在调用SHA256_Final函数之前,通常需要先调用SHA256_Init函数来初始化SHA256_CTX结构体,然后通过SHA256_Update函数将待哈希的数据添加到计算中。SHA256_Update函数可以多次调用,以处理不同部分的数据。当所有数据都已处理完毕,就可以调用SHA256_Final函数来生成最终的哈希值。
SHA256_Final函数会将SHA256_CTX结构体中的状态信息转化为最终的哈希值,并将这个哈希值存储在md指向的缓冲区中。完成这个操作后,SHA256_CTX结构体中的状态信息将被清除或重置,因此无法再次使用它来生成哈希值。
3.1 方案一
SHA256((const unsigned char *)buf_Input, (size_t)32, md); 计算Buf_input内的32个字节的SHA256的值。
3.2 方案二
SHA256_Init(&sha256);
SHA256_Update(&sha256, buf_Input, strlen((char *)buf_Input));
SHA256_Final(buf_HASH, &sha256);
注意SHA256_Update 需要输入实际传递进来的数据长度,需要使用strlen((char *)buf_Input)去计算,但是strlen计算的逻辑是遇到截止符"\0"才截止。所以在前面我们使用下面三种方案使buf_Input 计算出来的长度为32。
buf_Input = (unsigned char *)malloc(33);
memset(buf_Input,0xff,32);
buf_Input[32] = '\0';
反之,如果使用sizeof计算的是内存的大小。buf_Input 本质是一个指针,占用8字节的长度。
#include <string.h>
#include<stdio.h>
#include <openssl/sha.h>
#include <openssl/crypto.h>
#include <openssl/applink.c>
void printHash(unsigned char *md, int len)
{
int i = 0;
for (i = 0; i < len; i++)
{
printf("%02x", md[i]);
}
printf("\n");
}
int main()
{
unsigned char *buf_HASH;
unsigned char *buf_Input,buf_Test[32];
FILE *buf_Input_file;
//对数据进行sha256算法摘要
SHA256_CTX sha256;
unsigned char md[SHA256_DIGEST_LENGTH];
buf_HASH = (unsigned char *)malloc(32);
buf_Input = (unsigned char *)malloc(33);
memset(buf_HASH,0xff,32);
memset(buf_Input,0xff,32);
buf_Input[32] = '\0';
if((buf_Input_file = fopen("D:\\Coding\\C\\Openssl_test\\05_Sign_Verify_RSA\\05_Sign_Verify_RSA\\Wait_sign.bin","rb")) ==NULL)
{
printf("read Wait_sign.bin failure:\n");
}
else
{
fread(buf_Input,sizeof(unsigned char),32,buf_Input_file);
fclose(buf_Input_file);
}
printf("read start:\n");
printHash(buf_Input, SHA256_DIGEST_LENGTH);
printf("read end:\n");
SHA256((const unsigned char *)buf_Input, (size_t)32, md);
printf("Hash start:\n");
printHash(md, SHA256_DIGEST_LENGTH);
printf("Hash end:\n");
//不能用这种方式去计算开辟的空间长度,因为会出现内存开辟的内存空间正好有连续字节。注意strlen函数的原理是计算NULL
/****strlen 函数用于计算 C 风格字符串(以 null 终止符 \0 结尾的字符数组)的长度。当你调用 strlen((char *)buf_Input) 时,
你期望它返回的是从 buf_Input 指向的内存位置开始,直到遇到第一个 null 终止符的字符数。
如果你发现 strlen((char *)buf_Input) 返回了 37,那么这意味着从 buf_Input 指向的内存开始,连续有 37 个非 null 字符,直到第 38 个位置才遇到 null 终止符。****/
printf("strlen((char *)buf_Input) = %d %d:\n",strlen((char *)buf_Input),strlen((unsigned char *)buf_Input));
SHA256_Init(&sha256);
SHA256_Update(&sha256, buf_Input, strlen((char *)buf_Input));
SHA256_Final(buf_HASH, &sha256);
printf("SHA256_Init start:\n");
printHash(buf_HASH, SHA256_DIGEST_LENGTH);
printf("SHA256_Final end:\n");
/****sizeof(buf_Input) = 8是因为sizeof是计算内存的大小,buf_Input本质是一个指针,X64架构下就是8字节***/
memset(buf_HASH,0xff,32);
printf("sizeof(buf_Input) = %d %d:\n",sizeof(buf_Input),sizeof(buf_Test));
SHA256_Init(&sha256);
SHA256_Update(&sha256, buf_Input, sizeof(buf_Input));
SHA256_Final(buf_HASH, &sha256);
printf("SHA256_Init start 2:\n");
printHash(buf_HASH, SHA256_DIGEST_LENGTH);
printf("SHA256_Final end 2:\n");
free(buf_HASH);
free(buf_Input);
return 0;
}
附上测试结果:
read start:
4bdfd80bbed10d6d7a9bc0f8e199b35c08b3d79ad0e00210f5e6c7f32fbe08df
read end:
Hash start:
97f40ff3243630b2c9e37bf0c80349d1f74240ceaac61f0c1fa7ad0a93c1d7da
Hash end:
strlen((char *)buf_Input) = 32 32:
SHA256_Init start:
97f40ff3243630b2c9e37bf0c80349d1f74240ceaac61f0c1fa7ad0a93c1d7da
SHA256_Final end:
sizeof(buf_Input) = 8 8:
SHA256_Init start 2:
51dec461be3996751ab5ed7beb2731fc5dfcdbec6d04a0d598668970140e6e95
SHA256_Final end 2:
请按任意键继续. . .