OPENSSL-PKCS7入门知识介绍

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_signedAndEnvelopedPKCS7_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.rhkb.cn/news/265122.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【kubernetes】关于k8s集群中kubectl的陈述式资源管理

目录 一、k8s集群资源管理方式分类&#xff1a; &#xff08;1&#xff09;陈述式资源管理方式&#xff1a;增删查比较方便&#xff0c;但是改非常不方便 &#xff08;2&#xff09;声明式资源管理方式&#xff1a;yaml文件管理 二、陈述式资源管理方法&#xff1a; 三、ku…

重学Java 18.学生管理系统项目

臣无祖母&#xff0c;无以至今日&#xff0c;祖母无臣&#xff0c;无以终余年 母孙二人&#xff0c;更相为命&#xff0c;是以区区不能废远 —— 陈情表.李密 —— 24.2.20 一、编写JavaBean public class Student {//学号private int id;//姓名private String name;//年龄pr…

【C++精简版回顾】12.友元函数

1.友元函数 1.class class MM { public:MM(int age,string name):age(age),name(name){}friend void print(MM mm); private:int age;string name;void print() {cout << age << "岁的" << name << "喜欢你" << endl;} }; f…

用html编写的小广告板

用html编写的小广告板 相关代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</tit…

【洛谷 P8780】[蓝桥杯 2022 省 B] 刷题统计 题解(贪心算法+模拟+四则运算)

[蓝桥杯 2022 省 B] 刷题统计 题目描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 a a a 道题目&#xff0c;周六和周日每天做 b b b 道题目。请你帮小明计算&#xff0c;按照计划他将在第几天实现做题数大于等于 n n n 题? 输入格式 输入一…

可视化图文报表

Apache Echarts介绍 Apache Echarts是一款基于Javascript的数据可视化图表库&#xff0c;提供直观&#xff0c;生动&#xff0c;可交互&#xff0c;可个性化定制的数据可视化图表。 官网&#xff1a;Apache ECharts 入门案例&#xff1a; <!DOCTYPE html> <html>…

Springboot+vue图书管理系统(小白)

图书管理系统 简介&#xff1a;一个最简约的图书管理系统&#xff0c;适用于小白用来练手 前端&#xff1a;VueElementUIechars 后端&#xff1a;SpringbootMybatisMySQL 功能模块&#xff1a; 信息管理&#xff1a;公告信息 操作日志 用户管理&#xff1a;用户信息 图书…

快速搭建宠物医院服务小程序的步骤,无需编程经验

如果你是一家宠物医院或者宠物服务机构&#xff0c;想要拥有一款方便用户预约、查询信息的小程序&#xff0c;那么乔拓云网提供的轻应用小程序是你的不二选择。下面将为你详细介绍如何轻松打造宠物医院服务小程序。 1. 进入乔拓云网后台&#xff0c;点击【轻应用小程序】中的【…

Three.js-05坐标轴AxesHelper

1.构建对象 说明&#xff1a;参数一表示坐标轴的长度。红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴. const axesHelper new THREE.AxesHelper( 1 ); 2.设置位置 axesHelper.position.y1 axesHelper.position.x1 axesHelper.position.z1 3. 网格 说明&#xff1a;立方体…

Python爬虫-爬取B站番剧封面

本文是本人最近学习Python爬虫所做的小练习。如有侵权&#xff0c;请联系删除。 页面获取url 代码 import requests import os import re# 创建文件夹 path os.getcwd() /images if not os.path.exists(path):os.mkdir(path)# 当前页数 page 1 # 总页数 total_page 2# 自动…

MySQL:开始深入其数据(一)DML

在上一章初识MySQL了解了如何定义数据库和数据表&#xff08;DDL&#xff09;&#xff0c;接下来我们开始开始深入其数据,对其数据进行访问&#xff08;DAL&#xff09;、查询DQL&#xff08;&#xff09;和操作(DML)等。 通过DML语句操作管理数据库数据 DML (数据操作语言) …

2/22作业

1.按位置插入 void insert_pos(seq_p L,datetype value,int pos) { if(LNULL) { printf("入参为空\n"); return; } if(seq_full(L)) { printf("表已满\n"); return; } if(pos>L->len|…

学生成绩管理系统

用单链表数据结构完成c的学生成绩管理系统&#xff0c;此系统的具体功能如下&#xff1a; 本人小萌新一个&#xff0c;遇到BUG是正常现象。并且类与对象写的不太理想。- 写了一个Database存放所有数据&#xff0c;但这肯定浪费资源&#xff0c;你们看着改改吧。 class DataBase…

SpringCloud Alibaba 2022之Nacos学习

SpringCloud Alibaba 2022使用 SpringCloud Alibaba 2022需要Spring Boot 3.0以上的版本&#xff0c;同时JDK需要是17及以上的版本。具体的可以看官网的说明。 Spring Cloud Alibaba版本说明 环境搭建 这里搭建的是一个聚合项目。项目结构如下&#xff1a; 父项目的pom.xm…

矩阵的范数 matrix norm Frobenius norm 弗罗贝尼乌斯 范数

1&#xff0c;矩阵范数的定义 矩阵的范数&#xff0c;matrix norm即矩阵的模&#xff1b;它把一个矩阵空间变成为赋范线性空间&#xff1b; 从一个矩阵空间映射到非负实数的函数 满足以下条件&#xff1a; 1&#xff0c;严格的正定性。对于 , 则 ; and if , must ; 2&…

Vue3前端实现一个本地消息队列(MQ), 让消息延迟消费或者做缓存

MQ功能实现的具体代码(TsMQ.ts)&#xff1a; import { v4 as uuidx } from uuid;import emitter from /utils/mitt// 消息类 class Message {// 过期时间&#xff0c;0表示马上就消费exp: number;// 消费标识&#xff0c;避免重复消费tag : string;// 消息体body : any;constr…

大语言模型推理加速技术:模型压缩篇

原文&#xff1a;大语言模型推理加速技术&#xff1a;模型压缩篇 - 知乎 目录 简介 量化(Quantization) LLM.int8() GPTQ SmoothQuant AWQ 精简Attention 共享Attention参数 Multi-Query Attention Grouped-Query Attention 稀疏Attention Sliding Window Attenti…

uniapp的微信小程序授权头像昵称(最新版)

前面我出过两期博客关于小程序授权登录,利用php实现一个简单的小程序授权登录并存储授权用户信息到数据库的完整流程。无奈&#xff0c;小程序官方又整幺蛾子了。wx.getUserInfo接口收回&#xff0c;wx.getUserProfile接口也不让用。导致我的个人小程序&#xff1a;梦缘 的授权…

ESP32语音转文字齐护百度在线语音识别

一、导入(10分钟&#xff09; 学习目的 二、新授(70分钟) 1.预展示结果(5分钟) 2.本节课所用的软硬件(5分钟) 4.图形化块介绍(10分钟) 5.单个模块的简单使用(10分钟) 6.在线语音转换工具逻辑分析(10分钟) 7.在线语音转换工具分步实现(30分钟) 三、巩固练习(5分钟) 四、课堂小结…

transformer--输入(位置编码)

原理参考这篇文章&#xff0c; 这里是原始文章 import torch.nn as nn import torch import math from torch.autograd import Variable# 词嵌入 class Embeddings(nn.Module):# dim:词嵌入的维度&#xff0c;vocab:词表的大小def __init__(self, dim, vocab) -> None:supe…