Golang-PKCS7

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 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜡笔小新1849

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值