http://blog.csdn.net/zhouyuqwert/article/details/6603991
- #include <stdio.h>
- #include <string.h>
- #include <openssl/evp.h>
- #include <openssl/rsa.h>
- #include <openssl/x509.h>
- #include <openssl/des.h>
- #include "util/Base.h"
- typedef unsigned char BYTE;
- /*
- *
- *产生随机数
- *
- */
- unsigned char *getRandom(unsigned char *buf, size_t l) {
- if (!RAND_bytes(buf, l)) {
- fprintf(stderr, "The PRNG is not seeded!\n");
- return NULL;
- }
- printf((char*)buf);
- return buf;
- }
- /**
- *
- *信封加密解密
- *参考openssl编程.chm 21.10编程实例4
- *
- */
- int EVP_enc()
- {
- int ret,ekl[2],npubk,inl,outl,total=0,total2=0;
- unsigned long e=RSA_3;
- char *ek[2],iv[8],in[100],out[500],de[500];
- EVP_CIPHER_CTX ctx,ctx2;
- EVP_CIPHER *type;
- EVP_PKEY *pubkey[2];
- RSA *rkey;
- BIGNUM *bne;
- int i;
- /* 生成RSA密钥*/
- bne=BN_new();
- ret=BN_set_word(bne,e);
- rkey=RSA_new();
- ret=RSA_generate_key_ex(rkey,1024,bne,NULL);
- pubkey[0]=EVP_PKEY_new();
- EVP_PKEY_assign_RSA(pubkey[0],rkey); //初始化一个公钥为RSA的密钥对公钥
- type=EVP_des_ede3_cbc(); //对称密钥的算法
- npubk=1; //设置一个公钥加密
- EVP_CIPHER_CTX_init(&ctx); //初始化信封加密上下文
- ek[0]=malloc(500);
- ek[1]=malloc(500);
- ret=EVP_SealInit(&ctx,type,(BYTE**)ek,ekl,iv,pubkey,1); /* 只有一个公钥,如果为CBC算法IV会被产生*/
- if(ret!=1) goto err;
- strcpy(in,"openssl 编程"); //对称密钥(即将被加密为信封的数据)
- inl=strlen(in);
- ret=EVP_SealUpdate(&ctx,out,&outl,in,inl); //加密操作
- if(ret!=1)goto err;
- total+=outl;
- ret=EVP_SealFinal(&ctx,out+outl,&outl); //加密剩下的部分
- if(ret!=1) goto err;
- total+=outl;
- /**
- * 解密信封
- */
- memset(de,0,500);
- EVP_CIPHER_CTX_init(&ctx2); //初始化解密信封的上下文
- ret=EVP_OpenInit(&ctx2,EVP_des_ede3_cbc(),ek[0],ekl[0],iv,pubkey[0]); //设置公钥
- if(ret!=1) goto err;
- ret=EVP_OpenUpdate(&ctx2,de,&outl,out,total);
- total2+=outl;
- ret=EVP_OpenFinal(&ctx2,de+outl,&outl);
- total2+=outl;
- de[total2]=0;
- printf("%s\n",de);
- err:
- free(ek[0]);
- free(ek[1]);
- EVP_PKEY_free(pubkey[0]);
- BN_free(bne);
- getchar();
- return 0;
- }
- /**
- *
- *数字签名与验证
- *参考《精通PKI安全认证技术与编程实现》
- *
- **/
- void tSign()
- {
- BYTE sign_value[1024]; //保存签名值的数组
- int sign_len; //签名值长度
- EVP_MD_CTX mdctx; //摘要算法上下文变量
- char messl[] = "Test Message"; //签名的消息
- RSA* rsa = NULL; //RSA结构体变量
- EVP_PKEY* evpKey = NULL; //EVP KEY结构体变量
- 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");
- 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); //初始化摘要上下文
- if(!EVP_SignInit_ex(&mdctx,EVP_md5(),NULL)) //签名初始化,设置摘要算法
- {
- printf("err\n");
- EVP_PKEY_free(evpKey);
- RSA_free(rsa);
- return;
- }
- if(!EVP_SignUpdate(&mdctx,messl,strlen(messl))) //计算签名(摘要)Update
- {
- printf("err\n");
- EVP_PKEY_free(evpKey);
- RSA_free(rsa);
- return;
- }
- if(!EVP_SignFinal(&mdctx,sign_value,&sign_len,evpKey)) //签名输出
- {
- printf("err\n");
- EVP_PKEY_free(evpKey);
- RSA_free(rsa);
- return;
- }
- printf("消息\"%s\"的签名值是:\n",messl);
- for(i = 0; i < sign_len; i++)
- {
- if(i%16==0)
- printf("\n%08xH: ",i);
- printf("&%2x ",sign_value[i]);
- }
- printf("\n");
- EVP_MD_CTX_cleanup(&mdctx);
- printf("\n 正在验证签名...\n");
- //以下是验证签名的代码
- EVP_MD_CTX_init(&mdctx); //初始化摘要上下文
- 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, messl, strlen(messl))) //验证签名(摘要)Update
- {
- printf("err\n");
- EVP_PKEY_free(evpKey);
- RSA_free(rsa);
- return;
- }
- if(!EVP_VerifyFinal(&mdctx,sign_value,sign_len,evpKey))
- {
- printf("verify 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);
- return;
- }
- /**
- *
- *in为输入的字节数组,len为输入长度,out为输出hash值,outl为输出长度
- *MD5摘要算法得到16字节结果
- *
- */
- void hash_md5(BYTE *in,int len,BYTE* out,int *outl)
- {
- /*************
- *
- *将输入初始化到临时BYTE数组
- *
- **************/
- BYTE intemp[len];
- int j;int i;
- for(j = 0; j<len;j++)
- {
- intemp[j] = in[j];
- }
- for(i=0;i<16;i++)
- printf("%x ",out[i]);
- printf("\n");
- memset(out,0,16);
- intemp[len] = 0;
- size_t n;
- unsigned long err;
- printf("\nMD5 digesting:\n");
- printf("\n%s\n",intemp);
- MD5(intemp,n,out);
- printf("\n%d\n",n);
- printf("\n\nMD5 digest result :\n");
- printf("\n%s\n",out);
- /*****
- *
- *MD5输出为16字节
- *
- ******/
- //*outl = 16;
- for(i=0;i<16;i++)
- printf("%x ",out[i]);
- }