gitee.com/zhaochuninhefei/gmgo@v0.0.31-0.20240209061119-069254a02979/sm4/sm4.go (about)

     1  // Copyright (c) 2022 zhaochun
     2  // gmgo is licensed under Mulan PSL v2.
     3  // You can use this software according to the terms and conditions of the Mulan PSL v2.
     4  // You may obtain a copy of Mulan PSL v2 at:
     5  //          http://license.coscl.org.cn/MulanPSL2
     6  // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
     7  // See the Mulan PSL v2 for more details.
     8  
     9  package sm4
    10  
    11  import (
    12  	"crypto/cipher"
    13  	"crypto/rand"
    14  	"fmt"
    15  	"gitee.com/zhaochuninhefei/gmgo/utils"
    16  	"io"
    17  )
    18  
    19  // Sm4EncryptCbc sm4加密,CBC模式
    20  //goland:noinspection GoNameStartsWithPackageName
    21  func Sm4EncryptCbc(plainData, key []byte) (iv, encryptData []byte, err error) {
    22  	block, err := NewCipher(key)
    23  	if err != nil {
    24  		return nil, nil, err
    25  	}
    26  	paddedData := utils.PKCS7Padding(plainData, BlockSize)
    27  	encryptData = make([]byte, len(paddedData))
    28  	iv = make([]byte, BlockSize)
    29  	if _, err = io.ReadFull(rand.Reader, iv); err != nil {
    30  		return nil, nil, err
    31  	}
    32  	mode := cipher.NewCBCEncrypter(block, iv)
    33  	mode.CryptBlocks(encryptData, paddedData)
    34  	return
    35  }
    36  
    37  // Sm4EncryptCbcWithIV sm4加密,CBC模式,指定IV
    38  //goland:noinspection GoNameStartsWithPackageName
    39  func Sm4EncryptCbcWithIV(plainData, key, iv []byte) (encryptData []byte, err error) {
    40  	if len(iv) != BlockSize {
    41  		return nil, fmt.Errorf("sm4.Sm4EncryptCbcWithIV: iv长度不正确,不是Block字节数的长度. Block字节数: [%d]", BlockSize)
    42  	}
    43  	block, err := NewCipher(key)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	paddedData := utils.PKCS7Padding(plainData, BlockSize)
    48  	encryptData = make([]byte, len(paddedData))
    49  	mode := cipher.NewCBCEncrypter(block, iv)
    50  	mode.CryptBlocks(encryptData, paddedData)
    51  	return
    52  }
    53  
    54  // Sm4DecryptCbc sm4解密,CBC模式
    55  //goland:noinspection GoNameStartsWithPackageName
    56  func Sm4DecryptCbc(encryptData, key, iv []byte) (plainData []byte, err error) {
    57  	block, err := NewCipher(key)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	// 长度检查
    62  	length := len(encryptData)
    63  	if length < BlockSize || length%BlockSize != 0 {
    64  		return nil, fmt.Errorf("sm4.Sm4DecryptCbc: 密文长度不正确,不是Block字节数的整数倍. Block字节数: [%d]", BlockSize)
    65  	}
    66  	paddedData := make([]byte, len(encryptData))
    67  	mode := cipher.NewCBCDecrypter(block, iv)
    68  	mode.CryptBlocks(paddedData, encryptData)
    69  	plainData, err = utils.PKCS7UnPadding(paddedData, BlockSize)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  	return
    74  }
    75  
    76  // Sm4EncryptCfb sm4加密,CFB模式
    77  //goland:noinspection GoNameStartsWithPackageName
    78  func Sm4EncryptCfb(plainData, key []byte) (iv, encryptData []byte, err error) {
    79  	block, err := NewCipher(key)
    80  	if err != nil {
    81  		return nil, nil, err
    82  	}
    83  	encryptData = make([]byte, len(plainData))
    84  	iv = make([]byte, BlockSize)
    85  	if _, err = io.ReadFull(rand.Reader, iv); err != nil {
    86  		return nil, nil, err
    87  	}
    88  	mode := cipher.NewCFBEncrypter(block, iv)
    89  	mode.XORKeyStream(encryptData, plainData)
    90  	return
    91  }
    92  
    93  // Sm4DecryptCfb sm4解密,CFB模式
    94  //goland:noinspection GoNameStartsWithPackageName
    95  func Sm4DecryptCfb(encryptData, key, iv []byte) (plainData []byte, err error) {
    96  	block, err := NewCipher(key)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  	plainData = make([]byte, len(encryptData))
   101  	mode := cipher.NewCFBDecrypter(block, iv)
   102  	mode.XORKeyStream(plainData, encryptData)
   103  	return
   104  }
   105  
   106  // Sm4EncryptOfb sm4加密,OFB模式
   107  //goland:noinspection GoNameStartsWithPackageName
   108  func Sm4EncryptOfb(plainData, key []byte) (iv, encryptData []byte, err error) {
   109  	block, err := NewCipher(key)
   110  	if err != nil {
   111  		return nil, nil, err
   112  	}
   113  	encryptData = make([]byte, len(plainData))
   114  	iv = make([]byte, BlockSize)
   115  	if _, err = io.ReadFull(rand.Reader, iv); err != nil {
   116  		return nil, nil, err
   117  	}
   118  	mode := cipher.NewOFB(block, iv)
   119  	mode.XORKeyStream(encryptData, plainData)
   120  	return
   121  }
   122  
   123  // Sm4DecryptOfb sm4解密,OFB模式
   124  //goland:noinspection GoNameStartsWithPackageName
   125  func Sm4DecryptOfb(encryptData, key, iv []byte) (plainData []byte, err error) {
   126  	block, err := NewCipher(key)
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  	plainData = make([]byte, len(encryptData))
   131  	mode := cipher.NewOFB(block, iv)
   132  	mode.XORKeyStream(plainData, encryptData)
   133  	return
   134  }
   135  
   136  // Sm4EncryptGcm sm4加密,GCM模式
   137  //goland:noinspection GoNameStartsWithPackageName
   138  func Sm4EncryptGcm(plainData, key []byte) (nonce, encryptData []byte, err error) {
   139  	block, err := NewCipher(key)
   140  	if err != nil {
   141  		return nil, nil, err
   142  	}
   143  	sm4gcm, err := cipher.NewGCM(block)
   144  	if err != nil {
   145  		return nil, nil, err
   146  	}
   147  	nonce = make([]byte, sm4gcm.NonceSize())
   148  	_, err = io.ReadFull(rand.Reader, nonce)
   149  	if err != nil {
   150  		return nil, nil, err
   151  	}
   152  	encryptData = sm4gcm.Seal(nil, nonce, plainData, nil)
   153  	return
   154  }
   155  
   156  // Sm4DecryptGcm sm4解密,GCM模式
   157  //goland:noinspection GoNameStartsWithPackageName
   158  func Sm4DecryptGcm(encryptData, key, nonce []byte) ([]byte, error) {
   159  	block, err := NewCipher(key)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	sm4gcm, err := cipher.NewGCM(block)
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  	// nonce, ciphertext := data[:sm4gcm.NonceSize()], data[sm4gcm.NonceSize():]
   168  	out, err := sm4gcm.Open(nil, nonce, encryptData, nil)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  	return out, nil
   173  }
   174  
   175  // Sm4EncryptGcmWithNonce sm4加密,GCM模式
   176  //goland:noinspection GoNameStartsWithPackageName
   177  func Sm4EncryptGcmWithNonce(plainData, key, nonce, dst []byte) (encryptData []byte, err error) {
   178  	block, err := NewCipher(key)
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  	sm4gcm, err := cipher.NewGCM(block)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  	out := sm4gcm.Seal(dst, nonce, plainData, dst)
   187  	encryptData = out[len(dst):]
   188  	return
   189  }
   190  
   191  // Sm4DecryptGcmWithNonce sm4解密,GCM模式
   192  //goland:noinspection GoNameStartsWithPackageName
   193  func Sm4DecryptGcmWithNonce(encryptData, key, nonce, dst []byte) ([]byte, error) {
   194  	block, err := NewCipher(key)
   195  	if err != nil {
   196  		return nil, err
   197  	}
   198  	sm4gcm, err := cipher.NewGCM(block)
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  	out, err := sm4gcm.Open(encryptData[:0], nonce, encryptData, dst)
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  	return out, nil
   207  }