github.com/zhongdalu/gf@v1.0.0/g/crypto/gaes/gaes.go (about)

     1  // Copyright 2017 gf Author(https://github.com/zhongdalu/gf). 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/zhongdalu/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  	"errors"
    15  )
    16  
    17  const (
    18  	ivDefValue = "I Love Go Frame!"
    19  )
    20  
    21  // Encrypt is alias of EncryptCBC.
    22  func Encrypt(plainText []byte, key []byte, iv ...[]byte) ([]byte, error) {
    23  	return EncryptCBC(plainText, key, iv...)
    24  }
    25  
    26  // Decrypt is alias of DecryptCBC.
    27  func Decrypt(cipherText []byte, key []byte, iv ...[]byte) ([]byte, error) {
    28  	return DecryptCBC(cipherText, key, iv...)
    29  }
    30  
    31  // AES加密, 使用CBC模式,注意key必须为16/24/32位长度,iv初始化向量为非必需参数。
    32  func EncryptCBC(plainText []byte, key []byte, iv ...[]byte) ([]byte, error) {
    33  	block, err := aes.NewCipher(key)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	blockSize := block.BlockSize()
    38  	plainText = PKCS5Padding(plainText, blockSize)
    39  	ivValue := ([]byte)(nil)
    40  	if len(iv) > 0 {
    41  		ivValue = iv[0]
    42  	} else {
    43  		ivValue = []byte(ivDefValue)
    44  	}
    45  	blockMode := cipher.NewCBCEncrypter(block, ivValue)
    46  	cipherText := make([]byte, len(plainText))
    47  	blockMode.CryptBlocks(cipherText, plainText)
    48  
    49  	return cipherText, nil
    50  }
    51  
    52  // AES解密, 使用CBC模式,注意key必须为16/24/32位长度,iv初始化向量为非必需参数
    53  func DecryptCBC(cipherText []byte, key []byte, iv ...[]byte) ([]byte, error) {
    54  	block, err := aes.NewCipher(key)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	blockSize := block.BlockSize()
    59  	if len(cipherText) < blockSize {
    60  		return nil, errors.New("cipherText too short")
    61  	}
    62  	ivValue := ([]byte)(nil)
    63  	if len(iv) > 0 {
    64  		ivValue = iv[0]
    65  	} else {
    66  		ivValue = []byte(ivDefValue)
    67  	}
    68  	if len(cipherText)%blockSize != 0 {
    69  		return nil, errors.New("cipherText is not a multiple of the block size")
    70  	}
    71  	blockModel := cipher.NewCBCDecrypter(block, ivValue)
    72  	plainText := make([]byte, len(cipherText))
    73  	blockModel.CryptBlocks(plainText, cipherText)
    74  	plainText, e := PKCS5UnPadding(plainText, blockSize)
    75  	if e != nil {
    76  		return nil, e
    77  	}
    78  	return plainText, nil
    79  }
    80  
    81  func PKCS5Padding(src []byte, blockSize int) []byte {
    82  	padding := blockSize - len(src)%blockSize
    83  	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    84  	return append(src, padtext...)
    85  }
    86  
    87  func PKCS5UnPadding(src []byte, blockSize int) ([]byte, error) {
    88  	length := len(src)
    89  	if blockSize <= 0 {
    90  		return nil, errors.New("invalid blocklen")
    91  	}
    92  
    93  	if length%blockSize != 0 || length == 0 {
    94  		return nil, errors.New("invalid data len")
    95  	}
    96  
    97  	unpadding := int(src[length-1])
    98  	if unpadding > blockSize || unpadding == 0 {
    99  		return nil, errors.New("invalid padding")
   100  	}
   101  
   102  	padding := src[length-unpadding:]
   103  	for i := 0; i < unpadding; i++ {
   104  		if padding[i] != byte(unpadding) {
   105  			return nil, errors.New("invalid padding")
   106  		}
   107  	}
   108  
   109  	return src[:(length - unpadding)], nil
   110  }
   111  
   112  // AES加密, 使用CFB模式。
   113  // 注意key必须为16/24/32位长度,padding返回补位长度,iv初始化向量为非必需参数。
   114  func EncryptCFB(plainText []byte, key []byte, padding *int, iv ...[]byte) ([]byte, error) {
   115  	block, err := aes.NewCipher(key)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	blockSize := block.BlockSize()
   120  	plainText, *padding = ZeroPadding(plainText, blockSize) //补位0
   121  	ivValue := ([]byte)(nil)
   122  	if len(iv) > 0 {
   123  		ivValue = iv[0]
   124  	} else {
   125  		ivValue = []byte(ivDefValue)
   126  	}
   127  	stream := cipher.NewCFBEncrypter(block, ivValue)
   128  	cipherText := make([]byte, len(plainText))
   129  	stream.XORKeyStream(cipherText, plainText)
   130  	return cipherText, nil
   131  }
   132  
   133  // AES解密, 使用CFB模式。
   134  // 注意key必须为16/24/32位长度,unpadding为去补位长度,iv初始化向量为非必需参数。
   135  func DecryptCFB(cipherText []byte, key []byte, unpadding int, iv ...[]byte) ([]byte, error) {
   136  	block, err := aes.NewCipher(key)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  	if len(cipherText) < aes.BlockSize {
   141  		return nil, errors.New("cipherText too short")
   142  	}
   143  	ivValue := ([]byte)(nil)
   144  	if len(iv) > 0 {
   145  		ivValue = iv[0]
   146  	} else {
   147  		ivValue = []byte(ivDefValue)
   148  	}
   149  	stream := cipher.NewCFBDecrypter(block, ivValue)
   150  	plainText := make([]byte, len(cipherText))
   151  	stream.XORKeyStream(plainText, cipherText)
   152  	plainText = ZeroUnPadding(plainText, unpadding) //去补位0
   153  	return plainText, nil
   154  }
   155  
   156  func ZeroPadding(ciphertext []byte, blockSize int) ([]byte, int) {
   157  	padding := blockSize - len(ciphertext)%blockSize
   158  	padtext := bytes.Repeat([]byte{byte(0)}, padding)
   159  	return append(ciphertext, padtext...), padding
   160  }
   161  
   162  func ZeroUnPadding(plaintext []byte, unpadding int) []byte {
   163  	length := len(plaintext)
   164  	return plaintext[:(length - unpadding)]
   165  }