github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/sm4/sm4.go (about)

     1  // Copyright 2022 s1ren@github.com/hxx258456.
     2  
     3  package sm4
     4  
     5  import (
     6  	"bytes"
     7  	"crypto/cipher"
     8  	"crypto/rand"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  )
    13  
    14  // PKCS7Padding 根据pkcs7标准填充明文
    15  func PKCS7Padding(src []byte) []byte {
    16  	padding := BlockSize - len(src)%BlockSize
    17  	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    18  	return append(src, padtext...)
    19  }
    20  
    21  // PKCS7UnPadding 根据pkcs7标准去除填充
    22  func PKCS7UnPadding(src []byte) ([]byte, error) {
    23  	length := len(src)
    24  	if length == 0 {
    25  		return nil, errors.New("invalid pkcs7 padding (len(padtext) == 0)")
    26  	}
    27  	unpadding := int(src[length-1])
    28  	if unpadding > BlockSize || unpadding == 0 {
    29  		return nil, fmt.Errorf("invalid pkcs7 padding (unpadding > BlockSize || unpadding == 0). unpadding: %d, BlockSize: %d", unpadding, BlockSize)
    30  	}
    31  
    32  	pad := src[len(src)-unpadding:]
    33  	for i := 0; i < unpadding; i++ {
    34  		if pad[i] != byte(unpadding) {
    35  			return nil, errors.New("invalid pkcs7 padding (pad[i] != unpadding)")
    36  		}
    37  	}
    38  
    39  	return src[:(length - unpadding)], nil
    40  }
    41  
    42  // Sm4EncryptCbc sm4加密,CBC模式
    43  //
    44  //goland:noinspection GoNameStartsWithPackageName
    45  func Sm4EncryptCbc(plainData, key []byte) (iv, encryptData []byte, err error) {
    46  	block, err := NewCipher(key)
    47  	if err != nil {
    48  		return nil, nil, err
    49  	}
    50  	paddedData := PKCS7Padding(plainData)
    51  	encryptData = make([]byte, len(paddedData))
    52  	iv = make([]byte, BlockSize)
    53  	if _, err = io.ReadFull(rand.Reader, iv); err != nil {
    54  		return nil, nil, err
    55  	}
    56  	mode := cipher.NewCBCEncrypter(block, iv)
    57  	mode.CryptBlocks(encryptData, paddedData)
    58  	return
    59  }
    60  
    61  // Sm4DecryptCbc sm4解密,CBC模式
    62  //
    63  //goland:noinspection GoNameStartsWithPackageName
    64  func Sm4DecryptCbc(encryptData, key, iv []byte) (plainData []byte, err error) {
    65  	block, err := NewCipher(key)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	// 长度检查
    70  	length := len(encryptData)
    71  	if length < BlockSize || length%BlockSize != 0 {
    72  		return nil, fmt.Errorf("sm4.Sm4DecryptCbc: 密文长度不正确,不是Block字节数的整数倍. Block字节数: [%d]", BlockSize)
    73  	}
    74  	paddedData := make([]byte, len(encryptData))
    75  	mode := cipher.NewCBCDecrypter(block, iv)
    76  	mode.CryptBlocks(paddedData, encryptData)
    77  	plainData, err = PKCS7UnPadding(paddedData)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	return
    82  }
    83  
    84  // Sm4EncryptCfb sm4加密,CFB模式
    85  //
    86  //goland:noinspection GoNameStartsWithPackageName
    87  func Sm4EncryptCfb(plainData, key []byte) (iv, encryptData []byte, err error) {
    88  	block, err := NewCipher(key)
    89  	if err != nil {
    90  		return nil, nil, err
    91  	}
    92  	encryptData = make([]byte, len(plainData))
    93  	iv = make([]byte, BlockSize)
    94  	if _, err = io.ReadFull(rand.Reader, iv); err != nil {
    95  		return nil, nil, err
    96  	}
    97  	mode := cipher.NewCFBEncrypter(block, iv)
    98  	mode.XORKeyStream(encryptData, plainData)
    99  	return
   100  }
   101  
   102  // Sm4DecryptCfb sm4解密,CFB模式
   103  //
   104  //goland:noinspection GoNameStartsWithPackageName
   105  func Sm4DecryptCfb(encryptData, key, iv []byte) (plainData []byte, err error) {
   106  	block, err := NewCipher(key)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	plainData = make([]byte, len(encryptData))
   111  	mode := cipher.NewCFBDecrypter(block, iv)
   112  	mode.XORKeyStream(plainData, encryptData)
   113  	return
   114  }
   115  
   116  // Sm4EncryptOfb sm4加密,OFB模式
   117  //
   118  //goland:noinspection GoNameStartsWithPackageName
   119  func Sm4EncryptOfb(plainData, key []byte) (iv, encryptData []byte, err error) {
   120  	block, err := NewCipher(key)
   121  	if err != nil {
   122  		return nil, nil, err
   123  	}
   124  	encryptData = make([]byte, len(plainData))
   125  	iv = make([]byte, BlockSize)
   126  	if _, err = io.ReadFull(rand.Reader, iv); err != nil {
   127  		return nil, nil, err
   128  	}
   129  	mode := cipher.NewOFB(block, iv)
   130  	mode.XORKeyStream(encryptData, plainData)
   131  	return
   132  }
   133  
   134  // Sm4DecryptOfb sm4解密,OFB模式
   135  //
   136  //goland:noinspection GoNameStartsWithPackageName
   137  func Sm4DecryptOfb(encryptData, key, iv []byte) (plainData []byte, err error) {
   138  	block, err := NewCipher(key)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  	plainData = make([]byte, len(encryptData))
   143  	mode := cipher.NewOFB(block, iv)
   144  	mode.XORKeyStream(plainData, encryptData)
   145  	return
   146  }
   147  
   148  // Sm4EncryptGcm sm4加密,GCM模式
   149  //
   150  //goland:noinspection GoNameStartsWithPackageName
   151  func Sm4EncryptGcm(plainData, key []byte) (nonce, encryptData []byte, err error) {
   152  	block, err := NewCipher(key)
   153  	if err != nil {
   154  		return nil, nil, err
   155  	}
   156  	sm4gcm, err := cipher.NewGCM(block)
   157  	if err != nil {
   158  		return nil, nil, err
   159  	}
   160  	nonce = make([]byte, sm4gcm.NonceSize())
   161  	_, err = io.ReadFull(rand.Reader, nonce)
   162  	if err != nil {
   163  		return nil, nil, err
   164  	}
   165  	out := sm4gcm.Seal(nonce, nonce, plainData, nil)
   166  	encryptData = out[sm4gcm.NonceSize():]
   167  	return
   168  }
   169  
   170  // Sm4DecryptGcm sm4解密,GCM模式
   171  //
   172  //goland:noinspection GoNameStartsWithPackageName
   173  func Sm4DecryptGcm(encryptData, key, nonce []byte) ([]byte, error) {
   174  	block, err := NewCipher(key)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  	sm4gcm, err := cipher.NewGCM(block)
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  	// nonce, ciphertext := data[:sm4gcm.NonceSize()], data[sm4gcm.NonceSize():]
   183  	out, err := sm4gcm.Open(nil, nonce, encryptData, nil)
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  	return out, nil
   188  }
   189  
   190  // Sm4EncryptGcmWithNonce sm4加密,GCM模式
   191  //
   192  //goland:noinspection GoNameStartsWithPackageName
   193  func Sm4EncryptGcmWithNonce(plainData, key, nonce, dst []byte) (encryptData []byte, err 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 := sm4gcm.Seal(dst, nonce, plainData, dst)
   203  	encryptData = out[len(dst):]
   204  	return
   205  }
   206  
   207  // Sm4DecryptGcmWithNonce sm4解密,GCM模式
   208  //
   209  //goland:noinspection GoNameStartsWithPackageName
   210  func Sm4DecryptGcmWithNonce(encryptData, key, nonce, dst []byte) ([]byte, error) {
   211  	block, err := NewCipher(key)
   212  	if err != nil {
   213  		return nil, err
   214  	}
   215  	sm4gcm, err := cipher.NewGCM(block)
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  	out, err := sm4gcm.Open(encryptData[:0], nonce, encryptData, dst)
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  	return out, nil
   224  }