mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-26 20:26:19 +08:00
pkcs7: support CFCA legacy SM2 envelope message #225
This commit is contained in:
parent
fbe4073a46
commit
23081971e8
@ -8,6 +8,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/emmansun/gmsm/pkcs"
|
"github.com/emmansun/gmsm/pkcs"
|
||||||
|
"github.com/emmansun/gmsm/sm2"
|
||||||
"github.com/emmansun/gmsm/smx509"
|
"github.com/emmansun/gmsm/smx509"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,6 +25,16 @@ type decryptable interface {
|
|||||||
|
|
||||||
// Decrypt decrypts encrypted content info for recipient cert and private key
|
// Decrypt decrypts encrypted content info for recipient cert and private key
|
||||||
func (p7 *PKCS7) Decrypt(cert *smx509.Certificate, pkey crypto.PrivateKey) ([]byte, error) {
|
func (p7 *PKCS7) Decrypt(cert *smx509.Certificate, pkey crypto.PrivateKey) ([]byte, error) {
|
||||||
|
return p7.decrypt(cert, pkey, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptCFCA decrypts encrypted content info for recipient cert and private key whose SM2 encrypted key is C1C2C3 format
|
||||||
|
// and without 0x4 prefix.
|
||||||
|
func (p7 *PKCS7) DecryptCFCA(cert *smx509.Certificate, pkey crypto.PrivateKey) ([]byte, error) {
|
||||||
|
return p7.decrypt(cert, pkey, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p7 *PKCS7) decrypt(cert *smx509.Certificate, pkey crypto.PrivateKey, isCFCA bool) ([]byte, error) {
|
||||||
decryptableData, ok := p7.raw.(decryptable)
|
decryptableData, ok := p7.raw.(decryptable)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrNotEncryptedContent
|
return nil, ErrNotEncryptedContent
|
||||||
@ -36,7 +47,16 @@ func (p7 *PKCS7) Decrypt(cert *smx509.Certificate, pkey crypto.PrivateKey) ([]by
|
|||||||
switch pkey := pkey.(type) {
|
switch pkey := pkey.(type) {
|
||||||
case crypto.Decrypter:
|
case crypto.Decrypter:
|
||||||
// Generic case to handle anything that provides the crypto.Decrypter interface.
|
// Generic case to handle anything that provides the crypto.Decrypter interface.
|
||||||
contentKey, err := pkey.Decrypt(rand.Reader, recipient.EncryptedKey, nil)
|
encryptedKey := recipient.EncryptedKey
|
||||||
|
var decrypterOpts crypto.DecrypterOpts
|
||||||
|
if _, ok := pkey.(*sm2.PrivateKey); ok && isCFCA {
|
||||||
|
encryptedKey = make([]byte, len(recipient.EncryptedKey)+1)
|
||||||
|
encryptedKey[0] = 0x04
|
||||||
|
copy(encryptedKey[1:], recipient.EncryptedKey)
|
||||||
|
decrypterOpts = sm2.NewPlainDecrypterOpts(sm2.C1C2C3)
|
||||||
|
}
|
||||||
|
|
||||||
|
contentKey, err := pkey.Decrypt(rand.Reader, encryptedKey, decrypterOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -61,11 +61,11 @@ var ErrPSKNotProvided = errors.New("pkcs7: cannot encrypt content: PSK not provi
|
|||||||
// Encrypt creates and returns an envelope data PKCS7 structure with encrypted
|
// Encrypt creates and returns an envelope data PKCS7 structure with encrypted
|
||||||
// recipient keys for each recipient public key.
|
// recipient keys for each recipient public key.
|
||||||
//
|
//
|
||||||
// The algorithm used to perform encryption is determined by the argument cipher
|
// # The algorithm used to perform encryption is determined by the argument cipher
|
||||||
//
|
//
|
||||||
// TODO(fullsailor): Add support for encrypting content with other algorithms
|
// TODO(fullsailor): Add support for encrypting content with other algorithms
|
||||||
func Encrypt(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
func Encrypt(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
||||||
return encrypt(cipher, content, recipients, false)
|
return encrypt(cipher, content, recipients, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncryptSM creates and returns an envelope data PKCS7 structure with encrypted
|
// EncryptSM creates and returns an envelope data PKCS7 structure with encrypted
|
||||||
@ -73,12 +73,20 @@ func Encrypt(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificat
|
|||||||
// The OIDs use GM/T 0010 - 2012 set
|
// The OIDs use GM/T 0010 - 2012 set
|
||||||
//
|
//
|
||||||
// The algorithm used to perform encryption is determined by the argument cipher
|
// The algorithm used to perform encryption is determined by the argument cipher
|
||||||
//
|
|
||||||
func EncryptSM(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
func EncryptSM(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate) ([]byte, error) {
|
||||||
return encrypt(cipher, content, recipients, true)
|
return encrypt(cipher, content, recipients, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func encrypt(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificate, isSM bool) ([]byte, error) {
|
// 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 key []byte
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@ -110,7 +118,7 @@ func encrypt(cipher pkcs.Cipher, content []byte, recipients []*smx509.Certificat
|
|||||||
// Prepare each recipient's encrypted cipher key
|
// Prepare each recipient's encrypted cipher key
|
||||||
recipientInfos := make([]recipientInfo, len(recipients))
|
recipientInfos := make([]recipientInfo, len(recipients))
|
||||||
for i, recipient := range recipients {
|
for i, recipient := range recipients {
|
||||||
encrypted, err := encryptKey(key, recipient)
|
encrypted, err := encryptKey(key, recipient, isCFCA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -217,12 +225,20 @@ func marshalEncryptedContent(content []byte) asn1.RawValue {
|
|||||||
return asn1.RawValue{Tag: 0, Class: 2, Bytes: asn1Content, IsCompound: true}
|
return asn1.RawValue{Tag: 0, Class: 2, Bytes: asn1Content, IsCompound: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
func encryptKey(key []byte, recipient *smx509.Certificate) ([]byte, error) {
|
func encryptKey(key []byte, recipient *smx509.Certificate, isCFCA bool) ([]byte, error) {
|
||||||
if pub, ok := recipient.PublicKey.(*rsa.PublicKey); ok {
|
if pub, ok := recipient.PublicKey.(*rsa.PublicKey); ok {
|
||||||
return rsa.EncryptPKCS1v15(rand.Reader, pub, key)
|
return rsa.EncryptPKCS1v15(rand.Reader, pub, key)
|
||||||
}
|
}
|
||||||
if pub, ok := recipient.PublicKey.(*ecdsa.PublicKey); ok && pub.Curve == sm2.P256() {
|
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 sm2.EncryptASN1(rand.Reader, pub, key)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return nil, errors.New("pkcs7: only supports RSA/SM2 key")
|
return nil, errors.New("pkcs7: only supports RSA/SM2 key")
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,41 @@ func TestEncryptSM(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEncryptCFCA(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 := 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,
|
||||||
|
@ -254,7 +254,7 @@ func (saed *SignedAndEnvelopedData) AddCertificate(cert *smx509.Certificate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (saed *SignedAndEnvelopedData) AddRecipient(recipient *smx509.Certificate) error {
|
func (saed *SignedAndEnvelopedData) AddRecipient(recipient *smx509.Certificate) error {
|
||||||
encryptedKey, err := encryptKey(saed.cek, recipient)
|
encryptedKey, err := encryptKey(saed.cek, recipient, false) //TODO: check if CFCA has such function
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user