gitee.com/h79/goutils@v1.22.10/common/algorithm/pkcs7.go (about)

     1  package algorithm
     2  
     3  import (
     4  	"crypto/aes"
     5  	"crypto/cipher"
     6  	"crypto/rand"
     7  	"encoding/base64"
     8  	"fmt"
     9  	"io"
    10  )
    11  
    12  // PKCS7 for aes
    13  type PKCS7 struct {
    14  }
    15  
    16  func NewPKCS7() *PKCS7 {
    17  	return &PKCS7{}
    18  }
    19  
    20  func (pk *PKCS7) padding(ciphertext []byte, blockSize int) []byte {
    21  	return pkcs7Padding(ciphertext, blockSize)
    22  }
    23  
    24  func (pk *PKCS7) unPadding(data []byte) []byte {
    25  	return pkcs7UnPadding(data)
    26  }
    27  
    28  // aes加密,填充秘钥key的16位,24,32分别对应AES-128, AES-192, or AES-256.
    29  func (pk *PKCS7) aesCbcEncrypt(raw, key []byte, iv []byte) ([]byte, error) {
    30  	block, err := aes.NewCipher(key)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  
    35  	//填充原文
    36  	blockSize := block.BlockSize()
    37  	raw = pk.padding(raw, blockSize)
    38  
    39  	//初始向量IV必须是唯一,但不需要保密
    40  	var cipherText []byte
    41  	if len(iv) < blockSize {
    42  		//block大小 16
    43  		cipherText = make([]byte, blockSize+len(raw))
    44  		iv = cipherText[:blockSize]
    45  		if _, er := io.ReadFull(rand.Reader, iv); er != nil {
    46  			return nil, er
    47  		}
    48  	} else {
    49  		cipherText = make([]byte, len(raw))
    50  		blockSize = 0
    51  	}
    52  	//block大小和初始向量大小一定要一致
    53  	mode := cipher.NewCBCEncrypter(block, iv)
    54  	mode.CryptBlocks(cipherText[blockSize:], raw)
    55  
    56  	return cipherText, nil
    57  }
    58  
    59  func (pk *PKCS7) aesCbcDecrypt(encryptData, aesKey []byte, iv []byte) ([]byte, error) {
    60  	block, err := aes.NewCipher(aesKey)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	blockSize := block.BlockSize()
    66  
    67  	if len(encryptData) < blockSize {
    68  		return nil, fmt.Errorf("ciphertext too short")
    69  	}
    70  
    71  	if len(iv) == 0 {
    72  		iv = encryptData[:blockSize]
    73  		encryptData = encryptData[blockSize:]
    74  	}
    75  	// CBC mode always works in whole blocks.
    76  	if len(encryptData)%blockSize != 0 {
    77  		return nil, fmt.Errorf("ciphertext is not a multiple of the block size")
    78  	}
    79  
    80  	mode := cipher.NewCBCDecrypter(block, iv)
    81  
    82  	// CryptBlocks can work in-place if the two arguments are the same.
    83  	mode.CryptBlocks(encryptData, encryptData)
    84  
    85  	//解填充
    86  	return pk.unPadding(encryptData), nil
    87  }
    88  
    89  // Encrypt PKCS interface
    90  func (pk *PKCS7) Encrypt(raw, key []byte) (string, error) {
    91  	return pk.EncryptIv(raw, key, nil)
    92  }
    93  
    94  // EncryptIv
    95  // 带IV
    96  func (pk *PKCS7) EncryptIv(raw, aesKey []byte, iv []byte) (string, error) {
    97  	data, err := pk.aesCbcEncrypt(raw, aesKey, iv)
    98  	if err != nil {
    99  		return "", err
   100  	}
   101  	return base64.StdEncoding.EncodeToString(data), nil
   102  }
   103  
   104  // Decrypt PKCS interface
   105  func (pk *PKCS7) Decrypt(raw string, key []byte) ([]byte, error) {
   106  	return pk.DecryptIv(raw, key, nil)
   107  }
   108  
   109  // DecryptIv
   110  // 带IV
   111  func (pk *PKCS7) DecryptIv(raw string, aesKey []byte, iv []byte) ([]byte, error) {
   112  	data, err := base64.StdEncoding.DecodeString(raw)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	return pk.aesCbcDecrypt(data, aesKey, iv)
   117  }