#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]); }