github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/core/access_contoller/crypto/sdf/sm4key.go (about)

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