数字签名算法

来源:互联网 发布:中国网络电视直播台 编辑:程序博客网 时间:2024/06/06 00:25
#include<stdio.h> 
#include<openssl/evp.h> 
#include<string.h> 
#include<windows.h> 
#include<openssl/x509.h> 
  
void sign_test() 
{ 
    unsigned char sign_value[1024]; //保存签名值的数组 

    int sign_len; //签名的长度 

    EVP_MD_CTX mdctx; //摘要算法上下文变量 

    char mess1[]="Text Message"; //签名的信息 

    RSA *rsa=NULL; //RSA结构体变量 

    EVP_PKEY *evpKey=NULL; //EVPKEY 结构体变量 

    int i; 
  
    printf("正在产生RSA密钥...."); 
    rsa=RSA_generate_key(1024,RSA_F4,NULL,NULL); //产生一个1024 位的RSA密钥 

    if (rsa==NULL) 
    { 
        printf("gen rsa err\n"); 
        return; 
    } 
    printf("成功。\n"); 
    
    //The EVP_PKEY_new() function allocates an empty EVP_PKEY structure which is used by OpenSSL to store private keys. 

    evpKey=EVP_PKEY_new();//新建一个EVP_PKEY 变量 


    if (evpKey==NULL) 
    { 
        printf("EVP_PKEY_new err\n"); 
        RSA_free(rsa); 
        return; 
    } 


    if (EVP_PKEY_set1_RSA(evpKey,rsa) !=1) //保存RSA结构体到EVP_PKEY 结构体 

    { 
        printf("EVP_PKEY_set1_RSA err\n"); 
        RSA_free(rsa); 
        EVP_PKEY_free(evpKey); 
        return; 
    } 
    EVP_MD_CTX_init(&mdctx); //初始化摘要上下文 

    
    //该函数是一个宏定义函数#define EVP_SignInit_ex(a,b,c) EVP_DigestInit_ex(a,b,c)

    // int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);

    //EVP_DigestInit_ex() sets up digest context ctx to use a digest type from ENGINE impl. 

    //ctx must be initialized before calling this function. type will typically be supplied by a functionsuch as EVP_sha1(). 

    //If impl is NULL then the default implementation of digest type is used. 

    if (!EVP_SignInit_ex(&mdctx,EVP_md5(),NULL)) 
    { 
        printf("Init err\n"); 
        EVP_PKEY_free(evpKey); 
        RSA_free(rsa); 
        return; 
    } 

    //int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt);

    //EVP_DigestUpdate() hashes cnt bytes of data at d into the digest context ctx. 

    //This function can be called several times on the same ctx to hash additional data. 

    if (!EVP_SignUpdate(&mdctx,mess1,strlen(mess1))) //计算签名(摘要)Update 

    { 
        printf("EVP_SignUpdate err\n"); 
        EVP_PKEY_free(evpKey); 
        RSA_free(rsa); 
        return; 
    } 

    //int EVP_SignFinal(EVP_MD_CTX *ctx,unsigned char *sig,unsigned int *s, EVP_PKEY *pkey);

    //这是签名系列函数跟信息摘要函数开始不同的地方,其实,该函数是将签名操作的信息摘要结构ctx拷贝一份,

    //然后调用EVP_DigestFinal_ex完成信息摘要工作,然后开始对摘要信息用私钥pkey进行签名,并将签名信息保存在参数sig里面。

    //如果参数s不为NULL,那么就会将签名信息数据的长度(单位字节)保存在该参数中,通常写入的数据是EVP_PKEY_size(key)。

    //因为操作的时候是拷贝了一份ctx,所以,原来的ctx结构还可以继续使用EVP_SignUpdate和EVP_SignFinal函数来完成更多信息的签名工作。

    //不过,最后一定要使用EVP_MD_CTX_cleanup函数清除和释放ctx结构,否则就会造成内存泄漏。


    if(!EVP_SignFinal(&mdctx,sign_value,(unsigned int *)(&sign_len),evpKey))//签名输出 

    { 
        printf("EVP_SignFinal err \n"); 
        EVP_PKEY_free(evpKey); 
        RSA_free(rsa); 
        return; 
    } 
    printf("消息\"%s\"的签名值是:\n",mess1); 
    for(i=0;i<sign_len;i++) 
    { 
        if (i%6==0) 
            printf("\n%08xH:",i); 
            printf("%02x ",sign_value[i]); 
    } 
    printf("\n"); 
    EVP_MD_CTX_cleanup(&mdctx); 
    printf("\n 正在验证签名......\n"); 
    //以下为验证代码 

    if (!EVP_VerifyInit_ex(&mdctx,EVP_md5(),NULL)) 
    { 
        printf("EVP_VerifyInit_ex err\n"); 
        EVP_PKEY_free(evpKey); 
        RSA_free(rsa); 
        return; 
    } 
    if (!EVP_VerifyUpdate(&mdctx,mess1,strlen(mess1))) 
    { 
        printf ("EVP_VerifyUpdate err \n"); 
        EVP_PKEY_free(evpKey); 
        RSA_free(rsa); 
        return; 
    } 
    if (!EVP_VerifyFinal(&mdctx,sign_value,sign_len,evpKey)) 
    { 
        printf("EVP_VerifyFinal err \n"); 
        EVP_PKEY_free(evpKey); 
        RSA_free(rsa); 
        return; 
    } 
    else 
    { 
        printf ("验证签名正确..\n"); 
    } 
        EVP_PKEY_free(evpKey); 
        RSA_free(rsa); 
        EVP_MD_CTX_cleanup(&mdctx); 
        printf ("--------------------------------------\n"); 
        return; 
}
0 0
原创粉丝点击