OPENSSL-PKCS7入门知识介绍

news2025/1/15 22:34:18
1 PKCS7数据结构说明

p7包括6种数据内容:数据(data),签名数据(sign),数字信封数据(enveloped),签名数字信封数据(signed_and_enveloped),摘要数据(digest),加密数据(encrypted)。

数据(data):明文打包
type为NID_pkcs7_data,ASN1_OCTET_STRING类型,即为简单的ASN1_STRING数据类型。


签名数据(sign):把数据以及签名值打包,其中包括签名者的证书,CRL等,目的为确定发送者的身份。
type为NID_pkcs7_signed。PKCS7_SIGNED类型的数据,PKCS7_SIGNED定义如下:
typedef struct pkcs7_signed_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; 签名信息
struct pkcs7_st *contents;
} PKCS7_SIGNED;

数字信封数据(enveloped):使用接收者的公钥(从证书获取)加密数据。目的为保护数据,拥有私钥的接收者才能解开数据。
type为NID_pkcs7_enveloped。PKCS7_ENVELOPE类型的数据,PKCS7_ENVELOPE定义如下
typedef struct pkcs7_enveloped_st
{
ASN1_INTEGER *version; /* version 0 */
STACK_OF(PKCS7_RECIP_INFO) *recipientinfo;       //接收者的信息(可能存在多个)
PKCS7_ENC_CONTENT *enc_data;                          //用接收者公钥加密的信息
} PKCS7_ENVELOPE;

typedef struct pkcs7_recip_info_st {

    ASN1_INTEGER *version;      /* version 0 */

    PKCS7_ISSUER_AND_SERIAL *issuer_and_serial;   // 证书序列号

    X509_ALGOR *key_enc_algor;                                  //加密算法对象标识

    ASN1_OCTET_STRING *enc_key;                           //加密的报文秘钥

    X509 *cert;                                                            /* get the pub-key from this */

    const PKCS7_CTX *ctx;

} PKCS7_RECIP_INFO;

typedef struct pkcs7_enc_content_st {

    ASN1_OBJECT *content_type;

    X509_ALGOR *algorithm;                                      //加密算法

    ASN1_OCTET_STRING *enc_data; /* [ 0 ] */        // 加密内容信息

    const EVP_CIPHER *cipher;

    const PKCS7_CTX *ctx;

} PKCS7_ENC_CONTENT;


签名数字信封数据(signed_and_enveloped)
数字信封加签名
type为NID_pkcs7_signedAndEnveloped。

PKCS7_SIGN_ENVELOPE定义如下
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;


加密数据(encrypted)
使用对称算法加密数据。
type为NID_pkcs7_encrypted。PKCS7_ENCRYPT类型的数据,PKCS7_ENCRYPT定义如下
typedef struct pkcs7_encrypted_st
{
ASN1_INTEGER *version; /* version 0 */
PKCS7_ENC_CONTENT *enc_data;
} PKCS7_ENCRYPT;

2 pkcs7内容类型的编码解码
2.1pkcs7-data内容类型的编码解码

:Data内容类型旨在表示任意的字节串,比如ASCII文本文件;其翻译留给应用。这样的串无需任何内部的结构.
Data ::= OCTET STRING
pkcs7的类型为NID_pkcs7_data,
d为ASN1_OCTET_STRING *data;

一:对data内容进行编码
1.  新建一个PKCS7结构体。
p7 = PKCS7_new();
2.  设置p7结构体的类型为NID_pkcs7_data
PKCS7_set_type(p7,NID_pkcs7_data);
3.设置原文到ASN1_OCTET_STRING *data;
M_ASN1_OCTET_STRING_set(p7->d.data,src,srcLen);
4.   转换pkcs7结构体为der编码
derLen = i2d_PKCS7(p7,&tmpder);
i2d_PKCS7的返回值为der编码的长度。第二个参数为der编码输出。
注意:openssl输出后会更改tmpder的指针,故使用时应该用临时指针。比如欲输出der编码内容到变量der中。
代码应如下:
unsigned char *der = NULL;
unsigned char *dertmp = NULL;
unsigned long derLen;
derLen = i2d_PKCS7(p7,NULL);
der = malloc(derLen);
dertmp = der;
derLen = i2d_PKCS7(p7,&dertmp);
...
free(der);
二:对data内容p7数据包进行解码
解码的过程和编码相反。
1。转换der编码为pkcs7结构体
p7 =d2i_PKCS7 (NULL,dertmp,derLen)
2。检查p7 type是否是NID_pkcs7_data
if(OBJ_obj2nid(p7->type) != NID_pkcs7_data)  //数据类型是否为pkcs7_data
3。取出源数据
srcLen = p7->d.data->length;
memcpy(src,p7->d.data->data,srcLen);
2.2pkcs7- signed-data内容类型的编码解码

