📄 p7_test.c
字号:
/******************************************************************
程序说明:一个PKCS7标准里的encrypt-data content type的例子
该程序主要利用openssl定义的p7结构和相关的加密函数是实现了一个
PKCS7标准里的encrypt-data content type的加密,解密处理过程。
程序加密过程对指定的明文数据作了加密处理,然后打包成一个p7的标
准格式,进行DER编码后保存到指定的文件中;
程序的解密过程从指定的文件中读出一个encrypt-data content type
类型的PKCS7结构,对该结构里的密文数据进行解密处理,将解密出来的明
文打印输出。
程序里指定了密钥值和前导量以及加密的算法,明文数据也已经初始化,
有兴趣的读者可以对以上各项值作修改,但是要注意密钥长度,前导量长度
要和指定的算法对应起来。
对PKCS7标准的理解甚浅,也许这个处理流程有不大符合标准的地方,希
望读者能加以指正并提出宝贵意见,欢迎来信共同讨论(lxm7@x263.net)
/******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
//#include "apps.h"
#include <openssl/err.h>
#include <openssl/objects.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/pkcs7.h>
#include <openssl/pem.h>
unsigned char key[] = {0,1,2,3,4,5,6,7}; //密钥值
unsigned char iv[] = {1,2,3,4,5,6,7,8}; //加密前导量
int algorithm=NID_des_cbc; //加密算法
unsigned char text[]="hellow, everyone!"; //明文数据
int P7_EncryptData_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher);
int P7_EncryptData_set_EncAlg(PKCS7 *p7);
int P7_packet_data(unsigned char *plain,int plain_len,unsigned char *outdata,int *out_len);
int P7_EncryptData_set_EncContent(PKCS7 *p7,unsigned char *indata, int inlen);
int P7_enc_data(PKCS7 *p7, unsigned char *plain,int plain_len, unsigned char * cipher, int * cipher_len);
int P7_EncryptData_get_p7(unsigned char *filename,PKCS7 *p7);
int P7_EncryptData_get_cipher(PKCS7 *p7,unsigned char *cipher,int * cipher_len);
int P7_dec_data(PKCS7 *p7, unsigned char *plain,int*plain_len, unsigned char * cipher, int cipher_len);
int P7_unpacket_data(unsigned char *packet_data,int packet_data_len, unsigned char * outdata, int *outdata_len);
main(int argc, char **argv)
{
PKCS7 *p7=NULL;
int ret=0;
unsigned char *cipher=NULL;
int cipher_len=0;
unsigned char *packet_data=NULL;
int packet_data_len=0;
char *prog;
unsigned char file[20]="\0";
unsigned char *outdata=NULL;
int outdata_len=0;
EVP_CIPHER *cipher1=NULL;
unsigned char *out_temp=NULL;
FILE * bp;
prog=argv[0];
argc--; argv++;
if (argc!=2)
{
printf("HOW TO USE THIS PROGRAM:\n");
printf("%s [options] filename\n","command");
printf("where options are:\n");
printf("-e, encrypt data whitch be set in program and write the cipher to file.\n");
printf("-d, decrypt cipher from the appointed file.\n");
return 0;
}
strcpy(file,*(++argv));
argv--;
if (strcmp(*argv,"-e") == 0)
{
//创建一个nid=NID_pkcs7_encrypted类型的p7结构
p7=PKCS7_new();
PKCS7_set_type(p7,NID_pkcs7_encrypted);
//往p7结构里加入信息1:加入cipher信息
OpenSSL_add_all_algorithms();
if(!(cipher1 = EVP_get_cipherbynid(algorithm)))
{
printf("%s\n","程序设置EVP_cipher信息失败");
return 0;
}
ret=P7_EncryptData_set_cipher(p7,cipher1);
if (ret!=1)
{
PKCS7_free(p7);
printf("%s\n","p7结构设置EVP_cipher信息失败");
return 0;
}
//往p7结构里加入信息2:加入AlgorithmIdentifier信息
ret=P7_EncryptData_set_EncAlg(p7);
if (ret!=1)
{
PKCS7_free(p7);
printf("%s\n","p7结构设置算法失败");
return 0;
}
//将明文数据打包成一个PKCS#7格式的包,并转化成DER编码输出
packet_data=malloc(strlen(text)+1000);
memset(packet_data,0,strlen(text)+1000);
ret=P7_packet_data(text,strlen(text),packet_data,&packet_data_len);
if (ret!=1)
{
if (packet_data!=NULL) free(packet_data);
PKCS7_free(p7);
printf("%s\n","明文数据PKCS7打包失败");
return 0;
}
//做加密运算
cipher=malloc(packet_data_len+10);
memset(cipher,0,packet_data_len+10);
ret=P7_enc_data(p7, packet_data,packet_data_len, cipher, &cipher_len);
if (ret!=1)
{
if (packet_data!=NULL) free(packet_data);
if (cipher!=NULL) free(cipher);
PKCS7_free(p7);
printf("%s\n","EVP加密失败");
return 0;
}
//往p7结构里加入信息3:加入EncryptedContent信息
ret=P7_EncryptData_set_EncContent(p7,cipher,cipher_len);
if (ret!=1)
{
if (packet_data!=NULL) free(packet_data);
if (cipher!=NULL) free(cipher);
PKCS7_free(p7);
printf("%s\n","p7结构设置加密内容失败");
return 0;
}
//将P7结构DER编码写文件
bp = fopen(file, "wb");
ret=i2d_PKCS7(p7, NULL);
outdata=malloc(ret+1);
memset(outdata,0,ret+1);
out_temp=outdata; //下面调用i2d_PKCS7函数会改变out_temp的值(如果将out_temp作为参数输入),所以要用out_temp指针得回原先的地址值
//i=i2d_PKCS7(p7, &out_temp); 会改变der_mem的值
ret=i2d_PKCS7(p7, &out_temp);
fwrite(outdata,1,ret,bp);
fclose(bp);
printf("%s\n","success!");
}
if (strcmp(*argv,"-d") == 0)
{
//从source.dat文件读出一个nid=NID_pkcs7_encrypted类型的p7结构
p7=PKCS7_new();
ret=P7_EncryptData_get_p7(file,p7);
if (ret!=1)
{
printf("%s\n","从文件获取p7结构失败");
return 0;
}
//检查p7结构类型是否正确并从p7结构里取得密文数据
ret=P7_EncryptData_get_cipher(p7,NULL,&cipher_len);
if (ret!=1)
{
printf("%s\n","从p7结构获取EVP_cipher信息失败");
return 0;
}
cipher=malloc(cipher_len+1);
memset(cipher,0,cipher_len+1);
ret=P7_EncryptData_get_cipher(p7,cipher,&cipher_len);
if (ret!=1)
{
if (cipher!=NULL) free(cipher);
printf("%s\n","从p7结构获取密文数据失败");
return 0;
}
//做解密运算
packet_data=malloc(cipher_len);
memset(packet_data,0,cipher_len);
ret=P7_dec_data(p7, packet_data,&packet_data_len, cipher, cipher_len);
if (ret!=1)
{
if (packet_data!=NULL) free(packet_data);
if (cipher!=NULL) free(cipher);
PKCS7_free(p7);
printf("%s\n","解密失败");
return 0;
}
//从解密出来的明文数据中获取所要的数据(解密出来的明文是一个p7结构)
ret=P7_unpacket_data(packet_data,packet_data_len, NULL, &outdata_len);
if (ret!=1)
{
if (packet_data!=NULL) free(packet_data);
if (cipher!=NULL) free(cipher);
PKCS7_free(p7);
printf("%s\n","明文数据拆包失败");
return 0;
}
outdata=malloc(outdata_len+1);
memset(outdata,0,outdata_len+1);
ret=P7_unpacket_data(packet_data,packet_data_len, outdata, &outdata_len);
if (ret!=1)
{
if (outdata!=NULL) free(outdata);
if (packet_data!=NULL) free(packet_data);
if (cipher!=NULL) free(cipher);
PKCS7_free(p7);
printf("%s\n","明文数据拆包失败");
return 0;
}
//将数据打印
printf("%s\n",outdata);
}
if (packet_data!=NULL) free(packet_data);
if (outdata!=NULL) free(outdata);
if (cipher!=NULL) free(cipher);
PKCS7_free(p7);
return 1;
}
int P7_EncryptData_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher)
{
int i;
ASN1_OBJECT *objtmp;
PKCS7_ENC_CONTENT *ec;
i=OBJ_obj2nid(p7->type);
if (i!=NID_pkcs7_encrypted) return 0;
ec=p7->d.encrypted->enc_data;
/* Check cipher OID exists and has data in it*/
i = EVP_CIPHER_type(cipher);
if(i == NID_undef) return 0;
objtmp = OBJ_nid2obj(i);
ec->cipher = cipher;
return 1;
}
int P7_EncryptData_set_EncAlg(PKCS7 *p7)
{
int i;
X509_ALGOR *xalg=NULL;
const EVP_CIPHER *evp_cipher=NULL;
i=OBJ_obj2nid(p7->type);
if (i!=NID_pkcs7_encrypted) return 0;
i=OBJ_obj2nid(p7->type);
p7->state=PKCS7_S_HEADER;
xalg=p7->d.encrypted->enc_data->algorithm;
evp_cipher=p7->d.encrypted->enc_data->cipher;
if (evp_cipher == NULL) return 0;
xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher));
return 1;
}
int P7_packet_data(unsigned char *plain,int plain_len,unsigned char *outdata,int *out_len)
{
int i;
PKCS7 *p7_1=NULL; //注意是释放空间
unsigned char *der_mem = NULL;
unsigned char *temp = NULL; //注意:很有用
p7_1=PKCS7_new(); //创建一个nid=NID_pkcs7_data类型的p7结构
PKCS7_set_type(p7_1,NID_pkcs7_data);
M_ASN1_OCTET_STRING_set(p7_1->d.data,plain,plain_len);
i=i2d_PKCS7(p7_1, NULL);
*out_len=i;
der_mem=malloc(out_len+1);
memset(der_mem,0,out_len+1);
temp=der_mem; //下面调用i2d_PKCS7函数会改变der_mem的值(如果将der_mem作为参数输入),所以要用temp指针得回原先的地址值
//i=i2d_PKCS7(p7_1, &der_mem); 会改变der_mem的值
i=i2d_PKCS7(p7_1, &temp);
memcpy(outdata,der_mem,i);
if (der_mem!=NULL) free(der_mem);
PKCS7_free(p7_1);
return 1;
}
int P7_enc_data(PKCS7 *p7, unsigned char *plain,int plain_len, unsigned char * cipher, int * cipher_len)
{
const EVP_CIPHER *evp_cipher=NULL;
X509_ALGOR *xalg=NULL;
int i=0,outlen,tmplen;
EVP_CIPHER_CTX ctx;
unsigned char *outbuf=NULL;
//
i=OBJ_obj2nid(p7->type);
if (i!=NID_pkcs7_encrypted) return 0;
//
evp_cipher=p7->d.encrypted->enc_data->cipher;
xalg=p7->d.encrypted->enc_data->algorithm;
if (evp_cipher==NULL) return 0;
//
EVP_CIPHER_CTX_init(&ctx); //注意释放
EVP_CipherInit(&ctx, evp_cipher, key, iv, 1); //enc=1 加密
//对xalg->parameter赋值
if (xalg->parameter == NULL) xalg->parameter=ASN1_TYPE_new();
if(EVP_CIPHER_param_to_asn1(&ctx, xalg->parameter) < 0) return 0;
//加密
outbuf=malloc(plain_len+8);
memset(outbuf,0,plain_len+8);
if(!EVP_CipherUpdate(&ctx, outbuf, &outlen, plain, plain_len))
{
if (outbuf!=NULL) free(outbuf);
return 0;
}
if(!EVP_CipherFinal(&ctx, outbuf + outlen, &tmplen)) //注意,传入给下面函数的输出缓存参数必须注意不能覆盖了原来的加密输出的数据
{
if (outbuf!=NULL) free(outbuf);
return 0;
}
outlen += tmplen;
//
EVP_CIPHER_CTX_cleanup(&ctx);
*cipher_len=outlen;
memcpy(cipher,outbuf,outlen);
if (outbuf!=NULL) free(outbuf);
return 1;
}
int P7_EncryptData_set_EncContent(PKCS7 *p7,unsigned char *indata, int inlen)
{
int i=0;
p7->d.encrypted->enc_data->enc_data=ASN1_STRING_type_new(V_ASN1_OCTET_STRING);
i=OBJ_obj2nid(p7->type);
if (i==NID_pkcs7_encrypted)
M_ASN1_OCTET_STRING_set(p7->d.encrypted->enc_data->enc_data,indata,inlen);
else return 0;
return 1;
}
int P7_EncryptData_get_p7(unsigned char *filename,PKCS7 *p7)
{
FILE * bp;
int i=0,ret=0;
unsigned char *buf=NULL;
bp=fopen(filename,"rb");
if (bp==NULL) return 0;
fseek(bp,0,SEEK_END);
i = ftell(bp);
fseek(bp,0,SEEK_SET);
buf=malloc(i+1);
memset(buf,0,i+1);
ret=fread(buf,1,i,bp);
if (i!=ret)
{
if (buf!=NULL) free(buf);
fclose(bp);
return 0;
}
fclose(bp);
//
d2i_PKCS7(&p7, &buf, i);
if (p7==NULL)
{
if (buf!=NULL) free(buf);
return 0;
}
return 1;
}
int P7_EncryptData_get_cipher(PKCS7 *p7,unsigned char *cipher,int * cipher_len)
{
int i=0,ret=0;
X509_ALGOR *xalg=NULL;
ASN1_OCTET_STRING *enc_data;
i=OBJ_obj2nid(p7->type);
if (i!=NID_pkcs7_encrypted) return 0;
xalg=p7->d.encrypted->enc_data->algorithm;
i=OBJ_obj2nid(xalg->algorithm);
if (i!=NID_des_cbc) return 0; //因为加密过程选的是NID_des_cbc,所以这里进行一下判断,保证只对该算法作处理
//
enc_data=p7->d.encrypted->enc_data->enc_data;
*cipher_len=enc_data->length;
if (cipher==NULL) return 1;
memcpy(cipher,enc_data->data,enc_data->length);
return 1;
}
int P7_dec_data(PKCS7 *p7, unsigned char *plain,int *plain_len, unsigned char * cipher, int cipher_len)
{
const EVP_CIPHER *evp_cipher=NULL;
X509_ALGOR *xalg=NULL;
int i=0,tmplen;
EVP_CIPHER_CTX ctx;
//
i=OBJ_obj2nid(p7->type);
if (i!=NID_pkcs7_encrypted) return 0;
//
xalg=p7->d.encrypted->enc_data->algorithm;
i=OBJ_obj2nid(xalg->algorithm);
if (i!=NID_des_cbc) return 0; //因为加密过程选的是NID_des_cbc,所以这里进行一下判断,保证只对该算法作处理
//
OpenSSL_add_all_algorithms();
if(!(evp_cipher = EVP_get_cipherbynid(NID_des_cbc))) return 0;
//
EVP_CIPHER_CTX_init(&ctx); //注意释放
EVP_CipherInit(&ctx, evp_cipher, key, iv, 0); //enc=0 解密
//解密
if(!EVP_CipherUpdate(&ctx, plain, plain_len, cipher, cipher_len))
{
*plain_len=0;
return 0;
}
if(!EVP_CipherFinal(&ctx, plain + (*plain_len), &tmplen)) //注意,传入给下面函数的输出缓存参数必须注意不能覆盖了原来的加密输出的数据
{
*plain_len=0;
return 0;
}
(*plain_len) += tmplen;
//
EVP_CIPHER_CTX_cleanup(&ctx);
return 1;
}
int P7_unpacket_data(unsigned char *packet_data,int packet_data_len, unsigned char * outdata, int *outdata_len)
{
int i;
PKCS7 *p7_1=NULL; //注意是释放空间
ASN1_OCTET_STRING *tembuf=NULL;
unsigned char *der_mem = NULL;
unsigned char *temp = NULL; //注意:很有用
p7_1=PKCS7_new(); //创建一个p7结构
d2i_PKCS7(&p7_1, &packet_data, packet_data_len);
if (p7_1==NULL)
{
PKCS7_free(p7_1);
return 0;
}
//
i=OBJ_obj2nid(p7_1->type);
if (i!=NID_pkcs7_data)
{
PKCS7_free(p7_1);
return 0;
}
//
tembuf=p7_1->d.data;
if (tembuf->type!=V_ASN1_OCTET_STRING)
{
PKCS7_free(p7_1);
return 0;
}
*outdata_len=tembuf->length;
if (outdata==NULL) return 1;
memcpy(outdata,tembuf->data,tembuf->length);
PKCS7_free(p7_1);
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -