学习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等其他算法,就不说了。

 

 

 

 

posted @ 2012-08-02 18:25    阅读(3976)  评论(0编辑  收藏  举报