mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-28 05:06:18 +08:00
pkcs7: polish, improve maintainability
This commit is contained in:
parent
dc66ca673e
commit
9382886282
@ -24,6 +24,12 @@ SM2既然是椭圆曲线公钥密码算法,它就和NIST P系列椭圆曲线
|
|||||||
**注**:最新的阿里KMS支持ECIES,难道客户有这个需求?
|
**注**:最新的阿里KMS支持ECIES,难道客户有这个需求?
|
||||||
ECIES_DH_SHA_1_XOR_HMAC:遵循[SEC 1: Elliptic Curve Cryptography, Version 2.0](https://www.secg.org/sec1-v2.pdf)标准,密钥协商算法采用ECDH,密钥派生算法采用 KDF2 with SHA-1,MAC算法采用HMAC-SHA-1,对称加密算法采用XOR。
|
ECIES_DH_SHA_1_XOR_HMAC:遵循[SEC 1: Elliptic Curve Cryptography, Version 2.0](https://www.secg.org/sec1-v2.pdf)标准,密钥协商算法采用ECDH,密钥派生算法采用 KDF2 with SHA-1,MAC算法采用HMAC-SHA-1,对称加密算法采用XOR。
|
||||||
|
|
||||||
|
**业界对RSA非对称加密的安全性担忧与日俱增**:
|
||||||
|
* [The Marvin Attack](https://people.redhat.com/~hkario/marvin/)
|
||||||
|
* [CVE-2023-45287 Detail](https://nvd.nist.gov/vuln/detail/CVE-2023-45287)
|
||||||
|
* [Vulnerability Report: GO-2023-2375](https://pkg.go.dev/vuln/GO-2023-2375)
|
||||||
|
* [Seriously, stop using RSA](https://blog.trailofbits.com/2019/07/08/fuck-rsa/)
|
||||||
|
|
||||||
## SM2公私钥对
|
## SM2公私钥对
|
||||||
SM2公私钥对的话,要么是自己产生,要么是别的系统产生后通过某种方式传输给您的。
|
SM2公私钥对的话,要么是自己产生,要么是别的系统产生后通过某种方式传输给您的。
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ func (c *cbcBlockCipher) Encrypt(key, plaintext []byte) (*pkix.AlgorithmIdentifi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
ciphertext, err := cbcEncrypt(block, key, iv, plaintext)
|
ciphertext, err := cbcEncrypt(block, iv, plaintext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -144,10 +144,10 @@ func (c *cbcBlockCipher) Decrypt(key []byte, parameters *asn1.RawValue, encrypte
|
|||||||
return nil, errors.New("pkcs: invalid cipher parameters")
|
return nil, errors.New("pkcs: invalid cipher parameters")
|
||||||
}
|
}
|
||||||
|
|
||||||
return cbcDecrypt(block, key, iv, encryptedKey)
|
return cbcDecrypt(block, iv, encryptedKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cbcEncrypt(block cipher.Block, key, iv, plaintext []byte) ([]byte, error) {
|
func cbcEncrypt(block cipher.Block, iv, plaintext []byte) ([]byte, error) {
|
||||||
mode := cipher.NewCBCEncrypter(block, iv)
|
mode := cipher.NewCBCEncrypter(block, iv)
|
||||||
pkcs7 := padding.NewPKCS7Padding(uint(block.BlockSize()))
|
pkcs7 := padding.NewPKCS7Padding(uint(block.BlockSize()))
|
||||||
plainText := pkcs7.Pad(plaintext)
|
plainText := pkcs7.Pad(plaintext)
|
||||||
@ -156,7 +156,7 @@ func cbcEncrypt(block cipher.Block, key, iv, plaintext []byte) ([]byte, error) {
|
|||||||
return ciphertext, nil
|
return ciphertext, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cbcDecrypt(block cipher.Block, key, iv, ciphertext []byte) ([]byte, error) {
|
func cbcDecrypt(block cipher.Block, iv, ciphertext []byte) ([]byte, error) {
|
||||||
mode := cipher.NewCBCDecrypter(block, iv)
|
mode := cipher.NewCBCDecrypter(block, iv)
|
||||||
pkcs7 := padding.NewPKCS7Padding(uint(block.BlockSize()))
|
pkcs7 := padding.NewPKCS7Padding(uint(block.BlockSize()))
|
||||||
plaintext := make([]byte, len(ciphertext))
|
plaintext := make([]byte, len(ciphertext))
|
||||||
|
199
pkcs7/encrypt.go
199
pkcs7/encrypt.go
@ -1,187 +1,35 @@
|
|||||||
package pkcs7
|
package pkcs7
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/x509/pkix"
|
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/emmansun/gmsm/pkcs"
|
"github.com/emmansun/gmsm/pkcs"
|
||||||
"github.com/emmansun/gmsm/sm2"
|
|
||||||
"github.com/emmansun/gmsm/smx509"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type envelopedData struct {
|
|
||||||
Version int
|
|
||||||
RecipientInfos []recipientInfo `asn1:"set"`
|
|
||||||
EncryptedContentInfo encryptedContentInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
type encryptedData struct {
|
type encryptedData struct {
|
||||||
Version int
|
Version int
|
||||||
EncryptedContentInfo encryptedContentInfo
|
EncryptedContentInfo encryptedContentInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type recipientInfo struct {
|
|
||||||
Version int
|
|
||||||
IssuerAndSerialNumber issuerAndSerial
|
|
||||||
KeyEncryptionAlgorithm pkix.AlgorithmIdentifier
|
|
||||||
EncryptedKey []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type encryptedContentInfo struct {
|
|
||||||
ContentType asn1.ObjectIdentifier
|
|
||||||
ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
|
|
||||||
EncryptedContent asn1.RawValue `asn1:"tag:0,optional"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (data envelopedData) GetRecipient(cert *smx509.Certificate) *recipientInfo {
|
|
||||||
for _, recp := range data.RecipientInfos {
|
|
||||||
if isCertMatchForIssuerAndSerial(cert, recp.IssuerAndSerialNumber) {
|
|
||||||
return &recp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (data envelopedData) GetEncryptedContentInfo() *encryptedContentInfo {
|
|
||||||
return &data.EncryptedContentInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrUnsupportedEncryptionAlgorithm is returned when attempting to encrypt
|
|
||||||
// content with an unsupported algorithm.
|
|
||||||
var ErrUnsupportedEncryptionAlgorithm = errors.New("pkcs7: cannot encrypt content: only DES-CBC, AES-CBC, AES-GCM, SM4-CBC and SM4-GCM supported")
|
|
||||||
|
|
||||||
// ErrPSKNotProvided is returned when attempting to encrypt
|
// ErrPSKNotProvided is returned when attempting to encrypt
|
||||||
// using a PSK without actually providing the PSK.
|
// using a PSK without actually providing the PSK.
|
||||||
var ErrPSKNotProvided = errors.New("pkcs7: cannot encrypt content: PSK not provided")
|
var ErrPSKNotProvided = errors.New("pkcs7: cannot encrypt content: PSK not provided")
|
||||||
|
|
||||||
// Encrypt creates and returns an envelope data PKCS7 structure with encrypted
|
|
||||||
// recipient keys for each recipient public key.
|
|
||||||
//
|
|
||||||
// # The algorithm used to perform encryption is determined by the argument cipher
|
|
||||||
//
|
|
||||||
// TODO(fullsailor): Add support for encrypting content with other algorithms
|
|
||||||
func Encrypt(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
|
||||||
return encrypt(cipher, content, recipients, false, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncryptSM creates and returns an envelope data PKCS7 structure with encrypted
|
|
||||||
// recipient keys for each recipient public key.
|
|
||||||
// The OIDs use GM/T 0010 - 2012 set and the encrypted key use ASN.1 format.
|
|
||||||
//
|
|
||||||
// The algorithm used to perform encryption is determined by the argument cipher
|
|
||||||
func EncryptSM(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
|
||||||
return encrypt(cipher, content, recipients, true, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncryptCFCA creates and returns an envelope data PKCS7 structure with encrypted
|
|
||||||
// recipient keys for each recipient public key.
|
|
||||||
// The OIDs use GM/T 0010 - 2012 set and the encrypted key use C1C2C3 format and without 0x4 prefix.
|
|
||||||
//
|
|
||||||
// The algorithm used to perform encryption is determined by the argument cipher
|
|
||||||
func EncryptCFCA(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
|
||||||
return encrypt(cipher, content, recipients, true, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func encrypt(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate, isSM, isCFCA bool) ([]byte, error) {
|
|
||||||
var key []byte
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// Create key
|
|
||||||
key = make([]byte, cipher.KeySize())
|
|
||||||
_, err = rand.Read(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
id, ciphertext, err := cipher.Encrypt(key, content)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
envelope := envelopedData{
|
|
||||||
Version: 0,
|
|
||||||
EncryptedContentInfo: encryptedContentInfo{
|
|
||||||
ContentType: OIDData,
|
|
||||||
ContentEncryptionAlgorithm: *id,
|
|
||||||
EncryptedContent: marshalEncryptedContent(ciphertext),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if isSM {
|
|
||||||
envelope.Version = 1 // follow GB/T 35275-2017 9.1
|
|
||||||
envelope.EncryptedContentInfo.ContentType = SM2OIDData
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare each recipient's encrypted cipher key
|
|
||||||
recipientInfos := make([]recipientInfo, len(recipients))
|
|
||||||
for i, recipient := range recipients {
|
|
||||||
encrypted, err := encryptKey(key, recipient, isCFCA)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ias, err := cert2issuerAndSerial(recipient)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var keyEncryptionAlgorithm asn1.ObjectIdentifier = OIDEncryptionAlgorithmRSA
|
|
||||||
if recipient.SignatureAlgorithm == smx509.SM2WithSM3 {
|
|
||||||
keyEncryptionAlgorithm = OIDKeyEncryptionAlgorithmSM2
|
|
||||||
} else if isSM {
|
|
||||||
return nil, errors.New("pkcs7: Shangmi does not support RSA")
|
|
||||||
}
|
|
||||||
|
|
||||||
info := recipientInfo{
|
|
||||||
Version: 0,
|
|
||||||
IssuerAndSerialNumber: ias,
|
|
||||||
KeyEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
|
||||||
Algorithm: keyEncryptionAlgorithm,
|
|
||||||
},
|
|
||||||
EncryptedKey: encrypted,
|
|
||||||
}
|
|
||||||
if isSM {
|
|
||||||
info.Version = 1 // follow GB/T 35275-2017 9.1
|
|
||||||
}
|
|
||||||
recipientInfos[i] = info
|
|
||||||
}
|
|
||||||
|
|
||||||
envelope.RecipientInfos = recipientInfos
|
|
||||||
|
|
||||||
innerContent, err := asn1.Marshal(envelope)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare outer payload structure
|
|
||||||
wrapper := contentInfo{
|
|
||||||
ContentType: OIDEnvelopedData,
|
|
||||||
Content: asn1.RawValue{Class: asn1.ClassContextSpecific, Tag: 0, IsCompound: true, Bytes: innerContent},
|
|
||||||
}
|
|
||||||
|
|
||||||
if isSM {
|
|
||||||
wrapper.ContentType = SM2OIDEnvelopedData
|
|
||||||
}
|
|
||||||
|
|
||||||
return asn1.Marshal(wrapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncryptUsingPSK creates and returns an encrypted data PKCS7 structure,
|
// EncryptUsingPSK creates and returns an encrypted data PKCS7 structure,
|
||||||
// encrypted using caller provided pre-shared secret.
|
// encrypted using caller provided pre-shared secret.
|
||||||
func EncryptUsingPSK(cipher pkcs.Cipher, content []byte, key []byte) ([]byte, error) {
|
func EncryptUsingPSK(cipher pkcs.Cipher, content []byte, key []byte) ([]byte, error) {
|
||||||
return encryptUsingPSK(false, cipher, content, key)
|
return encryptUsingPSK(cipher, content, key, []asn1.ObjectIdentifier{OIDData, OIDEncryptedData}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncryptSMUsingPSK creates and returns an encrypted data PKCS7 structure,
|
// EncryptSMUsingPSK creates and returns an encrypted data PKCS7 structure,
|
||||||
// encrypted using caller provided pre-shared secret.
|
// encrypted using caller provided pre-shared secret.
|
||||||
// This method uses China Standard OID
|
// This method uses China Standard OID
|
||||||
func EncryptSMUsingPSK(cipher pkcs.Cipher, content []byte, key []byte) ([]byte, error) {
|
func EncryptSMUsingPSK(cipher pkcs.Cipher, content []byte, key []byte) ([]byte, error) {
|
||||||
return encryptUsingPSK(true, cipher, content, key)
|
return encryptUsingPSK(cipher, content, key, []asn1.ObjectIdentifier{SM2OIDData, SM2OIDEncryptedData}, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func encryptUsingPSK(isSM bool, cipher pkcs.Cipher, content []byte, key []byte) ([]byte, error) {
|
func encryptUsingPSK(cipher pkcs.Cipher, content []byte, key []byte, contentTypes []asn1.ObjectIdentifier, version int) ([]byte, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if key == nil {
|
if key == nil {
|
||||||
@ -195,16 +43,8 @@ func encryptUsingPSK(isSM bool, cipher pkcs.Cipher, content []byte, key []byte)
|
|||||||
|
|
||||||
// Prepare encrypted-data content
|
// Prepare encrypted-data content
|
||||||
ed := encryptedData{
|
ed := encryptedData{
|
||||||
Version: 0,
|
Version: version,
|
||||||
EncryptedContentInfo: encryptedContentInfo{
|
EncryptedContentInfo: newEncryptedContent(contentTypes[0], id, marshalEncryptedContent(ciphertext)),
|
||||||
ContentType: OIDData,
|
|
||||||
ContentEncryptionAlgorithm: *id,
|
|
||||||
EncryptedContent: marshalEncryptedContent(ciphertext),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if isSM {
|
|
||||||
ed.Version = 1 // follow GB/T 35275-2017 9.1
|
|
||||||
ed.EncryptedContentInfo.ContentType = SM2OIDData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
innerContent, err := asn1.Marshal(ed)
|
innerContent, err := asn1.Marshal(ed)
|
||||||
@ -212,38 +52,11 @@ func encryptUsingPSK(isSM bool, cipher pkcs.Cipher, content []byte, key []byte)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var contentType asn1.ObjectIdentifier = OIDEncryptedData
|
|
||||||
if isSM {
|
|
||||||
contentType = SM2OIDEncryptedData
|
|
||||||
}
|
|
||||||
// Prepare outer payload structure
|
// Prepare outer payload structure
|
||||||
wrapper := contentInfo{
|
wrapper := contentInfo{
|
||||||
ContentType: contentType,
|
ContentType: contentTypes[1],
|
||||||
Content: asn1.RawValue{Class: asn1.ClassContextSpecific, Tag: 0, IsCompound: true, Bytes: innerContent},
|
Content: asn1.RawValue{Class: asn1.ClassContextSpecific, Tag: 0, IsCompound: true, Bytes: innerContent},
|
||||||
}
|
}
|
||||||
|
|
||||||
return asn1.Marshal(wrapper)
|
return asn1.Marshal(wrapper)
|
||||||
}
|
}
|
||||||
|
|
||||||
func marshalEncryptedContent(content []byte) asn1.RawValue {
|
|
||||||
asn1Content, _ := asn1.Marshal(content)
|
|
||||||
return asn1.RawValue{Tag: 0, Class: asn1.ClassContextSpecific, Bytes: asn1Content, IsCompound: true}
|
|
||||||
}
|
|
||||||
|
|
||||||
func encryptKey(key []byte, recipient *smx509.Certificate, isCFCA bool) ([]byte, error) {
|
|
||||||
if pub, ok := recipient.PublicKey.(*rsa.PublicKey); ok {
|
|
||||||
return rsa.EncryptPKCS1v15(rand.Reader, pub, key)
|
|
||||||
}
|
|
||||||
if pub, ok := recipient.PublicKey.(*ecdsa.PublicKey); ok && pub.Curve == sm2.P256() {
|
|
||||||
if isCFCA {
|
|
||||||
encryptedKey, err := sm2.Encrypt(rand.Reader, pub, key, sm2.NewPlainEncrypterOpts(sm2.MarshalUncompressed, sm2.C1C2C3))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return encryptedKey[1:], nil
|
|
||||||
} else {
|
|
||||||
return sm2.EncryptASN1(rand.Reader, pub, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, errors.New("pkcs7: only supports RSA/SM2 key")
|
|
||||||
}
|
|
||||||
|
@ -2,131 +2,11 @@ package pkcs7
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/x509"
|
|
||||||
"encoding/pem"
|
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/emmansun/gmsm/pkcs"
|
"github.com/emmansun/gmsm/pkcs"
|
||||||
"github.com/emmansun/gmsm/smx509"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEncrypt(t *testing.T) {
|
|
||||||
ciphers := []pkcs.Cipher{
|
|
||||||
pkcs.DESCBC,
|
|
||||||
pkcs.TripleDESCBC,
|
|
||||||
pkcs.SM4CBC,
|
|
||||||
pkcs.SM4GCM,
|
|
||||||
pkcs.AES128CBC,
|
|
||||||
pkcs.AES192CBC,
|
|
||||||
pkcs.AES256CBC,
|
|
||||||
pkcs.AES128GCM,
|
|
||||||
pkcs.AES192GCM,
|
|
||||||
pkcs.AES256GCM,
|
|
||||||
}
|
|
||||||
sigalgs := []x509.SignatureAlgorithm{
|
|
||||||
x509.SHA1WithRSA,
|
|
||||||
x509.SHA256WithRSA,
|
|
||||||
x509.SHA512WithRSA,
|
|
||||||
smx509.SM2WithSM3,
|
|
||||||
}
|
|
||||||
for _, cipher := range ciphers {
|
|
||||||
for _, sigalg := range sigalgs {
|
|
||||||
plaintext := []byte("Hello Secret World!")
|
|
||||||
cert, err := createTestCertificate(sigalg)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
encrypted, err := Encrypt(cipher, plaintext, []*smx509.Certificate{cert.Certificate})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
p7, err := Parse(encrypted)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("cannot Parse encrypted result: %s", err)
|
|
||||||
}
|
|
||||||
result, err := p7.Decrypt(cert.Certificate, *cert.PrivateKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("cannot Decrypt encrypted result: %s", err)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(plaintext, result) {
|
|
||||||
t.Errorf("encrypted data does not match plaintext:\n\tExpected: %s\n\tActual: %s", plaintext, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncryptSM(t *testing.T) {
|
|
||||||
ciphers := []pkcs.Cipher{
|
|
||||||
pkcs.SM4CBC,
|
|
||||||
pkcs.SM4GCM,
|
|
||||||
}
|
|
||||||
sigalgs := []x509.SignatureAlgorithm{
|
|
||||||
smx509.SM2WithSM3,
|
|
||||||
}
|
|
||||||
for _, cipher := range ciphers {
|
|
||||||
for _, sigalg := range sigalgs {
|
|
||||||
plaintext := []byte("Hello Secret World!")
|
|
||||||
cert, err := createTestCertificate(sigalg)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
encrypted, err := EncryptSM(cipher, plaintext, []*smx509.Certificate{cert.Certificate})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: encrypted})
|
|
||||||
p7, err := Parse(encrypted)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("cannot Parse encrypted result: %s", err)
|
|
||||||
}
|
|
||||||
result, err := p7.Decrypt(cert.Certificate, *cert.PrivateKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("cannot Decrypt encrypted result: %s", err)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(plaintext, result) {
|
|
||||||
t.Errorf("encrypted data does not match plaintext:\n\tExpected: %s\n\tActual: %s", plaintext, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncryptCFCA(t *testing.T) {
|
|
||||||
ciphers := []pkcs.Cipher{
|
|
||||||
pkcs.SM4,
|
|
||||||
pkcs.SM4CBC,
|
|
||||||
pkcs.SM4GCM,
|
|
||||||
}
|
|
||||||
sigalgs := []x509.SignatureAlgorithm{
|
|
||||||
smx509.SM2WithSM3,
|
|
||||||
}
|
|
||||||
for _, cipher := range ciphers {
|
|
||||||
for _, sigalg := range sigalgs {
|
|
||||||
plaintext := []byte("Hello Secret World!")
|
|
||||||
cert, err := createTestCertificate(sigalg)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
encrypted, err := EncryptCFCA(cipher, plaintext, []*smx509.Certificate{cert.Certificate})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: encrypted})
|
|
||||||
p7, err := Parse(encrypted)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("cannot Parse encrypted result: %s", err)
|
|
||||||
}
|
|
||||||
result, err := p7.DecryptCFCA(cert.Certificate, *cert.PrivateKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("cannot Decrypt encrypted result: %s", err)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(plaintext, result) {
|
|
||||||
t.Errorf("encrypted data does not match plaintext:\n\tExpected: %s\n\tActual: %s", plaintext, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncryptUsingPSK(t *testing.T) {
|
func TestEncryptUsingPSK(t *testing.T) {
|
||||||
ciphers := []pkcs.Cipher{
|
ciphers := []pkcs.Cipher{
|
||||||
pkcs.DESCBC,
|
pkcs.DESCBC,
|
||||||
|
237
pkcs7/envelope.go
Normal file
237
pkcs7/envelope.go
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
package pkcs7
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/asn1"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/emmansun/gmsm/pkcs"
|
||||||
|
"github.com/emmansun/gmsm/sm2"
|
||||||
|
"github.com/emmansun/gmsm/smx509"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EnvelopedData struct {
|
||||||
|
ed envelopedData
|
||||||
|
key []byte
|
||||||
|
contentType asn1.ObjectIdentifier
|
||||||
|
encryptedContentType asn1.ObjectIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
type envelopedData struct {
|
||||||
|
Version int
|
||||||
|
RecipientInfos []recipientInfo `asn1:"set"`
|
||||||
|
EncryptedContentInfo encryptedContentInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type recipientInfo struct {
|
||||||
|
Version int
|
||||||
|
IssuerAndSerialNumber issuerAndSerial
|
||||||
|
KeyEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||||
|
EncryptedKey []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type encryptedContentInfo struct {
|
||||||
|
ContentType asn1.ObjectIdentifier
|
||||||
|
ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||||
|
EncryptedContent asn1.RawValue `asn1:"tag:0,optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data envelopedData) GetRecipient(cert *smx509.Certificate) *recipientInfo {
|
||||||
|
for _, recp := range data.RecipientInfos {
|
||||||
|
if isCertMatchForIssuerAndSerial(cert, recp.IssuerAndSerialNumber) {
|
||||||
|
return &recp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data envelopedData) GetEncryptedContentInfo() *encryptedContentInfo {
|
||||||
|
return &data.EncryptedContentInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUnsupportedEncryptionAlgorithm is returned when attempting to encrypt
|
||||||
|
// content with an unsupported algorithm.
|
||||||
|
var ErrUnsupportedEncryptionAlgorithm = errors.New("pkcs7: cannot encrypt content: only DES-CBC, AES-CBC, AES-GCM, SM4-CBC and SM4-GCM supported")
|
||||||
|
|
||||||
|
// Encrypt creates and returns an envelope data PKCS7 structure with encrypted
|
||||||
|
// recipient keys for each recipient public key.
|
||||||
|
//
|
||||||
|
// # The algorithm used to perform encryption is determined by the argument cipher
|
||||||
|
//
|
||||||
|
// TODO(fullsailor): Add support for encrypting content with other algorithms
|
||||||
|
func Encrypt(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
||||||
|
ed, err := NewEnvelopedData(cipher, content)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, recipient := range recipients {
|
||||||
|
if err := ed.AddRecipient(recipient, 0, func(cert *smx509.Certificate, key []byte) ([]byte, error) {
|
||||||
|
return encryptKey(key, cert, false)
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ed.Finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptSM creates and returns an envelope data PKCS7 structure with encrypted
|
||||||
|
// recipient keys for each recipient public key.
|
||||||
|
// The OIDs use GM/T 0010 - 2012 set and the encrypted key use ASN.1 format.
|
||||||
|
//
|
||||||
|
// The algorithm used to perform encryption is determined by the argument cipher
|
||||||
|
func EncryptSM(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
||||||
|
return encryptSM(cipher, content, recipients, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptCFCA creates and returns an envelope data PKCS7 structure with encrypted
|
||||||
|
// recipient keys for each recipient public key.
|
||||||
|
// The OIDs use GM/T 0010 - 2012 set and the encrypted key use C1C2C3 format and without 0x4 prefix.
|
||||||
|
//
|
||||||
|
// The algorithm used to perform encryption is determined by the argument cipher
|
||||||
|
func EncryptCFCA(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
||||||
|
return encryptSM(cipher, content, recipients, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func encryptSM(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate, isLegacyCFCA bool) ([]byte, error) {
|
||||||
|
ed, err := NewSM2EnvelopedData(cipher, content)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, recipient := range recipients {
|
||||||
|
if err := ed.AddRecipient(recipient, 1, func(cert *smx509.Certificate, key []byte) ([]byte, error) {
|
||||||
|
return encryptKey(key, cert, isLegacyCFCA)
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ed.Finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEnvelopedData creates a new EnvelopedData structure with the provided cipher and content.
|
||||||
|
func NewEnvelopedData(cipher pkcs.Cipher, content []byte) (*EnvelopedData, error) {
|
||||||
|
var key []byte
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Create key
|
||||||
|
key = make([]byte, cipher.KeySize())
|
||||||
|
if _, err = rand.Read(key); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
id, ciphertext, err := cipher.Encrypt(key, content)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ed := &EnvelopedData{}
|
||||||
|
ed.contentType = OIDEnvelopedData
|
||||||
|
ed.encryptedContentType = OIDData
|
||||||
|
ed.key = key
|
||||||
|
ed.ed = envelopedData{
|
||||||
|
Version: 0,
|
||||||
|
EncryptedContentInfo: newEncryptedContent(ed.encryptedContentType, id, marshalEncryptedContent(ciphertext)),
|
||||||
|
}
|
||||||
|
return ed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSM2EnvelopedData creates a new EnvelopedData structure with the provided cipher and content.
|
||||||
|
// The OIDs use GM/T 0010 - 2012 set.
|
||||||
|
func NewSM2EnvelopedData(cipher pkcs.Cipher, content []byte) (*EnvelopedData, error) {
|
||||||
|
var key []byte
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Create key
|
||||||
|
key = make([]byte, cipher.KeySize())
|
||||||
|
if _, err = rand.Read(key); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
id, ciphertext, err := cipher.Encrypt(key, content)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ed := &EnvelopedData{}
|
||||||
|
ed.contentType = SM2OIDEnvelopedData
|
||||||
|
ed.encryptedContentType = SM2OIDData
|
||||||
|
ed.key = key
|
||||||
|
ed.ed = envelopedData{
|
||||||
|
Version: 1,
|
||||||
|
EncryptedContentInfo: newEncryptedContent(ed.encryptedContentType, id, marshalEncryptedContent(ciphertext)),
|
||||||
|
}
|
||||||
|
return ed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRecipient adds a recipient to the EnvelopedData structure.
|
||||||
|
func (ed *EnvelopedData) AddRecipient(cert *smx509.Certificate, version int, encryptKeyFunc func(cert *smx509.Certificate, key []byte) ([]byte, error)) error {
|
||||||
|
encrypted, err := encryptKeyFunc(cert, ed.key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ias, err := cert2issuerAndSerial(cert)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var keyEncryptionAlgorithm asn1.ObjectIdentifier = OIDEncryptionAlgorithmRSA
|
||||||
|
if cert.SignatureAlgorithm == smx509.SM2WithSM3 {
|
||||||
|
keyEncryptionAlgorithm = OIDKeyEncryptionAlgorithmSM2
|
||||||
|
}
|
||||||
|
|
||||||
|
info := recipientInfo{
|
||||||
|
Version: version,
|
||||||
|
IssuerAndSerialNumber: ias,
|
||||||
|
KeyEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
||||||
|
Algorithm: keyEncryptionAlgorithm,
|
||||||
|
},
|
||||||
|
EncryptedKey: encrypted,
|
||||||
|
}
|
||||||
|
ed.ed.RecipientInfos = append(ed.ed.RecipientInfos, info)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish creates the final PKCS7 structure.
|
||||||
|
func (ed *EnvelopedData) Finish() ([]byte, error) {
|
||||||
|
innerContent, err := asn1.Marshal(ed.ed)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare outer payload structure
|
||||||
|
wrapper := contentInfo{
|
||||||
|
ContentType: ed.contentType,
|
||||||
|
Content: asn1.RawValue{Class: asn1.ClassContextSpecific, Tag: 0, IsCompound: true, Bytes: innerContent},
|
||||||
|
}
|
||||||
|
return asn1.Marshal(wrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEncryptedContent(contentType asn1.ObjectIdentifier, alg *pkix.AlgorithmIdentifier, ciphertext asn1.RawValue) encryptedContentInfo {
|
||||||
|
return encryptedContentInfo{
|
||||||
|
ContentType: contentType,
|
||||||
|
ContentEncryptionAlgorithm: *alg,
|
||||||
|
EncryptedContent: ciphertext,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalEncryptedContent(content []byte) asn1.RawValue {
|
||||||
|
asn1Content, _ := asn1.Marshal(content)
|
||||||
|
return asn1.RawValue{Tag: 0, Class: asn1.ClassContextSpecific, Bytes: asn1Content, IsCompound: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func encryptKey(key []byte, recipient *smx509.Certificate, isCFCA bool) ([]byte, error) {
|
||||||
|
if pub, ok := recipient.PublicKey.(*rsa.PublicKey); ok {
|
||||||
|
return rsa.EncryptPKCS1v15(rand.Reader, pub, key)
|
||||||
|
}
|
||||||
|
if pub, ok := recipient.PublicKey.(*ecdsa.PublicKey); ok && pub.Curve == sm2.P256() {
|
||||||
|
if isCFCA {
|
||||||
|
encryptedKey, err := sm2.Encrypt(rand.Reader, pub, key, sm2.NewPlainEncrypterOpts(sm2.MarshalUncompressed, sm2.C1C2C3))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return encryptedKey[1:], nil
|
||||||
|
} else {
|
||||||
|
return sm2.EncryptASN1(rand.Reader, pub, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("pkcs7: only supports RSA/SM2 key")
|
||||||
|
}
|
128
pkcs7/envelope_test.go
Normal file
128
pkcs7/envelope_test.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
package pkcs7
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/pem"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/emmansun/gmsm/pkcs"
|
||||||
|
"github.com/emmansun/gmsm/smx509"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEncrypt(t *testing.T) {
|
||||||
|
ciphers := []pkcs.Cipher{
|
||||||
|
pkcs.DESCBC,
|
||||||
|
pkcs.TripleDESCBC,
|
||||||
|
pkcs.SM4CBC,
|
||||||
|
pkcs.SM4GCM,
|
||||||
|
pkcs.AES128CBC,
|
||||||
|
pkcs.AES192CBC,
|
||||||
|
pkcs.AES256CBC,
|
||||||
|
pkcs.AES128GCM,
|
||||||
|
pkcs.AES192GCM,
|
||||||
|
pkcs.AES256GCM,
|
||||||
|
}
|
||||||
|
sigalgs := []x509.SignatureAlgorithm{
|
||||||
|
x509.SHA1WithRSA,
|
||||||
|
x509.SHA256WithRSA,
|
||||||
|
x509.SHA512WithRSA,
|
||||||
|
smx509.SM2WithSM3,
|
||||||
|
}
|
||||||
|
for _, cipher := range ciphers {
|
||||||
|
for _, sigalg := range sigalgs {
|
||||||
|
plaintext := []byte("Hello Secret World!")
|
||||||
|
cert, err := createTestCertificate(sigalg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
encrypted, err := Encrypt(cipher, plaintext, []*smx509.Certificate{cert.Certificate})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
p7, err := Parse(encrypted)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot Parse encrypted result: %s", err)
|
||||||
|
}
|
||||||
|
result, err := p7.Decrypt(cert.Certificate, *cert.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot Decrypt encrypted result: %s", err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(plaintext, result) {
|
||||||
|
t.Errorf("encrypted data does not match plaintext:\n\tExpected: %s\n\tActual: %s", plaintext, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncryptSM(t *testing.T) {
|
||||||
|
ciphers := []pkcs.Cipher{
|
||||||
|
pkcs.SM4CBC,
|
||||||
|
pkcs.SM4GCM,
|
||||||
|
}
|
||||||
|
sigalgs := []x509.SignatureAlgorithm{
|
||||||
|
smx509.SM2WithSM3,
|
||||||
|
}
|
||||||
|
for _, cipher := range ciphers {
|
||||||
|
for _, sigalg := range sigalgs {
|
||||||
|
plaintext := []byte("Hello Secret World!")
|
||||||
|
cert, err := createTestCertificate(sigalg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
encrypted, err := EncryptSM(cipher, plaintext, []*smx509.Certificate{cert.Certificate})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: encrypted})
|
||||||
|
p7, err := Parse(encrypted)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot Parse encrypted result: %s", err)
|
||||||
|
}
|
||||||
|
result, err := p7.Decrypt(cert.Certificate, *cert.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot Decrypt encrypted result: %s", err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(plaintext, result) {
|
||||||
|
t.Errorf("encrypted data does not match plaintext:\n\tExpected: %s\n\tActual: %s", plaintext, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncryptCFCA(t *testing.T) {
|
||||||
|
ciphers := []pkcs.Cipher{
|
||||||
|
pkcs.SM4,
|
||||||
|
pkcs.SM4CBC,
|
||||||
|
pkcs.SM4GCM,
|
||||||
|
}
|
||||||
|
sigalgs := []x509.SignatureAlgorithm{
|
||||||
|
smx509.SM2WithSM3,
|
||||||
|
}
|
||||||
|
for _, cipher := range ciphers {
|
||||||
|
for _, sigalg := range sigalgs {
|
||||||
|
plaintext := []byte("Hello Secret World!")
|
||||||
|
cert, err := createTestCertificate(sigalg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
encrypted, err := EncryptCFCA(cipher, plaintext, []*smx509.Certificate{cert.Certificate})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: encrypted})
|
||||||
|
p7, err := Parse(encrypted)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot Parse encrypted result: %s", err)
|
||||||
|
}
|
||||||
|
result, err := p7.DecryptCFCA(cert.Certificate, *cert.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot Decrypt encrypted result: %s", err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(plaintext, result) {
|
||||||
|
t.Errorf("encrypted data does not match plaintext:\n\tExpected: %s\n\tActual: %s", plaintext, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,9 +22,9 @@ type SignedData struct {
|
|||||||
sd signedData
|
sd signedData
|
||||||
certs []*smx509.Certificate
|
certs []*smx509.Certificate
|
||||||
data, messageDigest []byte
|
data, messageDigest []byte
|
||||||
|
contentTypeOid asn1.ObjectIdentifier
|
||||||
digestOid asn1.ObjectIdentifier
|
digestOid asn1.ObjectIdentifier
|
||||||
encryptionOid asn1.ObjectIdentifier
|
encryptionOid asn1.ObjectIdentifier
|
||||||
isSM bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSignedData takes data and initializes a PKCS7 SignedData struct that is
|
// NewSignedData takes data and initializes a PKCS7 SignedData struct that is
|
||||||
@ -43,7 +43,7 @@ func NewSignedData(data []byte) (*SignedData, error) {
|
|||||||
ContentInfo: ci,
|
ContentInfo: ci,
|
||||||
Version: 1,
|
Version: 1,
|
||||||
}
|
}
|
||||||
return &SignedData{sd: sd, data: data, digestOid: OIDDigestAlgorithmSHA1, isSM: false}, nil
|
return &SignedData{sd: sd, data: data, digestOid: OIDDigestAlgorithmSHA1, contentTypeOid: OIDSignedData}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSMSignedData takes data and initializes a PKCS7 SignedData struct that is
|
// NewSMSignedData takes data and initializes a PKCS7 SignedData struct that is
|
||||||
@ -56,7 +56,7 @@ func NewSMSignedData(data []byte) (*SignedData, error) {
|
|||||||
}
|
}
|
||||||
sd.sd.ContentInfo.ContentType = SM2OIDData
|
sd.sd.ContentInfo.ContentType = SM2OIDData
|
||||||
sd.digestOid = OIDDigestAlgorithmSM3
|
sd.digestOid = OIDDigestAlgorithmSM3
|
||||||
sd.isSM = true
|
sd.contentTypeOid = SM2OIDSignedData
|
||||||
return sd, nil
|
return sd, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,10 +300,7 @@ func (sd *SignedData) AddCertificate(cert *smx509.Certificate) {
|
|||||||
// Detach removes content from the signed data struct to make it a detached signature.
|
// Detach removes content from the signed data struct to make it a detached signature.
|
||||||
// This must be called right before Finish()
|
// This must be called right before Finish()
|
||||||
func (sd *SignedData) Detach() {
|
func (sd *SignedData) Detach() {
|
||||||
sd.sd.ContentInfo = contentInfo{ContentType: OIDData}
|
sd.sd.ContentInfo.Content = asn1.RawValue{}
|
||||||
if sd.isSM {
|
|
||||||
sd.sd.ContentInfo.ContentType = SM2OIDData
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSignedData returns the private Signed Data
|
// GetSignedData returns the private Signed Data
|
||||||
@ -321,12 +318,9 @@ func (sd *SignedData) Finish() ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
outer := contentInfo{
|
outer := contentInfo{
|
||||||
ContentType: OIDSignedData,
|
ContentType: sd.contentTypeOid,
|
||||||
Content: asn1.RawValue{Class: asn1.ClassContextSpecific, Tag: 0, Bytes: inner, IsCompound: true},
|
Content: asn1.RawValue{Class: asn1.ClassContextSpecific, Tag: 0, Bytes: inner, IsCompound: true},
|
||||||
}
|
}
|
||||||
if sd.isSM {
|
|
||||||
outer.ContentType = SM2OIDSignedData
|
|
||||||
}
|
|
||||||
return asn1.Marshal(outer)
|
return asn1.Marshal(outer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,8 +129,8 @@ type SignedAndEnvelopedData struct {
|
|||||||
sed signedEnvelopedData
|
sed signedEnvelopedData
|
||||||
certs []*smx509.Certificate
|
certs []*smx509.Certificate
|
||||||
data, cek []byte
|
data, cek []byte
|
||||||
|
contentTypeOid asn1.ObjectIdentifier
|
||||||
digestOid asn1.ObjectIdentifier
|
digestOid asn1.ObjectIdentifier
|
||||||
isSM bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSignedAndEnvelopedData takes data and cipher and initializes a new PKCS7 SignedAndEnvelopedData structure
|
// NewSignedAndEnvelopedData takes data and cipher and initializes a new PKCS7 SignedAndEnvelopedData structure
|
||||||
@ -160,7 +160,7 @@ func NewSignedAndEnvelopedData(data []byte, cipher pkcs.Cipher) (*SignedAndEnvel
|
|||||||
EncryptedContent: marshalEncryptedContent(ciphertext),
|
EncryptedContent: marshalEncryptedContent(ciphertext),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return &SignedAndEnvelopedData{sed: sed, data: data, cek: key, digestOid: OIDDigestAlgorithmSHA1, isSM: false}, nil
|
return &SignedAndEnvelopedData{sed: sed, data: data, cek: key, digestOid: OIDDigestAlgorithmSHA1, contentTypeOid: OIDSignedEnvelopedData}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSMSignedAndEnvelopedData takes data and cipher and initializes a new PKCS7(SM) SignedAndEnvelopedData structure
|
// NewSMSignedAndEnvelopedData takes data and cipher and initializes a new PKCS7(SM) SignedAndEnvelopedData structure
|
||||||
@ -170,8 +170,8 @@ func NewSMSignedAndEnvelopedData(data []byte, cipher pkcs.Cipher) (*SignedAndEnv
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
sd.contentTypeOid = SM2OIDSignedEnvelopedData
|
||||||
sd.digestOid = OIDDigestAlgorithmSM3
|
sd.digestOid = OIDDigestAlgorithmSM3
|
||||||
sd.isSM = true
|
|
||||||
sd.sed.EncryptedContentInfo.ContentType = SM2OIDData
|
sd.sed.EncryptedContentInfo.ContentType = SM2OIDData
|
||||||
return sd, nil
|
return sd, nil
|
||||||
}
|
}
|
||||||
@ -223,10 +223,11 @@ func (saed *SignedAndEnvelopedData) AddSignerChain(ee *smx509.Certificate, pkey
|
|||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("pkcs7: private key does not implement crypto.Signer")
|
return errors.New("pkcs7: private key does not implement crypto.Signer")
|
||||||
}
|
}
|
||||||
|
|
||||||
var signOpt crypto.SignerOpts
|
var signOpt crypto.SignerOpts
|
||||||
var tobeSigned []byte
|
var tobeSigned []byte
|
||||||
|
|
||||||
if saed.isSM {
|
if _, isSM2 := pkey.(sm2.Signer); isSM2 {
|
||||||
signOpt = sm2.DefaultSM2SignerOpts
|
signOpt = sm2.DefaultSM2SignerOpts
|
||||||
tobeSigned = saed.data
|
tobeSigned = saed.data
|
||||||
} else {
|
} else {
|
||||||
@ -272,8 +273,6 @@ func (saed *SignedAndEnvelopedData) AddRecipient(recipient *smx509.Certificate)
|
|||||||
var keyEncryptionAlgorithm asn1.ObjectIdentifier = OIDEncryptionAlgorithmRSA
|
var keyEncryptionAlgorithm asn1.ObjectIdentifier = OIDEncryptionAlgorithmRSA
|
||||||
if recipient.SignatureAlgorithm == smx509.SM2WithSM3 {
|
if recipient.SignatureAlgorithm == smx509.SM2WithSM3 {
|
||||||
keyEncryptionAlgorithm = OIDKeyEncryptionAlgorithmSM2
|
keyEncryptionAlgorithm = OIDKeyEncryptionAlgorithmSM2
|
||||||
} else if saed.isSM {
|
|
||||||
return errors.New("pkcs7: Shangmi does not support RSA")
|
|
||||||
}
|
}
|
||||||
info := recipientInfo{
|
info := recipientInfo{
|
||||||
Version: 1,
|
Version: 1,
|
||||||
@ -295,11 +294,8 @@ func (saed *SignedAndEnvelopedData) Finish() ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
outer := contentInfo{
|
outer := contentInfo{
|
||||||
ContentType: OIDSignedEnvelopedData,
|
ContentType: saed.contentTypeOid,
|
||||||
Content: asn1.RawValue{Class: asn1.ClassContextSpecific, Tag: 0, Bytes: inner, IsCompound: true},
|
Content: asn1.RawValue{Class: asn1.ClassContextSpecific, Tag: 0, Bytes: inner, IsCompound: true},
|
||||||
}
|
}
|
||||||
if saed.isSM {
|
|
||||||
outer.ContentType = SM2OIDSignedEnvelopedData
|
|
||||||
}
|
|
||||||
return asn1.Marshal(outer)
|
return asn1.Marshal(outer)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user