转自:http://linux.chinaunix.net/techdoc/net/2007/04/10/954867.shtml


用openssl的engine机制实现chiper,digest的替换遇到问题了,到底EVP是怎么样调用init,updata,final以及init,updata,final应该如何实现呢?
---------------------------------
消息摘要算法 
简单接口 
简单接口使用一个函数调用就可以完成消息摘要计算,这些接口包括MD2,MD4,MD5,MDC2,RIPEMD,SHA1,函数声明都一样。 
以MD5为例,函数声明为: 
unsigned char *MD5(const unsigned char *d, unsigned long n, unsigned char *md); 
其中 d 指向要计算消息摘要的数据,n 为数据长度,md 指向保存消息摘要的缓冲区。如果 md 不为 NULL,那么它的长度必须能够容纳计算出来的消息摘要。对MD5,这个长度至少是 MD5_DIGEST_LENGTH。如果 md 为 NULL,那么计算出来的消息摘要保存在一个静态数组里,函数返回指向这个数组的指针。 
    下面是一个使用MD()计算消息摘要的小程序: 
//ex1.cpp 
#include  
#include  
#include   
static char *hexstr(unsigned char *buf,int len) 

     const char *set = "0123456789abcdef"; 
     static char str[65],*tmp; 
     unsigned char *end;  
     if (len > 32) 
         len = 32;  
     end = buf + len; 
     tmp = &str[0];  
     while (buf  
     { 
         *tmp++ = set[ (*buf) >> 4 ]; 
         *tmp++ = set[ (*buf) & 0xF ]; 
         buf ++; 
     } 
     *tmp = '';  
     return str; 

int main(int argc, char* argv[]) 

     char *buf = "Hello,OpenSSL\n"; 
     unsigned char *md;  
     md = MD5((const unsigned char*)buf,strlen(buf),NULL); 
     printf("%s\n",hexstr(md,MD5_DIGEST_LENGTH));  
     return 0; 
}  
这个程序计算出字符串”Hello,OpenSSL\n”的消息摘要为97aa490ee85f397134404f7bb524b587。可以用Unix下的md5sum程序检验是否正确: 
[root@cat /root]# echo "Hello,OpenSSL" | md5sum 
97aa490ee85f397134404f7bb524b587  - 
可以看到结果一样。 
其它算法的计算类似,只用替换源代码中的md5为相应的算法名即可。 
标准接口
简单接口容易使用,但是它要求被摘要数据在时间和空间上都是连续的。要 
计算不连续数据的摘要,就必须使用标准接口。事实上,简单接口也是通过调用标准接口工作的。 
    以MD5为例,标准接口包括如下函数: 
    void MD5_Init(MD5_CTX *c); 
    void MD5_Update(MD5_CTX *c,const void *data,unsigned long len); 
    void MD5_Final(unsigned char *md, MD5_CTX *c); 
MD5_Init初始化MD5_CTX结构,MD5_Update计算摘要,MD5_Final输出摘要值。 
    下面是使用标准接口的 ex1.cpp 程序(只有main函数不同): 
//ex2.cpp 
//包含的头文件,hexstr函数都和 ex1.cpp一样 
int main(int argc, char* argv[]) 

     char *buf = "Hello"; 
     char *buf2 = ","; 
     char *buf3 = "OpenSSL\n"; 
     unsigned char md[MD5_DIGEST_LENGTH]; 
     MD5_CTX ctx; 
     MD5_Init(&ctx); 
     MD5_Update(&ctx,buf,strlen(buf)); 
     MD5_Update(&ctx,buf2,strlen(buf2)); 
     MD5_Update(&ctx,buf3,strlen(buf3)); 
     MD5_Final(md,&ctx); 
     
     printf("%s\n",hexstr(md,MD5_DIGEST_LENGTH)); 
     return 0; 

检验: 
    E:\ssl\md5\ex2\Debug>ex2 
97aa490ee85f397134404f7bb524b587 
可以看出,和 ex1 和 md5sum 的结果一致。    
EVP 接口
#include  
#include  
#include   
static char *hexstr(unsigned char *buf,int len) 

     const char *set = "0123456789abcdef"; 
     static char str[65],*tmp; 
     unsigned char *end;  
     if (len > 32) 
         len = 32;  
     end = buf + len; 
     tmp = &str[0];  
     while (buf  
     { 
         *tmp++ = set[ (*buf) >> 4 ]; 
         *tmp++ = set[ (*buf) & 0xF ]; 
         buf ++; 
     } 
     *tmp = '';  
     return str; 

int main(int argc, char* argv[]) 

     char *buf = "Hello"; 
     char *buf2 = ","; 
     char *buf3 = "OpenSSL\n"; 
     unsigned int mdlen; 
     unsigned char md[EVP_MAX_MD_SIZE]; 
     EVP_MD_CTX ctx; 
     const EVP_MD *type = EVP_md5();  
     OpenSSL_add_all_digests();  
     if (argc > 1) 
     { 
         type = EVP_get_digestbyname(argv[1]); 
         if (type == NULL) 
         { 
              fprintf(stderr,"Use default : MD5\n"); 
              type = EVP_md5(); 
         } 
     }  
     EVP_DigestInit(&ctx,type);  
     EVP_DigestUpdate(&ctx,buf,strlen(buf)); 
     EVP_DigestUpdate(&ctx,buf2,strlen(buf2)); 
     EVP_DigestUpdate(&ctx,buf3,strlen(buf3));  
     EVP_DigestFinal(&ctx,md,&mdlen);     
     printf("%s\n",hexstr(md,mdlen));  
     return 0; 

BIO 接口
BIO_f_md()返回消息摘要的BIO方法。任何经过一个消息摘要BIO的数据都 
被自动摘要。BIO_set_md设置一个消息摘要BIO所使用的摘要算法。 
    下面是使用BIO的MD5例子: 
#include  
#include  
#include  
#include   
static char *hexstr(unsigned char *buf,int len) 

     const char *set = "0123456789abcdef"; 
     static char str[65],*tmp; 
     unsigned char *end;  
     if (len > 32) 
         len = 32;  
     end = buf + len; 
     tmp = &str[0];  
     while (buf  
     { 
         *tmp++ = set[ (*buf) >> 4 ]; 
         *tmp++ = set[ (*buf) & 0xF ]; 
         buf ++; 
     } 
     *tmp = '';  
     return str; 

int main(int argc, char* argv[]) 

     int len; 
     const char *str = "Hello,OpenSSL\n"; 
     BIO *bio_null,*bio_md; 
     unsigned char md[EVP_MAX_MD_SIZE];  
     bio_null = BIO_new(BIO_s_null()); 
     bio_md = BIO_new(BIO_f_md()); 
     BIO_set_md(bio_md,EVP_md5()); 
     bio_md = BIO_push(bio_md,bio_null);  
     BIO_write(bio_md,str,strlen(str)); 
     BIO_flush(bio_md);  
     len = BIO_gets(bio_md,(char*)md,EVP_MAX_MD_SIZE); 
     printf("%s\n",hexstr(md,len));  
     BIO_free_all(bio_md); 
     return 0; 
}      
检验结果为:97aa490ee85f397134404f7bb524b587,与md5sum的结果相同, 注意消息摘要BIO比较特殊:数据经过这种BIO不被修改,只是摘要值保留在BIO中,需要用BIO_gets而不是BIO_read读取

Logo

更多推荐