gitee.com/lh-her-team/common@v1.5.1/crypto/sdf/sm4key.go (about)

     1  package sdf
     2  
     3  import (
     4  	"crypto/rand"
     5  	"fmt"
     6  	"strconv"
     7  
     8  	"gitee.com/lh-her-team/common/crypto/sdf/base"
     9  
    10  	"gitee.com/lh-her-team/common/crypto/sym/util"
    11  
    12  	bccrypto "gitee.com/lh-her-team/common/crypto"
    13  	"gitee.com/lh-her-team/common/crypto/sym/modes"
    14  	"github.com/pkg/errors"
    15  )
    16  
    17  const (
    18  	BLOCK_MODE_ECB = "ECB"
    19  	BLOCK_MODE_CTR = "CTR"
    20  )
    21  
    22  var defaultSM4Opts = &bccrypto.EncOpts{
    23  	EncodingType: modes.PADDING_PKCS5,
    24  	BlockMode:    BLOCK_MODE_ECB,
    25  	EnableMAC:    true,
    26  	Hash:         0,
    27  	Label:        nil,
    28  	EnableASN1:   false,
    29  }
    30  
    31  var _ bccrypto.SymmetricKey = (*sm4Key)(nil)
    32  
    33  type sm4Key struct {
    34  	sdfCtx    *SDFHandle
    35  	keyId     uint
    36  	keyPwd    []byte
    37  	keyType   SDFKeyType
    38  	blockSize int
    39  	keyHandle base.SessionHandle
    40  }
    41  
    42  func NewSecretKey(sdf *SDFHandle, keyId string, keyPwd []byte, tp bccrypto.KeyType) (bccrypto.SymmetricKey, error) {
    43  	if sdf == nil || len(keyId) == 0 {
    44  		return nil, errors.New("Invalid parameter, sdfHandle or keyId is nil")
    45  	}
    46  	//SM4 or AES
    47  	keyType := convertToSDFKeyType(tp)
    48  	//check keyId
    49  	keyIndex, err := strconv.Atoi(keyId)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	session, err := sdf.getSession()
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	defer sdf.returnSession(err, session)
    58  	keyHandle, err := sdf.ctx.SDFGetSymmKeyHandle(session, uint(keyIndex))
    59  	if err != nil {
    60  		return nil, errors.WithMessagef(err, "failed to get sym keyHandle, keyIndex = %d", keyIndex)
    61  	}
    62  	return &sm4Key{
    63  		sdfCtx:    sdf,
    64  		keyId:     uint(keyIndex),
    65  		keyPwd:    keyPwd,
    66  		keyType:   keyType,
    67  		blockSize: 16,
    68  		keyHandle: keyHandle,
    69  	}, nil
    70  }
    71  
    72  func (s *sm4Key) Bytes() ([]byte, error) {
    73  	return []byte(fmt.Sprintf("%d", s.keyId)), nil
    74  }
    75  
    76  func (s *sm4Key) Type() bccrypto.KeyType {
    77  	return bccrypto.SM4
    78  }
    79  
    80  func (s *sm4Key) String() (string, error) {
    81  	return fmt.Sprintf("%d", s.keyId), nil
    82  }
    83  
    84  func (s *sm4Key) Encrypt(plain []byte) ([]byte, error) {
    85  	return s.EncryptWithOpts(plain, defaultSM4Opts)
    86  }
    87  
    88  func (s *sm4Key) EncryptWithOpts(plain []byte, opts *bccrypto.EncOpts) ([]byte, error) {
    89  	if opts == nil {
    90  		opts = defaultSM4Opts
    91  	}
    92  	iv := make([]byte, s.blockSize)
    93  	if _, err := rand.Read(iv); err != nil {
    94  		return nil, err
    95  	}
    96  	var cipherWithPad []byte
    97  	switch opts.BlockMode {
    98  	case modes.BLOCK_MODE_CBC:
    99  		switch opts.EncodingType {
   100  		case modes.PADDING_PKCS5:
   101  			plainWithPad := util.PKCS5Padding(plain, s.blockSize)
   102  			ciphertext, err := s.sdfCtx.SymEncrypt(s.keyHandle, base.SGD_SMS4_CBC, iv, plainWithPad)
   103  			if err != nil {
   104  				return nil, err
   105  			}
   106  			cipherWithPad = append(iv, ciphertext...)
   107  		default:
   108  			return nil, fmt.Errorf("sm4 CBC encryption fails: invalid padding scheme [%s]", opts.EncodingType)
   109  		}
   110  	case BLOCK_MODE_ECB:
   111  		plainWithPad := util.PKCS5Padding(plain, s.blockSize)
   112  		ciphertext, err := s.sdfCtx.SymEncrypt(s.keyHandle, base.SGD_SMS4_ECB, nil, plainWithPad)
   113  		if err != nil {
   114  			return nil, err
   115  		}
   116  		cipherWithPad = ciphertext
   117  	default:
   118  		return nil, fmt.Errorf("sm4 encryption fails: unknown cipher block mode [%s]", opts.BlockMode)
   119  	}
   120  	return cipherWithPad, nil
   121  }
   122  
   123  func (s *sm4Key) Decrypt(ciphertext []byte) ([]byte, error) {
   124  	return s.DecryptWithOpts(ciphertext, defaultSM4Opts)
   125  }
   126  
   127  func (s *sm4Key) DecryptWithOpts(ciphertext []byte, opts *bccrypto.EncOpts) ([]byte, error) {
   128  	if len(ciphertext) < s.blockSize {
   129  		return nil, errors.New("invalid ciphertext length")
   130  	}
   131  	if opts == nil {
   132  		opts = defaultSM4Opts
   133  	}
   134  	switch opts.BlockMode {
   135  	case modes.BLOCK_MODE_CBC:
   136  		switch opts.EncodingType {
   137  		case modes.PADDING_PKCS5:
   138  			iv := ciphertext[:s.blockSize]
   139  			out, err := s.sdfCtx.SymDecrypt(s.keyHandle, base.SGD_SMS4_CBC, iv, ciphertext[s.blockSize:])
   140  			if err != nil {
   141  				return nil, err
   142  			}
   143  			return util.PKCS5UnPadding(out)
   144  		default:
   145  			return nil, fmt.Errorf("sm4 CBC encryption fails: invalid padding scheme [%s]", opts.EncodingType)
   146  		}
   147  	case BLOCK_MODE_ECB:
   148  		out, err := s.sdfCtx.SymDecrypt(s.keyHandle, base.SGD_SMS4_ECB, nil, ciphertext)
   149  		if err != nil {
   150  			return nil, err
   151  		}
   152  		return util.PKCS5UnPadding(out)
   153  	default:
   154  		return nil, fmt.Errorf("sm4 encryption fails: unknown cipher block mode [%s]", opts.BlockMode)
   155  	}
   156  }