PKCS7的数字信封格式分为两种:带签名的数字信封和不带签名的数字信封。由于这个数字信封的生成过程比较复杂,所以这两种格式比较容易记混,导致都搞不清楚一个数字信封里面到底是存储的什么内容了。下面我就详细的解释一下,这两种数字信封的生成过程和其详细的数据结构。
首先是不带签名的数字信封。
不带签名的数字信封内容类型由任意类型的加密内容和加密的一个/多个接收者的内容加密密钥组成,其生成过程如下:
1. 发送方随机产生一个对应于特定加密算法的内容加密密钥。
2. 发送方将内容加密密钥用每个接收者的公钥加密。
3. 对于每一个接收者,把加了密的内容加密密钥和接收者的其他信息放入RecipientInfo值中。
4. 用内容加密密钥加密内容。
5. 将所有接收者的RecipientInfo值和加了密的内容放入EnvelopedData值中。
用ASN.1来描述一下它的结构:
EnvelopedData ::= SEQUENCE {
version Version,
recipientInfos RecipientInfos,
encryptedContentInfo EncryptedContentInfo }
数据结构1
其中RecipientInfos 是一个集合的形式,包含一个或多个,即:
RecipientInfos ::= SET OF RecipientInfo
对于RecipientInfos 它的格式如下(我直接把注释贴的它的后面):
RecipientInfos ::= SEQUENCE {
version Version,语法的版本号
issuerAndSerialNumber IssuerAndSerialNumber, 接收者证书证书序列号
keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,接收者公钥加密加密密钥所用参数
encryptedKey EncryptedKey 内容加密密钥被接收者公钥加密后的结果}
数据结构2
EncryptedContentInfo ::= SEQUENCE {加密的数据
contentType ContentType,指示内容的类型
contentEncryptionAlgorithm 标识内容加密算法
ContentEncryptionAlgorithmIdentifier,
encryptedContent 内容加密的结果
[0] IMPLICIT EncryptedContent OPTIONAL }
数据结构3
发送给接收方后,解包的过程很简单:接收者用自己的私钥解开加密的内容加密密钥,然后用该密钥解密密文内容。整个过程参与非对称运算的只有接收方的密钥对。
带签名的数字信封要比这要复杂的多。
带签名的数字信封由任意类型的加密内容、加了密的一个/多个接收者的内容加密密钥和双重加密的一个/多个签名者的消息摘要。“双重加密”由签名者私钥的加密和内容加密密钥的加密组成。其生成过程如下:
1.发送方随机产生一个对应于特定加密算法的内容加密密钥。
2. 发送方将内容加密密钥用每个接收者的公钥加密。
3. 对于每一个接收者,把加了密的内容加密密钥和接收者的其他信息放入RecipientInfo值中,参见数据结构2。
4. 对于每一个签名者,他用自己的消息摘要算法计算出摘要值 (如果两个签名者使用同样的算法,那么摘要值只需计算一次) 。
5. 对于每一个签名者,消息摘要和相关的信息用自己的私钥加密,结果再用内容加密密钥加密。
6. 对于每一个签名者,把双重加密(即第5步中的先非对称加密,再对称加密的过程)的消息摘要和其他的签名者特定信息放入SignerInfo 值中。
7. 用内容加密密钥加密内容。
8. 把所有签名者的消息摘要算法、所有签名者的SignerInfo值、所有接收者的RecipientInfo值和加了密的内容一起放入SignedAndEnvelopedData 值中。
SignedAndEnvelopedData 的数据结构如下:
SignedAndEnvelopedData ::= SEQUENCE {
version Version, 语法的版本号
recipientInfos RecipientInfos, 接收者信息的集合
digestAlgorithms DigestAlgorithmIdentifiers,消息摘要算法标识符的集合
encryptedContentInfo EncryptedContentInfo, 加了密的内容
certificates
[0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
crls
[1] IMPLICIT CertificateRevocationLists OPTIONAL,
signerInfos SignerInfos }
数据结构4
其中, certificates是 PKCS # 6 扩展证书和 X.509 证书的集合。它表示集合足以包含从可识别的“根”或“顶级 CA ”到 signerInfo 域中所有签名者的证书链。可能有多于必要的证书,并且可能有足够的证书来包含链(从两个或多个独立的顶级 CA )。 也可能有少于必要的证书,比如验证签名有一个替换的方法来获得必要的证书 (e.g., 从一个先前证书集合中)。此属性最终来确定签名者身份。crls是证书撤销列表的集合。它表示集合包含足够的信息来决定certificates域中的证书是否是“hot listed”的,但这不是必须的。 可能有多于必要的crl,也可能有少于必要的crl。
signerInfos是每个签名者信息集合。至少要有一个元素。其每个元素的结构如下:
SignerInfo ::= SEQUENCE {
version Version,
issuerAndSerialNumber IssuerAndSerialNumber,
digestAlgorithm DigestAlgorithmIdentifier,
authenticatedAttributes
[0] IMPLICIT Attributes OPTIONAL,
digestEncryptionAlgorithm
DigestEncryptionAlgorithmIdentifier,
encryptedDigest EncryptedDigest,
unauthenticatedAttributes
[1] IMPLICIT Attributes OPTIONAL }
数据结构5
类型SignerInfo的域有以下意义,基本上是一些配置属性:
· version是指语法的版本号,这一标准中版本应该为1 。
· issuerAndSerialNumber签名证书的证书序列号。
· digestAlgorithm指定对内容和待鉴别属性(若存在的话)进行摘要计算的信息摘要算法(及相应的参数)。
· authenticatedAttributes是经由签名者签名的属性的集合。 该域是可选的,但是当被签名的ContentInfo的content type不是data类型时该域必须存在。如果该域存在,它必须包含至少两个属性:
1. PKCS #9 content-type 属性,当ContentInfo的content type值被签名时。
2. PKCS #9 message-digest 属性,当值是内容的消息摘要时(见下面)。
这里可能有用的其他属性类型如签名时间等也在PKCS#9中定义。
· digestEncryptionAlgorithm标识用签名者私钥加密消息摘要和相关信息的摘要加密算法(和相应的参数)。
· encryptedDigest是用签名者私钥加密消息摘要和相关信息后的结果。
· unauthenticatedAttributes是不被签名者签名的属性的集合。该域是可选的。这里可能有用的属性类型如countersignatures(连署)等在PKCS#9中定义。
其中 EncryptedDigest是一个十六进制字符串,即EncryptedDigest ::= OCTET STRING
接收方接到数字信封后,解封操作会复杂些:1.收方B接受到数字信封DE后,首先用自己的私钥PVB解密数字信封,取出对称密钥SK;
2.收方B用对称密钥SK通过DES算法解密加密信息E,还原出原文信息、数字签名SD及发方A证书的公钥PBA;
3. 收方B验证数字签名,先用发方A的公钥解密数字签名得数字摘要MD;
4.收方B同时将原文信息用同样的哈希运算,求得一个新的数字摘要MD’;
5.将两个数字摘要MD和MD’进行比较,验证原文是否被修改。如果二者相等,说明数据没有被篡改,是保密传输的,签名是真实的;否则拒绝该签名。
以上就是两种数字信封格式的完全解释。
顺便说一下,假设你在程序里拿到了一段数据,无法判断数据格式,可以将这段数据保存为文件,然后用ViewBer(下载地址http://simpleauthority.com/viewber.html)这个工具打开,然后选择查看OBJECT INTEGER选项,会显示当前的数据的oid。
然后去这个地址http://www.alvestrand.no/objectid/top.html查看一下oid的具体相关信息。
具体生成p7文件的VC项目,请到http://download.csdn.net/detail/yunnysunny/4555287 下载。