结构体和示例说明
p7.pem文本内容示例:
-----BEGIN PKCS7-----
MIIFDAYKKoEcz1UGAQQCBKCCBPwwggT4AgEBMYIBJzCCASMCAQAwgZAwgYYxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJIQjELMAkGA1UEBwwCV0gxEDAOBgNVBAoMB0luZm9TZWMxEjAQBgNVBAsMCVNTTC1Hcm91cDESMBAGA1UEAwwJRUNDRGVtb0NBMSMwIQYJKoZIhvcNAQkBFhRlbWFpbEBpbmZvc2VjLmNvbS5jbgIFFwEDF1UwDQYJKoEcz1UBgi0DBQAEfDB5AiEA6joyvPmCXrzkFM/Hj1kf6JcNWicUGT5cvXqWHmcyHmsCIEhzc7TIF8oIaF0mcLJ/DfnkX4v5GTv8RFEBsKhqC8+2BCDCpremE5cKPdXMXamd5l7ZP2yP+wp7VYx3vnSVl2SL5gQQrfwe5v5cG39MH46CzWkVqwAxDjAMBggqgRzPVQGDEQUAMDwGCiqBHM9VBgEEAgEwHAYIKoEcz1UBaAIEEMWQtu6KZJ0E/BXdo8U107GAENtdQcRvikZ3ifkcxPUWVnigggJ0MIICcDCCAhagAwIBAgIFFwEDF1UwCgYIKoEcz1UBg3UwgYYxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJIQjELMAkGA1UEBwwCV0gxEDAOBgNVBAoMB0luZm9TZWMxEjAQBgNVBAsMCVNTTC1Hcm91cDESMBAGA1UEAwwJRUNDRGVtb0NBMSMwIQYJKoZIhvcNAQkBFhRlbWFpbEBpbmZvc2VjLmNvbS5jbjAeFw0xNzAxMDMxMDA4MTBaFw0yNjExMTIxMDA4MTBaMHsxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJIQjEQMA4GA1UECgwHSW5mb1NlYzESMBAGA1UECwwJU1NMLUdyb3VwMRQwEgYDVQQDDAtFQ0NTaWduVXNlcjEjMCEGCSqGSIb3DQEJARYUZW1haWxAaW5mb3NlYy5jb20uY24wWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAAQ4PGbJsJpjqL6A6/Shmjk9bcOgU5uEDxjeQs0UWkPENY0KehNughYIR8QeUhWtLg6hNcr+0qcUldn01A+2vGyzo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUyabmGcopCxQxR8KdoajvrhEVemUwHwYDVR0jBBgwFoAUwnvRpdmD6ha5TMmcRWkxZxk16QMwCgYIKoEcz1UBg3UDSAAwRQIgDtU1XG2CYcoaJBe+34dfVseFiHLPIBYUfVyges37TVcCIQC8C91sIg3xiyXcwtxNmmWHKIzMTxTBZv+KilRgZehPjDGCAQAwgf0CAQEwgZAwgYYxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJIQjELMAkGA1UEBwwCV0gxEDAOBgNVBAoMB0luZm9TZWMxEjAQBgNVBAsMCVNTTC1Hcm91cDESMBAGA1UEAwwJRUNDRGVtb0NBMSMwIQYJKoZIhvcNAQkBFhRlbWFpbEBpbmZvc2VjLmNvbS5jbgIFFwEDF1UwDAYIKoEcz1UBgxEFADANBgkqgRzPVQGCLQEFAARIMEYCIQDrYTDMByQhxsCctfaDrxtLYEy/MtOkb7jvoYLrLQ6q3gIhAM4tu5A2fSJ9fjzQuky0bN0M2xKkcEv3Bo1r919LplNV
-----END PKCS7-----
P7结构体:
typedef struct pkcs7_st
{
/* The following is non NULL if it contains ASN1 encoding of
* this structure */
unsigned char *asn1;
long length;
#define PKCS7_S_HEADER 0
#define PKCS7_S_BODY 1
#define PKCS7_S_TAIL 2
int state; /* used during processing */
int detached;
ASN1_OBJECT *type;
/* content as defined by the type */
/* all encryption/message digests are applied to the 'contents',
* leaving out the 'type' field. */
union {
char *ptr;
/* NID_pkcs7_data */
ASN1_OCTET_STRING *data;
/* NID_pkcs7_signed */
PKCS7_SIGNED *sign;
/* NID_pkcs7_enveloped */
PKCS7_ENVELOPE *enveloped;
/* NID_pkcs7_signedAndEnveloped */
PKCS7_SIGN_ENVELOPE *signed_and_enveloped;
/* NID_pkcs7_digest */
PKCS7_DIGEST *digest;
/* NID_pkcs7_encrypted */
PKCS7_ENCRYPT *encrypted;
/* Anything else */
ASN1_TYPE *other;
} d;
} PKCS7;
带签名的数字信封结构体:
typedef struct pkcs7_signedandenveloped_st {
ASN1_INTEGER *version; /* version 1 */
STACK_OF(X509_ALGOR) *md_algs; /* md used */
STACK_OF(X509) *cert; /* [ 0 ] */
STACK_OF(X509_CRL) *crl; /* [ 1 ] */
STACK_OF(PKCS7_SIGNER_INFO) *signer_info; //签名者信息
PKCS7_ENC_CONTENT *enc_data; //对称密钥加密过后的密文
STACK_OF(PKCS7_RECIP_INFO) *recipientinfo; //接收者信息,包含加密过后的对称密钥
} PKCS7_SIGN_ENVELOPE;
通过指针一级级获取指定内容进行解密
部分代码示例:
void parse_pkcs7() {
//从文本中读取P7结构体
BIO *cert_bio = BIO_new_file("./p7.pem", "r");
PKCS7 *p7 = NULL;
p7=PEM_read_bio_PKCS7(cert_bio,NULL,NULL,NULL);
if(p7 == NULL) {
fprintf(stderr, "p7 = null\n");
return;
}
//打印P7结构
BIO *m_out = BIO_new_fp(stderr, BIO_NOCLOSE);
PKCS7_print_ctx(m_out, p7, 0, NULL);
//获取P7结构中信息
STACK_OF(PKCS7_RECIP_INFO) *rsk = p7->d.signed_and_enveloped->recipientinfo;
PKCS7_RECIP_INFO *ri = sk_PKCS7_RECIP_INFO_value(rsk, 0);
//读取加密私钥
BIO *key_bio = BIO_new_file("./key.pem", "r");
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(key_bio, NULL, NULL, "11111111");
if(pkey == NULL) {
fprintf(stderr, "PEM_read_bio_PrivateKey fail\n");
ERR_print_errors_fp(stderr);
}
unsigned char *pek = NULL;
int peklen = 1024;
fprintf(stderr, "22222222222222\n");
//解密P7结构中的接收者信息
if(pkcs7_decrypt_rinfo(&pek, &peklen, ri, pkey) == 0) {
fprintf(stderr, "pkcs7_decrypt_rinfo fail\n");
return;
}
fprintf(stderr, "111111111111111111\n");
//打印sm4对称密钥
PRINT_HEX("pek", pek, peklen);
//sm4解密获取原文
sms4_key_t dec;
sms4_set_decrypt_key(&dec, pek);
unsigned char out[2048] = {0};
unsigned char prikey[2048] = {0};
int outlen = 0;
memset(out, 0, 1024);
int tmplen = 0;
//获取密文
ASN1_OCTET_STRING *data_body = NULL;
data_body = p7->d.signed_and_enveloped->enc_data->enc_data;
sms4_ecb_encrypt(data_body->data, out, &dec, 0);
for (tmplen=SMS4_BLOCK_SIZE; tmplen<data_body->length; tmplen+=SMS4_BLOCK_SIZE)
sms4_ecb_encrypt(data_body->data+tmplen, out+tmplen, &dec, SMS4_DECRYPT);
//打印原文
PRINT_HEX("un-encpri",out,tmplen);
return;
}
该释放内存的记得释放内存,此处未处理。
通过P7函数接口进行解密(包含验签)
部分代码示例:
//读取P7
BIO *m_out = BIO_new_fp(stdout, BIO_NOCLOSE);
PKCS7_print_ctx(m_out, v_p7, 0, NULL);
//获取P7中的证书
if(OBJ_obj2nid((v_p7)->type) == NID_pkcs7_signedAndEnveloped){
STACK_OF(X509) *cert = v_p7->d.signed_and_enveloped->cert;
X509 *x509_sign = X509_dup(sk_X509_value(cert, 0));
}
//打印证书
X509_print_fp(stdout, x509_sign);
//获取加密证书
BIO *bio = BIO_new_file(cert_file, "r");
X509 *x509_enc = PEM_read_bio_X509(bio, NULL, 0, NULL);
//获取私钥
BIO *key_bio = BIO_new_file(key_file, "r");
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(key_bio, NULL, NULL, "11111111");
//解析出原始数据
//EVP_rc4 无法正常解密,需要额外处理
v_p7bio = PKCS7_dataDecode(v_p7, pkey, NULL, x509_enc);
if (v_p7bio == NULL) {
printf("v_p7bio is null.\n");
return;
}
//获取原文
user_data->len = BIO_ctrl_pending(v_p7bio);
user_data->data = (unsigned char *)malloc(user_data->len);
user_data->len = BIO_read(v_p7bio, user_data->data, user_data->len);
if ((int)user_data->len <= 0) {
if (user_data->data) {
free(user_data->data);
user_data->data = NULL;
}
}
//这一步很重要,不然BIO位置已经发生变化无法正确读取到
int rv = 0;
rv = BIO_reset(v_p7bio);
//获取签名相关信息
STACK_OF(PKCS7_SIGNER_INFO) *signifos;
signifos=PKCS7_get_signer_info(v_p7);
if (signifos == NULL) {
printf("signifos is null.\n");
return;
} else {
ERR_clear_error();
for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(signifos); i++) {
si = sk_PKCS7_SIGNER_INFO_value(signifos, i);
int j = 0;
//验签
j = PKCS7_signatureVerify(v_p7bio, v_p7, si, x509_sign);
if (j <= 0) {
printf("PKCS7 signatures error.\n");
return;
}
}
}
该释放内存的记得释放内存,此处未处理。