github.com/gogf/gf@v1.16.9/crypto/gaes/gaes.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  // Package gaes provides useful API for AES encryption/decryption algorithms.
     8  package gaes
     9  
    10  import (
    11  	"bytes"
    12  	"crypto/aes"
    13  	"crypto/cipher"
    14  	"github.com/gogf/gf/errors/gcode"
    15  	"github.com/gogf/gf/errors/gerror"
    16  )
    17  
    18  var (
    19  	// IVDefaultValue is the default value for IV.
    20  	// This can be changed globally.
    21  	IVDefaultValue = "I Love Go Frame!"
    22  )
    23  
    24  // Encrypt is alias of EncryptCBC.
    25  func Encrypt(plainText []byte, key []byte, iv ...[]byte) ([]byte, error) {
    26  	return EncryptCBC(plainText, key, iv...)
    27  }
    28  
    29  // Decrypt is alias of DecryptCBC.
    30  func Decrypt(cipherText []byte, key []byte, iv ...[]byte) ([]byte, error) {
    31  	return DecryptCBC(cipherText, key, iv...)
    32  }
    33  
    34  // EncryptCBC encrypts <plainText> using CBC mode.
    35  // Note that the key must be 16/24/32 bit length.
    36  // The parameter <iv> initialization vector is unnecessary.
    37  func EncryptCBC(plainText []byte, key []byte, iv ...[]byte) ([]byte, error) {
    38  	block, err := aes.NewCipher(key)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	blockSize := block.BlockSize()
    43  	plainText = PKCS5Padding(plainText, blockSize)
    44  	ivValue := ([]byte)(nil)
    45  	if len(iv) > 0 {
    46  		ivValue = iv[0]
    47  	} else {
    48  		ivValue = []byte(IVDefaultValue)
    49  	}
    50  	blockMode := cipher.NewCBCEncrypter(block, ivValue)
    51  	cipherText := make([]byte, len(plainText))
    52  	blockMode.CryptBlocks(cipherText, plainText)
    53  
    54  	return cipherText, nil
    55  }
    56  
    57  // DecryptCBC decrypts <cipherText> using CBC mode.
    58  // Note that the key must be 16/24/32 bit length.
    59  // The parameter <iv> initialization vector is unnecessary.
    60  func DecryptCBC(cipherText []byte, key []byte, iv ...[]byte) ([]byte, error) {
    61  	block, err := aes.NewCipher(key)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	blockSize := block.BlockSize()
    66  	if len(cipherText) < blockSize {
    67  		return nil, gerror.NewCode(gcode.CodeInvalidParameter, "cipherText too short")
    68  	}
    69  	ivValue := ([]byte)(nil)
    70  	if len(iv) > 0 {
    71  		ivValue = iv[0]
    72  	} else {
    73  		ivValue = []byte(IVDefaultValue)
    74  	}
    75  	if len(cipherText)%blockSize != 0 {
    76  		return nil, gerror.NewCode(gcode.CodeInvalidParameter, "cipherText is not a multiple of the block size")
    77  	}
    78  	blockModel := cipher.NewCBCDecrypter(block, ivValue)
    79  	plainText := make([]byte, len(cipherText))
    80  	blockModel.CryptBlocks(plainText, cipherText)
    81  	plainText, e := PKCS5UnPadding(plainText, blockSize)
    82  	if e != nil {
    83  		return nil, e
    84  	}
    85  	return plainText, nil
    86  }
    87  
    88  func PKCS5Padding(src []byte, blockSize int) []byte {
    89  	padding := blockSize - len(src)%blockSize
    90  	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    91  	return append(src, padtext...)
    92  }
    93  
    94  func PKCS5UnPadding(src []byte, blockSize int) ([]byte, error) {
    95  	length := len(src)
    96  	if blockSize <= 0 {
    97  		return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid blocklen")
    98  	}
    99  
   100  	if length%blockSize != 0 || length == 0 {
   101  		return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid data len")
   102  	}
   103  
   104  	unpadding := int(src[length-1])
   105  	if unpadding > blockSize || unpadding == 0 {
   106  		return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid padding")
   107  	}
   108  
   109  	padding := src[length-unpadding:]
   110  	for i := 0; i < unpadding; i++ {
   111  		if padding[i] != byte(unpadding) {
   112  			return nil, gerror.NewCode(gcode.CodeInvalidParameter, "invalid padding")
   113  		}
   114  	}
   115  
   116  	return src[:(length - unpadding)], nil
   117  }
   118  
   119  // EncryptCFB encrypts <plainText> using CFB mode.
   120  // Note that the key must be 16/24/32 bit length.
   121  // The parameter <iv> initialization vector is unnecessary.
   122  func EncryptCFB(plainText []byte, key []byte, padding *int, iv ...[]byte) ([]byte, error) {
   123  	block, err := aes.NewCipher(key)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	blockSize := block.BlockSize()
   128  	plainText, *padding = ZeroPadding(plainText, blockSize)
   129  	ivValue := ([]byte)(nil)
   130  	if len(iv) > 0 {
   131  		ivValue = iv[0]
   132  	} else {
   133  		ivValue = []byte(IVDefaultValue)
   134  	}
   135  	stream := cipher.NewCFBEncrypter(block, ivValue)
   136  	cipherText := make([]byte, len(plainText))
   137  	stream.XORKeyStream(cipherText, plainText)
   138  	return cipherText, nil
   139  }
   140  
   141  // DecryptCFB decrypts <plainText> using CFB mode.
   142  // Note that the key must be 16/24/32 bit length.
   143  // The parameter <iv> initialization vector is unnecessary.
   144  func DecryptCFB(cipherText []byte, key []byte, unPadding int, iv ...[]byte) ([]byte, error) {
   145  	block, err := aes.NewCipher(key)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  	if len(cipherText) < aes.BlockSize {
   150  		return nil, gerror.NewCode(gcode.CodeInvalidParameter, "cipherText too short")
   151  	}
   152  	ivValue := ([]byte)(nil)
   153  	if len(iv) > 0 {
   154  		ivValue = iv[0]
   155  	} else {
   156  		ivValue = []byte(IVDefaultValue)
   157  	}
   158  	stream := cipher.NewCFBDecrypter(block, ivValue)
   159  	plainText := make([]byte, len(cipherText))
   160  	stream.XORKeyStream(plainText, cipherText)
   161  	plainText = ZeroUnPadding(plainText, unPadding)
   162  	return plainText, nil
   163  }
   164  
   165  func ZeroPadding(cipherText []byte, blockSize int) ([]byte, int) {
   166  	padding := blockSize - len(cipherText)%blockSize
   167  	padText := bytes.Repeat([]byte{byte(0)}, padding)
   168  	return append(cipherText, padText...), padding
   169  }
   170  
   171  func ZeroUnPadding(plaintext []byte, unPadding int) []byte {
   172  	length := len(plaintext)
   173  	return plaintext[:(length - unPadding)]
   174  }