PKCS7_SIGNED 在openssl中的定义如下:
typedef struct pkcs7_signed_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;
struct pkcs7_st *contents;
} PKCS7_SIGNED;
signed内容类型由任意类型的内容和数字签名组成。任何类型的内容能够同时被任意数量的签名者签名。
签名数据的产生过程有如下几步:
1. 对于每一个签名者,他用消息摘要算法计算出摘要值 。
2. 对于每一个签名者,消息摘要和相关的信息用自己(发送方)的私钥加密。
3. 对于每一个签名者,把加密的消息摘要和其他的签名者特定信息放入signer_info值中。每个 签名者的证书、crl等也在这一步被收集进来。
4. 把所有签名者的信息摘要算法、他们的signer_info值和内容一起放进sign值中。

调用openssl的代码如下:
PKCS7* p7 = PKCS7_new();
PKCS7_set_type(p7, NID_pkcs7_signed);//设置类型为NID_pkcs7_signed
PKCS7_content_new(p7, NID_pkcs7_data);
PKCS7_set_detached(p7, 0);
//添加签名者信息,
//x509:签名证书,pkey:签名者私钥。EVP_sha1()签名者摘要算法。
PKCS7_SIGNER_INFO* info = PKCS7_add_signature(p7, x509, pkey, EVP_sha1());
//添加签名者证书
PKCS7_add_certificate(p7, x509);
//添加签名者的CA证书链
for (int i=0; i<sk_X509_num(ca); i++)
{
  PKCS7_add_certificate(p7, sk_X509_value(ca, i));
}
BIO* p7bio = PKCS7_dataInit(p7, NULL);
BIO_write(p7bio, "How are you!", strlen("How are you!"));//加入原始数据,
PKCS7_dataFinal(p7, p7bio); //处理数据。
//转换为der编码输出
i2d_PKCS7(p7,&dertmp);
PKCS7_free(p7);
BIO_free(p7bio);
解析P7签名的代码:
//der编码转换为PKCS7结构体
PKCS7 * p7 =d2i_PKCS7(NULL,dertmp,derLen)
//解析出原始数据
BIO *p7bio= PKCS7_dataDecode(p7,NULL,NULL,NULL);
//从BIO中读取原始数据,将得到"How are you!"
srcLen = BIO_read(p7bio,src,1024);
//获得签名者信息stack
STACK_OF(PKCS7_SIGNER_INFO) *sk = PKCS7_get_signer_info(p7);
//获得签名者个数(本例只有1个)
int signCount = sk_PKCS7_SIGNER_INFO_num(sk );
for(int i=0;i
{
//获得签名者信息
PKCS7_SIGNER_INFO *signInfo = sk_PKCS7_SIGNER_INFO_value(sk,i);
//获得签名者证书
X509 *cert= PKCS7_cert_from_signer_info(p7,signInfo);
//验证签名
if(PKCS7_signatureVerify(p7bio,p7,signInfo,cert) != 1)
{
    printf("signatureVerify Err\n");
}
}
2.3pkcs7-Enveloped-data内容类型的编码解码

PKCS7_ENVELOPE. enveloped在openssl中的定义如下:
typedef struct pkcs7_enveloped_st
{
ASN1_INTEGER             *version;     /* version 0 */
STACK_OF(PKCS7_RECIP_INFO)   *recipientinfo;
PKCS7_ENC_CONTENT         *enc_data;
} PKCS7_ENVELOPE;
enveloped-data内容类型由任意类型的加密内容和加密的一个/多个接收者的内容加密密钥组成。内容的密文和加密密钥一起构成了接收者的“数字信封”。任意类型的内容能够同时为任意数量的接收者进行封装。
Enveloped-data的组建过程分以下几步:
1.       随机产生一个对称密钥用于加密内容。
2.       内容加密密钥用每个接收者的公钥加密。
3.       对于每一个接收者,把内容加密密钥的密文和接收者的其他信息放入recipientinfo值中。
4.       用加密密钥加密内容。
5.       将所有接收者的recipientinfo值和加了密的内容放入EnvelopedData值中
接收者用自己的私钥解开内容加密密钥,然后用该密钥解密密文内容。
调用openssl的代码如下:
 

 PKCS7* p7 = PKCS7_new();
  //设置类型为NID_pkcs7_enveloped
PKCS7_set_type(p7, NID_pkcs7_enveloped);
//DES算法,用于加密内容“How are you!”
EVP_CIPHER *evp_cipher = EVP_des_cbc();
PKCS7_set_cipher(p7,cipher);
//设置接收者证书,获取公钥用于加密对称密钥
PKCS7_RECIP_INFO *p7recipinfo = PKCS7_add_recipient(p7,x509_Cert);
BIO *p7bio = PKCS7_dataInit(p7, NULL);
BIO_write(p7bio,”How Are You!”,strlen(“How Are You!”));
//完成数字信封的运算
PKCS7_dataFinal(p7, p7bio);
//转换PKCS7结构体为DER编码
derLen = i2d_PKCS7(p7,&derTmp);
BIO_free(p7bio);
PKCS7_free(p7);    
   
解P7数字信封的代码:
//der编码转换为PKCS7结构体
PKCS7* p7 = d2i_PKCS7(NULL,&derTmp,DataLen);
//解析出原始数据, evp_key:接收者私钥,x509_cert:接收者证书
BIO * p7bio = PKCS7_dataDecode(p7,evp_key,NULL,x509_cert);
//从BIO中读取原始数据,将得到"How are you!"
srcLen = BIO_read(p7bio,src,4096);
BIO_free(p7bio);
PKCS7_free(p7);
2.4pkcs7-Signed-and-enveloped-data内容类型的编码解码


PKCS7_SIGN_ENVELOPE *signed_and_enveloped在openssl中的定义如下:
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;
signed-and-enveloped-data内容类型由任意类型的加密内容、加了密的一个/多个接收者的内容加密密钥和双重加密的一个/多个签名者的消息摘要。“双重加密”由签名者私钥的加密和内容加密密钥的加密组成。
加了密的内容和加了密的内容加密密钥一起构成了接收者的“数字信封”。恢复的签名者单个加密的消息摘要是恢复的签名者内容的“数字签名”。任意类型的内容能够同时为任意数量的接收者进行封装和被任意数量的签名者进行签名。
signed-and-enveloped data的组建过程包括以下几步:
1. 随机产生一个对应于特定加密算法的内容加密密钥,比如des算法的8字节密钥。
2. 内容加密密钥用每个接收者的公钥加密。
3. 对于每一个接收者,把加了密的内容加密密钥和接收者的其他信息放入recipientinfo值中。
4. 对于每一个签名者,他用自己的消息摘要算法计算出摘要值 (如果两个签名者使用同样的算法,那么摘要值只需计算一次)。
5. 对于每一个签名者,消息摘要和相关的信息用自己的私钥加密(即签名),结果再用内容加密密钥加密。
6. 对于每一个签名者,把双重加密的消息摘要和其他的签名者特定信息放入signer_info值中。
7. 用内容加密密钥加密内容。
8. 把所有签名者的消息摘要算法、所有签名者的signer_info值、所有接收者的recipientinfo值和加了密的内容一起放入PKCS7_SIGN_ENVELOPE值中
接收者打开信封并验证签名分两步:
1. 加了密的内容加密密钥用接收者的私钥解开,并用内容加密密钥解开加密的内容。
2. 每个签名者双重加密的消息摘要用恢复的内容加密密钥解开,结果再用签名者公钥解密,恢复的消息摘要再和独立计算的消息摘要进行比较。
调用openssl的代码如下:

PKCS7* p7 = PKCS7_new();
  //设置类型为NID_pkcs7_signedAndEnveloped
    PKCS7_set_type(p7, NID_pkcs7_signedAndEnveloped);
    //DES算法,用于加密内容“How are you!”
    EVP_CIPHER *evp_cipher = EVP_des_cbc();
    PKCS7_set_cipher(p7,cipher);
//设置接收者证书,获取公钥用于加密对称密钥
    PKCS7_RECIP_INFO *p7recipinfo = PKCS7_add_recipient(p7, x509_RecCert);
    //x509:签名证书,pkey:签名者私钥。EVP_sha1()签名者摘要算法。
PKCS7_SIGNER_INFO* info = PKCS7_add_signature(p7, x509, pkey, EVP_sha1());
//添加签名者证书
PKCS7_add_certificate(p7, x509t);
//添加签名者的CA证书链
for (int i=0; i<sk_X509_num(ca); i++)
{
  PKCS7_add_certificate(p7, sk_X509_value(ca, i));
}
    BIO *p7bio = PKCS7_dataInit(p7, NULL);
    BIO_write(p7bio,”How Are You!”,strlen(“How Are You!”));
    //完成签名&数字信封的运算
    PKCS7_dataFinal(p7, p7bio);
    //转换PKCS7结构体为DER编码
    derLen = i2d_PKCS7(p7,&derTmp);
    BIO_free(p7bio);
    PKCS7_free(p7);  
3 PKCS7常量

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1470727.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中海油、中石化、中石油校招历年真题和题库

中海油、中石化、中石油是中国领先的石油和天然气公司&#xff0c;拥有雄厚的实力和丰富的资源&#xff0c;是许多求职者梦寐以求的就业机会。为了帮助应聘者更好地备战这三家公司的校园招聘&#xff0c;我特别整理了三套精心准备的校招试题资料&#xff0c;涵盖了各个领域的知…

ARM Cortex-X5 传言表现不佳,高功率浪涌和低多核分数影响即将推出的核心设计

ARM 的新 Cortex-X5 设计似乎遇到了问题&#xff0c;有新的传言称&#xff0c;超级核心在提高时钟速度时会经历严重的高功耗&#xff0c;并且当最大功率限制降低时&#xff0c;多核性能会下降。虽然这对高通来说可能不是问题&#xff0c;因为据说其 Snapdragon 8 Gen 4 采用定制…

uni-app vue3 setup nvue中webview层级覆盖问题

核心就是这两行&#xff0c;&#x1f923;发现设置后不能点击了&#xff0c;这个玩意可能只能弹窗打开的时候动态的修改 position: static, zindex: 0onLoad(options > {loadWebview()})function loadWebview() {let pageInfo uni.getSystemInfoSync();width.value pageI…

静态时序分析:SDC约束命令set_load详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 set_load命令用于指定端口(port)或线网(net)的负载电容&#xff0c;该指令的BNF范式&#xff08;有关BNF范式&#xff0c;可以参考以往文章&#xff09;为&#…

Kafka之Consumer源码

Consumer源码解读 Consumer初始化 从KafkaConsumer的构造方法出发&#xff0c;我们跟踪到核心实现方法 这个方法的前面代码部分都是一些配置&#xff0c;我们分析源码要抓核心&#xff0c;我把核心代码给摘出来 NetworkClient Consumer与Broker的核心通讯组件 ConsumerCoord…

【数据结构】周末作业

1.new(struct list_head*)malloc(sizeof(struct list_head*)); if(newNULL) { printf("失败\n"); return; } new->nextprev->next; prev->nextnew; return; 2.struct list_head* pprev->next; prev->nextp->next; p->next->prevpr…

[AutoSar]BSW_Com03 DBC详解 (二)

目录 关键词平台说明一、前言二、DBC Attributes2.1 添加方法2.2 GenMsgCycleTime2.3 GenMsgSendType2.4 GenSigStartValue 三、DBC Attributes 对照表 关键词 嵌入式、C语言、autosar、OS、BSW 平台说明 项目ValueOSautosar OSautosar厂商vector &#xff0c;芯片厂商TI 英…

通俗易懂理解EfficicentNet系列网络模型

一、参考资料 原始论文&#xff1a;[1] github代码&#xff1a;efficientnet EfficientNet系列(1): EfficientNetV2网络详解 EfficientNet网络详解 二、EfficientNet相关介绍 在之前的文章中&#xff0c;单独增加图像分辨率或增加网络深度或单独增加网络的宽度&#xff0…

matlab滤波器设计

1、内容简介 略 51-可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 matlab滤波器设计-butter、ellip、cheby1、cheby2_哔哩哔哩_bilibili 4、参考论文 略

自动驾驶---行业发展及就业环境杂谈

进入21世纪以来&#xff0c;自动驾驶行业有着飞速的发展&#xff0c;自动驾驶技术&#xff08;L2---L3&#xff09;也逐渐落地量产到寻常百姓家。虽然最早期量产FSD的特斯拉有着深厚的技术积累&#xff0c;但是进入2010年以后&#xff0c;国内的公司也逐渐发展起来自己的自动驾…

CSS 的盒模型

CSS 的盒模型 在HTML里&#xff0c;每一个元素就相当于是一个矩形的 “盒子” &#xff0c;这个盒子由以下这几个部分构成&#xff1a;1.边框border&#xff0c;2.内容content&#xff0c;3.内边距padding&#xff0c;4.外边距margin 边框border 基础属性描述border-width粗…

基于容器和集群技术的数据自动化采集设计和实现

目标&#xff1a;部署mysql服务容器并使用docker构建包含python爬虫脚本的容器采集数据到mysql数据库。 环境&#xff1a;Centos7、已配置Kubernetes集群及docker。 环境配置请参考以下文章&#xff1a; CentOS7搭建Kubernetes集群 Kubernetes集群信息如下(虚拟机主机名和IP…

apache 模式、优化、功能 与 nginx优化、应用

一、I/O模型——Input/Output模型 1.同步/异步 A程序需要调用B程序的某一个功能&#xff0c;A发送一个请求需要B完成一个任务 同步&#xff1a;B不会主动去通知A是否完成需要A自己去问 异步&#xff1a;B会主动通知A是否完成 2.阻塞/非阻塞 A发送一个请求需要B完成一个任务 …

【大数据】Flink SQL 语法篇(四):Group 聚合

Flink SQL 语法篇&#xff08;四&#xff09;&#xff1a;Group 聚合 1.基础概念2.窗口聚合和 Group 聚合3.SQL 语义4.Group 聚合支持 Grouping sets、Rollup、Cube 1.基础概念 Group 聚合定义&#xff08;支持 Batch / Streaming 任务&#xff09;&#xff1a;Flink 也支持 G…

Python及Pycharm专业版下载安装教程(Python 3.11版)附JetBrains学生认证教程

目录 一、Python下载及安装1、Python下载2、Python安装3、验证是否安装成功 二、PyCharm下载及安装1、PyCharm下载2、PyCharm安装3、激活PyCharm 三、JetBrains学生认证 本篇主要介绍Python和PyCharm专业版的下载及安装方式&#xff0c;以及通过两种方式进行JetBrains学生认证。…

第十篇【传奇开心果系列】Python的文本和语音相互转换库技术点案例示例:Microsoft Azure开发语音翻译应用程序经典案例

传奇开心果博文系列 系列博文目录Python的文本和语音相互转换库技术点案例示例系列 博文目录前言一、雏形示例代码二、扩展思路介绍三、Azure多语种支持示例代码四、Azure实时对话模式示例代码五、Azure自定义翻译模型示例代码六、Azure语音合成示例代码七、Azure用户界面优化示…

openGauss学习笔记-229 openGauss性能调优-系统调优-配置Ustore

文章目录 openGauss学习笔记-229 openGauss性能调优-系统调优-配置Ustore229.1 设计原理229.2 核心优势229.3 使用指导 openGauss学习笔记-229 openGauss性能调优-系统调优-配置Ustore Ustore存储引擎&#xff0c;又名In-place Update存储引擎&#xff08;原地更新&#xff09…

java面试(网络)

TCP和UDP有什么区别&#xff1f;TCP三次握手不是两次&#xff1f; TCP&#xff1a;面向连接&#xff0c;可靠的&#xff0c;传输层通信协议。点对点&#xff0c;占用资源多&#xff0c;效率低。 UDP&#xff1a;无连接&#xff0c;不可靠&#xff0c;传输层通信协议。广播&…

Nvidia Jetson Orin NX配置环境

Nvidia Jetson Orin NX配置环境配置环境 一、安装jetson5.1.2二、安装jtop三、配置CUDA和cuDNN四、安装Pytorch 先导片&#xff1a;Jetson采用arm64架构 一、安装jetson5.1.2 安装好jetson自带cuda、cudnn和tensorRT 官方文档 更换源 sudo vi /etc/apt/sources.list.d/nvidia…

力扣技巧题:丢失的数字

先排后找可以让结果更简单 int cmp(const void* a, const void* b){return *(int*)a - *(int*)b; } int missingNumber(int* nums, int numsSize){qsort(nums, numsSize, 4, cmp);for(int i0; i<numsSize; i){if(nums[i] i){continue;}else{return i;}}return numsSize; }…