PKCS7带签名的数字信封

结构体和示例说明

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;
			}
		}
	}

该释放内存的记得释放内存,此处未处理。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值