学习openssl中的hash算法
项目中实现了checksum服务,看了下实现,用的是openssl库中的hash算法。
很简单的一个实现如下:
1 std::string ChecksumImplement::SHA1(const std::string & str) 2 { 3 unsigned char sha1_digest[SHA1_DIGEST_LENGTH] = {0}; 4 ::SHA1(reinterpret_cast<const unsigned char *> (str.c_str()), str.length(), sha1_digest); 5 char buffout[SHA1_DIGEST_LENGTH * 4] = {0}; 6 for (int i = 0; i < SHA1_DIGEST_LENGTH; i++) { 7 sprintf(buffout + i * 2, "%02x", sha1_digest[i]); 8 } 9 return buffout; 10 }
更多说明:
SHA1散列函数是很常用的散列函数,它产生160bit(20字节)长度的散列值。
今天,我就来介绍利用OpenSSL现成的API来计算数据的SHA1散列值。
先来看OpenSSL的相关API声明:1 #include <openssl/sha.h> 2 unsigned char *SHA1(const unsigned char *d, unsigned long n, 3 unsigned char *md); 4 int SHA1_Init(SHA_CTX *c); 5 int SHA1_Update(SHA_CTX *c, const void *data, 6 unsigned long len); 7 int SHA1_Final(unsigned char *md, SHA_CTX *c);这里有2个(套)API可以来计算数据的SHA1散列值。
最先的SHA1函数很直白,参数d是数据块的起始地址,n是数据块的长度,计算的散列值存储在参数md指向的内存中。如果md为NULL,那么SHA1函数会把计算得到的散列值存储在函数内部的静态空间内,然后通过函数返回值返回给我们。刚才我们说过SHA1散列值的长度为20字节,所以md至少需要拥有20字节的空间大小。当然,OpenSSL已经为我们定义了常量SHA_DIGEST_LENGTH。
对于第二套API,我们看到由3个函数组成。粗粗一看,有些看客会觉得3个函数不就是完成SHA1函数的功能吗?为什么要搞3个函数来啊?呵呵,OpenSSL显然是有充分的理由来这么做的。这么做的关键是SHA1_Update这个函数可以被调用多次,这些待计算散列值的数据会被叠加,最终产生一个散列值。也许有人现在还没想到它的使用场景,我下面来举个例子点破。
比如一个文件大小为6GB,我们知道32位程序无法访问大于4GB的内存空间(其实程序员可以操作的最多也就3GB,程序/数据/栈/保护区等会占用1GB左右的空间),这时如何计算这个文件的散列值?SHA1肯定是不行的了。这时我们可以分N次来读这个文件,每次读1MB的数据,然后调用SHA1_Update函数来累计计算散列值,读完文件的所有数据后,我们再调用SHA1_Final函数来得到最终的散列值。
http://yinghao.blog.51cto.com/3072047/562542
项目里用第二套api实现了对文件做校验:
1 std::string ChecksumImplement::SHA1File(const std::string & filepath) 2 { 3 FILE * fp = fopen(filepath.c_str(), "rb"); 4 if (!fp) { 5 fprintf(stderr, "Could not open file: %s\n", filepath.c_str()); 6 return ""; 7 } 8 9 unsigned char buffin[BUFF_SIZE]; 10 unsigned char sha1_digest[SHA1_DIGEST_LENGTH] = {0}; 11 size_t nread; 12 13 SHA_CTX ctx; 14 SHA1_Init(&ctx); 15 16 while (nread = fread(buffin, 1, BUFF_SIZE, fp)) { 17 SHA1_Update(&ctx, buffin, nread); 18 } 19 20 SHA1_Final(sha1_digest, &ctx); 21 fclose(fp); 22 23 char buffout[SHA1_DIGEST_LENGTH * 4] = {0}; 24 for (int i = 0; i < SHA1_DIGEST_LENGTH; i++) 25 sprintf(buffout + i * 2, "%02x", sha1_digest[i]); 26 27 return buffout; 28 }
当然了,还有MD5等其他算法,就不说了。