GO语言-PKCS#7
什么是PKCS7?PKCS7定义一种通用的消息语法,包括数字签名和加密等用于增强的加密机制,PKCS#7与PEM兼容,所以不需其他密码操作,就可以将加密的消息转换成PEM消息。
在使用github的开源go代码对PKCS#7(github.com/tjfoc/gmsm/x509)操作时,发现源码只支持了RSA的操作,ECC椭圆曲线SM2并没有被支持。本人对github的pkcs7.go做了算法扩充,经过和OPENSSL产生的数据混合测试,成功验签和解密!!!
文末附上百度网盘链接。
创建PKCS#7的数字信封
// PKCS#7加密,指定对称算法
func PKCS7EncryptWithSymAlg(content []byte, recipients []*x509.Certificate, encAlg byte) ([]byte, error) {
return pkcs7Encrypt(content, recipients, encAlg)
}
// PKCS#7加密,对称算法由证书类型决定
func PKCS7Encrypt(content []byte, recipients []*x509.Certificate) ([]byte, error) {
if recipients == nil || len(recipients) == 0 {
return nil, errors.New("pkcs7: no certs")
}
cert := recipients[0]
switch cert.PublicKey.(type) {
case *sm2.PublicKey:
return pkcs7Encrypt(content, recipients, EncryptionAlgorithmSM4CBC)
case *rsa.PublicKey:
return pkcs7Encrypt(content, recipients, EncryptionAlgorithm3DESCBC)
default:
return nil, errors.New("pkcs7: error cert type")
}
}
解密PKCS#7数字信封
// Decrypt decrypts encrypted content info for recipient cert and private key
func (p7 *PKCS7) Decrypt(cert *x509.Certificate, pk crypto.PrivateKey) ([]byte, error) {
var err error
var contentKey []byte
data, ok := p7.raw.(envelopedData)
if !ok {
return nil, ErrNotEncryptedContent
}
recipient := selectRecipientForCertificate(data.RecipientInfos, cert)
if recipient.EncryptedKey == nil {
return nil, errors.New("pkcs7: no enveloped recipient for provided certificate")
}
switch pk.(type) {
case *rsa.PrivateKey:
pkey := pk.(*rsa.PrivateKey)
contentKey, err = rsa.DecryptPKCS1v15(rand.Reader, pkey, recipient.EncryptedKey)
if err != nil {
return nil, err
}
return data.EncryptedContentInfo.decrypt(contentKey)
case *sm2.PrivateKey:
pkey := pk.(*sm2.PrivateKey)
contentKey, err = sm2.DecryptAsn1(pkey, recipient.EncryptedKey)
if err != nil {
return nil, err
}
return data.EncryptedContentInfo.decrypt(contentKey)
}
fmt.Printf("Unsupported Private Key: %v\n", pk)
// TODO: SM decript
return nil, ErrPKCS7UnsupportedAlgorithm
}
解析PKCS7的数据:
func ParsePKCS7(data []byte) (p7 *PKCS7, err error) {
if len(data) == 0 {
return nil, errors.New("pkcs7: input data is empty")
}
var info contentInfo
der, err := ber2der(data)
if err != nil {
return nil, err
}
rest, err := asn1.Unmarshal(der, &info)
if len(rest) > 0 {
err = asn1.SyntaxError{Msg: "trailing data"}
return
}
if err != nil {
return
}
switch {
case info.ContentType.Equal(oidSignedData):
return parseSignedData(info.Content.Bytes)
case info.ContentType.Equal(oidSMSignedData):
return parseSignedData(info.Content.Bytes)
case info.ContentType.Equal(oidEnvelopedData):
return parseEnvelopedData(info.Content.Bytes)
case info.ContentType.Equal(oidSm2EnvelopedData):
return parseEnvelopedData(info.Content.Bytes)
}
return nil, ErrUnsupportedContentType
}
创建PKCS7的数据结构并签名
SignedData, err := NewSignedData(data, hash)
if err != nil {
return
}
var attr1 = make([]byte, 24)
copy(attr1, "helloBjCa")
var attr2 = make([]byte, 24)
copy(attr2, "helloBjCa")
var attrs1 = x509.SignerInfoConfig{
ExtraSignedAttributes : []x509.Attribute{
{
Type: asn1.ObjectIdentifier{2, 3, 4, 5, 6, 7, 8},
Value: attr1,
},
},
}
var attrs2 = x509.SignerInfoConfig{
ExtraSignedAttributes : []x509.Attribute{
{
Type: asn1.ObjectIdentifier{1, 1, 1, 1, 1, 1, 1},
Value: attr2,
},
},
}
if attrWith {
err = SignedData.AddSigner(cert, pkey, attrs1)
if err != nil {
return
}
err = SignedData.AddSigner(cert, pkey, attrs2)
if err != nil {
return
}
}
err = SignedData.DoSign(cert, pkey)
if err != nil {
return
}
if !dataWith{
SignedData.Detach()
}
p7SignData, err := SignedData.Finish()
链接: https://pan.baidu.com/s/11RZw6P0M4pjRxkYV086aeg
提取码: pc1v