添砖加⽡:⼏种常见的数据摘要算法(MD5、CRC32、SHA1和
SHA256)
1、算法概述
数据摘要算法是密码学算法中⾮常重要的⼀个分⽀,它通过对所有数据提取指纹信息以实现数据签名、数据完整性校验等功能,由于其不可逆性,有时候会被⽤做敏感信息的加密。数据摘要算法也被称为哈希(Hash)算法或散列算法。
1.1、CRC8、CRC16、CRC32
CRC(Cyclic Redundancy Check,循环冗余校验)算法出现时间较长,应⽤也⼗分⼴泛,尤其是通讯领域,现在应⽤最多的就是 CRC32 算法,它产⽣⼀个4字节(32位)的校验值,⼀般是以8位⼗六进制数,如FA 12 CD 45等。CRC算法的优点在于简便、速度快,严格的来说,CRC更应该被称为数据校验算法,但其功能与数据摘要算法类似,因此也作为测试的可选算法。
在 WinRAR、WinZIP 等软件中,也是以 CRC32 作为⽂件校验算法的。⼀般常见的简单⽂件校验(Simple File Verify –SFV)也是以 CRC32算法为基础,它通过⽣成⼀个后缀名为 .SFV 的⽂本⽂件,这样可以任何时候可以将⽂件内容 CRC32运算的结果与 .SFV ⽂件中的值对⽐来确定此⽂件的完整性。
与 SFV 相关⼯具软件有很多,如MagicSFV、MooSFV等。
1.2、MD2 、MD4、MD5
这是应⽤⾮常⼴泛的⼀个算法家族,尤其是 MD5(Message-Digest Algorithm 5,消息摘要算法版本5),它由MD2、MD3、MD4发展⽽来,由Ron Rivest(RSA公司)在1992年提出,被⼴泛应⽤于数据完整性校验、数据(消息)摘要、数据加密等。MD2、MD4、MD5 都产⽣16字节(128位)的校验值,⼀般⽤32位⼗六进制数表⽰。MD2的算法较慢但相对安全,MD4速度很快,但安全性下降,MD5⽐MD4更安全、速度更快。
在互联⽹上进⾏⼤⽂件传输时,都要得⽤MD5算法产⽣⼀个与⽂件匹配的、存储MD5值的⽂本⽂件(后缀名为 .md5
或.md5sum),这样接收者在接收到⽂件后,就可以利⽤与 SFV 类似的⽅法来检查⽂件完整性,绝⼤多数⼤型软件公司或开源组织都是以这种⽅式来校验数据完整性,⽽且部分操作系统也使⽤此算法来对⽤户密码进⾏加密,另外,它也是⽬前计算机犯罪中数据取证的最常⽤算法。
与MD5 相关的⼯具有很多,如 WinMD5等。
1.3、SHA1、SHA256、SHA384、SHA512
SHA(Secure Hash Algorithm)是由美国专门制定密码算法的标准机构—— 美国国家标准技术研究院(NIST)制定的,SHA系列算法的摘要长度分别为:SHA为20字节(160位)、SHA256为32字节(256位)、 SHA384为48字节(384位)、SHA512为64字节(512位),由于它产⽣的数据摘要的长度更长,因此更难以发⽣碰撞,因此也更为安全,它是未来数据摘要算法的发展⽅向。由于SHA系列算法的数据摘要长度较长,因此其运算速度与MD5相⽐,也相对较慢。
SHA1的应⽤较为⼴泛,主要应⽤于CA和数字证书中,另外在互联⽹中流⾏的BT软件中,也是使⽤SHA1来进⾏⽂件校验的。
1.4、RIPEMD、PANAMA、TIGER、ADLER32 等
RIPEMD是Hans Dobbertin等3⼈在对MD4,MD5缺陷分析基础上,于1996年提出来的,有4个标准128、160、256和320,其对应输出长度分别为16字节、20字节、32字节和40字节。IGER由Ross在1995年提出。Tiger号称是最快的Hash算法,专门为64位机器做了优化。
注:来源
2、算法测试
基于openssl中提供的MD5、SHA1、SHA256和zlib中提供的CRC32,测试平台:OSX10.12
check.h
#ifndef HEADER_CHECK_H
# define HEADER_CHECK_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include "zlib.h"
#ifdef __cplusplus
extern"C"{
#endif
#define BUFSIZE 1024*1024*2
/*
* 使⽤OpenSSL提供的MD5相关函数计算字符串和⼤⽂件的MD5值
*/
int calcBufMD5(unsigned char *src, size_t len,unsigned char *dst);
int calcFileMD5(const char *inFile,unsigned char *dst);
/*
* 使⽤OpenSSL提供的SHA1 SAH256函数分别计算字符串和⼤⽂件的SAH1 SAH256值 */
int calcBufSHA1(unsigned char *src, size_t len,unsigned char *dst);
int calcFileSHA1(const char *inFile,unsigned char *dst);
int calcBufSHA256(unsigned char *src, size_t len,unsigned char *dst);
int calcFileSHA256(const char *inFile,unsigned char *dst);
/*
* ⾃实现CRC32校验(查表法)
* ⽤以计算字符串和⼤⽂件的CRC32值
*/
unsigned int calcBufCRC32(unsigned int crc,unsigned char *buf,size_t len); unsigned int calcFileCRC32(const char *inFile);
# ifdef __cplusplus
}
# endif
# endif
View Code
check.c
#include "check.h"
#include <stdlib.h>
//计算字符串的MD5
int calcBufMD5(unsigned char *src,size_t len,unsigned char *dst)
{
if(NULL == src || NULL == dst)
{
fprintf(stderr,"%s\n","input parameter error");
return -1;
}
MD5(src,len,dst);
return0;
}
//计算⼤⽂件的MD5值
int calcFileMD5(const char *inFile,unsigned char *dst)
{
if(NULL == inFile || NULL == dst)
{
fprintf(stderr,"%s\n","input parameter error");
return -1;
}
char buf[BUFSIZE] = {0};
int nread;
MD5_CTX ctx;
FILE *fin = fopen(inFile,"r");
if(NULL == fin)
{
fprintf(stderr,"%s\n","open file error");
return -1;
}
MD5_Init(&ctx);
while((nread = fread(buf,1,BUFSIZE,fin)) > 0)
{
MD5_Update(&ctx,buf,nread);
}
MD5_Final(dst,&ctx);
return0;
}
//计算字符串的SHA1
int calcBufSHA1(unsigned char *src, size_t len,unsigned char *dst) {
if(NULL == src || NULL == dst)
{
fprintf(stderr,"%s\n","input parameter error");
return -1;
}
unsigned char sha[20] = {0};
char tmp[3] = {0};
int i;
SHA1(src,len,dst);
for(i = 0; i < 20; i++)
{
sprintf(tmp,"%02x",sha[i]);
strcat((char*)dst,tmp);
}
return0;
}
//计算⼤⽂件的SAH1
int calcFileSHA1(const char *inFile,unsigned char *dst)
{
if(NULL == inFile || NULL == dst)
{
fprintf(stderr,"%s\n","input parameter error");
return -1;
}
char buf[BUFSIZE] = {0};
unsigned char sha[20] = {0};
char tmp[3] = {0};
int i,nread;
SHA_CTX ctx;
FILE *fin = fopen(inFile,"r");
if(NULL == fin)
{
fprintf(stderr,"%s\n","open file error");
return -1;
}
SHA1_Init(&ctx);
while((nread = fread(buf,1,BUFSIZE,fin)) > 0)
{
SHA1_Update(&ctx,buf,nread);
}
SHA1_Final(dst,&ctx);
fclose(fin);
return0;
}
//计算字符串的SAH256
int calcBufSHA256(unsigned char *src, size_t len,unsigned char *dst) {
if(NULL == src || NULL == dst)
{
fprintf(stderr,"%s\n","input parameter error");
return -1;
}
unsigned char sha[32] = {0};
char tmp[3] = {0};
int i;
SHA256(src,len,dst);
return0;
}
/
/计算⼤⽂件的SAH256
int calcFileSHA256(const char *inFile,unsigned char *dst)
{
if(NULL == inFile || NULL == dst)
final sprintf是什么意思{
fprintf(stderr,"%s\n","input parameter error");
return -1;
}
char buf[BUFSIZE] = {0};
unsigned char sha[32] = {0};
char tmp[3] = {0};
int i,nread;
SHA256_CTX ctx;
FILE *fin = fopen(inFile,"r");
if(NULL == fin)
{
fprintf(stderr,"%s\n","open file error");
return -1;
}
SHA256_Init(&ctx);
while((nread = fread(buf,1,BUFSIZE,fin)) > 0)
{
SHA256_Update(&ctx,buf,nread);
}
SHA256_Final(dst,&ctx);
fclose(fin);
return0;
}
//计算字符串的CRC32
unsigned int calcBufCRC32(unsigned int crc,unsigned char *buf,size_t len) {
return crc32(crc,buf,len);
}
//计算⼤⽂件的CRC32
unsigned int calcFileCRC32(const char *inFile)
{
int nread;
unsigned char buf[BUFSIZE] = {0};
unsigned int crc = 0;
FILE *fin = fopen(inFile,"rb");
if(NULL == fin)
{
fprintf(stderr,"%s\n","open file error");
return -1;
}
while((nread = fread(buf,1,BUFSIZE,fin)) > 0)
crc = calcBufCRC32(crc,buf,nread);
fclose(fin);
return crc;
}
View Code
test.c
#include <stdio.h>
#include <sys/time.h>
#include "check.h"
int main(int argc,char *argv[])
{
unsigned char *data = "123";
struct timeval start;
struct timeval end;
double diff;
unsigned char *md = (unsigned char *)malloc(64);
if(NULL == md)
{
fprintf(stderr,"%s\n","malloc error");
return -1;
}
memset(md,0,sizeof(md));
gettimeofday(&start,NULL);
calcFileMD5(argv[1],md);
gettimeofday(&end,NULL);
diff = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec); printf("%s MD5:%s\n",argv[1],md);
for(int i = 0; i< 16;i++)
printf("%02x",md[i]);
printf("spend time :%fs\n\n",diff/1000000);
diff =0;
gettimeofday(&start,NULL);
unsigned crc = calcFileCRC32(argv[1]);
gettimeofday(&end,NULL);
diff = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
printf("%s CRC32:%u\n",argv[1],crc);
printf("spend time :%fs\n\n",diff/1000000);
diff = 0;
memset(md,0,sizeof(md));
gettimeofday(&start,NULL);
calcFileSHA1(argv[1],md);
gettimeofday(&end,NULL);
diff = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
printf("%s SHA1:%s\n",argv[1],md);
printf("spend time :%fs\n\n",diff/1000000);
diff =0;
memset(md,0,sizeof(md));
gettimeofday(&start,NULL);
calcFileSHA256(argv[1],md);
gettimeofday(&end,NULL);
diff = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
printf("%s SHA256:%s\n",argv[1],md);
printf("spend time :%fs\n\n",diff/1000000);
free(md);
return0;
}
View Code
说明:经过MD5、SHA1和SHA256计算出的校验值需要再经过⼀层转换,才能成为可识别的字符串,以MD5为例:for(int i = 0; i< 16;i++)
printf("%02x",md[i]);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论