mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-22 02:06:18 +08:00
84 lines
2.7 KiB
Go
84 lines
2.7 KiB
Go
// Copyright 2024 Sun Yimin. All rights reserved.
|
|
// Use of this source code is governed by a MIT-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package pkcs7
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/ecdsa"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"errors"
|
|
|
|
"github.com/emmansun/gmsm/sm2"
|
|
"github.com/emmansun/gmsm/smx509"
|
|
)
|
|
|
|
// Session is an interface that provides methods to generate and encrypt/decrypt data keys
|
|
type Session interface {
|
|
// GenerateDataKey returns the data key to be used for encryption
|
|
GenerateDataKey(size int) ([]byte, error)
|
|
|
|
// EncryptdDataKey encrypts the key with the provided certificate public key
|
|
EncryptdDataKey(key []byte, cert *smx509.Certificate, opts any) ([]byte, error)
|
|
|
|
// DecryptDataKey decrypts the key with the provided certificate private key
|
|
DecryptDataKey(key []byte, priv crypto.PrivateKey, cert *smx509.Certificate, opts any) ([]byte, error)
|
|
}
|
|
|
|
// DefaultSession is the default implementation of Session without any special handling (stateless).
|
|
// Custom implementations can be provided to handle key reuse, cache, etc.
|
|
type DefaultSession struct{}
|
|
|
|
func (DefaultSession) GenerateDataKey(size int) ([]byte, error) {
|
|
key := make([]byte, size)
|
|
if _, err := rand.Read(key); err != nil {
|
|
return nil, err
|
|
}
|
|
return key, nil
|
|
}
|
|
|
|
func (DefaultSession) EncryptdDataKey(key []byte, cert *smx509.Certificate, opts any) ([]byte, error) {
|
|
switch pub := cert.PublicKey.(type) {
|
|
case *rsa.PublicKey:
|
|
return rsa.EncryptPKCS1v15(rand.Reader, pub, key)
|
|
case *ecdsa.PublicKey:
|
|
if pub.Curve == sm2.P256() {
|
|
if isLegacyCFCA, ok := opts.(bool); ok && isLegacyCFCA {
|
|
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")
|
|
}
|
|
|
|
func (DefaultSession) DecryptDataKey(key []byte, priv crypto.PrivateKey, cert *smx509.Certificate, opts any) ([]byte, error) {
|
|
switch pkey := priv.(type) {
|
|
case crypto.Decrypter:
|
|
// Generic case to handle anything that provides the crypto.Decrypter interface.
|
|
encryptedKey := key
|
|
var decrypterOpts crypto.DecrypterOpts
|
|
if _, ok := pkey.(*sm2.PrivateKey); ok {
|
|
if isLegacyCFCA, ok := opts.(bool); ok && isLegacyCFCA {
|
|
encryptedKey = make([]byte, len(key)+1)
|
|
encryptedKey[0] = 0x04
|
|
copy(encryptedKey[1:], key)
|
|
decrypterOpts = sm2.NewPlainDecrypterOpts(sm2.C1C2C3)
|
|
}
|
|
}
|
|
contentKey, err := pkey.Decrypt(rand.Reader, encryptedKey, decrypterOpts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return contentKey, nil
|
|
}
|
|
return nil, ErrUnsupportedAlgorithm
|
|
}
|